diff --git a/.github/actions/bandit-scan/Dockerfile b/.github/actions/bandit-scan/Dockerfile new file mode 100644 index 000000000000..943f04fc8f37 --- /dev/null +++ b/.github/actions/bandit-scan/Dockerfile @@ -0,0 +1,7 @@ +FROM python:3.10-alpine AS base-action + +RUN pip3 install -U setuptools pip bandit + +COPY entrypoint.sh /entrypoint.sh +RUN chmod +x /entrypoint.sh +ENTRYPOINT ["sh","/entrypoint.sh"] diff --git a/.github/actions/bandit-scan/action.yaml b/.github/actions/bandit-scan/action.yaml new file mode 100644 index 000000000000..e0735450f574 --- /dev/null +++ b/.github/actions/bandit-scan/action.yaml @@ -0,0 +1,26 @@ +name: 'Bandit Scan' +description: 'This action performs a security vulnerability scan of python code using bandit library.' +inputs: + bandit-config: + description: 'Bandit configuration file' + required: false + input-dir: + description: 'Directory to scan' + required: false + default: '.' + format: + description: 'Output format (txt, csv, json, xml, yaml). Default: json' + required: false + default: 'json' + output-file: + description: "The report file to produce. Make sure to align your format with the file extension to avoid confusion." + required: false + default: "bandit-scan.json" +runs: + using: 'docker' + image: 'Dockerfile' + args: + - ${{ inputs.format }} + - ${{ inputs.bandit-config }} + - ${{ inputs.input-dir }} + - ${{ inputs.output-file }} diff --git a/.github/actions/bandit-scan/entrypoint.sh b/.github/actions/bandit-scan/entrypoint.sh new file mode 100755 index 000000000000..f52daddd781e --- /dev/null +++ b/.github/actions/bandit-scan/entrypoint.sh @@ -0,0 +1,13 @@ +#!/bin/bash +CFG="-c $2" +if [ -z "$1" ]; then + echo "No path to scan provided" + exit 1 +fi + +if [ -z "$2" ]; then + CFG = "" +fi + +bandit -f "$1" ${CFG} -r "$3" -o "$4" +exit 0 #we want to ignore the exit code of bandit (for now) diff --git a/.github/workflows/chroma-client-integration-test.yml b/.github/workflows/chroma-client-integration-test.yml index a4e70d13baff..25788090ef2e 100644 --- a/.github/workflows/chroma-client-integration-test.yml +++ b/.github/workflows/chroma-client-integration-test.yml @@ -8,7 +8,8 @@ on: branches: - main - '**' - + workflow_dispatch: + jobs: test: timeout-minutes: 90 diff --git a/.github/workflows/chroma-cluster-test.yml b/.github/workflows/chroma-cluster-test.yml new file mode 100644 index 000000000000..5ae873aa1984 --- /dev/null +++ b/.github/workflows/chroma-cluster-test.yml @@ -0,0 +1,31 @@ +name: Chroma Cluster Tests + +on: + push: + branches: + - main + pull_request: + branches: + - main + - '**' + workflow_dispatch: + +jobs: + test: + strategy: + matrix: + python: ['3.7'] + platform: [ubuntu-latest] + testfile: ["chromadb/test/ingest/test_producer_consumer.py"] # Just this one test for now + runs-on: ${{ matrix.platform }} + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Set up Python ${{ matrix.python }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python }} + - name: Install test dependencies + run: python -m pip install -r requirements.txt && python -m pip install -r requirements_dev.txt + - name: Integration Test + run: bin/cluster-test.sh ${{ matrix.testfile }} diff --git a/.github/workflows/chroma-integration-test.yml b/.github/workflows/chroma-integration-test.yml index e4a2b7517f5f..963a7b6ed634 100644 --- a/.github/workflows/chroma-integration-test.yml +++ b/.github/workflows/chroma-integration-test.yml @@ -9,6 +9,7 @@ on: branches: - main - '**' + workflow_dispatch: jobs: test: @@ -16,8 +17,9 @@ jobs: matrix: python: ['3.7'] platform: [ubuntu-latest, windows-latest] - testfile: ["--ignore-glob 'chromadb/test/property/*'", + testfile: ["--ignore-glob 'chromadb/test/property/*' --ignore='chromadb/test/test_cli.py'", "chromadb/test/property/test_add.py", + "chromadb/test/test_cli.py", "chromadb/test/property/test_collections.py", "chromadb/test/property/test_cross_version_persist.py", "chromadb/test/property/test_embeddings.py", diff --git a/.github/workflows/chroma-js-release.yml b/.github/workflows/chroma-js-release.yml new file mode 100644 index 000000000000..62af392c29b6 --- /dev/null +++ b/.github/workflows/chroma-js-release.yml @@ -0,0 +1,42 @@ +name: Chroma Release JS Client + +on: + push: + tags: + - 'js_release_*.*.*' # Match tags in the form js_release_X.Y.Z + - 'js_release_alpha_*.*.*' # Match tags in the form js_release_alpha_X.Y.Z + +jobs: + build-and-release: + runs-on: ubuntu-latest + permissions: write-all + steps: + - name: Check if tag matches the pattern + run: | + if [[ "${{ github.ref }}" =~ ^refs/tags/js_release_alpha_[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "Tag matches the pattern js_release_alpha_X.Y.Z" + echo "NPM_SCRIPT=release_alpha" >> "$GITHUB_ENV" + elif [[ "${{ github.ref }}" =~ ^refs/tags/js_release_[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "Tag matches the pattern js_release_X.Y.Z" + echo "NPM_SCRIPT=release" >> "$GITHUB_ENV" + else + echo "Tag does not match the release tag pattern, exiting workflow" + exit 1 + fi + - name: Checkout + uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Set up JS + uses: actions/setup-node@v3 + with: + node-version: '16.x' + registry-url: 'https://registry.npmjs.org' + - name: Install Client Dev Dependencies + run: npm install + working-directory: ./clients/js/ + - name: npm Test & Publish + run: npm run db:run && PORT=8001 npm run $NPM_SCRIPT + working-directory: ./clients/js/ + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.github/workflows/chroma-release-python-client.yml b/.github/workflows/chroma-release-python-client.yml index eeec25856423..c09c8c90f966 100644 --- a/.github/workflows/chroma-release-python-client.yml +++ b/.github/workflows/chroma-release-python-client.yml @@ -3,14 +3,27 @@ name: Chroma Release Python Client on: push: tags: - - '*' + - '[0-9]+.[0-9]+.[0-9]+' # Match tags in the form X.Y.Z branches: - main - hammad/thin_client jobs: + check_tag: + runs-on: ubuntu-latest + outputs: + tag_matches: ${{ steps.check-tag.outputs.tag_matches }} + steps: + - name: Check Tag + id: check-tag + run: | + if [[ ${{ github.event.ref }} =~ ^refs/tags/[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "tag_matches=true" >> $GITHUB_OUTPUT + fi build-and-release: runs-on: ubuntu-latest + needs: check_tag + if: needs.check_tag.outputs.tag_matches == 'true' permissions: write-all steps: - name: Checkout diff --git a/.github/workflows/chroma-release.yml b/.github/workflows/chroma-release.yml index 6c747637af87..a2f0a988a433 100644 --- a/.github/workflows/chroma-release.yml +++ b/.github/workflows/chroma-release.yml @@ -8,24 +8,38 @@ on: - main env: - REGISTRY: ghcr.io - IMAGE_NAME: "ghcr.io/chroma-core/chroma" + GHCR_IMAGE_NAME: "ghcr.io/chroma-core/chroma" + DOCKERHUB_IMAGE_NAME: "chromadb/chroma" + PLATFORMS: linux/amd64,linux/arm64 #linux/riscv64, linux/arm/v7 jobs: + check_tag: + runs-on: ubuntu-latest + outputs: + tag_matches: ${{ steps.check-tag.outputs.tag_matches }} + steps: + - name: Check Tag + id: check-tag + run: | + if [[ ${{ github.event.ref }} =~ ^refs/tags/[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "tag_matches=true" >> $GITHUB_OUTPUT + fi build-and-release: runs-on: ubuntu-latest + needs: check_tag permissions: write-all -# id-token: write -# contents: read -# deployments: write -# packages: write -# pull-requests: read -# statuses: write steps: - name: Checkout uses: actions/checkout@v3 with: fetch-depth: 0 + # https://github.com/docker/setup-qemu-action - for multiplatform builds + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 + # https://github.com/docker/setup-buildx-action - for multiplatform builds + - name: Set up Docker Buildx + id: buildx + uses: docker/setup-buildx-action@v2 - name: Set up Python uses: actions/setup-python@v4 with: @@ -36,34 +50,38 @@ jobs: run: python -m build - name: Test Client Package run: bin/test-package.sh dist/*.tar.gz - - name: Log in to the Container registry + - name: Log in to the Github Container registry uses: docker/login-action@v2.1.0 with: - registry: ${{ env.REGISTRY }} + registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} + - name: Login to DockerHub + uses: docker/login-action@v2.1.0 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Install setuptools_scm run: python -m pip install setuptools_scm - - name: Get Docker Tag - id: tag - run: echo "tag_name=$IMAGE_NAME:$(bin/version)" >> $GITHUB_OUTPUT + - name: Get Release Version + id: version + run: echo "version=$(python -m setuptools_scm)" >> $GITHUB_OUTPUT - name: Build and push prerelease Docker image - if: "!startsWith(github.ref, 'refs/tags/')" + if: "needs.check_tag.outputs.tag_matches != 'true'" uses: docker/build-push-action@v3.2.0 with: context: . + platforms: ${{ env.PLATFORMS }} push: true - tags: ${{ steps.tag.outputs.tag_name}} + tags: "${{ env.GHCR_IMAGE_NAME }}:${{ steps.version.outputs.version }},${{ env.DOCKERHUB_IMAGE_NAME }}:${{ steps.version.outputs.version }}" - name: Build and push release Docker image - if: "startsWith(github.ref, 'refs/tags/')" + if: "needs.check_tag.outputs.tag_matches == 'true'" uses: docker/build-push-action@v3.2.0 with: context: . + platforms: ${{ env.PLATFORMS }} push: true - tags: "${{ steps.tag.outputs.tag_name }},${{ env.IMAGE_NAME }}:latest" - - name: Get Release Version - id: version - run: echo "version=$(python -m setuptools_scm)" >> $GITHUB_OUTPUT + tags: "${{ env.GHCR_IMAGE_NAME }}:${{ steps.version.outputs.version }},${{ env.DOCKERHUB_IMAGE_NAME }}:${{ steps.version.outputs.version }},${{ env.GHCR_IMAGE_NAME }}:latest,${{ env.DOCKERHUB_IMAGE_NAME }}:latest" - name: Get current date id: builddate run: echo "builddate=$(date +'%Y-%m-%dT%H:%M')" >> $GITHUB_OUTPUT @@ -73,7 +91,7 @@ jobs: password: ${{ secrets.TEST_PYPI_API_TOKEN }} repository_url: https://test.pypi.org/legacy/ - name: Publish to PyPI - if: startsWith(github.ref, 'refs/tags') + if: "needs.check_tag.outputs.tag_matches == 'true'" uses: pypa/gh-action-pypi-publish@release/v1 with: password: ${{ secrets.PYPI_API_TOKEN }} @@ -84,31 +102,32 @@ jobs: aws-region: us-east-1 - name: Generate CloudFormation template id: generate-cf - if: "startsWith(github.ref, 'refs/tags/')" + if: "needs.check_tag.outputs.tag_matches == 'true'" run: "pip install boto3 && python bin/generate_cloudformation.py" - name: Release Tagged Version uses: ncipollo/release-action@v1.11.1 - if: "startsWith(github.ref, 'refs/tags/')" + if: "needs.check_tag.outputs.tag_matches == 'true'" with: body: | Version: `${{steps.version.outputs.version}}` Git ref: `${{github.ref}}` Build Date: `${{steps.builddate.outputs.builddate}}` PIP Package: `chroma-${{steps.version.outputs.version}}.tar.gz` - Docker Image: `${{steps.tag.outputs.tag_name}}` + Github Container Registry Image: `${{ env.GHCR_IMAGE_NAME }}:${{ steps.version.outputs.version }}` + DockerHub Image: `${{ env.DOCKERHUB_IMAGE_NAME }}:${{ steps.version.outputs.version }}` artifacts: "dist/chroma-${{steps.version.outputs.version}}.tar.gz" prerelease: true generateReleaseNotes: true - name: Update Tag uses: richardsimko/update-tag@v1.0.5 - if: "!startsWith(github.ref, 'refs/tags/')" + if: "needs.check_tag.outputs.tag_matches != 'true'" with: tag_name: latest env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Release Latest uses: ncipollo/release-action@v1.11.1 - if: "!startsWith(github.ref, 'refs/tags/')" + if: "needs.check_tag.outputs.tag_matches != 'true'" with: tag: "latest" name: "Latest" @@ -117,7 +136,8 @@ jobs: Git ref: `${{github.ref}}` Build Date: `${{steps.builddate.outputs.builddate}}` PIP Package: `chroma-${{steps.version.outputs.version}}.tar.gz` - Docker Image: `${{steps.tag.outputs.tag_name}}` + Github Container Registry Image: `${{ env.GHCR_IMAGE_NAME }}:${{ steps.version.outputs.version }}` + DockerHub Image: `${{ env.DOCKERHUB_IMAGE_NAME }}:${{ steps.version.outputs.version }}` artifacts: "dist/chroma-${{steps.version.outputs.version}}.tar.gz" allowUpdates: true prerelease: true diff --git a/.github/workflows/chroma-test.yml b/.github/workflows/chroma-test.yml index e0d44c2d6471..90ff2b669409 100644 --- a/.github/workflows/chroma-test.yml +++ b/.github/workflows/chroma-test.yml @@ -9,6 +9,7 @@ on: branches: - main - '**' + workflow_dispatch: jobs: test: diff --git a/.github/workflows/python-vuln.yaml b/.github/workflows/python-vuln.yaml new file mode 100644 index 000000000000..8e6c33a255c3 --- /dev/null +++ b/.github/workflows/python-vuln.yaml @@ -0,0 +1,28 @@ +name: Python Vulnerability Scan +on: + push: + branches: + - '*' + - '*/**' + paths: + - chromadb/** + - clients/python/** + workflow_dispatch: +jobs: + bandit-scan: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + - uses: ./.github/actions/bandit-scan/ + with: + input-dir: '.' + format: 'json' + bandit-config: 'bandit.yaml' + output-file: 'bandit-report.json' + - name: Upload Bandit Report + uses: actions/upload-artifact@v3 + with: + name: bandit-artifact + path: | + bandit-report.json diff --git a/.gitignore b/.gitignore index de36093c7f62..fd4f8aa8a977 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,10 @@ index_data +# Default configuration for persist_directory in chromadb/config.py +# Currently it's located in "./chroma/" +chroma/ + venv .env .chroma diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6b8fbca90794..5b2ed56635e4 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -32,4 +32,4 @@ repos: hooks: - id: mypy args: [--strict, --ignore-missing-imports, --follow-imports=silent, --disable-error-code=type-abstract] - additional_dependencies: ["types-requests", "pydantic", "overrides", "hypothesis", "pytest", "pypika", "numpy"] \ No newline at end of file + additional_dependencies: ["types-requests", "pydantic", "overrides", "hypothesis", "pytest", "pypika", "numpy", "types-protobuf"] diff --git a/DEVELOP.md b/DEVELOP.md index 29f36abb1ff9..f034e07bed38 100644 --- a/DEVELOP.md +++ b/DEVELOP.md @@ -43,7 +43,7 @@ print(api.heartbeat()) 3. With a persistent backend and a small frontend client -Run `docker-compose up -d --build` +Run `chroma run --path /chroma_db_path` ```python import chromadb api = chromadb.HttpClient(host="localhost", port="8000") diff --git a/README.md b/README.md index 7354f7ed9912..25db53b73d8c 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ ```bash pip install chromadb # python client # for javascript, npm install chromadb! -# for client-server mode, docker-compose up -d --build +# for client-server mode, chroma run --path /chroma_db_path ``` The core API is only 4 functions (run our [💡 Google Colab](https://colab.research.google.com/drive/1QEzFyqnoFxq7LUGyP1vzR4iLt9PpCDXv?usp=sharing) or [Replit template](https://replit.com/@swyx/BasicChromaStarter?v=1)): diff --git a/bandit.yaml b/bandit.yaml new file mode 100644 index 000000000000..9a93633ea12a --- /dev/null +++ b/bandit.yaml @@ -0,0 +1,4 @@ +# FILE: bandit.yaml +exclude_dirs: [ 'chromadb/test', 'bin', 'build', 'build', '.git', '.venv', 'venv', 'env','.github','examples','clients/js','.vscode' ] +tests: [ ] +skips: [ ] diff --git a/bin/build b/bin/build deleted file mode 100755 index 5e324198f858..000000000000 --- a/bin/build +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env bash - -docker build . --target chroma_server -t ghcr.io/chroma-core/chroma-server:`bin/version` diff --git a/bin/cluster-test.sh b/bin/cluster-test.sh new file mode 100755 index 000000000000..b7255eae60a5 --- /dev/null +++ b/bin/cluster-test.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +set -e + +function cleanup { + docker compose -f docker-compose.cluster.yml down --rmi local --volumes +} + +trap cleanup EXIT + +docker compose -f docker-compose.cluster.yml up -d --wait pulsar + +export CHROMA_CLUSTER_TEST_ONLY=1 + +echo testing: python -m pytest "$@" +python -m pytest "$@" diff --git a/bin/docker_entrypoint.sh b/bin/docker_entrypoint.sh index 3b0d146c70bb..ce500ee80b91 100755 --- a/bin/docker_entrypoint.sh +++ b/bin/docker_entrypoint.sh @@ -3,4 +3,4 @@ echo "Rebuilding hnsw to ensure architecture compatibility" pip install --force-reinstall --no-cache-dir chroma-hnswlib export IS_PERSISTENT=1 -uvicorn chromadb.app:app --workers 1 --host 0.0.0.0 --port 8000 --proxy-headers --log-config log_config.yml +uvicorn chromadb.app:app --workers 1 --host 0.0.0.0 --port 8000 --proxy-headers --log-config chromadb/log_config.yml diff --git a/bin/integration-test b/bin/integration-test index 1432a96656ab..54b4e387e086 100755 --- a/bin/integration-test +++ b/bin/integration-test @@ -6,6 +6,41 @@ export CHROMA_PORT=8000 function cleanup { docker compose -f docker-compose.test.yml down --rmi local --volumes + rm server.htpasswd .chroma_env +} + +function setup_auth { + local auth_type="$1" + case "$auth_type" in + basic) + docker run --rm --entrypoint htpasswd httpd:2 -Bbn admin admin > server.htpasswd + cat < .chroma_env +CHROMA_SERVER_AUTH_CREDENTIALS_FILE="/chroma/server.htpasswd" +CHROMA_SERVER_AUTH_CREDENTIALS_PROVIDER="chromadb.auth.providers.HtpasswdFileServerAuthCredentialsProvider" +CHROMA_SERVER_AUTH_PROVIDER="chromadb.auth.basic.BasicAuthServerProvider" +EOF + ;; + token) + cat < .chroma_env +CHROMA_SERVER_AUTH_CREDENTIALS="test-token" +CHROMA_SERVER_AUTH_TOKEN_TRANSPORT_HEADER="AUTHORIZATION" +CHROMA_SERVER_AUTH_CREDENTIALS_PROVIDER="chromadb.auth.token.TokenConfigServerAuthCredentialsProvider" +CHROMA_SERVER_AUTH_PROVIDER="chromadb.auth.token.TokenAuthServerProvider" +EOF + ;; + xtoken) + cat < .chroma_env +CHROMA_SERVER_AUTH_CREDENTIALS="test-token" +CHROMA_SERVER_AUTH_TOKEN_TRANSPORT_HEADER="X_CHROMA_TOKEN" +CHROMA_SERVER_AUTH_CREDENTIALS_PROVIDER="chromadb.auth.token.TokenConfigServerAuthCredentialsProvider" +CHROMA_SERVER_AUTH_PROVIDER="chromadb.auth.token.TokenAuthServerProvider" +EOF + ;; + *) + echo "Unknown auth type: $auth_type" + exit 1 + ;; + esac } trap cleanup EXIT @@ -16,11 +51,21 @@ export CHROMA_INTEGRATION_TEST_ONLY=1 export CHROMA_API_IMPL=chromadb.api.fastapi.FastAPI export CHROMA_SERVER_HOST=localhost export CHROMA_SERVER_HTTP_PORT=8000 - -echo testing: python -m pytest "$@" -python -m pytest "$@" +# +#echo testing: python -m pytest "$@" +#python -m pytest "$@" cd clients/js yarn yarn test:run +docker compose down cd ../.. +for auth_type in basic token xtoken; do + echo "Testing $auth_type auth" + setup_auth "$auth_type" + cd clients/js + docker compose --env-file ../../.chroma_env -f ../../docker-compose.test-auth.yml up --build -d + yarn test:run-auth-"$auth_type" + cd ../.. + docker compose down +done diff --git a/chromadb/__init__.py b/chromadb/__init__.py index 566874fc0a95..0ff5244a80f7 100644 --- a/chromadb/__init__.py +++ b/chromadb/__init__.py @@ -44,7 +44,7 @@ __settings = Settings() -__version__ = "0.4.6" +__version__ = "0.4.12" # Workaround to deal with Colab's old sqlite3 version try: diff --git a/chromadb/api/__init__.py b/chromadb/api/__init__.py index c1c83580e9e5..50f2ff1ecef5 100644 --- a/chromadb/api/__init__.py +++ b/chromadb/api/__init__.py @@ -378,3 +378,10 @@ def get_settings(self) -> Settings: """ pass + + @property + @abstractmethod + def max_batch_size(self) -> int: + """Return the maximum number of records that can be submitted in a single call + to submit_embeddings.""" + pass diff --git a/chromadb/api/fastapi.py b/chromadb/api/fastapi.py index bb191cd59f33..2ddd537ebffd 100644 --- a/chromadb/api/fastapi.py +++ b/chromadb/api/fastapi.py @@ -1,6 +1,16 @@ -from typing import Optional, cast +import json +import logging +from typing import Optional, cast, Tuple +from typing import Sequence +from uuid import UUID + +import requests +from overrides import override + +import chromadb.errors as errors +import chromadb.utils.embedding_functions as ef from chromadb.api import API -from chromadb.config import Settings, System +from chromadb.api.models.Collection import Collection from chromadb.api.types import ( Documents, Embeddings, @@ -13,41 +23,107 @@ GetResult, QueryResult, CollectionMetadata, + validate_batch, ) -import chromadb.utils.embedding_functions as ef -import requests -import json -from typing import Sequence -from chromadb.api.models.Collection import Collection -import chromadb.errors as errors -from uuid import UUID +from chromadb.auth import ( + ClientAuthProvider, +) +from chromadb.auth.providers import RequestsClientAuthProtocolAdapter +from chromadb.auth.registry import resolve_provider +from chromadb.config import Settings, System from chromadb.telemetry import Telemetry -from overrides import override +from urllib.parse import urlparse, urlunparse, quote + +logger = logging.getLogger(__name__) class FastAPI(API): _settings: Settings + _max_batch_size: int = -1 + + @staticmethod + def _validate_host(host: str) -> None: + parsed = urlparse(host) + if "/" in host and parsed.scheme not in {"http", "https"}: + raise ValueError( + "Invalid URL. " f"Unrecognized protocol - {parsed.scheme}." + ) + if "/" in host and (not host.startswith("http")): + raise ValueError( + "Invalid URL. " + "Seems that you are trying to pass URL as a host but without specifying the protocol. " + "Please add http:// or https:// to the host." + ) + + @staticmethod + def resolve_url( + chroma_server_host: str, + chroma_server_ssl_enabled: Optional[bool] = False, + default_api_path: Optional[str] = "", + chroma_server_http_port: Optional[int] = 8000, + ) -> str: + _skip_port = False + _chroma_server_host = chroma_server_host + FastAPI._validate_host(_chroma_server_host) + if _chroma_server_host.startswith("http"): + logger.debug("Skipping port as the user is passing a full URL") + _skip_port = True + parsed = urlparse(_chroma_server_host) + + scheme = "https" if chroma_server_ssl_enabled else parsed.scheme or "http" + net_loc = parsed.netloc or parsed.hostname or chroma_server_host + port = ( + ":" + str(parsed.port or chroma_server_http_port) if not _skip_port else "" + ) + path = parsed.path or default_api_path + + if not path or path == net_loc: + path = default_api_path if default_api_path else "" + if not path.endswith(default_api_path or ""): + path = path + default_api_path if default_api_path else "" + full_url = urlunparse( + (scheme, f"{net_loc}{port}", quote(path.replace("//", "/")), "", "", "") + ) + + return full_url def __init__(self, system: System): super().__init__(system) - url_prefix = "https" if system.settings.chroma_server_ssl_enabled else "http" system.settings.require("chroma_server_host") system.settings.require("chroma_server_http_port") self._telemetry_client = self.require(Telemetry) self._settings = system.settings - port_suffix = ( - f":{system.settings.chroma_server_http_port}" - if system.settings.chroma_server_http_port - else "" - ) - self._api_url = ( - f"{url_prefix}://{system.settings.chroma_server_host}{port_suffix}/api/v1" + self._api_url = FastAPI.resolve_url( + chroma_server_host=str(system.settings.chroma_server_host), + chroma_server_http_port=int(str(system.settings.chroma_server_http_port)), + chroma_server_ssl_enabled=system.settings.chroma_server_ssl_enabled, + default_api_path=system.settings.chroma_server_api_default_path, ) self._header = system.settings.chroma_server_headers - self._session = requests.Session() + if ( + system.settings.chroma_client_auth_provider + and system.settings.chroma_client_auth_protocol_adapter + ): + self._auth_provider = self.require( + resolve_provider( + system.settings.chroma_client_auth_provider, ClientAuthProvider + ) + ) + self._adapter = cast( + RequestsClientAuthProtocolAdapter, + system.require( + resolve_provider( + system.settings.chroma_client_auth_protocol_adapter, + RequestsClientAuthProtocolAdapter, + ) + ), + ) + self._session = self._adapter.session + else: + self._session = requests.Session() if self._header is not None: self._session.headers.update(self._header) @@ -222,6 +298,29 @@ def _delete( raise_chroma_error(resp) return cast(IDs, resp.json()) + def _submit_batch( + self, + batch: Tuple[ + IDs, Optional[Embeddings], Optional[Metadatas], Optional[Documents] + ], + url: str, + ) -> requests.Response: + """ + Submits a batch of embeddings to the database + """ + resp = self._session.post( + self._api_url + url, + data=json.dumps( + { + "ids": batch[0], + "embeddings": batch[1], + "metadatas": batch[2], + "documents": batch[3], + } + ), + ) + return resp + @override def _add( self, @@ -235,18 +334,9 @@ def _add( Adds a batch of embeddings to the database - pass in column oriented data lists """ - resp = self._session.post( - self._api_url + "/collections/" + str(collection_id) + "/add", - data=json.dumps( - { - "ids": ids, - "embeddings": embeddings, - "metadatas": metadatas, - "documents": documents, - } - ), - ) - + batch = (ids, embeddings, metadatas, documents) + validate_batch(batch, {"max_batch_size": self.max_batch_size}) + resp = self._submit_batch(batch, "/collections/" + str(collection_id) + "/add") raise_chroma_error(resp) return True @@ -263,18 +353,11 @@ def _update( Updates a batch of embeddings in the database - pass in column oriented data lists """ - resp = self._session.post( - self._api_url + "/collections/" + str(collection_id) + "/update", - data=json.dumps( - { - "ids": ids, - "embeddings": embeddings, - "metadatas": metadatas, - "documents": documents, - } - ), + batch = (ids, embeddings, metadatas, documents) + validate_batch(batch, {"max_batch_size": self.max_batch_size}) + resp = self._submit_batch( + batch, "/collections/" + str(collection_id) + "/update" ) - resp.raise_for_status() return True @@ -291,18 +374,11 @@ def _upsert( Upserts a batch of embeddings in the database - pass in column oriented data lists """ - resp = self._session.post( - self._api_url + "/collections/" + str(collection_id) + "/upsert", - data=json.dumps( - { - "ids": ids, - "embeddings": embeddings, - "metadatas": metadatas, - "documents": documents, - } - ), + batch = (ids, embeddings, metadatas, documents) + validate_batch(batch, {"max_batch_size": self.max_batch_size}) + resp = self._submit_batch( + batch, "/collections/" + str(collection_id) + "/upsert" ) - resp.raise_for_status() return True @@ -360,6 +436,15 @@ def get_settings(self) -> Settings: """Returns the settings of the client""" return self._settings + @property + @override + def max_batch_size(self) -> int: + if self._max_batch_size == -1: + resp = self._session.get(self._api_url + "/pre-flight-checks") + raise_chroma_error(resp) + self._max_batch_size = cast(int, resp.json()["max_batch_size"]) + return self._max_batch_size + def raise_chroma_error(resp: requests.Response) -> None: """Raises an error if the response is not ok, using a ChromaError if possible""" diff --git a/chromadb/api/segment.py b/chromadb/api/segment.py index 7f7712922fa0..00002f46d279 100644 --- a/chromadb/api/segment.py +++ b/chromadb/api/segment.py @@ -1,6 +1,7 @@ from chromadb.api import API from chromadb.config import Settings, System from chromadb.db.system import SysDB +from chromadb.ingest.impl.utils import create_topic_name from chromadb.segment import SegmentManager, MetadataReader, VectorReader from chromadb.telemetry import Telemetry from chromadb.ingest import Producer @@ -26,6 +27,7 @@ validate_update_metadata, validate_where, validate_where_document, + validate_batch, ) from chromadb.telemetry.events import CollectionAddEvent, CollectionDeleteEvent @@ -38,6 +40,7 @@ import logging import re + logger = logging.getLogger(__name__) @@ -128,6 +131,9 @@ def create_collection( coll = t.Collection( id=id, name=name, metadata=metadata, topic=self._topic(id), dimension=None ) + # TODO: Topic creation right now lives in the producer but it should be moved to the coordinator, + # and the producer should just be responsible for publishing messages. Coordinator should + # be responsible for all management of topics. self._producer.create_topic(coll["topic"]) segments = self._manager.create_segments(coll) self._sysdb.create_collection(coll) @@ -241,9 +247,18 @@ def _add( ) -> bool: coll = self._get_collection(collection_id) self._manager.hint_use_collection(collection_id, t.Operation.ADD) - + validate_batch( + (ids, embeddings, metadatas, documents), + {"max_batch_size": self.max_batch_size}, + ) records_to_submit = [] - for r in _records(t.Operation.ADD, ids, embeddings, metadatas, documents): + for r in _records( + t.Operation.ADD, + ids=ids, + embeddings=embeddings, + metadatas=metadatas, + documents=documents, + ): self._validate_embedding_record(coll, r) records_to_submit.append(r) self._producer.submit_embeddings(coll["topic"], records_to_submit) @@ -262,9 +277,18 @@ def _update( ) -> bool: coll = self._get_collection(collection_id) self._manager.hint_use_collection(collection_id, t.Operation.UPDATE) - + validate_batch( + (ids, embeddings, metadatas, documents), + {"max_batch_size": self.max_batch_size}, + ) records_to_submit = [] - for r in _records(t.Operation.UPDATE, ids, embeddings, metadatas, documents): + for r in _records( + t.Operation.UPDATE, + ids=ids, + embeddings=embeddings, + metadatas=metadatas, + documents=documents, + ): self._validate_embedding_record(coll, r) records_to_submit.append(r) self._producer.submit_embeddings(coll["topic"], records_to_submit) @@ -282,9 +306,18 @@ def _upsert( ) -> bool: coll = self._get_collection(collection_id) self._manager.hint_use_collection(collection_id, t.Operation.UPSERT) - + validate_batch( + (ids, embeddings, metadatas, documents), + {"max_batch_size": self.max_batch_size}, + ) records_to_submit = [] - for r in _records(t.Operation.UPSERT, ids, embeddings, metadatas, documents): + for r in _records( + t.Operation.UPSERT, + ids=ids, + embeddings=embeddings, + metadatas=metadatas, + documents=documents, + ): self._validate_embedding_record(coll, r) records_to_submit.append(r) self._producer.submit_embeddings(coll["topic"], records_to_submit) @@ -524,8 +557,13 @@ def reset(self) -> bool: def get_settings(self) -> Settings: return self._settings + @property + @override + def max_batch_size(self) -> int: + return self._producer.max_batch_size + def _topic(self, collection_id: UUID) -> str: - return f"persistent://{self._tenant_id}/{self._topic_ns}/{collection_id}" + return create_topic_name(self._tenant_id, self._topic_ns, str(collection_id)) # TODO: This could potentially cause race conditions in a distributed version of the # system, since the cache is only local. diff --git a/chromadb/api/types.py b/chromadb/api/types.py index dd50a05fc2d1..763672e17788 100644 --- a/chromadb/api/types.py +++ b/chromadb/api/types.py @@ -1,5 +1,4 @@ -from typing import Optional, Union, Sequence, TypeVar, List, Dict, Any - +from typing import Optional, Union, Sequence, TypeVar, List, Dict, Any, Tuple import numpy as np from typing_extensions import Literal, TypedDict, Protocol import chromadb.errors as errors @@ -209,6 +208,8 @@ def validate_where(where: Where) -> Where: if ( key != "$and" and key != "$or" + and key != "$in" + and key != "$nin" and not isinstance(value, (str, int, float, dict)) ): raise ValueError( @@ -240,15 +241,37 @@ def validate_where(where: Where) -> Where: raise ValueError( f"Expected operand value to be an int or a float for operator {operator}, got {operand}" ) - - if operator not in ["$gt", "$gte", "$lt", "$lte", "$ne", "$eq"]: + if operator in ["$in", "$nin"]: + if not isinstance(operand, list): + raise ValueError( + f"Expected operand value to be an list for operator {operator}, got {operand}" + ) + if operator not in [ + "$gt", + "$gte", + "$lt", + "$lte", + "$ne", + "$eq", + "$in", + "$nin", + ]: raise ValueError( - f"Expected where operator to be one of $gt, $gte, $lt, $lte, $ne, $eq, got {operator}" + f"Expected where operator to be one of $gt, $gte, $lt, $lte, $ne, $eq, $in, $nin, " + f"got {operator}" ) - if not isinstance(operand, (str, int, float)): + if not isinstance(operand, (str, int, float, list)): + raise ValueError( + f"Expected where operand value to be a str, int, float, or list of those type, got {operand}" + ) + if isinstance(operand, list) and ( + len(operand) == 0 + or not all(isinstance(x, type(operand[0])) for x in operand) + ): raise ValueError( - f"Expected where operand value to be a str, int, or float, got {operand}" + f"Expected where operand value to be a non-empty list, and all values to obe of the same type " + f"got {operand}" ) return where @@ -360,4 +383,15 @@ def validate_embeddings( raise ValueError( f"Expected each value in the embedding to be a int or float, got {embeddings}" ) + return embeddings.tolist() if isinstance(embeddings, np.ndarray) else embeddings # type: ignore + + +def validate_batch( + batch: Tuple[IDs, Optional[Embeddings], Optional[Metadatas], Optional[Documents]], + limits: Dict[str, Any], +) -> None: + if len(batch[0]) > limits["max_batch_size"]: + raise ValueError( + f"Batch size {len(batch[0])} exceeds maximum batch size {limits['max_batch_size']}" + ) diff --git a/chromadb/auth/__init__.py b/chromadb/auth/__init__.py new file mode 100644 index 000000000000..67f296bb35cc --- /dev/null +++ b/chromadb/auth/__init__.py @@ -0,0 +1,207 @@ +""" +Contains only Auth abstractions, no implementations. +""" +import base64 +import logging +from abc import ABC, abstractmethod +from enum import Enum +from typing import ( + Optional, + Dict, + TypeVar, + Tuple, + Generic, +) + +from overrides import EnforceOverrides, override +from pydantic import SecretStr + +from chromadb.config import ( + Component, + System, +) +from chromadb.errors import ChromaError + +logger = logging.getLogger(__name__) + +T = TypeVar("T") +S = TypeVar("S") + + +class AuthInfoType(Enum): + COOKIE = "cookie" + HEADER = "header" + URL = "url" + METADATA = "metadata" # gRPC + + +class ClientAuthResponse(EnforceOverrides, ABC): + @abstractmethod + def get_auth_info_type(self) -> AuthInfoType: + ... + + @abstractmethod + def get_auth_info(self) -> Tuple[str, SecretStr]: + ... + + +class ClientAuthProvider(Component): + def __init__(self, system: System) -> None: + super().__init__(system) + + @abstractmethod + def authenticate(self) -> ClientAuthResponse: + pass + + +class ClientAuthConfigurationProvider(Component): + def __init__(self, system: System) -> None: + super().__init__(system) + + @abstractmethod + def get_configuration(self) -> Optional[T]: + pass + + +class ClientAuthCredentialsProvider(Component, Generic[T]): + def __init__(self, system: System) -> None: + super().__init__(system) + + @abstractmethod + def get_credentials(self) -> T: + pass + + +class ClientAuthProtocolAdapter(Component, Generic[T]): + def __init__(self, system: System) -> None: + super().__init__(system) + + @abstractmethod + def inject_credentials(self, injection_context: T) -> None: + pass + + +# SERVER-SIDE Abstractions + + +class ServerAuthenticationRequest(EnforceOverrides, ABC, Generic[T]): + @abstractmethod + def get_auth_info( + self, auth_info_type: AuthInfoType, auth_info_id: Optional[str] = None + ) -> T: + """ + This method should return the necessary auth info based on the type of authentication (e.g. header, cookie, url) + and a given id for the respective auth type (e.g. name of the header, cookie, url param). + + :param auth_info_type: The type of auth info to return + :param auth_info_id: The id of the auth info to return + :return: The auth info which can be specific to the implementation + """ + pass + + +class ServerAuthenticationResponse(EnforceOverrides, ABC): + def success(self) -> bool: + raise NotImplementedError() + + +class ServerAuthProvider(Component): + def __init__(self, system: System) -> None: + super().__init__(system) + + @abstractmethod + def authenticate(self, request: ServerAuthenticationRequest[T]) -> bool: + pass + + +class ChromaAuthMiddleware(Component): + def __init__(self, system: System) -> None: + super().__init__(system) + + @abstractmethod + def authenticate( + self, request: ServerAuthenticationRequest[T] + ) -> Optional[ServerAuthenticationResponse]: + ... + + @abstractmethod + def ignore_operation(self, verb: str, path: str) -> bool: + ... + + @abstractmethod + def instrument_server(self, app: T) -> None: + ... + + +class ServerAuthConfigurationProvider(Component): + def __init__(self, system: System) -> None: + super().__init__(system) + + @abstractmethod + def get_configuration(self) -> Optional[T]: + pass + + +class AuthenticationError(ChromaError): + @override + def code(self) -> int: + return 401 + + @classmethod + @override + def name(cls) -> str: + return "AuthenticationError" + + +class AbstractCredentials(EnforceOverrides, ABC, Generic[T]): + """ + The class is used by Auth Providers to encapsulate credentials received from the server + and pass them to a ServerAuthCredentialsProvider. + """ + + @abstractmethod + def get_credentials(self) -> Dict[str, T]: + """ + Returns the data encapsulated by the credentials object. + """ + pass + + +class SecretStrAbstractCredentials(AbstractCredentials[SecretStr]): + @abstractmethod + @override + def get_credentials(self) -> Dict[str, SecretStr]: + """ + Returns the data encapsulated by the credentials object. + """ + pass + + +class BasicAuthCredentials(SecretStrAbstractCredentials): + def __init__(self, username: SecretStr, password: SecretStr) -> None: + self.username = username + self.password = password + + @override + def get_credentials(self) -> Dict[str, SecretStr]: + return {"username": self.username, "password": self.password} + + @staticmethod + def from_header(header: str) -> "BasicAuthCredentials": + """ + Parses a basic auth header and returns a BasicAuthCredentials object. + """ + header = header.replace("Basic ", "") + header = header.strip() + base64_decoded = base64.b64decode(header).decode("utf-8") + username, password = base64_decoded.split(":") + return BasicAuthCredentials(SecretStr(username), SecretStr(password)) + + +class ServerAuthCredentialsProvider(Component): + def __init__(self, system: System) -> None: + super().__init__(system) + + @abstractmethod + def validate_credentials(self, credentials: AbstractCredentials[T]) -> bool: + pass diff --git a/chromadb/auth/basic/__init__.py b/chromadb/auth/basic/__init__.py new file mode 100644 index 000000000000..a03d195e8aed --- /dev/null +++ b/chromadb/auth/basic/__init__.py @@ -0,0 +1,96 @@ +import base64 +import logging +from typing import Tuple, Any, cast + +from overrides import override +from pydantic import SecretStr + +from chromadb.auth import ( + ServerAuthProvider, + ClientAuthProvider, + ServerAuthenticationRequest, + ServerAuthCredentialsProvider, + AuthInfoType, + BasicAuthCredentials, + ClientAuthCredentialsProvider, + ClientAuthResponse, +) +from chromadb.auth.registry import register_provider, resolve_provider +from chromadb.config import System +from chromadb.utils import get_class + +logger = logging.getLogger(__name__) + +__all__ = ["BasicAuthServerProvider", "BasicAuthClientProvider"] + + +class BasicAuthClientAuthResponse(ClientAuthResponse): + def __init__(self, credentials: SecretStr) -> None: + self._credentials = credentials + + @override + def get_auth_info_type(self) -> AuthInfoType: + return AuthInfoType.HEADER + + @override + def get_auth_info(self) -> Tuple[str, SecretStr]: + return "Authorization", SecretStr( + f"Basic {self._credentials.get_secret_value()}" + ) + + +@register_provider("basic") +class BasicAuthClientProvider(ClientAuthProvider): + _credentials_provider: ClientAuthCredentialsProvider[Any] + + def __init__(self, system: System) -> None: + super().__init__(system) + self._settings = system.settings + system.settings.require("chroma_client_auth_credentials_provider") + self._credentials_provider = system.require( + get_class( + str(system.settings.chroma_client_auth_credentials_provider), + ClientAuthCredentialsProvider, + ) + ) + + @override + def authenticate(self) -> ClientAuthResponse: + _creds = self._credentials_provider.get_credentials() + return BasicAuthClientAuthResponse( + SecretStr( + base64.b64encode(f"{_creds.get_secret_value()}".encode("utf-8")).decode( + "utf-8" + ) + ) + ) + + +@register_provider("basic") +class BasicAuthServerProvider(ServerAuthProvider): + _credentials_provider: ServerAuthCredentialsProvider + + def __init__(self, system: System) -> None: + super().__init__(system) + self._settings = system.settings + system.settings.require("chroma_server_auth_credentials_provider") + self._credentials_provider = cast( + ServerAuthCredentialsProvider, + system.require( + resolve_provider( + str(system.settings.chroma_server_auth_credentials_provider), + ServerAuthCredentialsProvider, + ) + ), + ) + + @override + def authenticate(self, request: ServerAuthenticationRequest[Any]) -> bool: + try: + _auth_header = request.get_auth_info(AuthInfoType.HEADER, "Authorization") + return self._credentials_provider.validate_credentials( + BasicAuthCredentials.from_header(_auth_header) + ) + except Exception as e: + logger.error(f"BasicAuthServerProvider.authenticate failed: {repr(e)}") + return False diff --git a/chromadb/auth/fastapi.py b/chromadb/auth/fastapi.py new file mode 100644 index 000000000000..a488ef5f2b36 --- /dev/null +++ b/chromadb/auth/fastapi.py @@ -0,0 +1,121 @@ +# FAST API code +import logging +from typing import Optional, Dict, List, cast, Any + +from overrides import override +from starlette.middleware.base import BaseHTTPMiddleware, RequestResponseEndpoint +from starlette.requests import Request +from starlette.responses import Response, JSONResponse +from starlette.types import ASGIApp + +from chromadb.config import System +from chromadb.auth import ( + ServerAuthenticationRequest, + AuthInfoType, + ServerAuthenticationResponse, + ServerAuthProvider, + ChromaAuthMiddleware, +) +from chromadb.auth.registry import resolve_provider + +logger = logging.getLogger(__name__) + + +class FastAPIServerAuthenticationRequest(ServerAuthenticationRequest[Optional[str]]): + def __init__(self, request: Request) -> None: + self._request = request + + @override + def get_auth_info( + self, auth_info_type: AuthInfoType, auth_info_id: Optional[str] = None + ) -> Optional[str]: + if auth_info_type == AuthInfoType.HEADER: + return str(self._request.headers[auth_info_id]) + elif auth_info_type == AuthInfoType.COOKIE: + return str(self._request.cookies[auth_info_id]) + elif auth_info_type == AuthInfoType.URL: + return str(self._request.query_params[auth_info_id]) + elif auth_info_type == AuthInfoType.METADATA: + raise ValueError("Metadata not supported for FastAPI") + else: + raise ValueError(f"Unknown auth info type: {auth_info_type}") + + +class FastAPIServerAuthenticationResponse(ServerAuthenticationResponse): + _auth_success: bool + + def __init__(self, auth_success: bool) -> None: + self._auth_success = auth_success + + @override + def success(self) -> bool: + return self._auth_success + + +class FastAPIChromaAuthMiddleware(ChromaAuthMiddleware): + _auth_provider: ServerAuthProvider + + def __init__(self, system: System) -> None: + super().__init__(system) + self._system = system + self._settings = system.settings + self._settings.require("chroma_server_auth_provider") + self._ignore_auth_paths: Dict[ + str, List[str] + ] = self._settings.chroma_server_auth_ignore_paths + if self._settings.chroma_server_auth_provider: + logger.debug( + f"Server Auth Provider: {self._settings.chroma_server_auth_provider}" + ) + _cls = resolve_provider( + self._settings.chroma_server_auth_provider, ServerAuthProvider + ) + self._auth_provider = cast(ServerAuthProvider, self.require(_cls)) + + @override + def authenticate( + self, request: ServerAuthenticationRequest[Any] + ) -> Optional[ServerAuthenticationResponse]: + return FastAPIServerAuthenticationResponse( + self._auth_provider.authenticate(request) + ) + + @override + def ignore_operation(self, verb: str, path: str) -> bool: + if ( + path in self._ignore_auth_paths.keys() + and verb.upper() in self._ignore_auth_paths[path] + ): + logger.debug(f"Skipping auth for path {path} and method {verb}") + return True + return False + + @override + def instrument_server(self, app: ASGIApp) -> None: + # We can potentially add an `/auth` endpoint to the server to allow for more complex auth flows + return + + +class FastAPIChromaAuthMiddlewareWrapper(BaseHTTPMiddleware): # type: ignore + def __init__( + self, app: ASGIApp, auth_middleware: FastAPIChromaAuthMiddleware + ) -> None: + super().__init__(app) + self._middleware = auth_middleware + self._middleware.instrument_server(app) + + @override + async def dispatch( + self, request: Request, call_next: RequestResponseEndpoint + ) -> Response: + if self._middleware.ignore_operation(request.method, request.url.path): + logger.debug( + f"Skipping auth for path {request.url.path} and method {request.method}" + ) + return await call_next(request) + response = self._middleware.authenticate( + FastAPIServerAuthenticationRequest(request) + ) + if not response or not response.success(): + return JSONResponse({"error": "Unauthorized"}, status_code=401) + return await call_next(request) diff --git a/chromadb/auth/providers.py b/chromadb/auth/providers.py new file mode 100644 index 000000000000..a3bb23616e28 --- /dev/null +++ b/chromadb/auth/providers.py @@ -0,0 +1,171 @@ +import importlib +import logging +from typing import cast, Dict, TypeVar, Any + +import requests +from overrides import override +from pydantic import SecretStr + +from chromadb.auth import ( + ServerAuthCredentialsProvider, + AbstractCredentials, + ClientAuthCredentialsProvider, + AuthInfoType, + ClientAuthProvider, + ClientAuthProtocolAdapter, +) +from chromadb.auth.registry import register_provider, resolve_provider +from chromadb.config import System + +T = TypeVar("T") + +logger = logging.getLogger(__name__) + + +class HtpasswdServerAuthCredentialsProvider(ServerAuthCredentialsProvider): + _creds: Dict[str, SecretStr] + + def __init__(self, system: System) -> None: + super().__init__(system) + try: + # Equivalent to import onnxruntime + self.bc = importlib.import_module("bcrypt") + except ImportError: + raise ValueError( + "The bcrypt python package is not installed. Please install it with `pip install bcrypt`" + ) + + @override + def validate_credentials(self, credentials: AbstractCredentials[T]) -> bool: + _creds = cast(Dict[str, SecretStr], credentials.get_credentials()) + if len(_creds) != 2: + logger.error( + "Returned credentials did match expected format: dict[username:SecretStr, password: SecretStr]" + ) + return False + if "username" not in _creds or "password" not in _creds: + logger.error("Returned credentials do not contain username or password") + return False + _usr_check = bool( + _creds["username"].get_secret_value() + == self._creds["username"].get_secret_value() + ) + return _usr_check and self.bc.checkpw( + _creds["password"].get_secret_value().encode("utf-8"), + self._creds["password"].get_secret_value().encode("utf-8"), + ) + + +@register_provider("htpasswd_file") +class HtpasswdFileServerAuthCredentialsProvider(HtpasswdServerAuthCredentialsProvider): + def __init__(self, system: System) -> None: + super().__init__(system) + system.settings.require("chroma_server_auth_credentials_file") + _file = str(system.settings.chroma_server_auth_credentials_file) + with open(_file) as f: + _raw_creds = [v for v in f.readline().strip().split(":")] + self._creds = { + "username": SecretStr(_raw_creds[0]), + "password": SecretStr(_raw_creds[1]), + } + if ( + len(self._creds) != 2 + or "username" not in self._creds + or "password" not in self._creds + ): + raise ValueError( + "Invalid Htpasswd credentials found in [chroma_server_auth_credentials]. " + "Must be :." + ) + + +class HtpasswdConfigurationServerAuthCredentialsProvider( + HtpasswdServerAuthCredentialsProvider +): + def __init__(self, system: System) -> None: + super().__init__(system) + system.settings.require("chroma_server_auth_credentials") + _raw_creds = ( + str(system.settings.chroma_server_auth_credentials).strip().split(":") + ) + self._creds = { + "username": SecretStr(_raw_creds[0]), + "password": SecretStr(_raw_creds[1]), + } + if ( + len(self._creds) != 2 + or "username" not in self._creds + or "password" not in self._creds + ): + raise ValueError( + "Invalid Htpasswd credentials found in [chroma_server_auth_credentials]. " + "Must be :." + ) + + +class RequestsClientAuthProtocolAdapter( + ClientAuthProtocolAdapter[requests.PreparedRequest] +): + class _Session(requests.Session): + _protocol_adapter: ClientAuthProtocolAdapter[requests.PreparedRequest] + + def __init__( + self, protocol_adapter: ClientAuthProtocolAdapter[requests.PreparedRequest] + ) -> None: + super().__init__() + self._protocol_adapter = protocol_adapter + + @override + def send( + self, request: requests.PreparedRequest, **kwargs: Any + ) -> requests.Response: + self._protocol_adapter.inject_credentials(request) + return super().send(request, **kwargs) + + _session: _Session + _auth_provider: ClientAuthProvider + + def __init__(self, system: System) -> None: + super().__init__(system) + system.settings.require("chroma_client_auth_provider") + self._auth_provider = cast( + ClientAuthProvider, + system.require( + resolve_provider( + str(system.settings.chroma_client_auth_provider), ClientAuthProvider + ), + ), + ) + self._session = self._Session(self) + self._auth_header = self._auth_provider.authenticate() + + @property + def session(self) -> requests.Session: + return self._session + + @override + def inject_credentials(self, injection_context: requests.PreparedRequest) -> None: + if self._auth_header.get_auth_info_type() == AuthInfoType.HEADER: + _header_info = self._auth_header.get_auth_info() + injection_context.headers[_header_info[0]] = _header_info[ + 1 + ].get_secret_value() + else: + raise ValueError( + f"Unsupported auth type: {self._auth_header.get_auth_info_type()}" + ) + + +class ConfigurationClientAuthCredentialsProvider( + ClientAuthCredentialsProvider[SecretStr] +): + _creds: SecretStr + + def __init__(self, system: System) -> None: + super().__init__(system) + system.settings.require("chroma_client_auth_credentials") + self._creds = SecretStr(str(system.settings.chroma_client_auth_credentials)) + + @override + def get_credentials(self) -> SecretStr: + return self._creds diff --git a/chromadb/auth/registry.py b/chromadb/auth/registry.py new file mode 100644 index 000000000000..7e844753199b --- /dev/null +++ b/chromadb/auth/registry.py @@ -0,0 +1,107 @@ +import importlib +import logging +import pkgutil +from typing import Union, Dict, Type, Callable # noqa: F401 + +from chromadb.auth import ( + ClientAuthConfigurationProvider, + ClientAuthCredentialsProvider, + ClientAuthProtocolAdapter, + ServerAuthProvider, + ServerAuthConfigurationProvider, + ServerAuthCredentialsProvider, + ClientAuthProvider, +) +from chromadb.utils import get_class + +logger = logging.getLogger(__name__) +ProviderTypes = Union[ + "ClientAuthProvider", + "ClientAuthConfigurationProvider", + "ClientAuthCredentialsProvider", + "ServerAuthProvider", + "ServerAuthConfigurationProvider", + "ServerAuthCredentialsProvider", + "ClientAuthProtocolAdapter", +] + +_provider_registry = { + "client_auth_providers": {}, + "client_auth_config_providers": {}, + "client_auth_credentials_providers": {}, + "client_auth_protocol_adapters": {}, + "server_auth_providers": {}, + "server_auth_config_providers": {}, + "server_auth_credentials_providers": {}, +} # type: Dict[str, Dict[str, Type[ProviderTypes]]] + + +def register_classes_from_package(package_name: str) -> None: + package = importlib.import_module(package_name) + for _, module_name, _ in pkgutil.iter_modules(package.__path__): + full_module_name = f"{package_name}.{module_name}" + _ = importlib.import_module(full_module_name) + + +def register_provider( + short_hand: str, +) -> Callable[[Type[ProviderTypes]], Type[ProviderTypes]]: + def decorator(cls: Type[ProviderTypes]) -> Type[ProviderTypes]: + logger.debug("Registering provider: %s", short_hand) + global _provider_registry + if issubclass(cls, ClientAuthProvider): + _provider_registry["client_auth_providers"][short_hand] = cls + elif issubclass(cls, ClientAuthConfigurationProvider): + _provider_registry["client_auth_config_providers"][short_hand] = cls + elif issubclass(cls, ClientAuthCredentialsProvider): + _provider_registry["client_auth_credentials_providers"][short_hand] = cls + elif issubclass(cls, ClientAuthProtocolAdapter): + _provider_registry["client_auth_protocol_adapters"][short_hand] = cls + elif issubclass(cls, ServerAuthProvider): + _provider_registry["server_auth_providers"][short_hand] = cls + elif issubclass(cls, ServerAuthConfigurationProvider): + _provider_registry["server_auth_config_providers"][short_hand] = cls + elif issubclass(cls, ServerAuthCredentialsProvider): + _provider_registry["server_auth_credentials_providers"][short_hand] = cls + else: + raise ValueError( + "Only ClientAuthProvider, ClientAuthConfigurationProvider, " + "ClientAuthCredentialsProvider, ServerAuthProvider, " + "ServerAuthConfigurationProvider, and ServerAuthCredentialsProvider, ClientAuthProtocolAdapter " + "can be registered." + ) + return cls + + return decorator + + +def resolve_provider( + class_or_name: str, cls: Type[ProviderTypes] +) -> Type[ProviderTypes]: + register_classes_from_package("chromadb.auth") + global _provider_registry + if issubclass(cls, ClientAuthProvider): + _key = "client_auth_providers" + elif issubclass(cls, ClientAuthConfigurationProvider): + _key = "client_auth_config_providers" + elif issubclass(cls, ClientAuthCredentialsProvider): + _key = "client_auth_credentials_providers" + elif issubclass(cls, ClientAuthProtocolAdapter): + _key = "client_auth_protocol_adapters" + elif issubclass(cls, ServerAuthProvider): + _key = "server_auth_providers" + elif issubclass(cls, ServerAuthConfigurationProvider): + _key = "server_auth_config_providers" + elif issubclass(cls, ServerAuthCredentialsProvider): + _key = "server_auth_credentials_providers" + else: + raise ValueError( + "Only ClientAuthProvider, ClientAuthConfigurationProvider, " + "ClientAuthCredentialsProvider, ServerAuthProvider, " + "ServerAuthConfigurationProvider, and ServerAuthCredentialsProvider,ClientAuthProtocolAdapter " + "can be registered." + ) + if class_or_name in _provider_registry[_key]: + return _provider_registry[_key][class_or_name] + else: + return get_class(class_or_name, cls) # type: ignore diff --git a/chromadb/auth/token/__init__.py b/chromadb/auth/token/__init__.py new file mode 100644 index 000000000000..5132fa357987 --- /dev/null +++ b/chromadb/auth/token/__init__.py @@ -0,0 +1,196 @@ +import logging +import string +from enum import Enum +from typing import Tuple, Any, cast, Dict, TypeVar + +from overrides import override +from pydantic import SecretStr + +from chromadb.auth import ( + ServerAuthProvider, + ClientAuthProvider, + ServerAuthenticationRequest, + ServerAuthCredentialsProvider, + AuthInfoType, + ClientAuthCredentialsProvider, + ClientAuthResponse, + SecretStrAbstractCredentials, + AbstractCredentials, +) +from chromadb.auth.registry import register_provider, resolve_provider +from chromadb.config import System +from chromadb.utils import get_class + +T = TypeVar("T") + +logger = logging.getLogger(__name__) + +__all__ = ["TokenAuthServerProvider", "TokenAuthClientProvider"] + +_token_transport_headers = ["Authorization", "X-Chroma-Token"] + + +class TokenTransportHeader(Enum): + AUTHORIZATION = "Authorization" + X_CHROMA_TOKEN = "X-Chroma-Token" + + +class TokenAuthClientAuthResponse(ClientAuthResponse): + _token_transport_header: TokenTransportHeader + + def __init__( + self, + credentials: SecretStr, + token_transport_header: TokenTransportHeader = TokenTransportHeader.AUTHORIZATION, + ) -> None: + self._credentials = credentials + self._token_transport_header = token_transport_header + + @override + def get_auth_info_type(self) -> AuthInfoType: + return AuthInfoType.HEADER + + @override + def get_auth_info(self) -> Tuple[str, SecretStr]: + if self._token_transport_header == TokenTransportHeader.AUTHORIZATION: + return "Authorization", SecretStr( + f"Bearer {self._credentials.get_secret_value()}" + ) + elif self._token_transport_header == TokenTransportHeader.X_CHROMA_TOKEN: + return "X-Chroma-Token", SecretStr( + f"{self._credentials.get_secret_value()}" + ) + else: + raise ValueError( + f"Invalid token transport header: {self._token_transport_header}" + ) + + +def check_token(token: str) -> None: + token_str = str(token) + if not all( + c in string.digits + string.ascii_letters + string.punctuation + for c in token_str + ): + raise ValueError("Invalid token. Must contain only ASCII letters and digits.") + + +@register_provider("token_config") +class TokenConfigServerAuthCredentialsProvider(ServerAuthCredentialsProvider): + _token: SecretStr + + def __init__(self, system: System) -> None: + super().__init__(system) + system.settings.require("chroma_server_auth_credentials") + token_str = str(system.settings.chroma_server_auth_credentials) + check_token(token_str) + self._token = SecretStr(token_str) + + @override + def validate_credentials(self, credentials: AbstractCredentials[T]) -> bool: + _creds = cast(Dict[str, SecretStr], credentials.get_credentials()) + if "token" not in _creds: + logger.error("Returned credentials do not contain token") + return False + return _creds["token"].get_secret_value() == self._token.get_secret_value() + + +class TokenAuthCredentials(SecretStrAbstractCredentials): + _token: SecretStr + + def __init__(self, token: SecretStr) -> None: + self._token = token + + @override + def get_credentials(self) -> Dict[str, SecretStr]: + return {"token": self._token} + + @staticmethod + def from_header( + header: str, + token_transport_header: TokenTransportHeader = TokenTransportHeader.AUTHORIZATION, + ) -> "TokenAuthCredentials": + """ + Extracts token from header and returns a TokenAuthCredentials object. + """ + if token_transport_header == TokenTransportHeader.AUTHORIZATION: + header = header.replace("Bearer ", "") + header = header.strip() + token = header + elif token_transport_header == TokenTransportHeader.X_CHROMA_TOKEN: + header = header.strip() + token = header + else: + raise ValueError( + f"Invalid token transport header: {token_transport_header}" + ) + return TokenAuthCredentials(SecretStr(token)) + + +@register_provider("token") +class TokenAuthServerProvider(ServerAuthProvider): + _credentials_provider: ServerAuthCredentialsProvider + _token_transport_header: TokenTransportHeader = TokenTransportHeader.AUTHORIZATION + + def __init__(self, system: System) -> None: + super().__init__(system) + self._settings = system.settings + system.settings.require("chroma_server_auth_credentials_provider") + self._credentials_provider = cast( + ServerAuthCredentialsProvider, + system.require( + resolve_provider( + str(system.settings.chroma_server_auth_credentials_provider), + ServerAuthCredentialsProvider, + ) + ), + ) + if system.settings.chroma_server_auth_token_transport_header: + self._token_transport_header = TokenTransportHeader[ + str(system.settings.chroma_server_auth_token_transport_header) + ] + + @override + def authenticate(self, request: ServerAuthenticationRequest[Any]) -> bool: + try: + _auth_header = request.get_auth_info( + AuthInfoType.HEADER, self._token_transport_header.value + ) + return self._credentials_provider.validate_credentials( + TokenAuthCredentials.from_header( + _auth_header, self._token_transport_header + ) + ) + except Exception as e: + logger.error(f"TokenAuthServerProvider.authenticate failed: {repr(e)}") + return False + + +@register_provider("token") +class TokenAuthClientProvider(ClientAuthProvider): + _credentials_provider: ClientAuthCredentialsProvider[Any] + _token_transport_header: TokenTransportHeader = TokenTransportHeader.AUTHORIZATION + + def __init__(self, system: System) -> None: + super().__init__(system) + self._settings = system.settings + + system.settings.require("chroma_client_auth_credentials_provider") + self._credentials_provider = system.require( + get_class( + str(system.settings.chroma_client_auth_credentials_provider), + ClientAuthCredentialsProvider, + ) + ) + _token = self._credentials_provider.get_credentials() + check_token(_token.get_secret_value()) + if system.settings.chroma_client_auth_token_transport_header: + self._token_transport_header = TokenTransportHeader[ + str(system.settings.chroma_client_auth_token_transport_header) + ] + + @override + def authenticate(self) -> ClientAuthResponse: + _token = self._credentials_provider.get_credentials() + + return TokenAuthClientAuthResponse(_token, self._token_transport_header) diff --git a/chromadb/cli/__init__.py b/chromadb/cli/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/chromadb/cli/cli.py b/chromadb/cli/cli.py new file mode 100644 index 000000000000..d60a80b8a48e --- /dev/null +++ b/chromadb/cli/cli.py @@ -0,0 +1,87 @@ +import typer +import uvicorn +import os +import webbrowser + +app = typer.Typer() + +_logo = """ + \033[38;5;069m((((((((( \033[38;5;203m(((((\033[38;5;220m#### + \033[38;5;069m(((((((((((((\033[38;5;203m(((((((((\033[38;5;220m######### + \033[38;5;069m(((((((((((((\033[38;5;203m(((((((((((\033[38;5;220m########### + \033[38;5;069m((((((((((((((\033[38;5;203m((((((((((((\033[38;5;220m############ + \033[38;5;069m(((((((((((((\033[38;5;203m((((((((((((((\033[38;5;220m############# + \033[38;5;069m(((((((((((((\033[38;5;203m((((((((((((((\033[38;5;220m############# + \033[38;5;069m((((((((((((\033[38;5;203m(((((((((((((\033[38;5;220m############## + \033[38;5;069m((((((((((((\033[38;5;203m((((((((((((\033[38;5;220m############## + \033[38;5;069m((((((((((\033[38;5;203m(((((((((((\033[38;5;220m############# + \033[38;5;069m((((((((\033[38;5;203m((((((((\033[38;5;220m############## + \033[38;5;069m(((((\033[38;5;203m(((( \033[38;5;220m#########\033[0m + + """ + + +@app.command() # type: ignore +def run( + path: str = typer.Option( + "./chroma_data", help="The path to the file or directory." + ), + port: int = typer.Option(8000, help="The port to run the server on."), + test: bool = typer.Option(False, help="Test mode.", show_envvar=False, hidden=True), +) -> None: + """Run a chroma server""" + + print("\033[1m") # Bold logo + print(_logo) + print("\033[1m") # Bold + print("Running Chroma") + print("\033[0m") # Reset + + typer.echo(f"\033[1mSaving data to\033[0m: \033[32m{path}\033[0m") + typer.echo( + f"\033[1mConnect to chroma at\033[0m: \033[32mhttp://localhost:{port}\033[0m" + ) + typer.echo( + "\033[1mGetting started guide\033[0m: https://docs.trychroma.com/getting-started\n\n" + ) + + # set ENV variable for PERSIST_DIRECTORY to path + os.environ["IS_PERSISTENT"] = "True" + os.environ["PERSIST_DIRECTORY"] = path + + # get the path where chromadb is installed + chromadb_path = os.path.dirname(os.path.realpath(__file__)) + + # this is the path of the CLI, we want to move up one directory + chromadb_path = os.path.dirname(chromadb_path) + + config = { + "app": "chromadb.app:app", + "host": "0.0.0.0", + "port": port, + "workers": 1, + "log_config": f"{chromadb_path}/log_config.yml", + } + + if test: + return + + uvicorn.run(**config) + + +@app.command() # type: ignore +def help() -> None: + """Opens help url in your browser""" + + webbrowser.open("https://discord.gg/MMeYNTmh3x") + + +@app.command() # type: ignore +def docs() -> None: + """Opens docs url in your browser""" + + webbrowser.open("https://docs.trychroma.com") + + +if __name__ == "__main__": + app() diff --git a/chromadb/config.py b/chromadb/config.py index 5306d0912c7c..6167193acd26 100644 --- a/chromadb/config.py +++ b/chromadb/config.py @@ -1,12 +1,16 @@ -from pydantic import BaseSettings -from typing import Optional, List, Any, Dict, TypeVar, Set, cast, Iterable, Type -from typing_extensions import Literal -from abc import ABC import importlib +import inspect import logging -from overrides import EnforceOverrides, override +import os +from abc import ABC from graphlib import TopologicalSorter -import inspect +from typing import Optional, List, Any, Dict, Set, Iterable +from typing import Type, TypeVar, cast + +from overrides import EnforceOverrides +from overrides import override +from pydantic import BaseSettings, validator +from typing_extensions import Literal # The thin client will have a flag to control which implementations to use is_thin_client = False @@ -15,10 +19,8 @@ except ImportError: is_thin_client = False - logger = logging.getLogger(__name__) - LEGACY_ERROR = """\033[91mYou are using a deprecated configuration of Chroma. \033[94mIf you do not have data you wish to migrate, you only need to change how you construct @@ -59,7 +61,7 @@ } -class Settings(BaseSettings): +class Settings(BaseSettings): # type: ignore environment: str = "" # Legacy config has to be kept around because pydantic will error on nonexisting keys @@ -86,9 +88,66 @@ class Settings(BaseSettings): chroma_server_headers: Optional[Dict[str, str]] = None chroma_server_http_port: Optional[str] = None chroma_server_ssl_enabled: Optional[bool] = False + chroma_server_api_default_path: Optional[str] = "/api/v1" chroma_server_grpc_port: Optional[str] = None chroma_server_cors_allow_origins: List[str] = [] # eg ["http://localhost:3000"] + pulsar_broker_url: Optional[str] = None + pulsar_admin_port: Optional[str] = None + pulsar_broker_port: Optional[str] = None + + chroma_server_auth_provider: Optional[str] = None + + @validator("chroma_server_auth_provider", pre=True, always=True, allow_reuse=True) + def chroma_server_auth_provider_non_empty( + cls: Type["Settings"], v: str + ) -> Optional[str]: + if v and not v.strip(): + raise ValueError( + "chroma_server_auth_provider cannot be empty or just whitespace" + ) + return v + + chroma_server_auth_configuration_provider: Optional[str] = None + chroma_server_auth_configuration_file: Optional[str] = None + chroma_server_auth_credentials_provider: Optional[str] = None + chroma_server_auth_credentials_file: Optional[str] = None + chroma_server_auth_credentials: Optional[str] = None + + @validator( + "chroma_server_auth_credentials_file", pre=True, always=True, allow_reuse=True + ) + def chroma_server_auth_credentials_file_non_empty_file_exists( + cls: Type["Settings"], v: str + ) -> Optional[str]: + if v and not v.strip(): + raise ValueError( + "chroma_server_auth_credentials_file cannot be empty or just whitespace" + ) + if v and not os.path.isfile(os.path.join(v)): + raise ValueError( + f"chroma_server_auth_credentials_file [{v}] does not exist" + ) + return v + + chroma_client_auth_provider: Optional[str] = None + chroma_server_auth_ignore_paths: Dict[str, List[str]] = { + "/api/v1": ["GET"], + "/api/v1/heartbeat": ["GET"], + "/api/v1/version": ["GET"], + } + + chroma_client_auth_credentials_provider: Optional[ + str + ] = "chromadb.auth.providers.ConfigurationClientAuthCredentialsProvider" + chroma_client_auth_protocol_adapter: Optional[ + str + ] = "chromadb.auth.providers.RequestsClientAuthProtocolAdapter" + chroma_client_auth_credentials_file: Optional[str] = None + chroma_client_auth_credentials: Optional[str] = None + chroma_client_auth_token_transport_header: Optional[str] = None + chroma_server_auth_token_transport_header: Optional[str] = None + anonymized_telemetry: bool = True allow_reset: bool = False @@ -106,7 +165,7 @@ def require(self, key: str) -> Any: def __getitem__(self, key: str) -> Any: val = getattr(self, key) # Error on legacy config values - if val in _legacy_config_values: + if isinstance(val, str) and val in _legacy_config_values: raise ValueError(LEGACY_ERROR) return val @@ -158,7 +217,6 @@ def reset_state(self) -> None: class System(Component): settings: Settings - _instances: Dict[Type[Component], Component] def __init__(self, settings: Settings): @@ -169,7 +227,6 @@ def __init__(self, settings: Settings): "Chroma is running in http-only client mode, and can only be run with 'chromadb.api.fastapi.FastAPI' as the chroma_api_impl. \ see https://docs.trychroma.com/usage-guide?lang=py#using-the-python-http-only-client for more information." ) - # Validate settings don't contain any legacy config values for key in _legacy_config_keys: if settings[key] is not None: @@ -225,7 +282,9 @@ def stop(self) -> None: def reset_state(self) -> None: """Reset the state of this system and all constituents in reverse dependency order""" if not self.settings.allow_reset: - raise ValueError("Resetting is not allowed by this configuration (to enable it, set `allow_reset` to `True` in your Settings() or include `ALLOW_RESET=TRUE` in your environment variables)") + raise ValueError( + "Resetting is not allowed by this configuration (to enable it, set `allow_reset` to `True` in your Settings() or include `ALLOW_RESET=TRUE` in your environment variables)" + ) for component in reversed(list(self.components())): component.reset_state() diff --git a/chromadb/ingest/impl/pulsar.py b/chromadb/ingest/impl/pulsar.py new file mode 100644 index 000000000000..3f293c90580a --- /dev/null +++ b/chromadb/ingest/impl/pulsar.py @@ -0,0 +1,304 @@ +from __future__ import annotations +from collections import defaultdict +from typing import Any, Callable, Dict, List, Optional, Sequence, Set, Tuple +import uuid +from chromadb.config import Settings, System +from chromadb.ingest import Consumer, ConsumerCallbackFn, Producer +from overrides import overrides, EnforceOverrides +from uuid import UUID +from chromadb.ingest.impl.pulsar_admin import PulsarAdmin +from chromadb.ingest.impl.utils import create_pulsar_connection_str +from chromadb.proto.convert import from_proto_submit, to_proto_submit +import chromadb.proto.chroma_pb2 as proto +from chromadb.types import SeqId, SubmitEmbeddingRecord +import pulsar +from concurrent.futures import wait, Future + +from chromadb.utils.messageid import int_to_pulsar, pulsar_to_int + + +class PulsarProducer(Producer, EnforceOverrides): + _connection_str: str + _topic_to_producer: Dict[str, pulsar.Producer] + _client: pulsar.Client + _admin: PulsarAdmin + _settings: Settings + + def __init__(self, system: System) -> None: + pulsar_host = system.settings.require("pulsar_broker_url") + pulsar_port = system.settings.require("pulsar_broker_port") + self._connection_str = create_pulsar_connection_str(pulsar_host, pulsar_port) + self._topic_to_producer = {} + self._settings = system.settings + self._admin = PulsarAdmin(system) + super().__init__(system) + + @overrides + def start(self) -> None: + self._client = pulsar.Client(self._connection_str) + super().start() + + @overrides + def stop(self) -> None: + self._client.close() + super().stop() + + @overrides + def create_topic(self, topic_name: str) -> None: + self._admin.create_topic(topic_name) + + @overrides + def delete_topic(self, topic_name: str) -> None: + self._admin.delete_topic(topic_name) + + @overrides + def submit_embedding( + self, topic_name: str, embedding: SubmitEmbeddingRecord + ) -> SeqId: + """Add an embedding record to the given topic. Returns the SeqID of the record.""" + producer = self._get_or_create_producer(topic_name) + proto_submit: proto.SubmitEmbeddingRecord = to_proto_submit(embedding) + # TODO: batch performance / async + msg_id: pulsar.MessageId = producer.send(proto_submit.SerializeToString()) + return pulsar_to_int(msg_id) + + @overrides + def submit_embeddings( + self, topic_name: str, embeddings: Sequence[SubmitEmbeddingRecord] + ) -> Sequence[SeqId]: + if not self._running: + raise RuntimeError("Component not running") + + if len(embeddings) == 0: + return [] + + if len(embeddings) > self.max_batch_size: + raise ValueError( + f""" + Cannot submit more than {self.max_batch_size:,} embeddings at once. + Please submit your embeddings in batches of size + {self.max_batch_size:,} or less. + """ + ) + + producer = self._get_or_create_producer(topic_name) + protos_to_submit = [to_proto_submit(embedding) for embedding in embeddings] + + def create_producer_callback( + future: Future[int], + ) -> Callable[[Any, pulsar.MessageId], None]: + def producer_callback(res: Any, msg_id: pulsar.MessageId) -> None: + if msg_id: + future.set_result(pulsar_to_int(msg_id)) + else: + future.set_exception( + Exception( + "Unknown error while submitting embedding in producer_callback" + ) + ) + + return producer_callback + + futures = [] + for proto_to_submit in protos_to_submit: + future: Future[int] = Future() + producer.send_async( + proto_to_submit.SerializeToString(), + callback=create_producer_callback(future), + ) + futures.append(future) + + wait(futures) + + results: List[SeqId] = [] + for future in futures: + exception = future.exception() + if exception is not None: + raise exception + results.append(future.result()) + + return results + + @property + @overrides + def max_batch_size(self) -> int: + # For now, we use 1,000 + # TODO: tune this to a reasonable value by default + return 1000 + + def _get_or_create_producer(self, topic_name: str) -> pulsar.Producer: + if topic_name not in self._topic_to_producer: + producer = self._client.create_producer(topic_name) + self._topic_to_producer[topic_name] = producer + return self._topic_to_producer[topic_name] + + @overrides + def reset_state(self) -> None: + if not self._settings.require("allow_reset"): + raise ValueError( + "Resetting the database is not allowed. Set `allow_reset` to true in the config in tests or other non-production environments where reset should be permitted." + ) + for topic_name in self._topic_to_producer: + self._admin.delete_topic(topic_name) + self._topic_to_producer = {} + super().reset_state() + + +class PulsarConsumer(Consumer, EnforceOverrides): + class PulsarSubscription: + id: UUID + topic_name: str + start: int + end: int + callback: ConsumerCallbackFn + consumer: pulsar.Consumer + + def __init__( + self, + id: UUID, + topic_name: str, + start: int, + end: int, + callback: ConsumerCallbackFn, + consumer: pulsar.Consumer, + ): + self.id = id + self.topic_name = topic_name + self.start = start + self.end = end + self.callback = callback + self.consumer = consumer + + _connection_str: str + _client: pulsar.Client + _subscriptions: Dict[str, Set[PulsarSubscription]] + _settings: Settings + + def __init__(self, system: System) -> None: + pulsar_host = system.settings.require("pulsar_broker_url") + pulsar_port = system.settings.require("pulsar_broker_port") + self._connection_str = create_pulsar_connection_str(pulsar_host, pulsar_port) + self._subscriptions = defaultdict(set) + self._settings = system.settings + super().__init__(system) + + @overrides + def start(self) -> None: + self._client = pulsar.Client(self._connection_str) + super().start() + + @overrides + def stop(self) -> None: + self._client.close() + super().stop() + + @overrides + def subscribe( + self, + topic_name: str, + consume_fn: ConsumerCallbackFn, + start: Optional[SeqId] = None, + end: Optional[SeqId] = None, + id: Optional[UUID] = None, + ) -> UUID: + """Register a function that will be called to recieve embeddings for a given + topic. The given function may be called any number of times, with any number of + records, and may be called concurrently. + + Only records between start (exclusive) and end (inclusive) SeqIDs will be + returned. If start is None, the first record returned will be the next record + generated, not including those generated before creating the subscription. If + end is None, the consumer will consume indefinitely, otherwise it will + automatically be unsubscribed when the end SeqID is reached. + + If the function throws an exception, the function may be called again with the + same or different records. + + Takes an optional UUID as a unique subscription ID. If no ID is provided, a new + ID will be generated and returned.""" + if not self._running: + raise RuntimeError("Consumer must be started before subscribing") + + subscription_id = ( + id or uuid.uuid4() + ) # TODO: this should really be created by the coordinator and stored in sysdb + + start, end = self._validate_range(start, end) + + def wrap_callback(consumer: pulsar.Consumer, message: pulsar.Message) -> None: + msg_data = message.data() + msg_id = pulsar_to_int(message.message_id()) + submit_embedding_record = proto.SubmitEmbeddingRecord() + proto.SubmitEmbeddingRecord.ParseFromString( + submit_embedding_record, msg_data + ) + embedding_record = from_proto_submit(submit_embedding_record, msg_id) + consume_fn([embedding_record]) + consumer.acknowledge(message) + if msg_id == end: + self.unsubscribe(subscription_id) + + consumer = self._client.subscribe( + topic_name, + subscription_id.hex, + message_listener=wrap_callback, + ) + + subscription = self.PulsarSubscription( + subscription_id, topic_name, start, end, consume_fn, consumer + ) + self._subscriptions[topic_name].add(subscription) + + # NOTE: For some reason the seek() method expects a shadowed MessageId type + # which resides in _msg_id. + consumer.seek(int_to_pulsar(start)._msg_id) + + return subscription_id + + def _validate_range( + self, start: Optional[SeqId], end: Optional[SeqId] + ) -> Tuple[int, int]: + """Validate and normalize the start and end SeqIDs for a subscription using this + impl.""" + start = start or pulsar_to_int(pulsar.MessageId.latest) + end = end or self.max_seqid() + if not isinstance(start, int) or not isinstance(end, int): + raise ValueError("SeqIDs must be integers") + if start >= end: + raise ValueError(f"Invalid SeqID range: {start} to {end}") + return start, end + + @overrides + def unsubscribe(self, subscription_id: UUID) -> None: + """Unregister a subscription. The consume function will no longer be invoked, + and resources associated with the subscription will be released.""" + for topic_name, subscriptions in self._subscriptions.items(): + for subscription in subscriptions: + if subscription.id == subscription_id: + subscription.consumer.close() + subscriptions.remove(subscription) + if len(subscriptions) == 0: + del self._subscriptions[topic_name] + return + + @overrides + def min_seqid(self) -> SeqId: + """Return the minimum possible SeqID in this implementation.""" + return pulsar_to_int(pulsar.MessageId.earliest) + + @overrides + def max_seqid(self) -> SeqId: + """Return the maximum possible SeqID in this implementation.""" + return 2**192 - 1 + + @overrides + def reset_state(self) -> None: + if not self._settings.require("allow_reset"): + raise ValueError( + "Resetting the database is not allowed. Set `allow_reset` to true in the config in tests or other non-production environments where reset should be permitted." + ) + for topic_name, subscriptions in self._subscriptions.items(): + for subscription in subscriptions: + subscription.consumer.close() + self._subscriptions = defaultdict(set) + super().reset_state() diff --git a/chromadb/ingest/impl/pulsar_admin.py b/chromadb/ingest/impl/pulsar_admin.py new file mode 100644 index 000000000000..e031e4a238ba --- /dev/null +++ b/chromadb/ingest/impl/pulsar_admin.py @@ -0,0 +1,81 @@ +# A thin wrapper around the pulsar admin api +import requests +from chromadb.config import System +from chromadb.ingest.impl.utils import parse_topic_name + + +class PulsarAdmin: + """A thin wrapper around the pulsar admin api, only used for interim development towards distributed chroma. + This functionality will be moved to the chroma coordinator.""" + + _connection_str: str + + def __init__(self, system: System): + pulsar_host = system.settings.require("pulsar_broker_url") + pulsar_port = system.settings.require("pulsar_admin_port") + self._connection_str = f"http://{pulsar_host}:{pulsar_port}" + + # Create the default tenant and namespace + # This is a temporary workaround until we have a proper tenant/namespace management system + self.create_tenant("default") + self.create_namespace("default", "default") + + def create_tenant(self, tenant: str) -> None: + """Make a PUT request to the admin api to create the tenant""" + + path = f"/admin/v2/tenants/{tenant}" + url = self._connection_str + path + response = requests.put( + url, json={"allowedClusters": ["standalone"], "adminRoles": []} + ) # TODO: how to manage clusters? + + if response.status_code != 204 and response.status_code != 409: + raise RuntimeError(f"Failed to create tenant {tenant}") + + def create_namespace(self, tenant: str, namespace: str) -> None: + """Make a PUT request to the admin api to create the namespace""" + + path = f"/admin/v2/namespaces/{tenant}/{namespace}" + url = self._connection_str + path + response = requests.put(url) + + if response.status_code != 204 and response.status_code != 409: + raise RuntimeError(f"Failed to create namespace {namespace}") + + def create_topic(self, topic: str) -> None: + # TODO: support non-persistent topics? + tenant, namespace, topic_name = parse_topic_name(topic) + + if tenant != "default": + raise ValueError(f"Only the default tenant is supported, got {tenant}") + if namespace != "default": + raise ValueError( + f"Only the default namespace is supported, got {namespace}" + ) + + # Make a PUT request to the admin api to create the topic + path = f"/admin/v2/persistent/{tenant}/{namespace}/{topic_name}" + url = self._connection_str + path + response = requests.put(url) + + if response.status_code != 204 and response.status_code != 409: + raise RuntimeError(f"Failed to create topic {topic_name}") + + def delete_topic(self, topic: str) -> None: + tenant, namespace, topic_name = parse_topic_name(topic) + + if tenant != "default": + raise ValueError(f"Only the default tenant is supported, got {tenant}") + if namespace != "default": + raise ValueError( + f"Only the default namespace is supported, got {namespace}" + ) + + # Make a PUT request to the admin api to delete the topic + path = f"/admin/v2/persistent/{tenant}/{namespace}/{topic_name}" + # Force delete the topic + path += "?force=true" + url = self._connection_str + path + response = requests.delete(url) + if response.status_code != 204 and response.status_code != 409: + raise RuntimeError(f"Failed to delete topic {topic_name}") diff --git a/chromadb/ingest/impl/utils.py b/chromadb/ingest/impl/utils.py new file mode 100644 index 000000000000..144384d75db5 --- /dev/null +++ b/chromadb/ingest/impl/utils.py @@ -0,0 +1,20 @@ +import re +from typing import Tuple + +topic_regex = r"persistent:\/\/(?P.+)\/(?P.+)\/(?P.+)" + + +def parse_topic_name(topic_name: str) -> Tuple[str, str, str]: + """Parse the topic name into the tenant, namespace and topic name""" + match = re.match(topic_regex, topic_name) + if not match: + raise ValueError(f"Invalid topic name: {topic_name}") + return match.group("tenant"), match.group("namespace"), match.group("topic") + + +def create_pulsar_connection_str(host: str, port: str) -> str: + return f"pulsar://{host}:{port}" + + +def create_topic_name(tenant: str, namespace: str, topic: str) -> str: + return f"persistent://{tenant}/{namespace}/{topic}" diff --git a/chromadb/log_config.yml b/chromadb/log_config.yml new file mode 100644 index 000000000000..80e62479917c --- /dev/null +++ b/chromadb/log_config.yml @@ -0,0 +1,37 @@ +version: 1 +disable_existing_loggers: False +formatters: + default: + "()": uvicorn.logging.DefaultFormatter + format: '%(levelprefix)s [%(asctime)s] %(message)s' + use_colors: null + datefmt: '%d-%m-%Y %H:%M:%S' + access: + "()": uvicorn.logging.AccessFormatter + format: '%(levelprefix)s [%(asctime)s] %(client_addr)s - "%(request_line)s" %(status_code)s' + datefmt: '%d-%m-%Y %H:%M:%S' +handlers: + default: + formatter: default + class: logging.StreamHandler + stream: ext://sys.stderr + access: + formatter: access + class: logging.StreamHandler + stream: ext://sys.stdout + console: + class: logging.StreamHandler + stream: ext://sys.stdout + formatter: default + file: + class : logging.handlers.RotatingFileHandler + filename: chroma.log + formatter: default +loggers: + root: + level: WARN + handlers: [console, file] + chromadb: + level: DEBUG + uvicorn: + level: INFO diff --git a/chromadb/proto/chroma.proto b/chromadb/proto/chroma.proto new file mode 100644 index 000000000000..7eefed74e121 --- /dev/null +++ b/chromadb/proto/chroma.proto @@ -0,0 +1,40 @@ +syntax = "proto3"; + +package chroma; + +enum Operation { + ADD = 0; + UPDATE = 1; + UPSERT = 2; + DELETE = 3; +} + +enum ScalarEncoding { + FLOAT32 = 0; + INT32 = 1; +} + +message Vector { + int32 dimension = 1; + bytes vector = 2; + ScalarEncoding encoding = 3; +} + +message UpdateMetadataValue { + oneof value { + string string_value = 1; + int64 int_value = 2; + double float_value = 3; + } +} + +message UpdateMetadata { + map metadata = 1; +} + +message SubmitEmbeddingRecord { + string id = 1; + optional Vector vector = 2; + optional UpdateMetadata metadata = 3; + Operation operation = 4; +} diff --git a/chromadb/proto/chroma_pb2.py b/chromadb/proto/chroma_pb2.py new file mode 100644 index 000000000000..ca8952697afb --- /dev/null +++ b/chromadb/proto/chroma_pb2.py @@ -0,0 +1,42 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: chromadb/proto/chroma.proto +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder + +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile( + b'\n\x1b\x63hromadb/proto/chroma.proto\x12\x06\x63hroma"U\n\x06Vector\x12\x11\n\tdimension\x18\x01 \x01(\x05\x12\x0e\n\x06vector\x18\x02 \x01(\x0c\x12(\n\x08\x65ncoding\x18\x03 \x01(\x0e\x32\x16.chroma.ScalarEncoding"b\n\x13UpdateMetadataValue\x12\x16\n\x0cstring_value\x18\x01 \x01(\tH\x00\x12\x13\n\tint_value\x18\x02 \x01(\x03H\x00\x12\x15\n\x0b\x66loat_value\x18\x03 \x01(\x01H\x00\x42\x07\n\x05value"\x96\x01\n\x0eUpdateMetadata\x12\x36\n\x08metadata\x18\x01 \x03(\x0b\x32$.chroma.UpdateMetadata.MetadataEntry\x1aL\n\rMetadataEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12*\n\x05value\x18\x02 \x01(\x0b\x32\x1b.chroma.UpdateMetadataValue:\x02\x38\x01"\xb5\x01\n\x15SubmitEmbeddingRecord\x12\n\n\x02id\x18\x01 \x01(\t\x12#\n\x06vector\x18\x02 \x01(\x0b\x32\x0e.chroma.VectorH\x00\x88\x01\x01\x12-\n\x08metadata\x18\x03 \x01(\x0b\x32\x16.chroma.UpdateMetadataH\x01\x88\x01\x01\x12$\n\toperation\x18\x04 \x01(\x0e\x32\x11.chroma.OperationB\t\n\x07_vectorB\x0b\n\t_metadata*8\n\tOperation\x12\x07\n\x03\x41\x44\x44\x10\x00\x12\n\n\x06UPDATE\x10\x01\x12\n\n\x06UPSERT\x10\x02\x12\n\n\x06\x44\x45LETE\x10\x03*(\n\x0eScalarEncoding\x12\x0b\n\x07\x46LOAT32\x10\x00\x12\t\n\x05INT32\x10\x01\x62\x06proto3' +) + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages( + DESCRIPTOR, "chromadb.proto.chroma_pb2", _globals +) +if _descriptor._USE_C_DESCRIPTORS == False: + DESCRIPTOR._options = None + _UPDATEMETADATA_METADATAENTRY._options = None + _UPDATEMETADATA_METADATAENTRY._serialized_options = b"8\001" + _globals["_OPERATION"]._serialized_start = 563 + _globals["_OPERATION"]._serialized_end = 619 + _globals["_SCALARENCODING"]._serialized_start = 621 + _globals["_SCALARENCODING"]._serialized_end = 661 + _globals["_VECTOR"]._serialized_start = 39 + _globals["_VECTOR"]._serialized_end = 124 + _globals["_UPDATEMETADATAVALUE"]._serialized_start = 126 + _globals["_UPDATEMETADATAVALUE"]._serialized_end = 224 + _globals["_UPDATEMETADATA"]._serialized_start = 227 + _globals["_UPDATEMETADATA"]._serialized_end = 377 + _globals["_UPDATEMETADATA_METADATAENTRY"]._serialized_start = 301 + _globals["_UPDATEMETADATA_METADATAENTRY"]._serialized_end = 377 + _globals["_SUBMITEMBEDDINGRECORD"]._serialized_start = 380 + _globals["_SUBMITEMBEDDINGRECORD"]._serialized_end = 561 +# @@protoc_insertion_point(module_scope) diff --git a/chromadb/proto/chroma_pb2.pyi b/chromadb/proto/chroma_pb2.pyi new file mode 100644 index 000000000000..b13327e982fb --- /dev/null +++ b/chromadb/proto/chroma_pb2.pyi @@ -0,0 +1,247 @@ +""" +@generated by mypy-protobuf. Do not edit manually! +isort:skip_file +""" +import builtins +import collections.abc +import google.protobuf.descriptor +import google.protobuf.internal.containers +import google.protobuf.internal.enum_type_wrapper +import google.protobuf.message +import sys +import typing + +if sys.version_info >= (3, 10): + import typing as typing_extensions +else: + import typing_extensions + +DESCRIPTOR: google.protobuf.descriptor.FileDescriptor + +class _Operation: + ValueType = typing.NewType("ValueType", builtins.int) + V: typing_extensions.TypeAlias = ValueType + +class _OperationEnumTypeWrapper( + google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_Operation.ValueType], + builtins.type, +): + DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor + ADD: _Operation.ValueType # 0 + UPDATE: _Operation.ValueType # 1 + UPSERT: _Operation.ValueType # 2 + DELETE: _Operation.ValueType # 3 + +class Operation(_Operation, metaclass=_OperationEnumTypeWrapper): ... + +ADD: Operation.ValueType # 0 +UPDATE: Operation.ValueType # 1 +UPSERT: Operation.ValueType # 2 +DELETE: Operation.ValueType # 3 +global___Operation = Operation + +class _ScalarEncoding: + ValueType = typing.NewType("ValueType", builtins.int) + V: typing_extensions.TypeAlias = ValueType + +class _ScalarEncodingEnumTypeWrapper( + google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[ + _ScalarEncoding.ValueType + ], + builtins.type, +): + DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor + FLOAT32: _ScalarEncoding.ValueType # 0 + INT32: _ScalarEncoding.ValueType # 1 + +class ScalarEncoding(_ScalarEncoding, metaclass=_ScalarEncodingEnumTypeWrapper): ... + +FLOAT32: ScalarEncoding.ValueType # 0 +INT32: ScalarEncoding.ValueType # 1 +global___ScalarEncoding = ScalarEncoding + +@typing_extensions.final +class Vector(google.protobuf.message.Message): + DESCRIPTOR: google.protobuf.descriptor.Descriptor + + DIMENSION_FIELD_NUMBER: builtins.int + VECTOR_FIELD_NUMBER: builtins.int + ENCODING_FIELD_NUMBER: builtins.int + dimension: builtins.int + vector: builtins.bytes + encoding: global___ScalarEncoding.ValueType + def __init__( + self, + *, + dimension: builtins.int = ..., + vector: builtins.bytes = ..., + encoding: global___ScalarEncoding.ValueType = ..., + ) -> None: ... + def ClearField( + self, + field_name: typing_extensions.Literal[ + "dimension", b"dimension", "encoding", b"encoding", "vector", b"vector" + ], + ) -> None: ... + +global___Vector = Vector + +@typing_extensions.final +class UpdateMetadataValue(google.protobuf.message.Message): + DESCRIPTOR: google.protobuf.descriptor.Descriptor + + STRING_VALUE_FIELD_NUMBER: builtins.int + INT_VALUE_FIELD_NUMBER: builtins.int + FLOAT_VALUE_FIELD_NUMBER: builtins.int + string_value: builtins.str + int_value: builtins.int + float_value: builtins.float + def __init__( + self, + *, + string_value: builtins.str = ..., + int_value: builtins.int = ..., + float_value: builtins.float = ..., + ) -> None: ... + def HasField( + self, + field_name: typing_extensions.Literal[ + "float_value", + b"float_value", + "int_value", + b"int_value", + "string_value", + b"string_value", + "value", + b"value", + ], + ) -> builtins.bool: ... + def ClearField( + self, + field_name: typing_extensions.Literal[ + "float_value", + b"float_value", + "int_value", + b"int_value", + "string_value", + b"string_value", + "value", + b"value", + ], + ) -> None: ... + def WhichOneof( + self, oneof_group: typing_extensions.Literal["value", b"value"] + ) -> ( + typing_extensions.Literal["string_value", "int_value", "float_value"] | None + ): ... + +global___UpdateMetadataValue = UpdateMetadataValue + +@typing_extensions.final +class UpdateMetadata(google.protobuf.message.Message): + DESCRIPTOR: google.protobuf.descriptor.Descriptor + + @typing_extensions.final + class MetadataEntry(google.protobuf.message.Message): + DESCRIPTOR: google.protobuf.descriptor.Descriptor + + KEY_FIELD_NUMBER: builtins.int + VALUE_FIELD_NUMBER: builtins.int + key: builtins.str + @property + def value(self) -> global___UpdateMetadataValue: ... + def __init__( + self, + *, + key: builtins.str = ..., + value: global___UpdateMetadataValue | None = ..., + ) -> None: ... + def HasField( + self, field_name: typing_extensions.Literal["value", b"value"] + ) -> builtins.bool: ... + def ClearField( + self, + field_name: typing_extensions.Literal["key", b"key", "value", b"value"], + ) -> None: ... + + METADATA_FIELD_NUMBER: builtins.int + @property + def metadata( + self, + ) -> google.protobuf.internal.containers.MessageMap[ + builtins.str, global___UpdateMetadataValue + ]: ... + def __init__( + self, + *, + metadata: collections.abc.Mapping[builtins.str, global___UpdateMetadataValue] + | None = ..., + ) -> None: ... + def ClearField( + self, field_name: typing_extensions.Literal["metadata", b"metadata"] + ) -> None: ... + +global___UpdateMetadata = UpdateMetadata + +@typing_extensions.final +class SubmitEmbeddingRecord(google.protobuf.message.Message): + DESCRIPTOR: google.protobuf.descriptor.Descriptor + + ID_FIELD_NUMBER: builtins.int + VECTOR_FIELD_NUMBER: builtins.int + METADATA_FIELD_NUMBER: builtins.int + OPERATION_FIELD_NUMBER: builtins.int + id: builtins.str + @property + def vector(self) -> global___Vector: ... + @property + def metadata(self) -> global___UpdateMetadata: ... + operation: global___Operation.ValueType + def __init__( + self, + *, + id: builtins.str = ..., + vector: global___Vector | None = ..., + metadata: global___UpdateMetadata | None = ..., + operation: global___Operation.ValueType = ..., + ) -> None: ... + def HasField( + self, + field_name: typing_extensions.Literal[ + "_metadata", + b"_metadata", + "_vector", + b"_vector", + "metadata", + b"metadata", + "vector", + b"vector", + ], + ) -> builtins.bool: ... + def ClearField( + self, + field_name: typing_extensions.Literal[ + "_metadata", + b"_metadata", + "_vector", + b"_vector", + "id", + b"id", + "metadata", + b"metadata", + "operation", + b"operation", + "vector", + b"vector", + ], + ) -> None: ... + @typing.overload + def WhichOneof( + self, oneof_group: typing_extensions.Literal["_metadata", b"_metadata"] + ) -> typing_extensions.Literal["metadata"] | None: ... + @typing.overload + def WhichOneof( + self, oneof_group: typing_extensions.Literal["_vector", b"_vector"] + ) -> typing_extensions.Literal["vector"] | None: ... + +global___SubmitEmbeddingRecord = SubmitEmbeddingRecord diff --git a/chromadb/proto/convert.py b/chromadb/proto/convert.py new file mode 100644 index 000000000000..15d1363b05cf --- /dev/null +++ b/chromadb/proto/convert.py @@ -0,0 +1,150 @@ +import array +from typing import Optional, Tuple, Union +from chromadb.api.types import Embedding +import chromadb.proto.chroma_pb2 as proto +from chromadb.types import ( + EmbeddingRecord, + Metadata, + Operation, + ScalarEncoding, + SeqId, + SubmitEmbeddingRecord, + Vector, +) + + +def to_proto_vector(vector: Vector, encoding: ScalarEncoding) -> proto.Vector: + if encoding == ScalarEncoding.FLOAT32: + as_bytes = array.array("f", vector).tobytes() + proto_encoding = proto.ScalarEncoding.FLOAT32 + elif encoding == ScalarEncoding.INT32: + as_bytes = array.array("i", vector).tobytes() + proto_encoding = proto.ScalarEncoding.INT32 + else: + raise ValueError( + f"Unknown encoding {encoding}, expected one of {ScalarEncoding.FLOAT32} \ + or {ScalarEncoding.INT32}" + ) + + return proto.Vector(dimension=len(vector), vector=as_bytes, encoding=proto_encoding) + + +def from_proto_vector(vector: proto.Vector) -> Tuple[Embedding, ScalarEncoding]: + encoding = vector.encoding + as_array: array.array[float] | array.array[int] + if encoding == proto.ScalarEncoding.FLOAT32: + as_array = array.array("f") + out_encoding = ScalarEncoding.FLOAT32 + elif encoding == proto.ScalarEncoding.INT32: + as_array = array.array("i") + out_encoding = ScalarEncoding.INT32 + else: + raise ValueError( + f"Unknown encoding {encoding}, expected one of \ + {proto.ScalarEncoding.FLOAT32} or {proto.ScalarEncoding.INT32}" + ) + + as_array.frombytes(vector.vector) + return (as_array.tolist(), out_encoding) + + +def from_proto_operation(operation: proto.Operation.ValueType) -> Operation: + if operation == proto.Operation.ADD: + return Operation.ADD + elif operation == proto.Operation.UPDATE: + return Operation.UPDATE + elif operation == proto.Operation.UPSERT: + return Operation.UPSERT + elif operation == proto.Operation.DELETE: + return Operation.DELETE + else: + raise RuntimeError(f"Unknown operation {operation}") # TODO: full error + + +def from_proto_metadata(metadata: proto.UpdateMetadata) -> Optional[Metadata]: + if not metadata.metadata: + return None + out_metadata = {} + for key, value in metadata.metadata.items(): + if value.HasField("string_value"): + out_metadata[key] = value.string_value + elif value.HasField("int_value"): + out_metadata[key] = value.int_value + elif value.HasField("float_value"): + out_metadata[key] = value.float_value + else: + raise RuntimeError(f"Unknown metadata value type {value}") + return out_metadata + + +def from_proto_submit( + submit_embedding_record: proto.SubmitEmbeddingRecord, seq_id: SeqId +) -> EmbeddingRecord: + embedding, encoding = from_proto_vector(submit_embedding_record.vector) + record = EmbeddingRecord( + id=submit_embedding_record.id, + seq_id=seq_id, + embedding=embedding, + encoding=encoding, + metadata=from_proto_metadata(submit_embedding_record.metadata), + operation=from_proto_operation(submit_embedding_record.operation), + ) + return record + + +def to_proto_metadata_update_value( + value: Union[str, int, float, None] +) -> proto.UpdateMetadataValue: + if isinstance(value, str): + return proto.UpdateMetadataValue(string_value=value) + elif isinstance(value, int): + return proto.UpdateMetadataValue(int_value=value) + elif isinstance(value, float): + return proto.UpdateMetadataValue(float_value=value) + elif value is None: + return proto.UpdateMetadataValue() + else: + raise ValueError( + f"Unknown metadata value type {type(value)}, expected one of str, int, \ + float, or None" + ) + + +def to_proto_operation(operation: Operation) -> proto.Operation.ValueType: + if operation == Operation.ADD: + return proto.Operation.ADD + elif operation == Operation.UPDATE: + return proto.Operation.UPDATE + elif operation == Operation.UPSERT: + return proto.Operation.UPSERT + elif operation == Operation.DELETE: + return proto.Operation.DELETE + else: + raise ValueError( + f"Unknown operation {operation}, expected one of {Operation.ADD}, \ + {Operation.UPDATE}, {Operation.UPDATE}, or {Operation.DELETE}" + ) + + +def to_proto_submit( + submit_record: SubmitEmbeddingRecord, +) -> proto.SubmitEmbeddingRecord: + vector = None + if submit_record["embedding"] is not None and submit_record["encoding"] is not None: + vector = to_proto_vector(submit_record["embedding"], submit_record["encoding"]) + + metadata = None + if submit_record["metadata"] is not None: + metadata = { + k: to_proto_metadata_update_value(v) + for k, v in submit_record["metadata"].items() + } + + return proto.SubmitEmbeddingRecord( + id=submit_record["id"], + vector=vector, + metadata=proto.UpdateMetadata(metadata=metadata) + if metadata is not None + else None, + operation=to_proto_operation(submit_record["operation"]), + ) diff --git a/chromadb/segment/__init__.py b/chromadb/segment/__init__.py index 5c2f4316f06c..e92bccee6faf 100644 --- a/chromadb/segment/__init__.py +++ b/chromadb/segment/__init__.py @@ -39,6 +39,11 @@ def propagate_collection_metadata(metadata: Metadata) -> Optional[Metadata]: segment. Validation errors will be reported to the user.""" return None + @abstractmethod + def delete(self) -> None: + """Delete the segment and all its data""" + ... + S = TypeVar("S", bound=SegmentImplementation) diff --git a/chromadb/segment/impl/manager/local.py b/chromadb/segment/impl/manager/local.py index 1bf67aaf0491..e13452d41137 100644 --- a/chromadb/segment/impl/manager/local.py +++ b/chromadb/segment/impl/manager/local.py @@ -112,6 +112,9 @@ def delete_segments(self, collection_id: UUID) -> Sequence[UUID]: segments = self._sysdb.get_segments(collection=collection_id) for segment in segments: if segment["id"] in self._instances: + if segment["type"] == SegmentType.HNSW_LOCAL_PERSISTED.value: + instance = self.get_segment(collection_id, VectorReader) + instance.delete() del self._instances[segment["id"]] if collection_id in self._segment_cache: if segment["scope"] in self._segment_cache[collection_id]: diff --git a/chromadb/segment/impl/metadata/sqlite.py b/chromadb/segment/impl/metadata/sqlite.py index f4692fa73fa9..a7098d7808b6 100644 --- a/chromadb/segment/impl/metadata/sqlite.py +++ b/chromadb/segment/impl/metadata/sqlite.py @@ -1,8 +1,8 @@ -from typing import Optional, Sequence, Any, Tuple, cast, Generator, Union, Dict +from typing import Optional, Sequence, Any, Tuple, cast, Generator, Union, Dict, List from chromadb.segment import MetadataReader from chromadb.ingest import Consumer from chromadb.config import System -from chromadb.types import Segment +from chromadb.types import Segment, InclusionExclusionOperator from chromadb.db.impl.sqlite import SqliteDB from overrides import override from chromadb.db.base import ( @@ -105,7 +105,6 @@ def get_metadata( offset: Optional[int] = None, ) -> Sequence[MetadataEmbeddingRecord]: """Query for embedding metadata.""" - embeddings_t, metadata_t, fulltext_t = Tables( "embeddings", "embedding_metadata", "embedding_fulltext_search" ) @@ -135,7 +134,6 @@ def get_metadata( if where: q = q.where(self._where_map_criterion(q, where, embeddings_t, metadata_t)) - if where_document: q = q.where( self._where_doc_criterion(q, where_document, embeddings_t, fulltext_t) @@ -146,7 +144,6 @@ def get_metadata( limit = limit or 2**63 - 1 offset = offset or 0 - with self._db.tx() as cur: return list(islice(self._records(cur, q), offset, offset + limit)) @@ -405,7 +402,6 @@ def _where_map_criterion( self, q: QueryBuilder, where: Where, embeddings_t: Table, metadata_t: Table ) -> Criterion: clause: list[Criterion] = [] - for k, v in where.items(): if k == "$and": criteria = [ @@ -466,12 +462,16 @@ def _where_doc_criterion( raise ValueError(f"Unknown where_doc operator {k}") raise ValueError("Empty where_doc") + @override + def delete(self) -> None: + raise NotImplementedError() + def _encode_seq_id(seq_id: SeqId) -> bytes: """Encode a SeqID into a byte array""" - if seq_id.bit_length() < 64: + if seq_id.bit_length() <= 64: return int.to_bytes(seq_id, 8, "big") - elif seq_id.bit_length() < 192: + elif seq_id.bit_length() <= 192: return int.to_bytes(seq_id, 24, "big") else: raise ValueError(f"Unsupported SeqID: {seq_id}") @@ -488,24 +488,31 @@ def _decode_seq_id(seq_id_bytes: bytes) -> SeqId: def _where_clause( - expr: Union[LiteralValue, Dict[WhereOperator, LiteralValue]], + expr: Union[ + LiteralValue, + Dict[WhereOperator, LiteralValue], + Dict[InclusionExclusionOperator, List[LiteralValue]], + ], table: Table, ) -> Criterion: """Given a field name, an expression, and a table, construct a Pypika Criterion""" # Literal value case if isinstance(expr, (str, int, float, bool)): - return _where_clause({"$eq": expr}, table) + return _where_clause({cast(WhereOperator, "$eq"): expr}, table) # Operator dict case operator, value = next(iter(expr.items())) return _value_criterion(value, operator, table) -def _value_criterion(value: LiteralValue, op: WhereOperator, table: Table) -> Criterion: +def _value_criterion( + value: Union[LiteralValue, List[LiteralValue]], + op: Union[WhereOperator, InclusionExclusionOperator], + table: Table, +) -> Criterion: """Return a criterion to compare a value with the appropriate columns given its type and the operation type.""" - if isinstance(value, str): cols = [table.string_value] # isinstance(True, int) evaluates to True, so we need to check for bools separately @@ -515,6 +522,43 @@ def _value_criterion(value: LiteralValue, op: WhereOperator, table: Table) -> Cr cols = [table.int_value] elif isinstance(value, float) and op in ("$eq", "$ne"): cols = [table.float_value] + elif isinstance(value, list) and op in ("$in", "$nin"): + _v = value + if len(_v) == 0: + raise ValueError(f"Empty list for {op} operator") + if isinstance(value[0], str): + col_exprs = [ + table.string_value.isin(ParameterValue(_v)) + if op == "$in" + else table.str_value.notin(ParameterValue(_v)) + ] + elif isinstance(value[0], bool): + col_exprs = [ + table.bool_value.isin(ParameterValue(_v)) + if op == "$in" + else table.bool_value.notin(ParameterValue(_v)) + ] + elif isinstance(value[0], int): + col_exprs = [ + table.int_value.isin(ParameterValue(_v)) + if op == "$in" + else table.int_value.notin(ParameterValue(_v)) + ] + elif isinstance(value[0], float): + col_exprs = [ + table.float_value.isin(ParameterValue(_v)) + if op == "$in" + else table.float_value.notin(ParameterValue(_v)) + ] + elif isinstance(value, list) and op in ("$in", "$nin"): + col_exprs = [ + table.int_value.isin(ParameterValue(value)) + if op == "$in" + else table.int_value.notin(ParameterValue(value)), + table.float_value.isin(ParameterValue(value)) + if op == "$in" + else table.float_value.notin(ParameterValue(value)), + ] else: cols = [table.int_value, table.float_value] diff --git a/chromadb/segment/impl/vector/local_hnsw.py b/chromadb/segment/impl/vector/local_hnsw.py index 2b628bbcad9d..c45af628d2f8 100644 --- a/chromadb/segment/impl/vector/local_hnsw.py +++ b/chromadb/segment/impl/vector/local_hnsw.py @@ -305,3 +305,7 @@ def _write_records(self, records: Sequence[EmbeddingRecord]) -> None: batch.apply(record, label is not None) self._apply_batch(batch) + + @override + def delete(self) -> None: + raise NotImplementedError() diff --git a/chromadb/segment/impl/vector/local_persistent_hnsw.py b/chromadb/segment/impl/vector/local_persistent_hnsw.py index 0165e8358c2f..f8c74bd0fe7d 100644 --- a/chromadb/segment/impl/vector/local_persistent_hnsw.py +++ b/chromadb/segment/impl/vector/local_persistent_hnsw.py @@ -79,6 +79,7 @@ class PersistentLocalHnswSegment(LocalHnswSegment): _sync_threshold: int _persist_data: PersistentData _persist_directory: str + _allow_reset: bool def __init__(self, system: System, segment: Segment): super().__init__(system, segment) @@ -86,7 +87,7 @@ def __init__(self, system: System, segment: Segment): self._params = PersistentHnswParams(segment["metadata"] or {}) self._batch_size = self._params.batch_size self._sync_threshold = self._params.sync_threshold - + self._allow_reset = system.settings.allow_reset self._persist_directory = system.settings.require("persist_directory") self._curr_batch = Batch() self._brute_force_index = None @@ -206,7 +207,6 @@ def _write_records(self, records: Sequence[EmbeddingRecord]) -> None: """Add a batch of embeddings to the index""" if not self._running: raise RuntimeError("Cannot add embeddings to stopped component") - with WriteRWLock(self._lock): for record in records: if record["embedding"] is not None: @@ -224,11 +224,13 @@ def _write_records(self, records: Sequence[EmbeddingRecord]) -> None: exists_in_index = self._id_to_label.get( id, None ) is not None or self._brute_force_index.has_id(id) + exists_in_bf_index = self._brute_force_index.has_id(id) if op == Operation.DELETE: if exists_in_index: self._curr_batch.apply(record) - self._brute_force_index.delete([record]) + if exists_in_bf_index: + self._brute_force_index.delete([record]) else: logger.warning(f"Delete of nonexisting embedding ID: {id}") @@ -395,9 +397,18 @@ def query_vectors( @override def reset_state(self) -> None: + if self._allow_reset: + data_path = self._get_storage_folder() + if os.path.exists(data_path): + self.close_persistent_index() + shutil.rmtree(data_path, ignore_errors=True) + + @override + def delete(self) -> None: data_path = self._get_storage_folder() if os.path.exists(data_path): - shutil.rmtree(data_path, ignore_errors=True) + self.close_persistent_index() + shutil.rmtree(data_path, ignore_errors=False) @staticmethod def get_file_handle_count() -> int: diff --git a/chromadb/server/fastapi/__init__.py b/chromadb/server/fastapi/__init__.py index 249bcae167dd..e92d16d63ba4 100644 --- a/chromadb/server/fastapi/__init__.py +++ b/chromadb/server/fastapi/__init__.py @@ -8,10 +8,13 @@ from fastapi import HTTPException, status from uuid import UUID - import chromadb from chromadb.api.models.Collection import Collection from chromadb.api.types import GetResult, QueryResult +from chromadb.auth.fastapi import ( + FastAPIChromaAuthMiddleware, + FastAPIChromaAuthMiddlewareWrapper, +) from chromadb.config import Settings import chromadb.server import chromadb.api @@ -110,6 +113,12 @@ def __init__(self, settings: Settings): allow_origins=settings.chroma_server_cors_allow_origins, allow_methods=["*"], ) + if settings.chroma_server_auth_provider: + self._auth_middleware = self._api.require(FastAPIChromaAuthMiddleware) + self._app.add_middleware( + FastAPIChromaAuthMiddlewareWrapper, + auth_middleware=self._auth_middleware, + ) self.router = ChromaAPIRouter() @@ -117,6 +126,9 @@ def __init__(self, settings: Settings): self.router.add_api_route("/api/v1/reset", self.reset, methods=["POST"]) self.router.add_api_route("/api/v1/version", self.version, methods=["GET"]) self.router.add_api_route("/api/v1/heartbeat", self.heartbeat, methods=["GET"]) + self.router.add_api_route( + "/api/v1/pre-flight-checks", self.pre_flight_checks, methods=["GET"] + ) self.router.add_api_route( "/api/v1/collections", @@ -303,3 +315,8 @@ def get_nearest_neighbors( include=query.include, ) return nnresult + + def pre_flight_checks(self) -> Dict[str, Any]: + return { + "max_batch_size": self._api.max_batch_size, + } diff --git a/chromadb/test/auth/test_basic_auth.py b/chromadb/test/auth/test_basic_auth.py new file mode 100644 index 000000000000..f064be663358 --- /dev/null +++ b/chromadb/test/auth/test_basic_auth.py @@ -0,0 +1,12 @@ +import pytest + + +def test_invalid_auth_cred(api_wrong_cred): + with pytest.raises(Exception) as e: + api_wrong_cred.list_collections() + assert "Unauthorized" in str(e.value) + + +def test_server_basic_auth(api_with_server_auth): + cols = api_with_server_auth.list_collections() + assert len(cols) == 0 diff --git a/chromadb/test/auth/test_token_auth.py b/chromadb/test/auth/test_token_auth.py new file mode 100644 index 000000000000..4e99baae3064 --- /dev/null +++ b/chromadb/test/auth/test_token_auth.py @@ -0,0 +1,138 @@ +import string +from typing import Dict, Any + +import hypothesis.strategies as st +import pytest +from hypothesis import given, settings + +from chromadb.api import API +from chromadb.config import System +from chromadb.test.conftest import _fastapi_fixture + + +@st.composite +def token_config(draw: st.DrawFn) -> Dict[str, Any]: + token_header = draw(st.sampled_from(["AUTHORIZATION", "X_CHROMA_TOKEN", None])) + server_provider = draw( + st.sampled_from(["token", "chromadb.auth.token.TokenAuthServerProvider"]) + ) + client_provider = draw( + st.sampled_from(["token", "chromadb.auth.token.TokenAuthClientProvider"]) + ) + server_credentials_provider = draw( + st.sampled_from( + ["chromadb.auth.token.TokenConfigServerAuthCredentialsProvider"] + ) + ) + token = draw( + st.text( + alphabet=string.digits + string.ascii_letters + string.punctuation, + min_size=1, + max_size=50, + ) + ) + persistence = draw(st.booleans()) + return { + "token_transport_header": token_header, + "chroma_server_auth_credentials": token, + "chroma_client_auth_credentials": token, + "chroma_server_auth_provider": server_provider, + "chroma_client_auth_provider": client_provider, + "chroma_server_auth_credentials_provider": server_credentials_provider, + "is_persistent": persistence, + } + + +@settings(max_examples=10) +@given(token_config()) +def test_fastapi_server_token_auth(token_config: Dict[str, Any]) -> None: + api = _fastapi_fixture( + is_persistent=token_config["is_persistent"], + chroma_server_auth_provider=token_config["chroma_server_auth_provider"], + chroma_server_auth_credentials_provider=token_config[ + "chroma_server_auth_credentials_provider" + ], + chroma_server_auth_credentials=token_config["chroma_server_auth_credentials"], + chroma_client_auth_provider=token_config["chroma_client_auth_provider"], + chroma_client_auth_token_transport_header=token_config[ + "token_transport_header" + ], + chroma_server_auth_token_transport_header=token_config[ + "token_transport_header" + ], + chroma_client_auth_credentials=token_config["chroma_client_auth_credentials"], + ) + _sys: System = next(api) + _sys.reset_state() + _api = _sys.instance(API) + _api.heartbeat() + assert _api.list_collections() == [] + + +@st.composite +def random_token(draw: st.DrawFn) -> str: + return draw( + st.text(alphabet=string.ascii_letters + string.digits, min_size=1, max_size=5) + ) + + +@st.composite +def invalid_token(draw: st.DrawFn) -> str: + opposite_alphabet = set(string.printable) - set( + string.digits + string.ascii_letters + string.punctuation + ) + token = draw(st.text(alphabet=list(opposite_alphabet), min_size=1, max_size=50)) + return token + + +@settings(max_examples=10) +@given(tconf=token_config(), inval_tok=invalid_token()) +def test_invalid_token(tconf: Dict[str, Any], inval_tok: str) -> None: + api = _fastapi_fixture( + is_persistent=tconf["is_persistent"], + chroma_server_auth_provider=tconf["chroma_server_auth_provider"], + chroma_server_auth_credentials_provider=tconf[ + "chroma_server_auth_credentials_provider" + ], + chroma_server_auth_credentials=tconf["chroma_server_auth_credentials"], + chroma_server_auth_token_transport_header=tconf["token_transport_header"], + chroma_client_auth_provider=tconf["chroma_client_auth_provider"], + chroma_client_auth_token_transport_header=tconf["token_transport_header"], + chroma_client_auth_credentials=inval_tok, + ) + with pytest.raises(Exception) as e: + _sys: System = next(api) + _sys.reset_state() + _sys.instance(API) + assert "Invalid token" in str(e) + + +@settings(max_examples=10) +@given(token_config(), random_token()) +def test_fastapi_server_token_auth_wrong_token( + token_config: Dict[str, Any], random_token: str +) -> None: + api = _fastapi_fixture( + is_persistent=token_config["is_persistent"], + chroma_server_auth_provider=token_config["chroma_server_auth_provider"], + chroma_server_auth_credentials_provider=token_config[ + "chroma_server_auth_credentials_provider" + ], + chroma_server_auth_credentials=token_config["chroma_server_auth_credentials"], + chroma_server_auth_token_transport_header=token_config[ + "token_transport_header" + ], + chroma_client_auth_provider=token_config["chroma_client_auth_provider"], + chroma_client_auth_token_transport_header=token_config[ + "token_transport_header" + ], + chroma_client_auth_credentials=token_config["chroma_client_auth_credentials"] + + random_token, + ) + _sys: System = next(api) + _sys.reset_state() + _api = _sys.instance(API) + _api.heartbeat() + with pytest.raises(Exception) as e: + _api.list_collections() + assert "Unauthorized" in str(e) diff --git a/chromadb/test/conftest.py b/chromadb/test/conftest.py index b8b9fc864b54..fe91622e3832 100644 --- a/chromadb/test/conftest.py +++ b/chromadb/test/conftest.py @@ -1,14 +1,10 @@ -from chromadb.config import Settings, System -from chromadb.api import API -from chromadb.ingest import Producer -import chromadb.server.fastapi -from requests.exceptions import ConnectionError -import hypothesis -import tempfile +import logging +import multiprocessing import os -import uvicorn +import shutil +import socket +import tempfile import time -import pytest from typing import ( Generator, Iterator, @@ -18,19 +14,23 @@ Tuple, Callable, ) + +import hypothesis +import pytest +import uvicorn +from requests.exceptions import ConnectionError from typing_extensions import Protocol -import shutil -import logging -import socket -import multiprocessing -from chromadb.types import SeqId, SubmitEmbeddingRecord +import chromadb.server.fastapi +from chromadb.api import API +from chromadb.config import Settings, System from chromadb.db.mixins import embeddings_queue +from chromadb.ingest import Producer +from chromadb.types import SeqId, SubmitEmbeddingRecord root_logger = logging.getLogger() root_logger.setLevel(logging.DEBUG) # This will only run when testing - logger = logging.getLogger(__name__) hypothesis.settings.register_profile( @@ -53,7 +53,14 @@ def find_free_port() -> int: def _run_server( - port: int, is_persistent: bool = False, persist_directory: Optional[str] = None + port: int, + is_persistent: bool = False, + persist_directory: Optional[str] = None, + chroma_server_auth_provider: Optional[str] = None, + chroma_server_auth_credentials_provider: Optional[str] = None, + chroma_server_auth_credentials_file: Optional[str] = None, + chroma_server_auth_credentials: Optional[str] = None, + chroma_server_auth_token_transport_header: Optional[str] = None, ) -> None: """Run a Chroma server locally""" if is_persistent and persist_directory: @@ -66,6 +73,11 @@ def _run_server( is_persistent=is_persistent, persist_directory=persist_directory, allow_reset=True, + chroma_server_auth_provider=chroma_server_auth_provider, + chroma_server_auth_credentials_provider=chroma_server_auth_credentials_provider, + chroma_server_auth_credentials_file=chroma_server_auth_credentials_file, + chroma_server_auth_credentials=chroma_server_auth_credentials, + chroma_server_auth_token_transport_header=chroma_server_auth_token_transport_header, ) else: settings = Settings( @@ -76,6 +88,11 @@ def _run_server( chroma_segment_manager_impl="chromadb.segment.impl.manager.local.LocalSegmentManager", is_persistent=False, allow_reset=True, + chroma_server_auth_provider=chroma_server_auth_provider, + chroma_server_auth_credentials_provider=chroma_server_auth_credentials_provider, + chroma_server_auth_credentials_file=chroma_server_auth_credentials_file, + chroma_server_auth_credentials=chroma_server_auth_credentials, + chroma_server_auth_token_transport_header=chroma_server_auth_token_transport_header, ) server = chromadb.server.fastapi.FastAPI(settings) uvicorn.run(server.app(), host="0.0.0.0", port=port, log_level="error") @@ -94,18 +111,55 @@ def _await_server(api: API, attempts: int = 0) -> None: _await_server(api, attempts + 1) -def _fastapi_fixture(is_persistent: bool = False) -> Generator[System, None, None]: +def _fastapi_fixture( + is_persistent: bool = False, + chroma_server_auth_provider: Optional[str] = None, + chroma_server_auth_credentials_provider: Optional[str] = None, + chroma_client_auth_provider: Optional[str] = None, + chroma_server_auth_credentials_file: Optional[str] = None, + chroma_client_auth_credentials: Optional[str] = None, + chroma_server_auth_credentials: Optional[str] = None, + chroma_client_auth_token_transport_header: Optional[str] = None, + chroma_server_auth_token_transport_header: Optional[str] = None, +) -> Generator[System, None, None]: """Fixture generator that launches a server in a separate process, and yields a fastapi client connect to it""" port = find_free_port() logger.info(f"Running test FastAPI server on port {port}") ctx = multiprocessing.get_context("spawn") - args: Tuple[int, bool, Optional[str]] = (port, False, None) + args: Tuple[ + int, + bool, + Optional[str], + Optional[str], + Optional[str], + Optional[str], + Optional[str], + Optional[str], + ] = ( + port, + False, + None, + chroma_server_auth_provider, + chroma_server_auth_credentials_provider, + chroma_server_auth_credentials_file, + chroma_server_auth_credentials, + chroma_server_auth_token_transport_header, + ) persist_directory = None if is_persistent: persist_directory = tempfile.mkdtemp() - args = (port, is_persistent, persist_directory) + args = ( + port, + is_persistent, + persist_directory, + chroma_server_auth_provider, + chroma_server_auth_credentials_provider, + chroma_server_auth_credentials_file, + chroma_server_auth_credentials, + chroma_server_auth_token_transport_header, + ) proc = ctx.Process(target=_run_server, args=args, daemon=True) proc.start() settings = Settings( @@ -113,6 +167,9 @@ def _fastapi_fixture(is_persistent: bool = False) -> Generator[System, None, Non chroma_server_host="localhost", chroma_server_http_port=str(port), allow_reset=True, + chroma_client_auth_provider=chroma_client_auth_provider, + chroma_client_auth_credentials=chroma_client_auth_credentials, + chroma_client_auth_token_transport_header=chroma_client_auth_token_transport_header, ) system = System(settings) api = system.instance(API) @@ -134,6 +191,87 @@ def fastapi_persistent() -> Generator[System, None, None]: return _fastapi_fixture(is_persistent=True) +def fastapi_server_basic_auth() -> Generator[System, None, None]: + server_auth_file = os.path.abspath(os.path.join(".", "server.htpasswd")) + with open(server_auth_file, "w") as f: + f.write("admin:$2y$05$e5sRb6NCcSH3YfbIxe1AGu2h5K7OOd982OXKmd8WyQ3DRQ4MvpnZS\n") + for item in _fastapi_fixture( + is_persistent=False, + chroma_server_auth_provider="chromadb.auth.basic.BasicAuthServerProvider", + chroma_server_auth_credentials_provider="chromadb.auth.providers.HtpasswdFileServerAuthCredentialsProvider", + chroma_server_auth_credentials_file="./server.htpasswd", + chroma_client_auth_provider="chromadb.auth.basic.BasicAuthClientProvider", + chroma_client_auth_credentials="admin:admin", + ): + yield item + os.remove(server_auth_file) + + +def fastapi_server_basic_auth_param() -> Generator[System, None, None]: + server_auth_file = os.path.abspath(os.path.join(".", "server.htpasswd")) + with open(server_auth_file, "w") as f: + f.write("admin:$2y$05$e5sRb6NCcSH3YfbIxe1AGu2h5K7OOd982OXKmd8WyQ3DRQ4MvpnZS\n") + for item in _fastapi_fixture( + is_persistent=False, + chroma_server_auth_provider="chromadb.auth.basic.BasicAuthServerProvider", + chroma_server_auth_credentials_provider="chromadb.auth.providers.HtpasswdFileServerAuthCredentialsProvider", + chroma_server_auth_credentials_file="./server.htpasswd", + chroma_client_auth_provider="chromadb.auth.basic.BasicAuthClientProvider", + chroma_client_auth_credentials="admin:admin", + ): + yield item + os.remove(server_auth_file) + + +# TODO we need a generator for auth providers +def fastapi_server_basic_auth_file() -> Generator[System, None, None]: + server_auth_file = os.path.abspath(os.path.join(".", "server.htpasswd")) + with open(server_auth_file, "w") as f: + f.write("admin:$2y$05$e5sRb6NCcSH3YfbIxe1AGu2h5K7OOd982OXKmd8WyQ3DRQ4MvpnZS\n") + for item in _fastapi_fixture( + is_persistent=False, + chroma_server_auth_provider="chromadb.auth.basic.BasicAuthServerProvider", + chroma_server_auth_credentials_provider="chromadb.auth.providers.HtpasswdFileServerAuthCredentialsProvider", + chroma_server_auth_credentials_file="./server.htpasswd", + chroma_client_auth_provider="chromadb.auth.basic.BasicAuthClientProvider", + chroma_client_auth_credentials="admin:admin", + ): + yield item + os.remove(server_auth_file) + + +def fastapi_server_basic_auth_shorthand() -> Generator[System, None, None]: + server_auth_file = os.path.abspath(os.path.join(".", "server.htpasswd")) + with open(server_auth_file, "w") as f: + f.write("admin:$2y$05$e5sRb6NCcSH3YfbIxe1AGu2h5K7OOd982OXKmd8WyQ3DRQ4MvpnZS\n") + for item in _fastapi_fixture( + is_persistent=False, + chroma_server_auth_provider="basic", + chroma_server_auth_credentials_provider="htpasswd_file", + chroma_server_auth_credentials_file="./server.htpasswd", + chroma_client_auth_provider="basic", + chroma_client_auth_credentials="admin:admin", + ): + yield item + os.remove(server_auth_file) + + +def fastapi_server_basic_auth_invalid_cred() -> Generator[System, None, None]: + server_auth_file = os.path.abspath(os.path.join(".", "server.htpasswd")) + with open(server_auth_file, "w") as f: + f.write("admin:$2y$05$e5sRb6NCcSH3YfbIxe1AGu2h5K7OOd982OXKmd8WyQ3DRQ4MvpnZS\n") + for item in _fastapi_fixture( + is_persistent=False, + chroma_server_auth_provider="chromadb.auth.basic.BasicAuthServerProvider", + chroma_server_auth_credentials_provider="chromadb.auth.providers.HtpasswdFileServerAuthCredentialsProvider", + chroma_server_auth_credentials_file="./server.htpasswd", + chroma_client_auth_provider="chromadb.auth.basic.BasicAuthClientProvider", + chroma_client_auth_credentials="admin:admin1", + ): + yield item + os.remove(server_auth_file) + + def integration() -> Generator[System, None, None]: """Fixture generator for returning a client configured via environmenet variables, intended for externally configured integration tests @@ -192,11 +330,35 @@ def system_fixtures() -> List[Callable[[], Generator[System, None, None]]]: return fixtures +def system_fixtures_auth() -> List[Callable[[], Generator[System, None, None]]]: + fixtures = [ + fastapi_server_basic_auth_param, + fastapi_server_basic_auth_file, + fastapi_server_basic_auth_shorthand, + ] + return fixtures + + +def system_fixtures_wrong_auth() -> List[Callable[[], Generator[System, None, None]]]: + fixtures = [fastapi_server_basic_auth_invalid_cred] + return fixtures + + +@pytest.fixture(scope="module", params=system_fixtures_wrong_auth()) +def system_wrong_auth(request: pytest.FixtureRequest) -> Generator[API, None, None]: + yield next(request.param()) + + @pytest.fixture(scope="module", params=system_fixtures()) def system(request: pytest.FixtureRequest) -> Generator[API, None, None]: yield next(request.param()) +@pytest.fixture(scope="module", params=system_fixtures_auth()) +def system_auth(request: pytest.FixtureRequest) -> Generator[API, None, None]: + yield next(request.param()) + + @pytest.fixture(scope="function") def api(system: System) -> Generator[API, None, None]: system.reset_state() @@ -204,6 +366,23 @@ def api(system: System) -> Generator[API, None, None]: yield api +@pytest.fixture(scope="function") +def api_wrong_cred( + system_wrong_auth: System, +) -> Generator[API, None, None]: + system_wrong_auth.reset_state() + api = system_wrong_auth.instance(API) + yield api + + +@pytest.fixture(scope="function") +def api_with_server_auth(system_auth: System) -> Generator[API, None, None]: + _sys = system_auth + _sys.reset_state() + api = _sys.instance(API) + yield api + + # Producer / Consumer fixtures # diff --git a/chromadb/test/ef/test_default_ef.py b/chromadb/test/ef/test_default_ef.py new file mode 100644 index 000000000000..e1ed55206602 --- /dev/null +++ b/chromadb/test/ef/test_default_ef.py @@ -0,0 +1,62 @@ +from typing import List, Hashable + +import hypothesis.strategies as st +import onnxruntime +import pytest +from hypothesis import given + +from chromadb.utils.embedding_functions import ONNXMiniLM_L6_V2 + + +def unique_by(x: Hashable) -> Hashable: + return x + + +@given( + providers=st.lists( + st.sampled_from(onnxruntime.get_all_providers()).filter( + lambda x: x not in onnxruntime.get_available_providers() + ), + unique_by=unique_by, + min_size=1, + ) +) +def test_unavailable_provider_multiple(providers: List[str]) -> None: + with pytest.raises(ValueError) as e: + ef = ONNXMiniLM_L6_V2(preferred_providers=providers) + ef(["test"]) + assert "Preferred providers must be subset of available providers" in str(e.value) + + +@given( + providers=st.lists( + st.sampled_from(onnxruntime.get_all_providers()).filter( + lambda x: x in onnxruntime.get_available_providers() + ), + min_size=1, + unique_by=unique_by, + ) +) +def test_available_provider(providers: List[str]) -> None: + ef = ONNXMiniLM_L6_V2(preferred_providers=providers) + ef(["test"]) + + +def test_warning_no_providers_supplied() -> None: + ef = ONNXMiniLM_L6_V2() + ef(["test"]) + + +@given( + providers=st.lists( + st.sampled_from(onnxruntime.get_all_providers()).filter( + lambda x: x in onnxruntime.get_available_providers() + ), + min_size=1, + ).filter(lambda x: len(x) > len(set(x))) +) +def test_provider_repeating(providers: List[str]) -> None: + with pytest.raises(ValueError) as e: + ef = ONNXMiniLM_L6_V2(preferred_providers=providers) + ef(["test"]) + assert "Preferred providers must be unique" in str(e.value) diff --git a/chromadb/test/ingest/test_producer_consumer.py b/chromadb/test/ingest/test_producer_consumer.py index 84aa69ffd076..1163889a2460 100644 --- a/chromadb/test/ingest/test_producer_consumer.py +++ b/chromadb/test/ingest/test_producer_consumer.py @@ -1,3 +1,4 @@ +import asyncio import os import shutil import tempfile @@ -16,6 +17,7 @@ ) from chromadb.ingest import Producer, Consumer from chromadb.db.impl.sqlite import SqliteDB +from chromadb.ingest.impl.utils import create_topic_name from chromadb.test.conftest import ProducerFn from chromadb.types import ( SubmitEmbeddingRecord, @@ -51,8 +53,33 @@ def sqlite_persistent() -> Generator[Tuple[Producer, Consumer], None, None]: shutil.rmtree(save_path) +def pulsar() -> Generator[Tuple[Producer, Consumer], None, None]: + """Fixture generator for pulsar Producer + Consumer. This fixture requires a running + pulsar cluster. You can use bin/cluster-test.sh to start a standalone pulsar and run this test + """ + system = System( + Settings( + allow_reset=True, + chroma_producer_impl="chromadb.ingest.impl.pulsar.PulsarProducer", + chroma_consumer_impl="chromadb.ingest.impl.pulsar.PulsarConsumer", + pulsar_broker_url="localhost", + pulsar_admin_port="8080", + pulsar_broker_port="6650", + ) + ) + producer = system.require(Producer) + consumer = system.require(Consumer) + system.start() + yield producer, consumer + system.stop() + + def fixtures() -> List[Callable[[], Generator[Tuple[Producer, Consumer], None, None]]]: - return [sqlite, sqlite_persistent] + fixtures = [sqlite, sqlite_persistent] + if "CHROMA_CLUSTER_TEST_ONLY" in os.environ: + fixtures = [pulsar] + + return fixtures @pytest.fixture(scope="module", params=fixtures()) @@ -89,14 +116,20 @@ class CapturingConsumeFn: waiters: List[Tuple[int, Event]] def __init__(self) -> None: + """A function that captures embeddings and allows you to wait for a certain + number of embeddings to be available. It must be constructed in the thread with + the main event loop + """ self.embeddings = [] self.waiters = [] + self._loop = asyncio.get_event_loop() def __call__(self, embeddings: Sequence[EmbeddingRecord]) -> None: self.embeddings.extend(embeddings) for n, event in self.waiters: if len(self.embeddings) >= n: - event.set() + # event.set() is not thread safe, so we need to call it in the main event loop + self._loop.call_soon_threadsafe(event.set) async def get(self, n: int, timeout_secs: int = 10) -> Sequence[EmbeddingRecord]: "Wait until at least N embeddings are available, then return all embeddings" @@ -132,6 +165,10 @@ def assert_records_match( assert_approx_equal(inserted["embedding"], consumed["embedding"]) +def full_topic_name(topic_name: str) -> str: + return create_topic_name("default", "default", topic_name) + + @pytest.mark.asyncio async def test_backfill( producer_consumer: Tuple[Producer, Consumer], @@ -140,12 +177,14 @@ async def test_backfill( ) -> None: producer, consumer = producer_consumer producer.reset_state() + consumer.reset_state() - producer.create_topic("test_topic") - embeddings = produce_fns(producer, "test_topic", sample_embeddings, 3)[0] + topic_name = full_topic_name("test_topic") + producer.create_topic(topic_name) + embeddings = produce_fns(producer, topic_name, sample_embeddings, 3)[0] consume_fn = CapturingConsumeFn() - consumer.subscribe("test_topic", consume_fn, start=consumer.min_seqid()) + consumer.subscribe(topic_name, consume_fn, start=consumer.min_seqid()) recieved = await consume_fn.get(3) assert_records_match(embeddings, recieved) @@ -158,18 +197,21 @@ async def test_notifications( ) -> None: producer, consumer = producer_consumer producer.reset_state() - producer.create_topic("test_topic") + consumer.reset_state() + topic_name = full_topic_name("test_topic") + + producer.create_topic(topic_name) embeddings: List[SubmitEmbeddingRecord] = [] consume_fn = CapturingConsumeFn() - consumer.subscribe("test_topic", consume_fn, start=consumer.min_seqid()) + consumer.subscribe(topic_name, consume_fn, start=consumer.min_seqid()) for i in range(10): e = next(sample_embeddings) embeddings.append(e) - producer.submit_embedding("test_topic", e) + producer.submit_embedding(topic_name, e) received = await consume_fn.get(i + 1) assert_records_match(embeddings, received) @@ -181,8 +223,11 @@ async def test_multiple_topics( ) -> None: producer, consumer = producer_consumer producer.reset_state() - producer.create_topic("test_topic_1") - producer.create_topic("test_topic_2") + consumer.reset_state() + topic_name_1 = full_topic_name("test_topic_1") + topic_name_2 = full_topic_name("test_topic_2") + producer.create_topic(topic_name_1) + producer.create_topic(topic_name_2) embeddings_1: List[SubmitEmbeddingRecord] = [] embeddings_2: List[SubmitEmbeddingRecord] = [] @@ -190,19 +235,19 @@ async def test_multiple_topics( consume_fn_1 = CapturingConsumeFn() consume_fn_2 = CapturingConsumeFn() - consumer.subscribe("test_topic_1", consume_fn_1, start=consumer.min_seqid()) - consumer.subscribe("test_topic_2", consume_fn_2, start=consumer.min_seqid()) + consumer.subscribe(topic_name_1, consume_fn_1, start=consumer.min_seqid()) + consumer.subscribe(topic_name_2, consume_fn_2, start=consumer.min_seqid()) for i in range(10): e_1 = next(sample_embeddings) embeddings_1.append(e_1) - producer.submit_embedding("test_topic_1", e_1) + producer.submit_embedding(topic_name_1, e_1) results_2 = await consume_fn_1.get(i + 1) assert_records_match(embeddings_1, results_2) e_2 = next(sample_embeddings) embeddings_2.append(e_2) - producer.submit_embedding("test_topic_2", e_2) + producer.submit_embedding(topic_name_2, e_2) results_2 = await consume_fn_2.get(i + 1) assert_records_match(embeddings_2, results_2) @@ -215,21 +260,23 @@ async def test_start_seq_id( ) -> None: producer, consumer = producer_consumer producer.reset_state() - producer.create_topic("test_topic") + consumer.reset_state() + topic_name = full_topic_name("test_topic") + producer.create_topic(topic_name) consume_fn_1 = CapturingConsumeFn() consume_fn_2 = CapturingConsumeFn() - consumer.subscribe("test_topic", consume_fn_1, start=consumer.min_seqid()) + consumer.subscribe(topic_name, consume_fn_1, start=consumer.min_seqid()) - embeddings = produce_fns(producer, "test_topic", sample_embeddings, 5)[0] + embeddings = produce_fns(producer, topic_name, sample_embeddings, 5)[0] results_1 = await consume_fn_1.get(5) assert_records_match(embeddings, results_1) start = consume_fn_1.embeddings[-1]["seq_id"] - consumer.subscribe("test_topic", consume_fn_2, start=start) - second_embeddings = produce_fns(producer, "test_topic", sample_embeddings, 5)[0] + consumer.subscribe(topic_name, consume_fn_2, start=start) + second_embeddings = produce_fns(producer, topic_name, sample_embeddings, 5)[0] assert isinstance(embeddings, list) embeddings.extend(second_embeddings) results_2 = await consume_fn_2.get(5) @@ -244,20 +291,22 @@ async def test_end_seq_id( ) -> None: producer, consumer = producer_consumer producer.reset_state() - producer.create_topic("test_topic") + consumer.reset_state() + topic_name = full_topic_name("test_topic") + producer.create_topic(topic_name) consume_fn_1 = CapturingConsumeFn() consume_fn_2 = CapturingConsumeFn() - consumer.subscribe("test_topic", consume_fn_1, start=consumer.min_seqid()) + consumer.subscribe(topic_name, consume_fn_1, start=consumer.min_seqid()) - embeddings = produce_fns(producer, "test_topic", sample_embeddings, 10)[0] + embeddings = produce_fns(producer, topic_name, sample_embeddings, 10)[0] results_1 = await consume_fn_1.get(10) assert_records_match(embeddings, results_1) end = consume_fn_1.embeddings[-5]["seq_id"] - consumer.subscribe("test_topic", consume_fn_2, start=consumer.min_seqid(), end=end) + consumer.subscribe(topic_name, consume_fn_2, start=consumer.min_seqid(), end=end) results_2 = await consume_fn_2.get(6) assert_records_match(embeddings[:6], results_2) @@ -274,14 +323,16 @@ async def test_submit_batch( ) -> None: producer, consumer = producer_consumer producer.reset_state() + consumer.reset_state() + topic_name = full_topic_name("test_topic") embeddings = [next(sample_embeddings) for _ in range(100)] - producer.create_topic("test_topic") - producer.submit_embeddings("test_topic", embeddings=embeddings) + producer.create_topic(topic_name) + producer.submit_embeddings(topic_name, embeddings=embeddings) consume_fn = CapturingConsumeFn() - consumer.subscribe("test_topic", consume_fn, start=consumer.min_seqid()) + consumer.subscribe(topic_name, consume_fn, start=consumer.min_seqid()) recieved = await consume_fn.get(100) assert_records_match(embeddings, recieved) @@ -295,13 +346,16 @@ async def test_multiple_topics_batch( ) -> None: producer, consumer = producer_consumer producer.reset_state() + consumer.reset_state() - N_TOPICS = 100 + N_TOPICS = 2 consume_fns = [CapturingConsumeFn() for _ in range(N_TOPICS)] for i in range(N_TOPICS): - producer.create_topic(f"test_topic_{i}") + producer.create_topic(full_topic_name(f"test_topic_{i}")) consumer.subscribe( - f"test_topic_{i}", consume_fns[i], start=consumer.min_seqid() + full_topic_name(f"test_topic_{i}"), + consume_fns[i], + start=consumer.min_seqid(), ) embeddings_n: List[List[SubmitEmbeddingRecord]] = [[] for _ in range(N_TOPICS)] @@ -310,17 +364,17 @@ async def test_multiple_topics_batch( N_TO_PRODUCE = 100 total_produced = 0 for i in range(N_TO_PRODUCE // PRODUCE_BATCH_SIZE): - for i in range(N_TOPICS): - embeddings_n[i].extend( + for n in range(N_TOPICS): + embeddings_n[n].extend( produce_fns( producer, - f"test_topic_{i}", + full_topic_name(f"test_topic_{n}"), sample_embeddings, PRODUCE_BATCH_SIZE, )[0] ) - recieved = await consume_fns[i].get(total_produced + PRODUCE_BATCH_SIZE) - assert_records_match(embeddings_n[i], recieved) + recieved = await consume_fns[n].get(total_produced + PRODUCE_BATCH_SIZE) + assert_records_match(embeddings_n[n], recieved) total_produced += PRODUCE_BATCH_SIZE @@ -331,19 +385,21 @@ async def test_max_batch_size( ) -> None: producer, consumer = producer_consumer producer.reset_state() - max_batch_size = producer_consumer[0].max_batch_size + consumer.reset_state() + topic_name = full_topic_name("test_topic") + max_batch_size = producer.max_batch_size assert max_batch_size > 0 # Make sure that we can produce a batch of size max_batch_size embeddings = [next(sample_embeddings) for _ in range(max_batch_size)] consume_fn = CapturingConsumeFn() - consumer.subscribe("test_topic", consume_fn, start=consumer.min_seqid()) - producer.submit_embeddings("test_topic", embeddings=embeddings) + consumer.subscribe(topic_name, consume_fn, start=consumer.min_seqid()) + producer.submit_embeddings(topic_name, embeddings=embeddings) received = await consume_fn.get(max_batch_size, timeout_secs=120) assert_records_match(embeddings, received) embeddings = [next(sample_embeddings) for _ in range(max_batch_size + 1)] # Make sure that we can't produce a batch of size > max_batch_size with pytest.raises(ValueError) as e: - producer.submit_embeddings("test_topic", embeddings=embeddings) + producer.submit_embeddings(topic_name, embeddings=embeddings) assert "Cannot submit more than" in str(e.value) diff --git a/chromadb/test/property/strategies.py b/chromadb/test/property/strategies.py index 35310691a165..60bb5ac3bb67 100644 --- a/chromadb/test/property/strategies.py +++ b/chromadb/test/property/strategies.py @@ -14,6 +14,7 @@ from dataclasses import dataclass from chromadb.api.types import Documents, Embeddings, Metadata +from chromadb.types import LiteralValue # Set the random seed for reproducibility np.random.seed(0) # unnecessary, hypothesis does this for us @@ -460,6 +461,26 @@ def is_valid(self, rule) -> bool: # type: ignore return True +def opposite_value(value: LiteralValue) -> SearchStrategy[Any]: + """ + Returns a strategy that will generate all valid values except the input value - testing of $nin + """ + if isinstance(value, float): + return st.floats(allow_nan=False, allow_infinity=False).filter( + lambda x: x != value + ) + elif isinstance(value, str): + return safe_text.filter(lambda x: x != value) + elif isinstance(value, bool): + return st.booleans().filter(lambda x: x != value) + elif isinstance(value, int): + return st.integers(min_value=-(2**31), max_value=2**31 - 1).filter( + lambda x: x != value + ) + else: + return st.from_type(type(value)).filter(lambda x: x != value) + + @st.composite def where_clause(draw: st.DrawFn, collection: Collection) -> types.Where: """Generate a filter that could be used in a query against the given collection""" @@ -469,7 +490,7 @@ def where_clause(draw: st.DrawFn, collection: Collection) -> types.Where: key = draw(st.sampled_from(known_keys)) value = collection.known_metadata_keys[key] - legal_ops: List[Optional[str]] = [None, "$eq", "$ne"] + legal_ops: List[Optional[str]] = [None, "$eq", "$ne", "$in", "$nin"] if not isinstance(value, str) and not isinstance(value, bool): legal_ops.extend(["$gt", "$lt", "$lte", "$gte"]) if isinstance(value, float): @@ -480,6 +501,14 @@ def where_clause(draw: st.DrawFn, collection: Collection) -> types.Where: if op is None: return {key: value} + elif op == "$in": + if isinstance(value, str) and not value: + return {} + return {key: {op: [value, *[draw(opposite_value(value)) for _ in range(3)]]}} + elif op == "$nin": + if isinstance(value, str) and not value: + return {} + return {key: {op: [draw(opposite_value(value)) for _ in range(3)]}} else: return {key: {op: value}} diff --git a/chromadb/test/property/test_add.py b/chromadb/test/property/test_add.py index 602df2fa81b0..1980ed2a9d91 100644 --- a/chromadb/test/property/test_add.py +++ b/chromadb/test/property/test_add.py @@ -1,11 +1,15 @@ -from typing import cast +import random +import uuid +from random import randint +from typing import cast, List, Any, Dict import pytest import hypothesis.strategies as st from hypothesis import given, settings from chromadb.api import API -from chromadb.api.types import Embeddings +from chromadb.api.types import Embeddings, Metadatas import chromadb.test.property.strategies as strategies import chromadb.test.property.invariants as invariants +from chromadb.utils.batch_utils import create_batches collection_st = st.shared(strategies.collections(with_hnsw_params=True), key="coll") @@ -44,6 +48,79 @@ def test_add( ) +def create_large_recordset( + min_size: int = 45000, + max_size: int = 50000, +) -> strategies.RecordSet: + size = randint(min_size, max_size) + + ids = [str(uuid.uuid4()) for _ in range(size)] + metadatas = [{"some_key": f"{i}"} for i in range(size)] + documents = [f"Document {i}" for i in range(size)] + embeddings = [[1, 2, 3] for _ in range(size)] + record_set: Dict[str, List[Any]] = { + "ids": ids, + "embeddings": cast(Embeddings, embeddings), + "metadatas": metadatas, + "documents": documents, + } + return record_set + + +@given(collection=collection_st) +@settings(deadline=None, max_examples=1) +def test_add_large(api: API, collection: strategies.Collection) -> None: + api.reset() + record_set = create_large_recordset( + min_size=api.max_batch_size, + max_size=api.max_batch_size + int(api.max_batch_size * random.random()), + ) + coll = api.create_collection( + name=collection.name, + metadata=collection.metadata, + embedding_function=collection.embedding_function, + ) + normalized_record_set = invariants.wrap_all(record_set) + + if not invariants.is_metadata_valid(normalized_record_set): + with pytest.raises(Exception): + coll.add(**normalized_record_set) + return + for batch in create_batches( + api=api, + ids=cast(List[str], record_set["ids"]), + embeddings=cast(Embeddings, record_set["embeddings"]), + metadatas=cast(Metadatas, record_set["metadatas"]), + documents=cast(List[str], record_set["documents"]), + ): + coll.add(*batch) + invariants.count(coll, cast(strategies.RecordSet, normalized_record_set)) + + +@given(collection=collection_st) +@settings(deadline=None, max_examples=1) +def test_add_large_exceeding(api: API, collection: strategies.Collection) -> None: + api.reset() + record_set = create_large_recordset( + min_size=api.max_batch_size, + max_size=api.max_batch_size + int(api.max_batch_size * random.random()), + ) + coll = api.create_collection( + name=collection.name, + metadata=collection.metadata, + embedding_function=collection.embedding_function, + ) + normalized_record_set = invariants.wrap_all(record_set) + + if not invariants.is_metadata_valid(normalized_record_set): + with pytest.raises(Exception): + coll.add(**normalized_record_set) + return + with pytest.raises(Exception) as e: + coll.add(**record_set) + assert "exceeds maximum batch size" in str(e.value) + + # TODO: This test fails right now because the ids are not sorted by the input order @pytest.mark.xfail( reason="This is expected to fail right now. We should change the API to sort the \ diff --git a/chromadb/test/property/test_client_url.py b/chromadb/test/property/test_client_url.py new file mode 100644 index 000000000000..cc5df1e05141 --- /dev/null +++ b/chromadb/test/property/test_client_url.py @@ -0,0 +1,134 @@ +from typing import Optional +from urllib.parse import urlparse + +import pytest +from hypothesis import given, strategies as st + +from chromadb.api.fastapi import FastAPI + + +def hostname_strategy() -> st.SearchStrategy[str]: + label = st.text( + alphabet=st.characters(min_codepoint=97, max_codepoint=122), + min_size=1, + max_size=63, + ) + return st.lists(label, min_size=1, max_size=3).map("-".join) + + +tld_list = ["com", "org", "net", "edu"] + + +def domain_strategy() -> st.SearchStrategy[str]: + label = st.text( + alphabet=st.characters(min_codepoint=97, max_codepoint=122), + min_size=1, + max_size=63, + ) + tld = st.sampled_from(tld_list) + return st.tuples(label, tld).map(".".join) + + +port_strategy = st.one_of(st.integers(min_value=1, max_value=65535), st.none()) + +ssl_enabled_strategy = st.booleans() + + +def url_path_strategy() -> st.SearchStrategy[str]: + path_segment = st.text( + alphabet=st.sampled_from("abcdefghijklmnopqrstuvwxyz/-_"), + min_size=1, + max_size=10, + ) + return ( + st.lists(path_segment, min_size=1, max_size=5) + .map("/".join) + .map(lambda x: "/" + x) + ) + + +def is_valid_url(url: str) -> bool: + try: + parsed = urlparse(url) + return all([parsed.scheme, parsed.netloc]) + except Exception: + return False + + +def generate_valid_domain_url() -> st.SearchStrategy[str]: + return st.builds( + lambda url_scheme, hostname, url_path: f"{url_scheme}{hostname}{url_path}", + url_scheme=st.sampled_from(["http://", "https://"]), + hostname=domain_strategy(), + url_path=url_path_strategy(), + ) + + +def generate_invalid_domain_url() -> st.SearchStrategy[str]: + return st.builds( + lambda url_scheme, hostname, url_path: f"{url_scheme}{hostname}{url_path}", + url_scheme=st.builds( + lambda scheme, suffix: f"{scheme}{suffix}", + scheme=st.text(max_size=10), + suffix=st.sampled_from(["://", ":///", ":////", ""]), + ), + hostname=domain_strategy(), + url_path=url_path_strategy(), + ) + + +host_or_domain_strategy = st.one_of( + generate_valid_domain_url(), domain_strategy(), st.sampled_from(["localhost"]) +) + + +@given( + hostname=host_or_domain_strategy, + port=port_strategy, + ssl_enabled=ssl_enabled_strategy, + default_api_path=st.sampled_from(["/api/v1", "/api/v2", None]), +) +def test_url_resolve( + hostname: str, + port: Optional[int], + ssl_enabled: bool, + default_api_path: Optional[str], +) -> None: + _url = FastAPI.resolve_url( + chroma_server_host=hostname, + chroma_server_http_port=port, + chroma_server_ssl_enabled=ssl_enabled, + default_api_path=default_api_path, + ) + assert is_valid_url(_url), f"Invalid URL: {_url}" + assert ( + _url.startswith("https") if ssl_enabled else _url.startswith("http") + ), f"Invalid URL: {_url} - SSL Enabled: {ssl_enabled}" + if hostname.startswith("http"): + assert ":" + str(port) not in _url, f"Port in URL not expected: {_url}" + else: + assert ":" + str(port) in _url, f"Port in URL expected: {_url}" + if default_api_path: + assert _url.endswith(default_api_path), f"Invalid URL: {_url}" + + +@given( + hostname=generate_invalid_domain_url(), + port=port_strategy, + ssl_enabled=ssl_enabled_strategy, + default_api_path=st.sampled_from(["/api/v1", "/api/v2", None]), +) +def test_resolve_invalid( + hostname: str, + port: Optional[int], + ssl_enabled: bool, + default_api_path: Optional[str], +) -> None: + with pytest.raises(ValueError) as e: + FastAPI.resolve_url( + chroma_server_host=hostname, + chroma_server_http_port=port, + chroma_server_ssl_enabled=ssl_enabled, + default_api_path=default_api_path, + ) + assert "Invalid URL" in str(e.value) diff --git a/chromadb/test/property/test_embeddings.py b/chromadb/test/property/test_embeddings.py index a495eb9fe649..db68a03f9213 100644 --- a/chromadb/test/property/test_embeddings.py +++ b/chromadb/test/property/test_embeddings.py @@ -367,35 +367,42 @@ def test_escape_chars_in_ids(api: API) -> None: assert coll.count() == 0 -def test_delete_empty_fails(api: API): +@pytest.mark.parametrize( + "kwargs", + [ + {}, + {"ids": []}, + {"where": {}}, + {"where_document": {}}, + {"where_document": {}, "where": {}}, + ], +) +def test_delete_empty_fails(api: API, kwargs: dict): api.reset() coll = api.create_collection(name="foo") - - error_valid = ( - lambda e: "You must provide either ids, where, or where_document to delete." - in e - ) - with pytest.raises(Exception) as e: - coll.delete() - assert error_valid(str(e)) - - with pytest.raises(Exception): - coll.delete(ids=[]) - assert error_valid(str(e)) - - with pytest.raises(Exception): - coll.delete(where={}) - assert error_valid(str(e)) - - with pytest.raises(Exception): - coll.delete(where_document={}) - assert error_valid(str(e)) - - with pytest.raises(Exception): - coll.delete(where_document={}, where={}) - assert error_valid(str(e)) - + coll.delete(**kwargs) + assert "You must provide either ids, where, or where_document to delete." in str(e) + + +@pytest.mark.parametrize( + "kwargs", + [ + {"ids": ["foo"]}, + {"where": {"foo": "bar"}}, + {"where_document": {"$contains": "bar"}}, + {"ids": ["foo"], "where": {"foo": "bar"}}, + {"ids": ["foo"], "where_document": {"$contains": "bar"}}, + { + "ids": ["foo"], + "where": {"foo": "bar"}, + "where_document": {"$contains": "bar"}, + }, + ], +) +def test_delete_success(api: API, kwargs: dict): + api.reset() + coll = api.create_collection(name="foo") # Should not raise coll.delete(where_document={"$contains": "bar"}) coll.delete(where={"foo": "bar"}) @@ -429,3 +436,4 @@ def test_autocasting_validate_embeddings_incompatible_types( validate_embeddings(embds) assert "Expected each value in the embedding to be a int or float" in str(e) + diff --git a/chromadb/test/property/test_filtering.py b/chromadb/test/property/test_filtering.py index d9ca874bf452..ddcdefb0ed3f 100644 --- a/chromadb/test/property/test_filtering.py +++ b/chromadb/test/property/test_filtering.py @@ -42,11 +42,16 @@ def _filter_where_clause(clause: Where, metadata: Metadata) -> bool: if key == "$or": assert isinstance(expr, list) return any(_filter_where_clause(clause, metadata) for clause in expr) + if key == "$in": + assert isinstance(expr, list) + return metadata[key] in expr if key in metadata else False + if key == "$nin": + assert isinstance(expr, list) + return metadata[key] not in expr # expr is an operator expression assert isinstance(expr, dict) op, val = list(expr.items())[0] - assert isinstance(metadata, dict) if key not in metadata: return False @@ -55,6 +60,10 @@ def _filter_where_clause(clause: Where, metadata: Metadata) -> bool: return key in metadata and metadata_key == val elif op == "$ne": return key in metadata and metadata_key != val + elif op == "$in": + return key in metadata and metadata_key in val + elif op == "$nin": + return key in metadata and metadata_key not in val # The following conditions only make sense for numeric values assert isinstance(metadata_key, int) or isinstance(metadata_key, float) @@ -132,7 +141,6 @@ def _filter_embedding_set( ) if not _filter_where_doc_clause(filter["where_document"], documents[i]): ids.discard(normalized_record_set["ids"][i]) - return list(ids) @@ -174,7 +182,6 @@ def test_filterable_metadata_get( return coll.add(**record_set) - for filter in filters: result_ids = coll.get(**filter)["ids"] expected_ids = _filter_embedding_set(record_set, filter) diff --git a/chromadb/test/segment/test_vector.py b/chromadb/test/segment/test_vector.py index cf55985d0f49..3a9145827e9f 100644 --- a/chromadb/test/segment/test_vector.py +++ b/chromadb/test/segment/test_vector.py @@ -516,3 +516,153 @@ def test_delete_without_add( producer.submit_embedding(topic, delete_record) except BaseException: pytest.fail("Unexpected error. Deleting on an empty segment should not raise.") + + +def test_delete_with_local_segment_storage( + system: System, + sample_embeddings: Iterator[SubmitEmbeddingRecord], + vector_reader: Type[VectorReader], + produce_fns: ProducerFn, +) -> None: + producer = system.instance(Producer) + system.reset_state() + segment_definition = create_random_segment_definition() + topic = str(segment_definition["topic"]) + + segment = vector_reader(system, segment_definition) + segment.start() + + embeddings, seq_ids = produce_fns( + producer=producer, topic=topic, embeddings=sample_embeddings, n=5 + ) + + sync(segment, seq_ids[-1]) + assert segment.count() == 5 + + delete_record = SubmitEmbeddingRecord( + id=embeddings[0]["id"], + embedding=None, + encoding=None, + metadata=None, + operation=Operation.DELETE, + ) + assert isinstance(seq_ids, List) + seq_ids.append( + produce_fns( + producer=producer, + topic=topic, + n=1, + embeddings=(delete_record for _ in range(1)), + )[1][0] + ) + + sync(segment, seq_ids[-1]) + + # Assert that the record is gone using `count` + assert segment.count() == 4 + + # Assert that the record is gone using `get` + assert segment.get_vectors(ids=[embeddings[0]["id"]]) == [] + results = segment.get_vectors() + assert len(results) == 4 + # get_vectors returns results in arbitrary order + results = sorted(results, key=lambda v: v["id"]) + for actual, expected in zip(results, embeddings[1:]): + assert actual["id"] == expected["id"] + assert approx_equal_vector( + actual["embedding"], cast(Vector, expected["embedding"]) + ) + + # Assert that the record is gone from KNN search + vector = cast(Vector, embeddings[0]["embedding"]) + query = VectorQuery( + vectors=[vector], k=10, allowed_ids=None, options=None, include_embeddings=False + ) + knn_results = segment.query_vectors(query) + assert len(results) == 4 + assert set(r["id"] for r in knn_results[0]) == set(e["id"] for e in embeddings[1:]) + + # Delete is idempotent + if isinstance(segment, PersistentLocalHnswSegment): + assert os.path.exists(segment._get_storage_folder()) + segment.delete() + assert not os.path.exists(segment._get_storage_folder()) + segment.delete() # should not raise + elif isinstance(segment, LocalHnswSegment): + with pytest.raises(NotImplementedError): + segment.delete() + + +def test_reset_state_ignored_for_allow_reset_false( + system: System, + sample_embeddings: Iterator[SubmitEmbeddingRecord], + vector_reader: Type[VectorReader], + produce_fns: ProducerFn, +) -> None: + producer = system.instance(Producer) + system.reset_state() + segment_definition = create_random_segment_definition() + topic = str(segment_definition["topic"]) + + segment = vector_reader(system, segment_definition) + segment.start() + + embeddings, seq_ids = produce_fns( + producer=producer, topic=topic, embeddings=sample_embeddings, n=5 + ) + + sync(segment, seq_ids[-1]) + assert segment.count() == 5 + + delete_record = SubmitEmbeddingRecord( + id=embeddings[0]["id"], + embedding=None, + encoding=None, + metadata=None, + operation=Operation.DELETE, + ) + assert isinstance(seq_ids, List) + seq_ids.append( + produce_fns( + producer=producer, + topic=topic, + n=1, + embeddings=(delete_record for _ in range(1)), + )[1][0] + ) + + sync(segment, seq_ids[-1]) + + # Assert that the record is gone using `count` + assert segment.count() == 4 + + # Assert that the record is gone using `get` + assert segment.get_vectors(ids=[embeddings[0]["id"]]) == [] + results = segment.get_vectors() + assert len(results) == 4 + # get_vectors returns results in arbitrary order + results = sorted(results, key=lambda v: v["id"]) + for actual, expected in zip(results, embeddings[1:]): + assert actual["id"] == expected["id"] + assert approx_equal_vector( + actual["embedding"], cast(Vector, expected["embedding"]) + ) + + # Assert that the record is gone from KNN search + vector = cast(Vector, embeddings[0]["embedding"]) + query = VectorQuery( + vectors=[vector], k=10, allowed_ids=None, options=None, include_embeddings=False + ) + knn_results = segment.query_vectors(query) + assert len(results) == 4 + assert set(r["id"] for r in knn_results[0]) == set(e["id"] for e in embeddings[1:]) + + if isinstance(segment, PersistentLocalHnswSegment): + if segment._allow_reset: + assert os.path.exists(segment._get_storage_folder()) + segment.reset_state() + assert not os.path.exists(segment._get_storage_folder()) + else: + assert os.path.exists(segment._get_storage_folder()) + segment.reset_state() + assert os.path.exists(segment._get_storage_folder()) diff --git a/chromadb/test/test_api.py b/chromadb/test/test_api.py index dc2a21f0467b..8a12a1d97354 100644 --- a/chromadb/test/test_api.py +++ b/chromadb/test/test_api.py @@ -1,5 +1,8 @@ # type: ignore +import requests + import chromadb +from chromadb.api.fastapi import FastAPI from chromadb.api.types import QueryResult from chromadb.config import Settings import chromadb.server.fastapi @@ -163,6 +166,22 @@ def test_heartbeat(api): assert heartbeat > datetime.now() - timedelta(seconds=10) +def test_max_batch_size(api): + print(api) + batch_size = api.max_batch_size + assert batch_size > 0 + + +def test_pre_flight_checks(api): + if not isinstance(api, FastAPI): + pytest.skip("Not a FastAPI instance") + + resp = requests.get(f"{api._api_url}/pre-flight-checks") + assert resp.status_code == 200 + assert resp.json() is not None + assert "max_batch_size" in resp.json().keys() + + batch_records = { "embeddings": [[1.1, 2.3, 3.2], [1.2, 2.24, 3.2]], "ids": ["https://example.com/1", "https://example.com/2"], diff --git a/chromadb/test/test_cli.py b/chromadb/test/test_cli.py new file mode 100644 index 000000000000..231877341f56 --- /dev/null +++ b/chromadb/test/test_cli.py @@ -0,0 +1,21 @@ +from typer.testing import CliRunner + +from chromadb.cli.cli import app + +runner = CliRunner() + + +def test_app() -> None: + result = runner.invoke( + app, + [ + "run", + "--path", + "chroma_test_data", + "--port", + "8001", + "--test", + ], + ) + assert "chroma_test_data" in result.stdout + assert "8001" in result.stdout diff --git a/chromadb/types.py b/chromadb/types.py index fd5c3709045a..713cab7757c1 100644 --- a/chromadb/types.py +++ b/chromadb/types.py @@ -122,7 +122,11 @@ class VectorQueryResult(TypedDict): Literal["$ne"], Literal["$eq"], ] -OperatorExpression = Dict[Union[WhereOperator, LogicalOperator], LiteralValue] +InclusionExclusionOperator = Union[Literal["$in"], Literal["$nin"]] +OperatorExpression = Union[ + Dict[Union[WhereOperator, LogicalOperator], LiteralValue], + Dict[InclusionExclusionOperator, List[LiteralValue]], +] Where = Dict[ Union[str, LogicalOperator], Union[LiteralValue, OperatorExpression, List["Where"]] diff --git a/chromadb/utils/__init__.py b/chromadb/utils/__init__.py index e69de29bb2d1..fe6bb81853b1 100644 --- a/chromadb/utils/__init__.py +++ b/chromadb/utils/__init__.py @@ -0,0 +1,12 @@ +import importlib +from typing import Type, TypeVar, cast + +C = TypeVar("C") + + +def get_class(fqn: str, type: Type[C]) -> Type[C]: + """Given a fully qualifed class name, import the module and return the class""" + module_name, class_name = fqn.rsplit(".", 1) + module = importlib.import_module(module_name) + cls = getattr(module, class_name) + return cast(Type[C], cls) diff --git a/chromadb/utils/batch_utils.py b/chromadb/utils/batch_utils.py new file mode 100644 index 000000000000..c8c1ac1e4761 --- /dev/null +++ b/chromadb/utils/batch_utils.py @@ -0,0 +1,34 @@ +from typing import Optional, Tuple, List +from chromadb.api import API +from chromadb.api.types import ( + Documents, + Embeddings, + IDs, + Metadatas, +) + + +def create_batches( + api: API, + ids: IDs, + embeddings: Optional[Embeddings] = None, + metadatas: Optional[Metadatas] = None, + documents: Optional[Documents] = None, +) -> List[Tuple[IDs, Embeddings, Optional[Metadatas], Optional[Documents]]]: + _batches: List[ + Tuple[IDs, Embeddings, Optional[Metadatas], Optional[Documents]] + ] = [] + if len(ids) > api.max_batch_size: + # create split batches + for i in range(0, len(ids), api.max_batch_size): + _batches.append( + ( # type: ignore + ids[i : i + api.max_batch_size], + embeddings[i : i + api.max_batch_size] if embeddings else None, + metadatas[i : i + api.max_batch_size] if metadatas else None, + documents[i : i + api.max_batch_size] if documents else None, + ) + ) + else: + _batches.append((ids, embeddings, metadatas, documents)) # type: ignore + return _batches diff --git a/chromadb/utils/distance_functions.py b/chromadb/utils/distance_functions.py index 88fc77060f76..e7e77bf7f94c 100644 --- a/chromadb/utils/distance_functions.py +++ b/chromadb/utils/distance_functions.py @@ -1,18 +1,22 @@ -from typing import Dict, Callable +""" +These functions match what the spec of hnswlib is. +""" import numpy as np -import numpy.typing as npt +from numpy.typing import ArrayLike -# These match what the spec of hnswlib is -# This epsilon is used to prevent division by zero and the value is the same -# https://github.com/nmslib/hnswlib/blob/359b2ba87358224963986f709e593d799064ace6/python_bindings/bindings.cpp#L238 -NORM_EPS = 1e-30 -distance_functions: Dict[str, Callable[[npt.ArrayLike, npt.ArrayLike], float]] = { - "l2": lambda x, y: np.linalg.norm(x - y) ** 2, # type: ignore - "cosine": lambda x, y: 1 - np.dot(x, y) / ((np.linalg.norm(x) + NORM_EPS) * (np.linalg.norm(y) + NORM_EPS)), # type: ignore - "ip": lambda x, y: 1 - np.dot(x, y), # type: ignore -} +def l2(x: ArrayLike, y: ArrayLike) -> float: + return np.linalg.norm(x - y) ** 2 -l2 = distance_functions["l2"] -cosine = distance_functions["cosine"] -ip = distance_functions["ip"] + +def cosine(x: ArrayLike, y: ArrayLike) -> float: + # This epsilon is used to prevent division by zero, and the value is the same + # https://github.com/nmslib/hnswlib/blob/359b2ba87358224963986f709e593d799064ace6/python_bindings/bindings.cpp#L238 + NORM_EPS = 1e-30 + return 1 - np.dot(x, y) / ( + (np.linalg.norm(x) + NORM_EPS) * (np.linalg.norm(y) + NORM_EPS) + ) + + +def ip(x: ArrayLike, y: ArrayLike) -> float: + return 1 - np.dot(x, y) diff --git a/chromadb/utils/embedding_functions.py b/chromadb/utils/embedding_functions.py index c51995c9460d..124213c365b1 100644 --- a/chromadb/utils/embedding_functions.py +++ b/chromadb/utils/embedding_functions.py @@ -1,3 +1,5 @@ +import logging + from chromadb.api.types import Documents, EmbeddingFunction, Embeddings from pathlib import Path import os @@ -14,6 +16,8 @@ except ImportError: is_thin_client = False +logger = logging.getLogger(__name__) + class SentenceTransformerEmbeddingFunction(EmbeddingFunction): # Since we do dynamic imports we have to type this as Any @@ -244,9 +248,20 @@ class ONNXMiniLM_L6_V2(EmbeddingFunction): # https://github.com/python/mypy/issues/7291 mypy makes you type the constructor if # no args - def __init__(self) -> None: + def __init__(self, preferred_providers: Optional[List[str]] = None) -> None: # Import dependencies on demand to mirror other embedding functions. This # breaks typechecking, thus the ignores. + # convert the list to set for unique values + if preferred_providers and not all( + [isinstance(i, str) for i in preferred_providers] + ): + raise ValueError("Preferred providers must be a list of strings") + # check for duplicate providers + if preferred_providers and len(preferred_providers) != len( + set(preferred_providers) + ): + raise ValueError("Preferred providers must be unique") + self._preferred_providers = preferred_providers try: # Equivalent to import onnxruntime self.ort = importlib.import_module("onnxruntime") @@ -334,10 +349,27 @@ def _init_model_and_tokenizer(self) -> None: # https://github.com/UKPLab/sentence-transformers/blob/3e1929fddef16df94f8bc6e3b10598a98f46e62d/docs/_static/html/models_en_sentence_embeddings.html#LL480 self.tokenizer.enable_truncation(max_length=256) self.tokenizer.enable_padding(pad_id=0, pad_token="[PAD]", length=256) + + if self._preferred_providers is None or len(self._preferred_providers) == 0: + if len(self.ort.get_available_providers()) > 0: + logger.debug( + f"WARNING: No ONNX providers provided, defaulting to available providers: " + f"{self.ort.get_available_providers()}" + ) + self._preferred_providers = self.ort.get_available_providers() + elif not set(self._preferred_providers).issubset( + set(self.ort.get_available_providers()) + ): + raise ValueError( + f"Preferred providers must be subset of available providers: {self.ort.get_available_providers()}" + ) self.model = self.ort.InferenceSession( os.path.join( self.DOWNLOAD_PATH, self.EXTRACTED_FOLDER_NAME, "model.onnx" - ) + ), + # Since 1.9 onnyx runtime requires providers to be specified when there are multiple available - https://onnxruntime.ai/docs/api/python/api_summary.html + # This is probably not ideal but will improve DX as no exceptions will be raised in multi-provider envs + providers=self._preferred_providers, ) def __call__(self, texts: Documents) -> Embeddings: diff --git a/clients/js/DEVELOP.md b/clients/js/DEVELOP.md index d106513054b6..c82fd15327ed 100644 --- a/clients/js/DEVELOP.md +++ b/clients/js/DEVELOP.md @@ -5,25 +5,63 @@ This readme is helpful for local dev. ### Prereqs: - Make sure you have Java installed (for the generator). You can download it from [java.com](https://java.com) +- Make sure you set ALLOW_RESET=True for your Docker Container. If you don't do this, tests won't pass. +``` +environment: + - IS_PERSISTENT=TRUE + - ALLOW_RESET=True +``` - Make sure you are running the docker backend at localhost:8000 (\*there is probably a way to stand up the fastapi server by itself and programmatically in the loop of generating this, but not prioritizing it for now. It may be important for the release) ### Generating 1. `yarn` to install deps -2. `yarn genapi-zsh` if you have zsh +2. `yarn genapi` 3. Examples are in the `examples` folder. There is one for the browser and one for node. Run them with `yarn dev`, eg `cd examples/browser && yarn dev` ### Running test -`yarn test` will launch a test docker backend. -`yarn test:run` will run against the docker backend you have running. But CAUTION, it will delete data. +`yarn test` will launch a test docker backend, run a db cleanup and run tests. +`yarn test:run` will run against the docker backend you have running. But CAUTION, it will delete data. This is the easiest and fastest way to run tests. ### Pushing to npm -The goal of the design is that this will be added to our github action releases so that the JS API is always up to date and pinned against the python backend API. +#### Automatically +##### Increase the version number +1. Create a new PR for the release that upgrades the version in code. Name it `js_release/A.B.C` for production releases and `js_release_alpha/A.B.C` for alpha releases. In the package.json update the version number to the new version. For production releases this is just the version number, for alpha +releases this is the version number with '-alphaX' appended to it. For example, if the current version is 1.0.0, the alpha release would be 1.0.0-alpha1 for the first alpha release, 1.0.0-alpha2 for the second alpha release, etc. +2. Add the "release" label to this PR +3. Once the PR is merged, tag your commit SHA with the release version + +```bash +git tag js_release_A.B.C + +# or for alpha releases: + +git tag js_release_alpha_A.B.C +``` + +4. You need to then wait for the github action for main for `chroma js release` to complete on main. + +##### Perform the release +1. Push your tag to origin to create the release + +```bash + +git push origin js_release_A.B.C + +# or for alpha releases: + +git push origin js_release_alpha_A.B.C +``` +2. This will trigger a Github action which performs the release + +#### Manually `npm run release` pushes the `package.json` defined packaged to the package manager for authenticated users. It will build, test, and then publish the new version. + + ### Useful links https://gaganpreet.in/posts/hyperproductive-apis-fastapi/ diff --git a/clients/js/package.json b/clients/js/package.json index 663042b775ce..b48269e6f648 100644 --- a/clients/js/package.json +++ b/clients/js/package.json @@ -1,16 +1,16 @@ { "name": "chromadb", - "version": "1.5.6", + "version": "1.5.11", "description": "A JavaScript interface for chroma", "keywords": [], "author": "", "license": "Apache-2.0", "devDependencies": { + "@openapi-generator-plus/typescript-fetch-client-generator": "^1.5.0", "@types/jest": "^29.5.0", "jest": "^29.5.0", "npm-run-all": "^4.1.5", "openapi-generator-plus": "^2.6.0", - "@openapi-generator-plus/typescript-fetch-client-generator": "^1.5.0", "prettier": "2.8.7", "rimraf": "^5.0.0", "ts-jest": "^29.1.0", @@ -19,7 +19,7 @@ "typescript": "^5.0.4" }, "main": "dist/main/index.js", - "module": "dist/module/index.js", + "module": "dist/module/index.js", "exports": { "require": "./dist/main/index.js", "import": "./dist/module/index.js" @@ -29,22 +29,51 @@ "dist" ], "scripts": { - "test": "run-s db:clean db:run test:runfull db:clean", + "test": "run-s db:clean db:cleanauth db:run test:runfull db:clean db:run-auth test:runfull-authonly db:cleanauth", + "testnoauth": "run-s db:clean db:run test:runfull db:clean", + "testauth": "run-s db:cleanauth db:run-auth test:runfull-authonly db:cleanauth", "test:set-port": "cross-env URL=localhost:8001", - "test:run": "jest --runInBand", - "test:runfull": "PORT=8001 jest --runInBand", + "test:run": "jest --runInBand --testPathIgnorePatterns=test/auth.*.test.ts", + "test:run-auth-basic": "jest --runInBand --testPathPattern=test/auth.basic.test.ts", + "test:run-auth-token": "jest --runInBand --testPathPattern=test/auth.token.test.ts", + "test:run-auth-xtoken": "XTOKEN_TEST=true jest --runInBand --testPathPattern=test/auth.token.test.ts", + "test:runfull": "PORT=8001 jest --runInBand --testPathIgnorePatterns=test/auth.*.test.ts", + "test:runfull-authonly": "run-s db:run-auth-basic test:runfull-authonly-basic db:clean db:run-auth-token test:runfull-authonly-token db:clean db:run-auth-xtoken test:runfull-authonly-xtoken db:clean", + "test:runfull-authonly-basic": "PORT=8001 jest --runInBand --testPathPattern=test/auth.basic.test.ts", + "test:runfull-authonly-token": "PORT=8001 jest --runInBand --testPathPattern=test/auth.token.test.ts", + "test:runfull-authonly-xtoken": "PORT=8001 XTOKEN_TEST=true jest --runInBand --testPathPattern=test/auth.token.test.ts", "test:update": "run-s db:clean db:run && jest --runInBand --updateSnapshot && run-s db:clean", "db:clean": "cd ../.. && CHROMA_PORT=8001 docker-compose -f docker-compose.test.yml down --volumes", + "db:cleanauth": "cd ../.. && CHROMA_PORT=8001 docker-compose -f docker-compose.test-auth.yml down --volumes", "db:run": "cd ../.. && CHROMA_PORT=8001 docker-compose -f docker-compose.test.yml up --detach && sleep 5", + "db:run-auth-basic": "cd ../.. && docker run --rm --entrypoint htpasswd httpd:2 -Bbn admin admin > server.htpasswd && echo \"CHROMA_SERVER_AUTH_CREDENTIALS_FILE=/chroma/server.htpasswd\\nCHROMA_SERVER_AUTH_CREDENTIALS_PROVIDER=chromadb.auth.providers.HtpasswdFileServerAuthCredentialsProvider\\nCHROMA_SERVER_AUTH_PROVIDER=chromadb.auth.basic.BasicAuthServerProvider\\nCHROMA_PORT=8001\" > .chroma_env && docker-compose -f docker-compose.test-auth.yml --env-file ./.chroma_env up --detach && sleep 5", + "db:run-auth-token": "cd ../.. && echo \"CHROMA_SERVER_AUTH_CREDENTIALS=test-token\nCHROMA_SERVER_AUTH_CREDENTIALS_PROVIDER=chromadb.auth.token.TokenConfigServerAuthCredentialsProvider\nCHROMA_SERVER_AUTH_PROVIDER=chromadb.auth.token.TokenAuthServerProvider\\nCHROMA_PORT=8001\" > .chroma_env && docker-compose -f docker-compose.test-auth.yml --env-file ./.chroma_env up --detach && sleep 5", + "db:run-auth-xtoken": "cd ../.. && echo \"CHROMA_SERVER_AUTH_TOKEN_TRANSPORT_HEADER=X_CHROMA_TOKEN\nCHROMA_SERVER_AUTH_CREDENTIALS=test-token\nCHROMA_SERVER_AUTH_CREDENTIALS_PROVIDER=chromadb.auth.token.TokenConfigServerAuthCredentialsProvider\nCHROMA_SERVER_AUTH_PROVIDER=chromadb.auth.token.TokenAuthServerProvider\\nCHROMA_PORT=8001\" > .chroma_env && docker-compose -f docker-compose.test-auth.yml --env-file ./.chroma_env up --detach && sleep 5", "clean": "rimraf dist", "build": "run-s clean build:*", "build:main": "tsc -p tsconfig.json", "build:module": "tsc -p tsconfig.module.json", "genapi": "./genapi.sh", "prettier": "prettier --write .", - "release": "run-s build test:run && npm publish" + "release": "run-s build test:run && npm publish", + "release_alpha": "run-s build test:run && npm publish --tag alpha" + }, + "engines": { + "node": ">=14.17.0" }, "dependencies": { "isomorphic-fetch": "^3.0.0" + }, + "peerDependencies": { + "cohere-ai": "^5.0.0 || ^6.0.0", + "openai": "^3.0.0 || ^4.0.0" + }, + "peerDependenciesMeta": { + "cohere-ai": { + "optional": true + }, + "openai": { + "optional": true + } } } diff --git a/clients/js/src/ChromaClient.ts b/clients/js/src/ChromaClient.ts index 8278c41a17ad..a5779dbba1ea 100644 --- a/clients/js/src/ChromaClient.ts +++ b/clients/js/src/ChromaClient.ts @@ -1,8 +1,13 @@ import { IEmbeddingFunction } from './embeddings/IEmbeddingFunction'; -import { Configuration, ApiApi as DefaultApi, Api } from "./generated"; +import { Configuration, ApiApi as DefaultApi } from "./generated"; import { handleSuccess, handleError } from "./utils"; import { Collection } from './Collection'; import { CollectionMetadata, CollectionType, ConfigOptions } from './types'; +import { + AuthOptions, + ClientAuthProtocolAdapter, + IsomorphicFetchClientAuthProtocolAdapter +} from "./auth"; export class ChromaClient { @@ -10,6 +15,7 @@ export class ChromaClient { * @ignore */ private api: DefaultApi & ConfigOptions; + private apiAdapter: ClientAuthProtocolAdapter|undefined; /** * Creates a new ChromaClient instance. @@ -26,16 +32,24 @@ export class ChromaClient { */ constructor({ path, - fetchOptions + fetchOptions, + auth, }: { path?: string, - fetchOptions?: RequestInit + fetchOptions?: RequestInit, + auth?: AuthOptions, } = {}) { if (path === undefined) path = "http://localhost:8000"; const apiConfig: Configuration = new Configuration({ basePath: path, }); - this.api = new DefaultApi(apiConfig); + if (auth !== undefined) { + this.apiAdapter = new IsomorphicFetchClientAuthProtocolAdapter(new DefaultApi(apiConfig), auth); + this.api = this.apiAdapter.getApi(); + } else { + this.api = new DefaultApi(apiConfig); + } + this.api.options = fetchOptions ?? {}; } diff --git a/clients/js/src/auth.ts b/clients/js/src/auth.ts new file mode 100644 index 000000000000..4f833f97d617 --- /dev/null +++ b/clients/js/src/auth.ts @@ -0,0 +1,321 @@ +import {ApiApi as DefaultApi} from "./generated"; + +export interface ClientAuthProvider { + /** + * Abstract method for authenticating a client. + */ + authenticate(): ClientAuthResponse; +} + +export interface ClientAuthConfigurationProvider { + /** + * Abstract method for getting the configuration for the client. + */ + getConfig(): T; +} + +export interface ClientAuthCredentialsProvider { + /** + * Abstract method for getting the credentials for the client. + * @param user + */ + getCredentials(user?: string): T; +} + +enum AuthInfoType { + COOKIE = "cookie", + HEADER = "header", + URL = "url", + METADATA = "metadata" + +} + +export interface ClientAuthResponse { + getAuthInfoType(): AuthInfoType; + + getAuthInfo(): { key: string, value: string }; +} + + +export interface AbstractCredentials { + getCredentials(): T; +} + +export interface ClientAuthProtocolAdapter { + injectCredentials(injectionContext: T): T; + + getApi(): any; +} + + +class SecretStr { + constructor(private readonly secret: string) { + } + + getSecret(): string { + return this.secret; + } +} + +const base64Encode = (str: string): string => { + return Buffer.from(str).toString('base64'); +}; + +class BasicAuthCredentials implements AbstractCredentials { + private readonly credentials: SecretStr; + + constructor(_creds: string) { + this.credentials = new SecretStr(base64Encode(_creds)) + } + + getCredentials(): SecretStr { + //encode base64 + return this.credentials; + } +} + + +class BasicAuthClientAuthResponse implements ClientAuthResponse { + constructor(private readonly credentials: BasicAuthCredentials) { + } + + getAuthInfo(): { key: string; value: string } { + return {key: "Authorization", value: "Basic " + this.credentials.getCredentials().getSecret()}; + } + + getAuthInfoType(): AuthInfoType { + return AuthInfoType.HEADER; + } +} + +export class BasicAuthCredentialsProvider implements ClientAuthCredentialsProvider { + private readonly credentials: BasicAuthCredentials; + + /** + * Creates a new BasicAuthCredentialsProvider. This provider loads credentials from provided text credentials or from the environment variable CHROMA_CLIENT_AUTH_CREDENTIALS. + * @param _creds - The credentials + * @throws {Error} If neither credentials provider or text credentials are supplied. + */ + + constructor(_creds: string | undefined) { + if (_creds === undefined && !process.env.CHROMA_CLIENT_AUTH_CREDENTIALS) throw new Error("Credentials must be supplied via environment variable (CHROMA_CLIENT_AUTH_CREDENTIALS) or passed in as configuration."); + this.credentials = new BasicAuthCredentials((_creds ?? process.env.CHROMA_CLIENT_AUTH_CREDENTIALS) as string); + } + + getCredentials(): BasicAuthCredentials { + return this.credentials; + } +} + +class BasicAuthClientAuthProvider implements ClientAuthProvider { + private readonly credentialsProvider: ClientAuthCredentialsProvider; + + /** + * Creates a new BasicAuthClientAuthProvider. + * @param options - The options for the authentication provider. + * @param options.textCredentials - The credentials for the authentication provider. + * @param options.credentialsProvider - The credentials provider for the authentication provider. + * @throws {Error} If neither credentials provider or text credentials are supplied. + */ + + constructor(options: { + textCredentials: any; + credentialsProvider: ClientAuthCredentialsProvider | undefined + }) { + if (!options.credentialsProvider && !options.textCredentials) { + throw new Error("Either credentials provider or text credentials must be supplied."); + } + this.credentialsProvider = options.credentialsProvider || new BasicAuthCredentialsProvider(options.textCredentials); + } + + authenticate(): ClientAuthResponse { + return new BasicAuthClientAuthResponse(this.credentialsProvider.getCredentials()); + } +} + +class TokenAuthCredentials implements AbstractCredentials { + private readonly credentials: SecretStr; + + constructor(_creds: string) { + this.credentials = new SecretStr(_creds) + } + + getCredentials(): SecretStr { + return this.credentials; + } +} + +export class TokenCredentialsProvider implements ClientAuthCredentialsProvider { + private readonly credentials: TokenAuthCredentials; + + constructor(_creds: string | undefined) { + if (_creds === undefined && !process.env.CHROMA_CLIENT_AUTH_CREDENTIALS) throw new Error("Credentials must be supplied via environment variable (CHROMA_CLIENT_AUTH_CREDENTIALS) or passed in as configuration."); + this.credentials = new TokenAuthCredentials((_creds ?? process.env.CHROMA_CLIENT_AUTH_CREDENTIALS) as string); + } + + getCredentials(): TokenAuthCredentials { + return this.credentials; + } +} + +export class TokenClientAuthProvider implements ClientAuthProvider { + private readonly credentialsProvider: ClientAuthCredentialsProvider; + private readonly providerOptions: { headerType: TokenHeaderType }; + + constructor(options: { + textCredentials: any; + credentialsProvider: ClientAuthCredentialsProvider | undefined, + providerOptions?: { headerType: TokenHeaderType } + }) { + if (!options.credentialsProvider && !options.textCredentials) { + throw new Error("Either credentials provider or text credentials must be supplied."); + } + if (options.providerOptions === undefined || !options.providerOptions.hasOwnProperty("headerType")) { + this.providerOptions = {headerType: "AUTHORIZATION"}; + } else { + this.providerOptions = {headerType: options.providerOptions.headerType}; + } + this.credentialsProvider = options.credentialsProvider || new TokenCredentialsProvider(options.textCredentials); + } + + authenticate(): ClientAuthResponse { + return new TokenClientAuthResponse(this.credentialsProvider.getCredentials(), this.providerOptions.headerType); + } + +} + + +type TokenHeaderType = 'AUTHORIZATION' | 'X_CHROMA_TOKEN'; + +const TokenHeader: Record { key: string; value: string; }> = { + AUTHORIZATION: (value: string) => ({key: "Authorization", value: `Bearer ${value}`}), + X_CHROMA_TOKEN: (value: string) => ({key: "X-Chroma-Token", value: value}) +} + +class TokenClientAuthResponse implements ClientAuthResponse { + constructor(private readonly credentials: TokenAuthCredentials, private readonly headerType: TokenHeaderType = 'AUTHORIZATION') { + } + + getAuthInfo(): { key: string; value: string } { + if (this.headerType === 'AUTHORIZATION') { + return TokenHeader.AUTHORIZATION(this.credentials.getCredentials().getSecret()); + } else if (this.headerType === 'X_CHROMA_TOKEN') { + return TokenHeader.X_CHROMA_TOKEN(this.credentials.getCredentials().getSecret()); + } else { + throw new Error("Invalid header type: " + this.headerType + ". Valid types are: " + Object.keys(TokenHeader).join(", ")); + } + } + + getAuthInfoType(): AuthInfoType { + return AuthInfoType.HEADER; + } +} + + +export class IsomorphicFetchClientAuthProtocolAdapter implements ClientAuthProtocolAdapter { + authProvider: ClientAuthProvider | undefined; + wrapperApi: DefaultApi | undefined; + + /** + * Creates a new adapter of IsomorphicFetchClientAuthProtocolAdapter. + * @param api - The API to wrap. + * @param authConfiguration - The configuration for the authentication provider. + */ + + constructor(private api: DefaultApi, authConfiguration: AuthOptions) { + + switch (authConfiguration.provider) { + case "basic": + this.authProvider = new BasicAuthClientAuthProvider({ + textCredentials: authConfiguration.credentials, + credentialsProvider: authConfiguration.credentialsProvider + }); + break; + case "token": + this.authProvider = new TokenClientAuthProvider({ + textCredentials: authConfiguration.credentials, + credentialsProvider: authConfiguration.credentialsProvider, + providerOptions: authConfiguration.providerOptions + }); + break; + default: + this.authProvider = undefined; + break; + } + if (this.authProvider !== undefined) { + this.wrapperApi = this.wrapMethods(this.api); + } + } + + getApi(): DefaultApi { + return this.wrapperApi ?? this.api; + } + + getAllMethods(obj: any): string[] { + let methods: string[] = []; + let currentObj = obj; + + do { + const objMethods = Object.getOwnPropertyNames(currentObj) + .filter(name => typeof currentObj[name] === 'function' && name !== 'constructor'); + + methods = methods.concat(objMethods); + currentObj = Object.getPrototypeOf(currentObj); + } while (currentObj); + + return methods; + } + + wrapMethods(obj: any): any { + let self = this; + const methodNames = Object.getOwnPropertyNames(Object.getPrototypeOf(obj)) + .filter(name => typeof obj[name] === 'function' && name !== 'constructor'); + + return new Proxy(obj, { + get(target, prop: string) { + if (methodNames.includes(prop)) { + return new Proxy(target[prop], { + apply(fn, thisArg, args) { + const modifiedArgs = args.map(arg => { + if (arg && typeof arg === 'object' && 'method' in arg) { + return self.injectCredentials(arg as RequestInit); + } + return arg; + }); + if (Object.keys(modifiedArgs[modifiedArgs.length - 1]).length === 0) { + modifiedArgs[modifiedArgs.length - 1] = self.injectCredentials({} as RequestInit); + } else { + modifiedArgs[modifiedArgs.length - 1] = self.injectCredentials(modifiedArgs[modifiedArgs.length - 1] as RequestInit); + } + return fn.apply(thisArg, modifiedArgs); + } + }); + } + return target[prop]; + } + }); + } + + injectCredentials(injectionContext: RequestInit): RequestInit { + const authInfo = this.authProvider?.authenticate().getAuthInfo(); + if (authInfo) { + const {key, value} = authInfo; + injectionContext = { + ...injectionContext, + headers: { + [key]: value + }, + } + } + return injectionContext; + } +} + + +export type AuthOptions = { + provider: ClientAuthProvider | string | undefined, + credentialsProvider?: ClientAuthCredentialsProvider | undefined, + configProvider?: ClientAuthConfigurationProvider | undefined, + credentials?: any | undefined, + providerOptions?: any | undefined +} diff --git a/clients/js/src/embeddings/OpenAIEmbeddingFunction.ts b/clients/js/src/embeddings/OpenAIEmbeddingFunction.ts index 334a5a03ef68..3a87ae1f9071 100644 --- a/clients/js/src/embeddings/OpenAIEmbeddingFunction.ts +++ b/clients/js/src/embeddings/OpenAIEmbeddingFunction.ts @@ -1,16 +1,83 @@ -import { IEmbeddingFunction } from "./IEmbeddingFunction"; +import {IEmbeddingFunction} from "./IEmbeddingFunction"; + let OpenAIApi: any; +let openAiVersion = null; +let openAiMajorVersion = null; + +interface OpenAIAPI { + createEmbedding: (params: { + model: string; + input: string[]; + user?: string; + }) => Promise; +} + +class OpenAIAPIv3 implements OpenAIAPI { + private readonly configuration: any; + private openai: any; + + constructor(configuration: { organization: string, apiKey: string }) { + this.configuration = new OpenAIApi.Configuration({ + organization: configuration.organization, + apiKey: configuration.apiKey, + }); + this.openai = new OpenAIApi.OpenAIApi(this.configuration); + } + + public async createEmbedding(params: { + model: string, + input: string[], + user?: string + }): Promise { + const embeddings: number[][] = []; + const response = await this.openai.createEmbedding({ + model: params.model, + input: params.input, + }).catch((error: any) => { + throw error; + }); + // @ts-ignore + const data = response.data["data"]; + for (let i = 0; i < data.length; i += 1) { + embeddings.push(data[i]["embedding"]); + } + return embeddings + } +} + +class OpenAIAPIv4 implements OpenAIAPI { + private readonly apiKey: any; + private openai: any; + + constructor(apiKey: any) { + this.apiKey = apiKey; + this.openai = new OpenAIApi({ + apiKey: this.apiKey, + }); + } + + public async createEmbedding(params: { + model: string, + input: string[], + user?: string + }): Promise { + const embeddings: number[][] = []; + const response = await this.openai.embeddings.create(params); + const data = response["data"]; + for (let i = 0; i < data.length; i += 1) { + embeddings.push(data[i]["embedding"]); + } + return embeddings + } +} export class OpenAIEmbeddingFunction implements IEmbeddingFunction { private api_key: string; private org_id: string; private model: string; + private openaiApi: OpenAIAPI; - constructor({ - openai_api_key, - openai_model, - openai_organization_id, - }: { + constructor({openai_api_key, openai_model, openai_organization_id}: { openai_api_key: string, openai_model?: string, openai_organization_id?: string @@ -18,31 +85,41 @@ export class OpenAIEmbeddingFunction implements IEmbeddingFunction { try { // eslint-disable-next-line global-require,import/no-extraneous-dependencies OpenAIApi = require("openai"); - } catch { - throw new Error( - "Please install the openai package to use the OpenAIEmbeddingFunction, `npm install -S openai`" - ); + let version = null; + try { + const {VERSION} = require('openai/version'); + version = VERSION; + } catch (e) { + version = "3.x"; + } + openAiVersion = version.replace(/[^0-9.]/g, ''); + openAiMajorVersion = openAiVersion.split('.')[0]; + } catch (_a) { + // @ts-ignore + if (_a.code === 'MODULE_NOT_FOUND') { + throw new Error("Please install the openai package to use the OpenAIEmbeddingFunction, `npm install -S openai`"); + } + throw _a; // Re-throw other errors } this.api_key = openai_api_key; this.org_id = openai_organization_id || ""; this.model = openai_model || "text-embedding-ada-002"; + if (openAiMajorVersion > 3) { + this.openaiApi = new OpenAIAPIv4(this.api_key); + } else { + this.openaiApi = new OpenAIAPIv3({ + organization: this.org_id, + apiKey: this.api_key, + }); + } } public async generate(texts: string[]): Promise { - const configuration = new OpenAIApi.Configuration({ - organization: this.org_id, - apiKey: this.api_key, - }); - const openai = new OpenAIApi.OpenAIApi(configuration); - const embeddings = []; - const response = await openai.createEmbedding({ + return await this.openaiApi.createEmbedding({ model: this.model, input: texts, + }).catch((error: any) => { + throw error; }); - const data = response.data["data"]; - for (let i = 0; i < data.length; i += 1) { - embeddings.push(data[i]["embedding"]); - } - return embeddings; } } diff --git a/clients/js/src/embeddings/TransformersEmbeddingFunction.ts b/clients/js/src/embeddings/TransformersEmbeddingFunction.ts index 887910c159bc..960a69c03642 100644 --- a/clients/js/src/embeddings/TransformersEmbeddingFunction.ts +++ b/clients/js/src/embeddings/TransformersEmbeddingFunction.ts @@ -1,3 +1,4 @@ +import { importOptionalModule } from "../utils"; import { IEmbeddingFunction } from "./IEmbeddingFunction"; // Dynamically import module @@ -26,11 +27,9 @@ export class TransformersEmbeddingFunction implements IEmbeddingFunction { progress_callback?: Function | null; } = {}) { try { - // Since Transformers.js is an ESM package, we use the dynamic `import` syntax instead of `require`. - // Also, since we use `"module": "commonjs"` in tsconfig.json, we use the following workaround to ensure - // the dynamic import is not transpiled to a `require` statement. - // For more information, see https://github.com/microsoft/TypeScript/issues/43329#issuecomment-1008361973 - TransformersApi = Function('return import("@xenova/transformers")')(); + // Use dynamic import to support browser environments because we do not have a bundler that handles browser support. + // The util importOptionalModule is used to prevent issues when bundlers try to locate the dependency even when it's optional. + TransformersApi = importOptionalModule("@xenova/transformers"); } catch (e) { throw new Error( "Please install the @xenova/transformers package to use the TransformersEmbeddingFunction, `npm install -S @xenova/transformers`." diff --git a/clients/js/src/embeddings/WebAIEmbeddingFunction.ts b/clients/js/src/embeddings/WebAIEmbeddingFunction.ts index e76bc5c20f0c..983d4b39fce8 100755 --- a/clients/js/src/embeddings/WebAIEmbeddingFunction.ts +++ b/clients/js/src/embeddings/WebAIEmbeddingFunction.ts @@ -1,3 +1,4 @@ +import { importOptionalModule } from "../utils"; import { IEmbeddingFunction } from "./IEmbeddingFunction"; /** @@ -157,15 +158,15 @@ export class WebAIEmbeddingFunction implements IEmbeddingFunction { ) { this.proxy = proxy ? proxy : true; try { - // @ts-ignore - const webAI = await import("@visheratin/web-ai"); + const webAI = await importOptionalModule("@visheratin/web-ai"); if (wasmPath) { webAI.SessionParams.wasmRoot = wasmPath; } switch (modality) { case "text": { - // @ts-ignore - const webAIText = await import("@visheratin/web-ai/text"); + const webAIText = await importOptionalModule( + "@visheratin/web-ai/text" + ); let id = "mini-lm-v2-quant"; //default text model if (modelID) { id = modelID; @@ -182,8 +183,9 @@ export class WebAIEmbeddingFunction implements IEmbeddingFunction { ); } case "image": { - // @ts-ignore - const webAIImage = await import("@visheratin/web-ai/image"); + const webAIImage = await importOptionalModule( + "@visheratin/web-ai/image" + ); let id = "efficientformer-l1-feature-quant"; //default image model if (modelID) { id = modelID; @@ -200,8 +202,9 @@ export class WebAIEmbeddingFunction implements IEmbeddingFunction { ); } case "multimodal": { - // @ts-ignore - const webAIImage = await import("@visheratin/web-ai/multimodal"); + const webAIImage = await importOptionalModule( + "@visheratin/web-ai/multimodal" + ); let id = "clip-base-quant"; //default multimodal model if (modelID) { id = modelID; diff --git a/clients/js/src/types.ts b/clients/js/src/types.ts index 8787d5e5659e..1f1dd04c4c82 100644 --- a/clients/js/src/types.ts +++ b/clients/js/src/types.ts @@ -20,13 +20,15 @@ export type IDs = ID[]; export type PositiveInteger = number; -type LiteralValue = string | number; +type LiteralValue = string | number | boolean; +type ListLiteralValue = LiteralValue[]; type LiteralNumber = number; type LogicalOperator = "$and" | "$or"; +type InclusionOperator = "$in" | "$nin"; type WhereOperator = "$gt" | "$gte" | "$lt" | "$lte" | "$ne" | "$eq"; type OperatorExpression = { - [key in WhereOperator | LogicalOperator]?: LiteralValue | LiteralNumber; + [key in WhereOperator | InclusionOperator | LogicalOperator ]?: LiteralValue | ListLiteralValue; }; type BaseWhere = { @@ -77,4 +79,4 @@ export type CollectionMetadata = Record; // see all options here: https://www.jsdocs.io/package/@types/node-fetch#RequestInit export type ConfigOptions = { options?: RequestInit; -}; \ No newline at end of file +}; diff --git a/clients/js/src/utils.ts b/clients/js/src/utils.ts index 619152854830..62a7931e1366 100644 --- a/clients/js/src/utils.ts +++ b/clients/js/src/utils.ts @@ -1,66 +1,84 @@ -import { Api } from "./generated" +import { Api } from "./generated"; import Count200Response = Api.Count200Response; // a function to convert a non-Array object to an Array export function toArray(obj: T | Array): Array { - if (Array.isArray(obj)) { - return obj; - } else { - return [obj]; - } + if (Array.isArray(obj)) { + return obj; + } else { + return [obj]; + } } // a function to convert an array to array of arrays -export function toArrayOfArrays(obj: Array> | Array): Array> { - if (Array.isArray(obj[0])) { - return obj as Array>; - } else { - return [obj] as Array>; - } +export function toArrayOfArrays( + obj: Array> | Array +): Array> { + if (Array.isArray(obj[0])) { + return obj as Array>; + } else { + return [obj] as Array>; + } } // we need to override constructors to make it work with jest // https://stackoverflow.com/questions/76007003/jest-tobeinstanceof-expected-constructor-array-received-constructor-array export function repack(value: unknown): any { - if (Boolean(value) && typeof value === "object") { - if (Array.isArray(value)) { - return new Array(...value); - } else { - return { ...value }; - } + if (Boolean(value) && typeof value === "object") { + if (Array.isArray(value)) { + return new Array(...value); } else { - return value; + return { ...value }; } + } else { + return value; + } } export async function handleError(error: unknown) { - - if (error instanceof Response) { - try { - const res = await error.json(); - if ("error" in res) { - return { error: res.error }; - } - } catch (e: unknown) { - return { - //@ts-ignore - error: - e && typeof e === "object" && "message" in e - ? e.message - : "unknown error", - }; - } + if (error instanceof Response) { + try { + const res = await error.json(); + if ("error" in res) { + return { error: res.error }; + } + } catch (e: unknown) { + return { + //@ts-ignore + error: + e && typeof e === "object" && "message" in e + ? e.message + : "unknown error", + }; } - return { error }; + } + return { error }; } -export async function handleSuccess(response: Response | string | Count200Response) { - switch (true) { - case response instanceof Response: - return repack(await (response as Response).json()); - case typeof response === "string": - return repack((response as string)); // currently version is the only thing that return non-JSON - default: - return repack(response); - } +export async function handleSuccess( + response: Response | string | Count200Response +) { + switch (true) { + case response instanceof Response: + return repack(await (response as Response).json()); + case typeof response === "string": + return repack(response as string); // currently version is the only thing that return non-JSON + default: + return repack(response); + } +} + +/** + * Dynamically imports a specified module, providing a workaround for browser environments. + * This function is necessary because we dynamically import optional dependencies + * which can cause issues with bundlers that detect the import and throw an error + * on build time when the dependency is not installed. + * Using this workaround, the dynamic import is only evaluated on runtime + * where we work with try-catch when importing optional dependencies. + * + * @param {string} moduleName - Specifies the module to import. + * @returns {Promise} Returns a Promise that resolves to the imported module. + */ +export async function importOptionalModule(moduleName: string) { + return Function(`return import("${moduleName}")`)(); } diff --git a/clients/js/test/add.collections.test.ts b/clients/js/test/add.collections.test.ts index d18a8085bc9d..cb89fa8dbe06 100644 --- a/clients/js/test/add.collections.test.ts +++ b/clients/js/test/add.collections.test.ts @@ -3,7 +3,8 @@ import chroma from './initClient' import { DOCUMENTS, EMBEDDINGS, IDS } from './data'; import { METADATAS } from './data'; import { IncludeEnum } from "../src/types"; - +import {OpenAIEmbeddingFunction} from "../src/embeddings/OpenAIEmbeddingFunction"; +import {CohereEmbeddingFunction} from "../src/embeddings/CohereEmbeddingFunction"; test("it should add single embeddings to a collection", async () => { await chroma.reset(); const collection = await chroma.createCollection({ name: "test" }); @@ -35,6 +36,49 @@ test("it should add batch embeddings to a collection", async () => { expect(res.embeddings).toEqual(EMBEDDINGS); // reverse because of the order of the ids }); + +if (!process.env.OPENAI_API_KEY) { + test.skip("it should add OpenAI embeddings", async () => { + }); +} else { + test("it should add OpenAI embeddings", async () => { + await chroma.reset(); + const embedder = new OpenAIEmbeddingFunction({ openai_api_key: process.env.OPENAI_API_KEY || "" }) + const collection = await chroma.createCollection({ name: "test" ,embeddingFunction: embedder}); + const embeddings = await embedder.generate(DOCUMENTS); + await collection.add({ ids: IDS, embeddings: embeddings }); + const count = await collection.count(); + expect(count).toBe(3); + var res = await collection.get({ + ids: IDS, include: [ + IncludeEnum.Embeddings, + ] + }); + expect(res.embeddings).toEqual(embeddings); // reverse because of the order of the ids + }); +} + +if (!process.env.COHERE_API_KEY) { + test.skip("it should add Cohere embeddings", async () => { + }); +} else { + test("it should add Cohere embeddings", async () => { + await chroma.reset(); + const embedder = new CohereEmbeddingFunction({ cohere_api_key: process.env.COHERE_API_KEY || "" }) + const collection = await chroma.createCollection({ name: "test" ,embeddingFunction: embedder}); + const embeddings = await embedder.generate(DOCUMENTS); + await collection.add({ ids: IDS, embeddings: embeddings }); + const count = await collection.count(); + expect(count).toBe(3); + var res = await collection.get({ + ids: IDS, include: [ + IncludeEnum.Embeddings, + ] + }); + expect(res.embeddings).toEqual(embeddings); // reverse because of the order of the ids + }); +} + test("add documents", async () => { await chroma.reset(); const collection = await chroma.createCollection({ name: "test" }); diff --git a/clients/js/test/auth.basic.test.ts b/clients/js/test/auth.basic.test.ts new file mode 100644 index 000000000000..6bbcf2300876 --- /dev/null +++ b/clients/js/test/auth.basic.test.ts @@ -0,0 +1,33 @@ +import {expect, test} from "@jest/globals"; +import {ChromaClient} from "../src/ChromaClient"; +import {chromaBasic} from "./initClientWithAuth"; +import chromaNoAuth from "./initClient"; + +test("it should get the version without auth needed", async () => { + const version = await chromaNoAuth.version(); + expect(version).toBeDefined(); + expect(version).toMatch(/^[0-9]+\.[0-9]+\.[0-9]+$/); +}); + +test("it should get the heartbeat without auth needed", async () => { + const heartbeat = await chromaNoAuth.heartbeat(); + expect(heartbeat).toBeDefined(); + expect(heartbeat).toBeGreaterThan(0); +}); + +test("it should raise error when non authenticated", async () => { + await expect(chromaNoAuth.listCollections()).rejects.toMatchObject({ + status: 401 + }); +}); + +test('it should list collections', async () => { + await chromaBasic.reset() + let collections = await chromaBasic.listCollections() + expect(collections).toBeDefined() + expect(collections).toBeInstanceOf(Array) + expect(collections.length).toBe(0) + await chromaBasic.createCollection({name: "test"}); + collections = await chromaBasic.listCollections() + expect(collections.length).toBe(1) +}) diff --git a/clients/js/test/auth.token.test.ts b/clients/js/test/auth.token.test.ts new file mode 100644 index 000000000000..96612480ac87 --- /dev/null +++ b/clients/js/test/auth.token.test.ts @@ -0,0 +1,59 @@ +import {expect, test} from "@jest/globals"; +import {ChromaClient} from "../src/ChromaClient"; +import {chromaTokenDefault, chromaTokenBearer, chromaTokenXToken} from "./initClientWithAuth"; +import chromaNoAuth from "./initClient"; + +test("it should get the version without auth needed", async () => { + const version = await chromaNoAuth.version(); + expect(version).toBeDefined(); + expect(version).toMatch(/^[0-9]+\.[0-9]+\.[0-9]+$/); +}); + +test("it should get the heartbeat without auth needed", async () => { + const heartbeat = await chromaNoAuth.heartbeat(); + expect(heartbeat).toBeDefined(); + expect(heartbeat).toBeGreaterThan(0); +}); + +test("it should raise error when non authenticated", async () => { + await expect(chromaNoAuth.listCollections()).rejects.toMatchObject({ + status: 401 + }); +}); + +if (!process.env.XTOKEN_TEST) { + test('it should list collections with default token config', async () => { + await chromaTokenDefault.reset() + let collections = await chromaTokenDefault.listCollections() + expect(collections).toBeDefined() + expect(collections).toBeInstanceOf(Array) + expect(collections.length).toBe(0) + const collection = await chromaTokenDefault.createCollection({name: "test"}); + collections = await chromaTokenDefault.listCollections() + expect(collections.length).toBe(1) + }) + + test('it should list collections with explicit bearer token config', async () => { + await chromaTokenBearer.reset() + let collections = await chromaTokenBearer.listCollections() + expect(collections).toBeDefined() + expect(collections).toBeInstanceOf(Array) + expect(collections.length).toBe(0) + const collection = await chromaTokenBearer.createCollection({name: "test"}); + collections = await chromaTokenBearer.listCollections() + expect(collections.length).toBe(1) + }) +} else { + + test('it should list collections with explicit x-token token config', async () => { + await chromaTokenXToken.reset() + let collections = await chromaTokenXToken.listCollections() + expect(collections).toBeDefined() + expect(collections).toBeInstanceOf(Array) + expect(collections.length).toBe(0) + const collection = await chromaTokenXToken.createCollection({name: "test"}); + collections = await chromaTokenXToken.listCollections() + expect(collections.length).toBe(1) + }) + +} diff --git a/clients/js/test/client.test.ts b/clients/js/test/client.test.ts index 5fbf2b09b8eb..512237a24570 100644 --- a/clients/js/test/client.test.ts +++ b/clients/js/test/client.test.ts @@ -191,5 +191,5 @@ test('wrong code returns an error', async () => { // @ts-ignore - supposed to fail const results = await collection.get({ where: { "test": { "$contains": "hello" } } }); expect(results.error).toBeDefined() - expect(results.error).toBe("ValueError('Expected where operator to be one of $gt, $gte, $lt, $lte, $ne, $eq, got $contains')") + expect(results.error).toContain("ValueError('Expected where operator") }) diff --git a/clients/js/test/initClientWithAuth.ts b/clients/js/test/initClientWithAuth.ts new file mode 100644 index 000000000000..4c061d089d5c --- /dev/null +++ b/clients/js/test/initClientWithAuth.ts @@ -0,0 +1,14 @@ +import {ChromaClient} from "../src/ChromaClient"; + +const PORT = process.env.PORT || "8000"; +const URL = "http://localhost:" + PORT; +export const chromaBasic = new ChromaClient({path: URL, auth: {provider: "basic", credentials: "admin:admin"}}); +export const chromaTokenDefault = new ChromaClient({path: URL, auth: {provider: "token", credentials: "test-token"}}); +export const chromaTokenBearer = new ChromaClient({ + path: URL, + auth: {provider: "token", credentials: "test-token", providerOptions: {headerType: "AUTHORIZATION"}} +}); +export const chromaTokenXToken = new ChromaClient({ + path: URL, + auth: {provider: "token", credentials: "test-token", providerOptions: {headerType: "X_CHROMA_TOKEN"}} +}); diff --git a/clients/js/test/query.collection.test.ts b/clients/js/test/query.collection.test.ts index 05125a27ffa0..878ed0a71df3 100644 --- a/clients/js/test/query.collection.test.ts +++ b/clients/js/test/query.collection.test.ts @@ -86,3 +86,71 @@ test("it should query a collection with text", async () => { expect.arrayContaining(results.documents[0]) ); }) + + +test("it should query a collection with text and where", async () => { + await chroma.reset(); + let embeddingFunction = new TestEmbeddingFunction(); + const collection = await chroma.createCollection({ name: "test", embeddingFunction: embeddingFunction }); + await collection.add({ ids: IDS, embeddings: EMBEDDINGS, metadatas: METADATAS, documents: DOCUMENTS }); + + const results = await collection.query({ + queryTexts: ["test"], + nResults: 3, + where: { "float_value" : 2 } + }); + + expect(results).toBeDefined(); + expect(results).toBeInstanceOf(Object); + expect(results.ids.length).toBe(1); + expect(["test3"]).toEqual(expect.arrayContaining(results.ids[0])); + expect(["test2"]).not.toEqual(expect.arrayContaining(results.ids[0])); + expect(["This is a third test"]).toEqual( + expect.arrayContaining(results.documents[0]) + ); +}) + + +test("it should query a collection with text and where in", async () => { + await chroma.reset(); + let embeddingFunction = new TestEmbeddingFunction(); + const collection = await chroma.createCollection({ name: "test", embeddingFunction: embeddingFunction }); + await collection.add({ ids: IDS, embeddings: EMBEDDINGS, metadatas: METADATAS, documents: DOCUMENTS }); + + const results = await collection.query({ + queryTexts: ["test"], + nResults: 3, + where: { "float_value" : { '$in': [2,5,10] }} + }); + + expect(results).toBeDefined(); + expect(results).toBeInstanceOf(Object); + expect(results.ids.length).toBe(1); + expect(["test3"]).toEqual(expect.arrayContaining(results.ids[0])); + expect(["test2"]).not.toEqual(expect.arrayContaining(results.ids[0])); + expect(["This is a third test"]).toEqual( + expect.arrayContaining(results.documents[0]) + ); +}) + +test("it should query a collection with text and where nin", async () => { + await chroma.reset(); + let embeddingFunction = new TestEmbeddingFunction(); + const collection = await chroma.createCollection({ name: "test", embeddingFunction: embeddingFunction }); + await collection.add({ ids: IDS, embeddings: EMBEDDINGS, metadatas: METADATAS, documents: DOCUMENTS }); + + const results = await collection.query({ + queryTexts: ["test"], + nResults: 3, + where: { "float_value" : { '$nin': [-2,0] }} + }); + + expect(results).toBeDefined(); + expect(results).toBeInstanceOf(Object); + expect(results.ids.length).toBe(1); + expect(["test3"]).toEqual(expect.arrayContaining(results.ids[0])); + expect(["test2"]).not.toEqual(expect.arrayContaining(results.ids[0])); + expect(["This is a third test"]).toEqual( + expect.arrayContaining(results.documents[0]) + ); +}) diff --git a/clients/js/yarn.lock b/clients/js/yarn.lock index 746947e86b59..33df6f74dde8 100644 --- a/clients/js/yarn.lock +++ b/clients/js/yarn.lock @@ -3,322 +3,320 @@ "@ampproject/remapping@^2.2.0": - version "2.2.0" - resolved "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz" - integrity sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w== + version "2.2.1" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.1.tgz#99e8e11851128b8702cd57c33684f1d0f260b630" + integrity sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg== dependencies: - "@jridgewell/gen-mapping" "^0.1.0" + "@jridgewell/gen-mapping" "^0.3.0" "@jridgewell/trace-mapping" "^0.3.9" "@apidevtools/openapi-schemas@^2.1.0": version "2.1.0" - resolved "https://registry.npmjs.org/@apidevtools/openapi-schemas/-/openapi-schemas-2.1.0.tgz" + resolved "https://registry.yarnpkg.com/@apidevtools/openapi-schemas/-/openapi-schemas-2.1.0.tgz#9fa08017fb59d80538812f03fc7cac5992caaa17" integrity sha512-Zc1AlqrJlX3SlpupFGpiLi2EbteyP7fXmUOGup6/DnkRgjP9bgMM/ag+n91rsv0U1Gpz0H3VILA/o3bW7Ua6BQ== "@apidevtools/swagger-methods@^3.0.2": version "3.0.2" - resolved "https://registry.npmjs.org/@apidevtools/swagger-methods/-/swagger-methods-3.0.2.tgz" + resolved "https://registry.yarnpkg.com/@apidevtools/swagger-methods/-/swagger-methods-3.0.2.tgz#b789a362e055b0340d04712eafe7027ddc1ac267" integrity sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg== -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.18.6": - version "7.18.6" - resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz" - integrity sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q== +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.22.10", "@babel/code-frame@^7.22.5": + version "7.22.13" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.22.13.tgz#e3c1c099402598483b7a8c46a721d1038803755e" + integrity sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w== dependencies: - "@babel/highlight" "^7.18.6" + "@babel/highlight" "^7.22.13" + chalk "^2.4.2" -"@babel/compat-data@^7.20.5": - version "7.21.0" - resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.21.0.tgz" - integrity sha512-gMuZsmsgxk/ENC3O/fRw5QY8A9/uxQbbCEypnLIiYYc/qVJtEV7ouxC3EllIIwNzMqAQee5tanFabWsUOutS7g== +"@babel/compat-data@^7.22.9": + version "7.22.9" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.22.9.tgz#71cdb00a1ce3a329ce4cbec3a44f9fef35669730" + integrity sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ== -"@babel/core@^7.0.0", "@babel/core@^7.0.0-0", "@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.8.0", "@babel/core@>=7.0.0-beta.0 <8": - version "7.21.0" - resolved "https://registry.npmjs.org/@babel/core/-/core-7.21.0.tgz" - integrity sha512-PuxUbxcW6ZYe656yL3EAhpy7qXKq0DmYsrJLpbB8XrsCP9Nm+XCg9XFMb5vIDliPD7+U/+M+QJlH17XOcB7eXA== +"@babel/core@^7.11.6", "@babel/core@^7.12.3": + version "7.22.11" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.22.11.tgz#8033acaa2aa24c3f814edaaa057f3ce0ba559c24" + integrity sha512-lh7RJrtPdhibbxndr6/xx0w8+CVlY5FJZiaSz908Fpy+G0xkBFTvwLcKJFF4PJxVfGhVWNebikpWGnOoC71juQ== dependencies: "@ampproject/remapping" "^2.2.0" - "@babel/code-frame" "^7.18.6" - "@babel/generator" "^7.21.0" - "@babel/helper-compilation-targets" "^7.20.7" - "@babel/helper-module-transforms" "^7.21.0" - "@babel/helpers" "^7.21.0" - "@babel/parser" "^7.21.0" - "@babel/template" "^7.20.7" - "@babel/traverse" "^7.21.0" - "@babel/types" "^7.21.0" + "@babel/code-frame" "^7.22.10" + "@babel/generator" "^7.22.10" + "@babel/helper-compilation-targets" "^7.22.10" + "@babel/helper-module-transforms" "^7.22.9" + "@babel/helpers" "^7.22.11" + "@babel/parser" "^7.22.11" + "@babel/template" "^7.22.5" + "@babel/traverse" "^7.22.11" + "@babel/types" "^7.22.11" convert-source-map "^1.7.0" debug "^4.1.0" gensync "^1.0.0-beta.2" - json5 "^2.2.2" - semver "^6.3.0" + json5 "^2.2.3" + semver "^6.3.1" -"@babel/generator@^7.21.0", "@babel/generator@^7.7.2": - version "7.21.1" - resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.21.1.tgz" - integrity sha512-1lT45bAYlQhFn/BHivJs43AiW2rg3/UbLyShGfF3C0KmHvO5fSghWd5kBJy30kpRRucGzXStvnnCFniCR2kXAA== +"@babel/generator@^7.22.10", "@babel/generator@^7.7.2": + version "7.22.10" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.22.10.tgz#c92254361f398e160645ac58831069707382b722" + integrity sha512-79KIf7YiWjjdZ81JnLujDRApWtl7BxTqWD88+FFdQEIOG8LJ0etDOM7CXuIgGJa55sGOwZVwuEsaLEm0PJ5/+A== dependencies: - "@babel/types" "^7.21.0" + "@babel/types" "^7.22.10" "@jridgewell/gen-mapping" "^0.3.2" "@jridgewell/trace-mapping" "^0.3.17" jsesc "^2.5.1" -"@babel/helper-compilation-targets@^7.20.7": - version "7.20.7" - resolved "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz" - integrity sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ== +"@babel/helper-compilation-targets@^7.22.10": + version "7.22.10" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.10.tgz#01d648bbc25dd88f513d862ee0df27b7d4e67024" + integrity sha512-JMSwHD4J7SLod0idLq5PKgI+6g/hLD/iuWBq08ZX49xE14VpVEojJ5rHWptpirV2j020MvypRLAXAO50igCJ5Q== dependencies: - "@babel/compat-data" "^7.20.5" - "@babel/helper-validator-option" "^7.18.6" - browserslist "^4.21.3" + "@babel/compat-data" "^7.22.9" + "@babel/helper-validator-option" "^7.22.5" + browserslist "^4.21.9" lru-cache "^5.1.1" - semver "^6.3.0" + semver "^6.3.1" -"@babel/helper-environment-visitor@^7.18.9": - version "7.18.9" - resolved "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz" - integrity sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg== +"@babel/helper-environment-visitor@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz#f06dd41b7c1f44e1f8da6c4055b41ab3a09a7e98" + integrity sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q== -"@babel/helper-function-name@^7.21.0": - version "7.21.0" - resolved "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz" - integrity sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg== +"@babel/helper-function-name@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz#ede300828905bb15e582c037162f99d5183af1be" + integrity sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ== dependencies: - "@babel/template" "^7.20.7" - "@babel/types" "^7.21.0" + "@babel/template" "^7.22.5" + "@babel/types" "^7.22.5" -"@babel/helper-hoist-variables@^7.18.6": - version "7.18.6" - resolved "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz" - integrity sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q== +"@babel/helper-hoist-variables@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz#c01a007dac05c085914e8fb652b339db50d823bb" + integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw== dependencies: - "@babel/types" "^7.18.6" + "@babel/types" "^7.22.5" -"@babel/helper-module-imports@^7.18.6": - version "7.18.6" - resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz" - integrity sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA== +"@babel/helper-module-imports@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.22.5.tgz#1a8f4c9f4027d23f520bd76b364d44434a72660c" + integrity sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg== dependencies: - "@babel/types" "^7.18.6" + "@babel/types" "^7.22.5" -"@babel/helper-module-transforms@^7.21.0": - version "7.21.0" - resolved "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.21.0.tgz" - integrity sha512-eD/JQ21IG2i1FraJnTMbUarAUkA7G988ofehG5MDCRXaUU91rEBJuCeSoou2Sk1y4RbLYXzqEg1QLwEmRU4qcQ== +"@babel/helper-module-transforms@^7.22.9": + version "7.22.9" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.22.9.tgz#92dfcb1fbbb2bc62529024f72d942a8c97142129" + integrity sha512-t+WA2Xn5K+rTeGtC8jCsdAH52bjggG5TKRuRrAGNM/mjIbO4GxvlLMFOEz9wXY5I2XQ60PMFsAG2WIcG82dQMQ== dependencies: - "@babel/helper-environment-visitor" "^7.18.9" - "@babel/helper-module-imports" "^7.18.6" - "@babel/helper-simple-access" "^7.20.2" - "@babel/helper-split-export-declaration" "^7.18.6" - "@babel/helper-validator-identifier" "^7.19.1" - "@babel/template" "^7.20.7" - "@babel/traverse" "^7.21.0" - "@babel/types" "^7.21.0" + "@babel/helper-environment-visitor" "^7.22.5" + "@babel/helper-module-imports" "^7.22.5" + "@babel/helper-simple-access" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + "@babel/helper-validator-identifier" "^7.22.5" "@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.22.5", "@babel/helper-plugin-utils@^7.8.0": version "7.22.5" - resolved "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz#dd7ee3735e8a313b9f7b05a773d892e88e6d7295" integrity sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg== -"@babel/helper-simple-access@^7.20.2": - version "7.20.2" - resolved "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz" - integrity sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA== +"@babel/helper-simple-access@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz#4938357dc7d782b80ed6dbb03a0fba3d22b1d5de" + integrity sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w== dependencies: - "@babel/types" "^7.20.2" + "@babel/types" "^7.22.5" -"@babel/helper-split-export-declaration@^7.18.6": - version "7.18.6" - resolved "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz" - integrity sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA== +"@babel/helper-split-export-declaration@^7.22.6": + version "7.22.6" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz#322c61b7310c0997fe4c323955667f18fcefb91c" + integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g== dependencies: - "@babel/types" "^7.18.6" + "@babel/types" "^7.22.5" -"@babel/helper-string-parser@^7.19.4": - version "7.19.4" - resolved "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz" - integrity sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw== +"@babel/helper-string-parser@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz#533f36457a25814cf1df6488523ad547d784a99f" + integrity sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw== -"@babel/helper-validator-identifier@^7.18.6", "@babel/helper-validator-identifier@^7.19.1": - version "7.19.1" - resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz" - integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w== +"@babel/helper-validator-identifier@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz#9544ef6a33999343c8740fa51350f30eeaaaf193" + integrity sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ== -"@babel/helper-validator-option@^7.18.6": - version "7.21.0" - resolved "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.21.0.tgz" - integrity sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ== +"@babel/helper-validator-option@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.22.5.tgz#de52000a15a177413c8234fa3a8af4ee8102d0ac" + integrity sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw== -"@babel/helpers@^7.21.0": - version "7.21.0" - resolved "https://registry.npmjs.org/@babel/helpers/-/helpers-7.21.0.tgz" - integrity sha512-XXve0CBtOW0pd7MRzzmoyuSj0e3SEzj8pgyFxnTT1NJZL38BD1MK7yYrm8yefRPIDvNNe14xR4FdbHwpInD4rA== +"@babel/helpers@^7.22.11": + version "7.22.11" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.22.11.tgz#b02f5d5f2d7abc21ab59eeed80de410ba70b056a" + integrity sha512-vyOXC8PBWaGc5h7GMsNx68OH33cypkEDJCHvYVVgVbbxJDROYVtexSk0gK5iCF1xNjRIN2s8ai7hwkWDq5szWg== dependencies: - "@babel/template" "^7.20.7" - "@babel/traverse" "^7.21.0" - "@babel/types" "^7.21.0" + "@babel/template" "^7.22.5" + "@babel/traverse" "^7.22.11" + "@babel/types" "^7.22.11" -"@babel/highlight@^7.18.6": - version "7.18.6" - resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz" - integrity sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g== +"@babel/highlight@^7.22.13": + version "7.22.13" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.22.13.tgz#9cda839e5d3be9ca9e8c26b6dd69e7548f0cbf16" + integrity sha512-C/BaXcnnvBCmHTpz/VGZ8jgtE2aYlW4hxDhseJAWZb7gqGM/qtCK6iZUb0TyKFf7BOUsBH7Q7fkRsDRhg1XklQ== dependencies: - "@babel/helper-validator-identifier" "^7.18.6" - chalk "^2.0.0" + "@babel/helper-validator-identifier" "^7.22.5" + chalk "^2.4.2" js-tokens "^4.0.0" -"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.21.0": - version "7.21.1" - resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.21.1.tgz" - integrity sha512-JzhBFpkuhBNYUY7qs+wTzNmyCWUHEaAFpQQD2YfU1rPL38/L43Wvid0fFkiOCnHvsGncRZgEPyGnltABLcVDTg== +"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.22.11", "@babel/parser@^7.22.5": + version "7.22.14" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.22.14.tgz#c7de58e8de106e88efca42ce17f0033209dfd245" + integrity sha512-1KucTHgOvaw/LzCVrEOAyXkr9rQlp0A1HiHRYnSUE9dmb8PvPW7o5sscg+5169r54n3vGlbx6GevTE/Iw/P3AQ== "@babel/plugin-syntax-async-generators@^7.8.4": version "7.8.4" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== dependencies: "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-bigint@^7.8.3": version "7.8.3" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz#4c9a6f669f5d0cdf1b90a1671e9a146be5300cea" integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg== dependencies: "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-class-properties@^7.8.3": version "7.12.13" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== dependencies: "@babel/helper-plugin-utils" "^7.12.13" "@babel/plugin-syntax-import-meta@^7.8.3": version "7.10.4" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-json-strings@^7.8.3": version "7.8.3" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== dependencies: "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-jsx@^7.7.2": version "7.22.5" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.22.5.tgz" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.22.5.tgz#a6b68e84fb76e759fc3b93e901876ffabbe1d918" integrity sha512-gvyP4hZrgrs/wWMaocvxZ44Hw0b3W8Pe+cMxc8V1ULQ07oh8VNbIRaoD1LRZVTvD+0nieDKjfgKg89sD7rrKrg== dependencies: "@babel/helper-plugin-utils" "^7.22.5" "@babel/plugin-syntax-logical-assignment-operators@^7.8.3": version "7.10.4" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": version "7.8.3" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== dependencies: "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-numeric-separator@^7.8.3": version "7.10.4" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-object-rest-spread@^7.8.3": version "7.8.3" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== dependencies: "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-optional-catch-binding@^7.8.3": version "7.8.3" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== dependencies: "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-optional-chaining@^7.8.3": version "7.8.3" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== dependencies: "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-top-level-await@^7.8.3": version "7.14.5" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== dependencies: "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-typescript@^7.7.2": version "7.22.5" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.22.5.tgz" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.22.5.tgz#aac8d383b062c5072c647a31ef990c1d0af90272" integrity sha512-1mS2o03i7t1c6VzH6fdQ3OA8tcEIxwG18zIPRp+UY1Ihv6W+XZzBCVxExF9upussPXJ0xE9XRHwMoNs1ep/nRQ== dependencies: "@babel/helper-plugin-utils" "^7.22.5" -"@babel/template@^7.20.7", "@babel/template@^7.3.3": - version "7.20.7" - resolved "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz" - integrity sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw== - dependencies: - "@babel/code-frame" "^7.18.6" - "@babel/parser" "^7.20.7" - "@babel/types" "^7.20.7" - -"@babel/traverse@^7.21.0", "@babel/traverse@^7.7.2": - version "7.21.0" - resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.0.tgz" - integrity sha512-Xdt2P1H4LKTO8ApPfnO1KmzYMFpp7D/EinoXzLYN/cHcBNrVCAkAtGUcXnHXrl/VGktureU6fkQrHSBE2URfoA== - dependencies: - "@babel/code-frame" "^7.18.6" - "@babel/generator" "^7.21.0" - "@babel/helper-environment-visitor" "^7.18.9" - "@babel/helper-function-name" "^7.21.0" - "@babel/helper-hoist-variables" "^7.18.6" - "@babel/helper-split-export-declaration" "^7.18.6" - "@babel/parser" "^7.21.0" - "@babel/types" "^7.21.0" +"@babel/template@^7.22.5", "@babel/template@^7.3.3": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.5.tgz#0c8c4d944509875849bd0344ff0050756eefc6ec" + integrity sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw== + dependencies: + "@babel/code-frame" "^7.22.5" + "@babel/parser" "^7.22.5" + "@babel/types" "^7.22.5" + +"@babel/traverse@^7.22.11": + version "7.22.11" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.22.11.tgz#71ebb3af7a05ff97280b83f05f8865ac94b2027c" + integrity sha512-mzAenteTfomcB7mfPtyi+4oe5BZ6MXxWcn4CX+h4IRJ+OOGXBrWU6jDQavkQI9Vuc5P+donFabBfFCcmWka9lQ== + dependencies: + "@babel/code-frame" "^7.22.10" + "@babel/generator" "^7.22.10" + "@babel/helper-environment-visitor" "^7.22.5" + "@babel/helper-function-name" "^7.22.5" + "@babel/helper-hoist-variables" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + "@babel/parser" "^7.22.11" + "@babel/types" "^7.22.11" debug "^4.1.0" globals "^11.1.0" -"@babel/types@^7.0.0", "@babel/types@^7.18.6", "@babel/types@^7.20.2", "@babel/types@^7.20.7", "@babel/types@^7.21.0", "@babel/types@^7.3.0", "@babel/types@^7.3.3": - version "7.21.0" - resolved "https://registry.npmjs.org/@babel/types/-/types-7.21.0.tgz" - integrity sha512-uR7NWq2VNFnDi7EYqiRz2Jv/VQIu38tu64Zy8TX2nQFQ6etJ9V/Rr2msW8BS132mum2rL645qpDrLtAJtVpuow== +"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.22.10", "@babel/types@^7.22.11", "@babel/types@^7.22.5", "@babel/types@^7.3.3": + version "7.22.11" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.22.11.tgz#0e65a6a1d4d9cbaa892b2213f6159485fe632ea2" + integrity sha512-siazHiGuZRz9aB9NpHy9GOs9xiQPKnMzgdr493iI1M67vRXpnEq8ZOOKzezC5q7zwuQ6sDhdSp4SD9ixKSqKZg== dependencies: - "@babel/helper-string-parser" "^7.19.4" - "@babel/helper-validator-identifier" "^7.19.1" + "@babel/helper-string-parser" "^7.22.5" + "@babel/helper-validator-identifier" "^7.22.5" to-fast-properties "^2.0.0" "@bcoe/v8-coverage@^0.2.3": version "0.2.3" - resolved "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz" + resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== "@cspotcode/source-map-support@^0.8.0": version "0.8.1" - resolved "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz" + resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw== dependencies: "@jridgewell/trace-mapping" "0.3.9" "@isaacs/cliui@^8.0.2": version "8.0.2" - resolved "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz" + resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA== dependencies: string-width "^5.1.2" @@ -330,7 +328,7 @@ "@istanbuljs/load-nyc-config@^1.0.0": version "1.1.0" - resolved "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz" + resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== dependencies: camelcase "^5.3.1" @@ -341,113 +339,113 @@ "@istanbuljs/schema@^0.1.2": version "0.1.3" - resolved "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz" + resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== -"@jest/console@^29.5.0": - version "29.5.0" - resolved "https://registry.npmjs.org/@jest/console/-/console-29.5.0.tgz" - integrity sha512-NEpkObxPwyw/XxZVLPmAGKE89IQRp4puc6IQRPru6JKd1M3fW9v1xM1AnzIJE65hbCkzQAdnL8P47e9hzhiYLQ== +"@jest/console@^29.6.4": + version "29.6.4" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-29.6.4.tgz#a7e2d84516301f986bba0dd55af9d5fe37f46527" + integrity sha512-wNK6gC0Ha9QeEPSkeJedQuTQqxZYnDPuDcDhVuVatRvMkL4D0VTvFVZj+Yuh6caG2aOfzkUZ36KtCmLNtR02hw== dependencies: - "@jest/types" "^29.5.0" + "@jest/types" "^29.6.3" "@types/node" "*" chalk "^4.0.0" - jest-message-util "^29.5.0" - jest-util "^29.5.0" + jest-message-util "^29.6.3" + jest-util "^29.6.3" slash "^3.0.0" -"@jest/core@^29.5.0": - version "29.5.0" - resolved "https://registry.npmjs.org/@jest/core/-/core-29.5.0.tgz" - integrity sha512-28UzQc7ulUrOQw1IsN/kv1QES3q2kkbl/wGslyhAclqZ/8cMdB5M68BffkIdSJgKBUt50d3hbwJ92XESlE7LiQ== +"@jest/core@^29.6.4": + version "29.6.4" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-29.6.4.tgz#265ebee05ec1ff3567757e7a327155c8d6bdb126" + integrity sha512-U/vq5ccNTSVgYH7mHnodHmCffGWHJnz/E1BEWlLuK5pM4FZmGfBn/nrJGLjUsSmyx3otCeqc1T31F4y08AMDLg== dependencies: - "@jest/console" "^29.5.0" - "@jest/reporters" "^29.5.0" - "@jest/test-result" "^29.5.0" - "@jest/transform" "^29.5.0" - "@jest/types" "^29.5.0" + "@jest/console" "^29.6.4" + "@jest/reporters" "^29.6.4" + "@jest/test-result" "^29.6.4" + "@jest/transform" "^29.6.4" + "@jest/types" "^29.6.3" "@types/node" "*" ansi-escapes "^4.2.1" chalk "^4.0.0" ci-info "^3.2.0" exit "^0.1.2" graceful-fs "^4.2.9" - jest-changed-files "^29.5.0" - jest-config "^29.5.0" - jest-haste-map "^29.5.0" - jest-message-util "^29.5.0" - jest-regex-util "^29.4.3" - jest-resolve "^29.5.0" - jest-resolve-dependencies "^29.5.0" - jest-runner "^29.5.0" - jest-runtime "^29.5.0" - jest-snapshot "^29.5.0" - jest-util "^29.5.0" - jest-validate "^29.5.0" - jest-watcher "^29.5.0" + jest-changed-files "^29.6.3" + jest-config "^29.6.4" + jest-haste-map "^29.6.4" + jest-message-util "^29.6.3" + jest-regex-util "^29.6.3" + jest-resolve "^29.6.4" + jest-resolve-dependencies "^29.6.4" + jest-runner "^29.6.4" + jest-runtime "^29.6.4" + jest-snapshot "^29.6.4" + jest-util "^29.6.3" + jest-validate "^29.6.3" + jest-watcher "^29.6.4" micromatch "^4.0.4" - pretty-format "^29.5.0" + pretty-format "^29.6.3" slash "^3.0.0" strip-ansi "^6.0.0" -"@jest/environment@^29.5.0": - version "29.5.0" - resolved "https://registry.npmjs.org/@jest/environment/-/environment-29.5.0.tgz" - integrity sha512-5FXw2+wD29YU1d4I2htpRX7jYnAyTRjP2CsXQdo9SAM8g3ifxWPSV0HnClSn71xwctr0U3oZIIH+dtbfmnbXVQ== +"@jest/environment@^29.6.4": + version "29.6.4" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-29.6.4.tgz#78ec2c9f8c8829a37616934ff4fea0c028c79f4f" + integrity sha512-sQ0SULEjA1XUTHmkBRl7A1dyITM9yb1yb3ZNKPX3KlTd6IG7mWUe3e2yfExtC2Zz1Q+mMckOLHmL/qLiuQJrBQ== dependencies: - "@jest/fake-timers" "^29.5.0" - "@jest/types" "^29.5.0" + "@jest/fake-timers" "^29.6.4" + "@jest/types" "^29.6.3" "@types/node" "*" - jest-mock "^29.5.0" + jest-mock "^29.6.3" -"@jest/expect-utils@^29.5.0": - version "29.5.0" - resolved "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.5.0.tgz" - integrity sha512-fmKzsidoXQT2KwnrwE0SQq3uj8Z763vzR8LnLBwC2qYWEFpjX8daRsk6rHUM1QvNlEW/UJXNXm59ztmJJWs2Mg== +"@jest/expect-utils@^29.6.4": + version "29.6.4" + resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.6.4.tgz#17c7dfe6cec106441f218b0aff4b295f98346679" + integrity sha512-FEhkJhqtvBwgSpiTrocquJCdXPsyvNKcl/n7A3u7X4pVoF4bswm11c9d4AV+kfq2Gpv/mM8x7E7DsRvH+djkrg== dependencies: - jest-get-type "^29.4.3" + jest-get-type "^29.6.3" -"@jest/expect@^29.5.0": - version "29.5.0" - resolved "https://registry.npmjs.org/@jest/expect/-/expect-29.5.0.tgz" - integrity sha512-PueDR2HGihN3ciUNGr4uelropW7rqUfTiOn+8u0leg/42UhblPxHkfoh0Ruu3I9Y1962P3u2DY4+h7GVTSVU6g== +"@jest/expect@^29.6.4": + version "29.6.4" + resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-29.6.4.tgz#1d6ae17dc68d906776198389427ab7ce6179dba6" + integrity sha512-Warhsa7d23+3X5bLbrbYvaehcgX5TLYhI03JKoedTiI8uJU4IhqYBWF7OSSgUyz4IgLpUYPkK0AehA5/fRclAA== dependencies: - expect "^29.5.0" - jest-snapshot "^29.5.0" + expect "^29.6.4" + jest-snapshot "^29.6.4" -"@jest/fake-timers@^29.5.0": - version "29.5.0" - resolved "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.5.0.tgz" - integrity sha512-9ARvuAAQcBwDAqOnglWq2zwNIRUDtk/SCkp/ToGEhFv5r86K21l+VEs0qNTaXtyiY0lEePl3kylijSYJQqdbDg== +"@jest/fake-timers@^29.6.4": + version "29.6.4" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-29.6.4.tgz#45a27f093c43d5d989362a3e7a8c70c83188b4f6" + integrity sha512-6UkCwzoBK60edXIIWb0/KWkuj7R7Qq91vVInOe3De6DSpaEiqjKcJw4F7XUet24Wupahj9J6PlR09JqJ5ySDHw== dependencies: - "@jest/types" "^29.5.0" + "@jest/types" "^29.6.3" "@sinonjs/fake-timers" "^10.0.2" "@types/node" "*" - jest-message-util "^29.5.0" - jest-mock "^29.5.0" - jest-util "^29.5.0" + jest-message-util "^29.6.3" + jest-mock "^29.6.3" + jest-util "^29.6.3" -"@jest/globals@^29.5.0": - version "29.5.0" - resolved "https://registry.npmjs.org/@jest/globals/-/globals-29.5.0.tgz" - integrity sha512-S02y0qMWGihdzNbUiqSAiKSpSozSuHX5UYc7QbnHP+D9Lyw8DgGGCinrN9uSuHPeKgSSzvPom2q1nAtBvUsvPQ== +"@jest/globals@^29.6.4": + version "29.6.4" + resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-29.6.4.tgz#4f04f58731b062b44ef23036b79bdb31f40c7f63" + integrity sha512-wVIn5bdtjlChhXAzVXavcY/3PEjf4VqM174BM3eGL5kMxLiZD5CLnbmkEyA1Dwh9q8XjP6E8RwjBsY/iCWrWsA== dependencies: - "@jest/environment" "^29.5.0" - "@jest/expect" "^29.5.0" - "@jest/types" "^29.5.0" - jest-mock "^29.5.0" + "@jest/environment" "^29.6.4" + "@jest/expect" "^29.6.4" + "@jest/types" "^29.6.3" + jest-mock "^29.6.3" -"@jest/reporters@^29.5.0": - version "29.5.0" - resolved "https://registry.npmjs.org/@jest/reporters/-/reporters-29.5.0.tgz" - integrity sha512-D05STXqj/M8bP9hQNSICtPqz97u7ffGzZu+9XLucXhkOFBqKcXe04JLZOgIekOxdb73MAoBUFnqvf7MCpKk5OA== +"@jest/reporters@^29.6.4": + version "29.6.4" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-29.6.4.tgz#9d6350c8a2761ece91f7946e97ab0dabc06deab7" + integrity sha512-sxUjWxm7QdchdrD3NfWKrL8FBsortZeibSJv4XLjESOOjSUOkjQcb0ZHJwfhEGIvBvTluTzfG2yZWZhkrXJu8g== dependencies: "@bcoe/v8-coverage" "^0.2.3" - "@jest/console" "^29.5.0" - "@jest/test-result" "^29.5.0" - "@jest/transform" "^29.5.0" - "@jest/types" "^29.5.0" - "@jridgewell/trace-mapping" "^0.3.15" + "@jest/console" "^29.6.4" + "@jest/test-result" "^29.6.4" + "@jest/transform" "^29.6.4" + "@jest/types" "^29.6.3" + "@jridgewell/trace-mapping" "^0.3.18" "@types/node" "*" chalk "^4.0.0" collect-v8-coverage "^1.0.0" @@ -455,156 +453,148 @@ glob "^7.1.3" graceful-fs "^4.2.9" istanbul-lib-coverage "^3.0.0" - istanbul-lib-instrument "^5.1.0" + istanbul-lib-instrument "^6.0.0" istanbul-lib-report "^3.0.0" istanbul-lib-source-maps "^4.0.0" istanbul-reports "^3.1.3" - jest-message-util "^29.5.0" - jest-util "^29.5.0" - jest-worker "^29.5.0" + jest-message-util "^29.6.3" + jest-util "^29.6.3" + jest-worker "^29.6.4" slash "^3.0.0" string-length "^4.0.1" strip-ansi "^6.0.0" v8-to-istanbul "^9.0.1" -"@jest/schemas@^29.4.3": - version "29.4.3" - resolved "https://registry.npmjs.org/@jest/schemas/-/schemas-29.4.3.tgz" - integrity sha512-VLYKXQmtmuEz6IxJsrZwzG9NvtkQsWNnWMsKxqWNu3+CnfzJQhp0WDDKWLVV9hLKr0l3SLLFRqcYHjhtyuDVxg== +"@jest/schemas@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.3.tgz#430b5ce8a4e0044a7e3819663305a7b3091c8e03" + integrity sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA== dependencies: - "@sinclair/typebox" "^0.25.16" + "@sinclair/typebox" "^0.27.8" -"@jest/source-map@^29.4.3": - version "29.4.3" - resolved "https://registry.npmjs.org/@jest/source-map/-/source-map-29.4.3.tgz" - integrity sha512-qyt/mb6rLyd9j1jUts4EQncvS6Yy3PM9HghnNv86QBlV+zdL2inCdK1tuVlL+J+lpiw2BI67qXOrX3UurBqQ1w== +"@jest/source-map@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-29.6.3.tgz#d90ba772095cf37a34a5eb9413f1b562a08554c4" + integrity sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw== dependencies: - "@jridgewell/trace-mapping" "^0.3.15" + "@jridgewell/trace-mapping" "^0.3.18" callsites "^3.0.0" graceful-fs "^4.2.9" -"@jest/test-result@^29.5.0": - version "29.5.0" - resolved "https://registry.npmjs.org/@jest/test-result/-/test-result-29.5.0.tgz" - integrity sha512-fGl4rfitnbfLsrfx1uUpDEESS7zM8JdgZgOCQuxQvL1Sn/I6ijeAVQWGfXI9zb1i9Mzo495cIpVZhA0yr60PkQ== +"@jest/test-result@^29.6.4": + version "29.6.4" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-29.6.4.tgz#adf5c79f6e1fb7405ad13d67d9e2b6ff54b54c6b" + integrity sha512-uQ1C0AUEN90/dsyEirgMLlouROgSY+Wc/JanVVk0OiUKa5UFh7sJpMEM3aoUBAz2BRNvUJ8j3d294WFuRxSyOQ== dependencies: - "@jest/console" "^29.5.0" - "@jest/types" "^29.5.0" + "@jest/console" "^29.6.4" + "@jest/types" "^29.6.3" "@types/istanbul-lib-coverage" "^2.0.0" collect-v8-coverage "^1.0.0" -"@jest/test-sequencer@^29.5.0": - version "29.5.0" - resolved "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.5.0.tgz" - integrity sha512-yPafQEcKjkSfDXyvtgiV4pevSeyuA6MQr6ZIdVkWJly9vkqjnFfcfhRQqpD5whjoU8EORki752xQmjaqoFjzMQ== +"@jest/test-sequencer@^29.6.4": + version "29.6.4" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-29.6.4.tgz#86aef66aaa22b181307ed06c26c82802fb836d7b" + integrity sha512-E84M6LbpcRq3fT4ckfKs9ryVanwkaIB0Ws9bw3/yP4seRLg/VaCZ/LgW0MCq5wwk4/iP/qnilD41aj2fsw2RMg== dependencies: - "@jest/test-result" "^29.5.0" + "@jest/test-result" "^29.6.4" graceful-fs "^4.2.9" - jest-haste-map "^29.5.0" + jest-haste-map "^29.6.4" slash "^3.0.0" -"@jest/transform@^29.5.0": - version "29.5.0" - resolved "https://registry.npmjs.org/@jest/transform/-/transform-29.5.0.tgz" - integrity sha512-8vbeZWqLJOvHaDfeMuoHITGKSz5qWc9u04lnWrQE3VyuSw604PzQM824ZeX9XSjUCeDiE3GuxZe5UKa8J61NQw== +"@jest/transform@^29.6.4": + version "29.6.4" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-29.6.4.tgz#a6bc799ef597c5d85b2e65a11fd96b6b239bab5a" + integrity sha512-8thgRSiXUqtr/pPGY/OsyHuMjGyhVnWrFAwoxmIemlBuiMyU1WFs0tXoNxzcr4A4uErs/ABre76SGmrr5ab/AA== dependencies: "@babel/core" "^7.11.6" - "@jest/types" "^29.5.0" - "@jridgewell/trace-mapping" "^0.3.15" + "@jest/types" "^29.6.3" + "@jridgewell/trace-mapping" "^0.3.18" babel-plugin-istanbul "^6.1.1" chalk "^4.0.0" convert-source-map "^2.0.0" fast-json-stable-stringify "^2.1.0" graceful-fs "^4.2.9" - jest-haste-map "^29.5.0" - jest-regex-util "^29.4.3" - jest-util "^29.5.0" + jest-haste-map "^29.6.4" + jest-regex-util "^29.6.3" + jest-util "^29.6.3" micromatch "^4.0.4" pirates "^4.0.4" slash "^3.0.0" write-file-atomic "^4.0.2" -"@jest/types@^29.0.0", "@jest/types@^29.5.0": - version "29.5.0" - resolved "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz" - integrity sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog== +"@jest/types@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.6.3.tgz#1131f8cf634e7e84c5e77bab12f052af585fba59" + integrity sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw== dependencies: - "@jest/schemas" "^29.4.3" + "@jest/schemas" "^29.6.3" "@types/istanbul-lib-coverage" "^2.0.0" "@types/istanbul-reports" "^3.0.0" "@types/node" "*" "@types/yargs" "^17.0.8" chalk "^4.0.0" -"@jridgewell/gen-mapping@^0.1.0": - version "0.1.1" - resolved "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz" - integrity sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w== - dependencies: - "@jridgewell/set-array" "^1.0.0" - "@jridgewell/sourcemap-codec" "^1.4.10" - -"@jridgewell/gen-mapping@^0.3.2": - version "0.3.2" - resolved "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz" - integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A== +"@jridgewell/gen-mapping@^0.3.0", "@jridgewell/gen-mapping@^0.3.2": + version "0.3.3" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz#7e02e6eb5df901aaedb08514203b096614024098" + integrity sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ== dependencies: "@jridgewell/set-array" "^1.0.1" "@jridgewell/sourcemap-codec" "^1.4.10" "@jridgewell/trace-mapping" "^0.3.9" -"@jridgewell/resolve-uri@^3.0.3", "@jridgewell/resolve-uri@3.1.0": - version "3.1.0" - resolved "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz" - integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== +"@jridgewell/resolve-uri@^3.0.3", "@jridgewell/resolve-uri@^3.1.0": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz#c08679063f279615a3326583ba3a90d1d82cc721" + integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA== -"@jridgewell/set-array@^1.0.0", "@jridgewell/set-array@^1.0.1": +"@jridgewell/set-array@^1.0.1": version "1.1.2" - resolved "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== -"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@1.4.14": - version "1.4.14" - resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz" - integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== - -"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.15", "@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.9": - version "0.3.17" - resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz" - integrity sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g== - dependencies: - "@jridgewell/resolve-uri" "3.1.0" - "@jridgewell/sourcemap-codec" "1.4.14" +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": + version "1.4.15" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" + integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== "@jridgewell/trace-mapping@0.3.9": version "0.3.9" - resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9" integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== dependencies: "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" +"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.9": + version "0.3.19" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz#f8a3249862f91be48d3127c3cfe992f79b4b8811" + integrity sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + "@jsdevtools/ono@^7.1.3": version "7.1.3" - resolved "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz" + resolved "https://registry.yarnpkg.com/@jsdevtools/ono/-/ono-7.1.3.tgz#9df03bbd7c696a5c58885c34aa06da41c8543796" integrity sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg== "@nodelib/fs.scandir@2.1.5": version "2.1.5" - resolved "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== dependencies: "@nodelib/fs.stat" "2.0.5" run-parallel "^1.1.9" -"@nodelib/fs.stat@^2.0.2", "@nodelib/fs.stat@2.0.5": +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": version "2.0.5" - resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== "@nodelib/fs.walk@^1.2.3": version "1.2.8" - resolved "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== dependencies: "@nodelib/fs.scandir" "2.1.5" @@ -612,7 +602,7 @@ "@openapi-generator-plus/core@2.6.0": version "2.6.0" - resolved "https://registry.npmjs.org/@openapi-generator-plus/core/-/core-2.6.0.tgz" + resolved "https://registry.yarnpkg.com/@openapi-generator-plus/core/-/core-2.6.0.tgz#4004d92eb59c96d83ede224a71536027ce09fe86" integrity sha512-tEIIndmPMEzlCzEmKersKhOOSJ0XfIXbQOoEp85BH/J4vpnc1gncKwP1OqmAZs08uC5lbLSbqP4ZgJGtFr6JsQ== dependencies: "@openapi-generator-plus/indexed-type" "1.0.0" @@ -623,7 +613,7 @@ "@openapi-generator-plus/generator-common@1.3.3": version "1.3.3" - resolved "https://registry.npmjs.org/@openapi-generator-plus/generator-common/-/generator-common-1.3.3.tgz" + resolved "https://registry.yarnpkg.com/@openapi-generator-plus/generator-common/-/generator-common-1.3.3.tgz#331eabeee1ad757360af01e4b0881d55d8f72556" integrity sha512-B+q6e3yMaplqrjja8fhHPeyaqvRLKQyRxx0Ag0hrM+KjohXnauqfv0zZYkqs6+Jw8596JtQqAQ/lokRFYzdWVA== dependencies: "@openapi-generator-plus/types" "^2.5.0" @@ -633,7 +623,7 @@ "@openapi-generator-plus/handlebars-templates@1.2.4": version "1.2.4" - resolved "https://registry.npmjs.org/@openapi-generator-plus/handlebars-templates/-/handlebars-templates-1.2.4.tgz" + resolved "https://registry.yarnpkg.com/@openapi-generator-plus/handlebars-templates/-/handlebars-templates-1.2.4.tgz#eb418776a50a5390228abdb87a2df0ab2748f1a1" integrity sha512-+Q8VRayFih8xE9FD+Z7K5/tVU0Eqfn6tB8LUzmIRYmUihYMQorho/360srUcSMO6s1pneBLP337a9+DAgU9yzw== dependencies: "@openapi-generator-plus/generator-common" "1.3.3" @@ -644,14 +634,14 @@ marked "^4.0.15" pluralize "^8.0.0" -"@openapi-generator-plus/indexed-type@^1.0.0", "@openapi-generator-plus/indexed-type@1.0.0": +"@openapi-generator-plus/indexed-type@1.0.0", "@openapi-generator-plus/indexed-type@^1.0.0": version "1.0.0" - resolved "https://registry.npmjs.org/@openapi-generator-plus/indexed-type/-/indexed-type-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/@openapi-generator-plus/indexed-type/-/indexed-type-1.0.0.tgz#0cde3bd7e3ad3ab9ee3ee5f41927aa3683b69978" integrity sha512-RGUrlulyLoH7+V6wDalDGD9bfwTyDgIMZnfPo5GmaQs3CGOZ2aSHYAsB78gVTz2KWTyc5Ov4doi2lPENeUarZQ== "@openapi-generator-plus/java-like-generator-helper@2.1.4": version "2.1.4" - resolved "https://registry.npmjs.org/@openapi-generator-plus/java-like-generator-helper/-/java-like-generator-helper-2.1.4.tgz" + resolved "https://registry.yarnpkg.com/@openapi-generator-plus/java-like-generator-helper/-/java-like-generator-helper-2.1.4.tgz#06436742969edce9e328aa2b250b889dcb7d74d8" integrity sha512-c7/eWPF7PEgusOXGXLRwiX56OLn6YUxMG88EJ7WnAGPnVUNxA3FfggDschH9hGpE62guLLiahJ/5qngyzACg5g== dependencies: "@openapi-generator-plus/generator-common" "1.3.3" @@ -660,7 +650,7 @@ "@openapi-generator-plus/json-schema-ref-parser@^9.0.11": version "9.0.11" - resolved "https://registry.npmjs.org/@openapi-generator-plus/json-schema-ref-parser/-/json-schema-ref-parser-9.0.11.tgz" + resolved "https://registry.yarnpkg.com/@openapi-generator-plus/json-schema-ref-parser/-/json-schema-ref-parser-9.0.11.tgz#076c6b085e2acfcd3097841bb75a9cff96702ae3" integrity sha512-SJbsXJgQozq86V2ImkLuthI9d7esDIPjG/MUw2BEVa3HLIi/lHMmAVpUvBGNIpK4+yvUGmZSpgLOLmW3R9XoTA== dependencies: "@jsdevtools/ono" "^7.1.3" @@ -670,7 +660,7 @@ "@openapi-generator-plus/swagger-parser@^10.1.0": version "10.1.0" - resolved "https://registry.npmjs.org/@openapi-generator-plus/swagger-parser/-/swagger-parser-10.1.0.tgz" + resolved "https://registry.yarnpkg.com/@openapi-generator-plus/swagger-parser/-/swagger-parser-10.1.0.tgz#b9643176358abdb9e7092f1ad2c3a49d6e077e02" integrity sha512-Nxa6cAcJR6f2qieIa/pXTg0B9LqwzwYj6/AHBS39jE/eizJrhHQm74kqzABPjrFhvp9EcZD9E8IBuRunFfQULg== dependencies: "@apidevtools/openapi-schemas" "^2.1.0" @@ -681,14 +671,14 @@ ajv-draft-04 "^1.0.0" call-me-maybe "^1.0.1" -"@openapi-generator-plus/types@^2.0.0", "@openapi-generator-plus/types@^2.5.0", "@openapi-generator-plus/types@2.5.0": +"@openapi-generator-plus/types@2.5.0", "@openapi-generator-plus/types@^2.0.0", "@openapi-generator-plus/types@^2.5.0": version "2.5.0" - resolved "https://registry.npmjs.org/@openapi-generator-plus/types/-/types-2.5.0.tgz" + resolved "https://registry.yarnpkg.com/@openapi-generator-plus/types/-/types-2.5.0.tgz#d36c1fb929bd5b5c640317b0033cfaf9a86f7817" integrity sha512-jELZ0fQx8FluA4EsekiGeRus0ZfrE+CbIswzUTcaUEKruv1Jm0q9aXEU2mAzVrzp+F92HOMqI5JyiUSBkv9hcw== "@openapi-generator-plus/typescript-fetch-client-generator@^1.5.0": version "1.5.0" - resolved "https://registry.npmjs.org/@openapi-generator-plus/typescript-fetch-client-generator/-/typescript-fetch-client-generator-1.5.0.tgz" + resolved "https://registry.yarnpkg.com/@openapi-generator-plus/typescript-fetch-client-generator/-/typescript-fetch-client-generator-1.5.0.tgz#d8e2687b6cb5578ce458d61999e154f296fb3800" integrity sha512-ZnMHRD38eMLEe26dWm5o0yz2lVSL+yb+ANNtqimMkR8r0aCwUIHBb4jZo4jz7iwN2rxqBn5iyca6V9lMZDpZkQ== dependencies: "@openapi-generator-plus/generator-common" "1.3.3" @@ -700,7 +690,7 @@ "@openapi-generator-plus/typescript-generator-common@1.5.4": version "1.5.4" - resolved "https://registry.npmjs.org/@openapi-generator-plus/typescript-generator-common/-/typescript-generator-common-1.5.4.tgz" + resolved "https://registry.yarnpkg.com/@openapi-generator-plus/typescript-generator-common/-/typescript-generator-common-1.5.4.tgz#85099df4d547d0273e7e394ca35a71b68648fed3" integrity sha512-sN7q6fCiG3d+MZoVfU1Fqz685YiBBxE2rK37uY5iwz+TkQVAVepSW4RD9011Q/q82d415Fqy8vT4C836WyrV8w== dependencies: "@openapi-generator-plus/generator-common" "1.3.3" @@ -710,9 +700,9 @@ handlebars "^4.7.7" pluralize "^8.0.0" -"@openapi-generator-plus/utils@^1.0.1", "@openapi-generator-plus/utils@1.0.1": +"@openapi-generator-plus/utils@1.0.1", "@openapi-generator-plus/utils@^1.0.1": version "1.0.1" - resolved "https://registry.npmjs.org/@openapi-generator-plus/utils/-/utils-1.0.1.tgz" + resolved "https://registry.yarnpkg.com/@openapi-generator-plus/utils/-/utils-1.0.1.tgz#123d84a8a60ad905a0028f8ea64ee4bf08d04f67" integrity sha512-WceEoFbMmhdqnj2qzdsZTb7ZXH5boNp9LYJHNwD+7A0Y3UfHOh+KHMrKrO6+3K8O0g6dxjYWvG2/ZNLX8VbybA== dependencies: "@openapi-generator-plus/indexed-type" "^1.0.0" @@ -720,56 +710,109 @@ "@pkgjs/parseargs@^0.11.0": version "0.11.0" - resolved "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz" + resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== -"@sinclair/typebox@^0.25.16": - version "0.25.23" - resolved "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.25.23.tgz" - integrity sha512-VEB8ygeP42CFLWyAJhN5OklpxUliqdNEUcXb4xZ/CINqtYGTjL5ukluKdKzQ0iWdUxyQ7B0539PAUhHKrCNWSQ== +"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf" + integrity sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ== + +"@protobufjs/base64@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/base64/-/base64-1.1.2.tgz#4c85730e59b9a1f1f349047dbf24296034bb2735" + integrity sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg== + +"@protobufjs/codegen@^2.0.4": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@protobufjs/codegen/-/codegen-2.0.4.tgz#7ef37f0d010fb028ad1ad59722e506d9262815cb" + integrity sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg== + +"@protobufjs/eventemitter@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz#355cbc98bafad5978f9ed095f397621f1d066b70" + integrity sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q== + +"@protobufjs/fetch@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/fetch/-/fetch-1.1.0.tgz#ba99fb598614af65700c1619ff06d454b0d84c45" + integrity sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ== + dependencies: + "@protobufjs/aspromise" "^1.1.1" + "@protobufjs/inquire" "^1.1.0" + +"@protobufjs/float@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@protobufjs/float/-/float-1.0.2.tgz#5e9e1abdcb73fc0a7cb8b291df78c8cbd97b87d1" + integrity sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ== + +"@protobufjs/inquire@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/inquire/-/inquire-1.1.0.tgz#ff200e3e7cf2429e2dcafc1140828e8cc638f089" + integrity sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q== + +"@protobufjs/path@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/path/-/path-1.1.2.tgz#6cc2b20c5c9ad6ad0dccfd21ca7673d8d7fbf68d" + integrity sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA== + +"@protobufjs/pool@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/pool/-/pool-1.1.0.tgz#09fd15f2d6d3abfa9b65bc366506d6ad7846ff54" + integrity sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw== + +"@protobufjs/utf8@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" + integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw== + +"@sinclair/typebox@^0.27.8": + version "0.27.8" + resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e" + integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA== "@sinonjs/commons@^3.0.0": version "3.0.0" - resolved "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz" + resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-3.0.0.tgz#beb434fe875d965265e04722ccfc21df7f755d72" integrity sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA== dependencies: type-detect "4.0.8" "@sinonjs/fake-timers@^10.0.2": version "10.3.0" - resolved "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz" + resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz#55fdff1ecab9f354019129daf4df0dd4d923ea66" integrity sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA== dependencies: "@sinonjs/commons" "^3.0.0" "@tsconfig/node10@^1.0.7": version "1.0.9" - resolved "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz" + resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.9.tgz#df4907fc07a886922637b15e02d4cebc4c0021b2" integrity sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA== "@tsconfig/node12@^1.0.7": version "1.0.11" - resolved "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz" + resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d" integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag== "@tsconfig/node14@^1.0.0": version "1.0.3" - resolved "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz" + resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1" integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== "@tsconfig/node16@^1.0.2": - version "1.0.3" - resolved "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz" - integrity sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ== + version "1.0.4" + resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.4.tgz#0b92dcc0cc1c81f6f306a381f28e31b1a56536e9" + integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== "@tsd/typescript@~5.0.2": version "5.0.4" - resolved "https://registry.npmjs.org/@tsd/typescript/-/typescript-5.0.4.tgz" + resolved "https://registry.yarnpkg.com/@tsd/typescript/-/typescript-5.0.4.tgz#18aa4eb2c35c6bf9aab3199c289be319bedb7e9c" integrity sha512-YQi2lvZSI+xidKeUjlbv6b6Zw7qB3aXHw5oGJLs5OOGAEqKIOvz5UIAkWyg0bJbkSUWPBEtaOHpVxU4EYBO1Jg== "@types/babel__core@^7.1.14": version "7.20.1" - resolved "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.1.tgz" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.1.tgz#916ecea274b0c776fec721e333e55762d3a9614b" integrity sha512-aACu/U/omhdk15O4Nfb+fHgH/z3QsfQzpnvRZhYhThms83ZnAOZz7zZAWO7mn2yyNQaA4xTO8GLK3uqFU4bYYw== dependencies: "@babel/parser" "^7.20.7" @@ -780,42 +823,42 @@ "@types/babel__generator@*": version "7.6.4" - resolved "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz" + resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.4.tgz#1f20ce4c5b1990b37900b63f050182d28c2439b7" integrity sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg== dependencies: "@babel/types" "^7.0.0" "@types/babel__template@*": version "7.4.1" - resolved "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz" + resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.1.tgz#3d1a48fd9d6c0edfd56f2ff578daed48f36c8969" integrity sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g== dependencies: "@babel/parser" "^7.1.0" "@babel/types" "^7.0.0" "@types/babel__traverse@*", "@types/babel__traverse@^7.0.6": - version "7.18.3" - resolved "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.3.tgz" - integrity sha512-1kbcJ40lLB7MHsj39U4Sh1uTd2E7rLEa79kmDpI6cy+XiXsteB3POdQomoq4FxszMrO3ZYchkhYJw7A2862b3w== + version "7.20.1" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.20.1.tgz#dd6f1d2411ae677dcb2db008c962598be31d6acf" + integrity sha512-MitHFXnhtgwsGZWtT68URpOvLN4EREih1u3QtQiN4VdAxWKRVvGCSvw/Qth0M0Qq3pJpnGOu5JaM/ydK7OGbqg== dependencies: - "@babel/types" "^7.3.0" + "@babel/types" "^7.20.7" "@types/eslint@^7.2.13": version "7.29.0" - resolved "https://registry.npmjs.org/@types/eslint/-/eslint-7.29.0.tgz" + resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-7.29.0.tgz#e56ddc8e542815272720bb0b4ccc2aff9c3e1c78" integrity sha512-VNcvioYDH8/FxaeTKkM4/TiTwt6pBV9E3OfGmvaw8tPl0rrHCJ4Ll15HRT+pMiFAf/MLQvAzC+6RzUMEL9Ceng== dependencies: "@types/estree" "*" "@types/json-schema" "*" "@types/estree@*": - version "1.0.0" - resolved "https://registry.npmjs.org/@types/estree/-/estree-1.0.0.tgz" - integrity sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ== + version "1.0.1" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.1.tgz#aa22750962f3bf0e79d753d3cc067f010c95f194" + integrity sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA== "@types/glob@^7.1.3": version "7.2.0" - resolved "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz" + resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.2.0.tgz#bc1b5bf3aa92f25bd5dd39f35c57361bdce5b2eb" integrity sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA== dependencies: "@types/minimatch" "*" @@ -823,51 +866,56 @@ "@types/graceful-fs@^4.1.3": version "4.1.6" - resolved "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz" + resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.6.tgz#e14b2576a1c25026b7f02ede1de3b84c3a1efeae" integrity sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw== dependencies: "@types/node" "*" "@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": version "2.0.4" - resolved "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz#8467d4b3c087805d63580480890791277ce35c44" integrity sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g== "@types/istanbul-lib-report@*": version "3.0.0" - resolved "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#c14c24f18ea8190c118ee7562b7ff99a36552686" integrity sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg== dependencies: "@types/istanbul-lib-coverage" "*" "@types/istanbul-reports@^3.0.0": version "3.0.1" - resolved "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz" + resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz#9153fe98bba2bd565a63add9436d6f0d7f8468ff" integrity sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw== dependencies: "@types/istanbul-lib-report" "*" "@types/jest@^29.5.0": - version "29.5.2" - resolved "https://registry.npmjs.org/@types/jest/-/jest-29.5.2.tgz" - integrity sha512-mSoZVJF5YzGVCk+FsDxzDuH7s+SCkzrgKZzf0Z0T2WudhBUPoF6ktoTPC4R0ZoCPCV5xUvuU6ias5NvxcBcMMg== + version "29.5.4" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.4.tgz#9d0a16edaa009a71e6a71a999acd582514dab566" + integrity sha512-PhglGmhWeD46FYOVLt3X7TiWjzwuVGW9wG/4qocPevXMjCmrIc5b6db9WjeGE4QYVpUAWMDv3v0IiBwObY289A== dependencies: expect "^29.0.0" pretty-format "^29.0.0" "@types/json-schema@*", "@types/json-schema@^7.0.6": - version "7.0.11" - resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz" - integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== + version "7.0.12" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.12.tgz#d70faba7039d5fca54c83c7dbab41051d2b6f6cb" + integrity sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA== + +"@types/long@^4.0.1": + version "4.0.2" + resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.2.tgz#b74129719fc8d11c01868010082d483b7545591a" + integrity sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA== "@types/minimatch@*": version "5.1.2" - resolved "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz" + resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-5.1.2.tgz#07508b45797cb81ec3f273011b054cd0755eddca" integrity sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA== "@types/minimist@^1.2.0": version "1.2.2" - resolved "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz" + resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.2.tgz#ee771e2ba4b3dc5b372935d549fd9617bf345b8c" integrity sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ== "@types/node@*": @@ -875,51 +923,81 @@ resolved "https://registry.npmjs.org/@types/node/-/node-18.14.0.tgz" integrity sha512-5EWrvLmglK+imbCJY0+INViFWUHg1AHel1sq4ZVSfdcNqGy9Edv3UB9IIzzg+xPaUcAgZYcfVs2fBcwDeZzU0A== +"@types/node@>=13.7.0": + version "20.5.0" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.5.0.tgz#7fc8636d5f1aaa3b21e6245e97d56b7f56702313" + integrity sha512-Mgq7eCtoTjT89FqNoTzzXg2XvCi5VMhRV6+I2aYanc6kQCBImeNaAYRs/DyoVqk1YEUJK5gN9VO7HRIdz4Wo3Q== + "@types/normalize-package-data@^2.4.0": version "2.4.1" - resolved "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz" + resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz#d3357479a0fdfdd5907fe67e17e0a85c906e1301" integrity sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw== -"@types/prettier@^2.1.5": - version "2.7.3" - resolved "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.3.tgz" - integrity sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA== - "@types/stack-utils@^2.0.0": version "2.0.1" - resolved "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz" + resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c" integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw== "@types/yargs-parser@*": version "21.0.0" - resolved "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz" + resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.0.tgz#0c60e537fa790f5f9472ed2776c2b71ec117351b" integrity sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA== "@types/yargs@^17.0.8": - version "17.0.22" - resolved "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.22.tgz" - integrity sha512-pet5WJ9U8yPVRhkwuEIp5ktAeAqRZOq4UdAyWLWzxbtpyXnzbtLdKiXAjJzi/KLmPGS9wk86lUFWZFN6sISo4g== + version "17.0.24" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.24.tgz#b3ef8d50ad4aa6aecf6ddc97c580a00f5aa11902" + integrity sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw== dependencies: "@types/yargs-parser" "*" +"@visheratin/web-ai-node@^1.3.1": + version "1.3.1" + resolved "https://registry.yarnpkg.com/@visheratin/web-ai-node/-/web-ai-node-1.3.1.tgz#8d146183f5c5862bbd6e6d8582b2ac7463187a24" + integrity sha512-O2GLX/Jyzi/LtN8J8uPSuwXF0yNiDYB6Bswj9hkYuoVeoPT0BV+1T4VPu3OaHaEq2/vIyTUBQbQHR6udqdTw0w== + dependencies: + comlink "4.3.1" + localforage "1.10.0" + onnxruntime-common "1.15.1" + pako "2.1.0" + +"@visheratin/web-ai@^1.3.1": + version "1.3.1" + resolved "https://registry.yarnpkg.com/@visheratin/web-ai/-/web-ai-1.3.1.tgz#b3723b62b55016c0d3dd3a8daf119cc8a08b194b" + integrity sha512-OWyYrTFAbHFijHmpfuJ6lzeLziYOt8jyHL6GeryRzUE671aRG3cDk6wRz/MJknJeWS0T1545jzkmDF/4blYPCQ== + dependencies: + comlink "4.3.1" + localforage "1.10.0" + onnxruntime-common "1.15.1" + pako "2.1.0" + +"@xenova/transformers@^2.5.2": + version "2.5.4" + resolved "https://registry.yarnpkg.com/@xenova/transformers/-/transformers-2.5.4.tgz#baaa5d59b63a25879718a5b82aa49d6af63dbe51" + integrity sha512-hXk/8j5E5Ql4PmP7/n45zSRVjTB1iLTUvRJum8ywU/aAXg4QW2SYQqb0oCBrY7yCG8Hb/8s3C+TevHjgWEbLkw== + dependencies: + onnxruntime-web "1.14.0" + sharp "^0.32.0" + optionalDependencies: + onnxruntime-node "1.14.0" + acorn-walk@^8.1.1: version "8.2.0" - resolved "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== acorn@^8.4.1: - version "8.8.2" - resolved "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz" - integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw== + version "8.10.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.10.0.tgz#8be5b3907a67221a81ab23c7889c4c5526b62ec5" + integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw== ajv-draft-04@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/ajv-draft-04/-/ajv-draft-04-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/ajv-draft-04/-/ajv-draft-04-1.0.0.tgz#3b64761b268ba0b9e668f0b41ba53fce0ad77fc8" integrity sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw== -ajv@^8.5.0, ajv@^8.6.3: +ajv@^8.6.3: version "8.12.0" - resolved "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.12.0.tgz#d1a0527323e22f53562c567c00991577dfbe19d1" integrity sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA== dependencies: fast-deep-equal "^3.1.1" @@ -929,60 +1007,53 @@ ajv@^8.5.0, ajv@^8.6.3: ansi-colors@^4.1.1: version "4.1.3" - resolved "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b" integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw== ansi-escapes@^4.2.1: version "4.3.2" - resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== dependencies: type-fest "^0.21.3" ansi-regex@^5.0.1: version "5.0.1" - resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== ansi-regex@^6.0.1: version "6.0.1" - resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a" integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA== ansi-styles@^3.2.1: version "3.2.1" - resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== dependencies: color-convert "^1.9.0" -ansi-styles@^4.0.0: - version "4.3.0" - resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" - integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== - dependencies: - color-convert "^2.0.1" - -ansi-styles@^4.1.0: +ansi-styles@^4.0.0, ansi-styles@^4.1.0: version "4.3.0" - resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== dependencies: color-convert "^2.0.1" ansi-styles@^5.0.0: version "5.2.0" - resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== ansi-styles@^6.1.0: version "6.2.1" - resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== anymatch@^3.0.3: version "3.1.3" - resolved "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== dependencies: normalize-path "^3.0.0" @@ -990,52 +1061,89 @@ anymatch@^3.0.3: arg@^4.1.0: version "4.1.3" - resolved "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz" + resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== argparse@^1.0.7: version "1.0.10" - resolved "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== dependencies: sprintf-js "~1.0.2" argparse@^2.0.1: version "2.0.1" - resolved "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== +array-buffer-byte-length@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz#fabe8bc193fea865f317fe7807085ee0dee5aead" + integrity sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A== + dependencies: + call-bind "^1.0.2" + is-array-buffer "^3.0.1" + array-union@^2.1.0: version "2.1.0" - resolved "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== +arraybuffer.prototype.slice@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.1.tgz#9b5ea3868a6eebc30273da577eb888381c0044bb" + integrity sha512-09x0ZWFEjj4WD8PDbykUwo3t9arLn8NIzmmYEJFpYekOAQjpkGSyrQhNoRTcwwcFRu+ycWF78QZ63oWTqSjBcw== + dependencies: + array-buffer-byte-length "^1.0.0" + call-bind "^1.0.2" + define-properties "^1.2.0" + get-intrinsic "^1.2.1" + is-array-buffer "^3.0.2" + is-shared-array-buffer "^1.0.2" + arrify@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz" + resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" integrity sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA== +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== + available-typed-arrays@^1.0.5: version "1.0.5" - resolved "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz" + resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== -babel-jest@^29.0.0, babel-jest@^29.5.0: - version "29.5.0" - resolved "https://registry.npmjs.org/babel-jest/-/babel-jest-29.5.0.tgz" - integrity sha512-mA4eCDh5mSo2EcA9xQjVTpmbbNk32Zb3Q3QFQsNhaK56Q+yoXowzFodLux30HRgyOho5rsQ6B0P9QpMkvvnJ0Q== +axios@^0.26.0: + version "0.26.1" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.26.1.tgz#1ede41c51fcf51bbbd6fd43669caaa4f0495aaa9" + integrity sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA== + dependencies: + follow-redirects "^1.14.8" + +b4a@^1.6.4: + version "1.6.4" + resolved "https://registry.yarnpkg.com/b4a/-/b4a-1.6.4.tgz#ef1c1422cae5ce6535ec191baeed7567443f36c9" + integrity sha512-fpWrvyVHEKyeEvbKZTVOeZF3VSKKWtJxFIxX/jaVPf+cLbGUSitjb49pHLqPV2BUNNZ0LcoeEGfE/YCpyDYHIw== + +babel-jest@^29.6.4: + version "29.6.4" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.6.4.tgz#98dbc45d1c93319c82a8ab4a478b670655dd2585" + integrity sha512-meLj23UlSLddj6PC+YTOFRgDAtjnZom8w/ACsrx0gtPtv5cJZk0A5Unk5bV4wixD7XaPCN1fQvpww8czkZURmw== dependencies: - "@jest/transform" "^29.5.0" + "@jest/transform" "^29.6.4" "@types/babel__core" "^7.1.14" babel-plugin-istanbul "^6.1.1" - babel-preset-jest "^29.5.0" + babel-preset-jest "^29.6.3" chalk "^4.0.0" graceful-fs "^4.2.9" slash "^3.0.0" babel-plugin-istanbul@^6.1.1: version "6.1.1" - resolved "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz" + resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz#fa88ec59232fd9b4e36dbbc540a8ec9a9b47da73" integrity sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA== dependencies: "@babel/helper-plugin-utils" "^7.0.0" @@ -1044,10 +1152,10 @@ babel-plugin-istanbul@^6.1.1: istanbul-lib-instrument "^5.0.4" test-exclude "^6.0.0" -babel-plugin-jest-hoist@^29.5.0: - version "29.5.0" - resolved "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.5.0.tgz" - integrity sha512-zSuuuAlTMT4mzLj2nPnUm6fsE6270vdOfnpbJ+RmruU75UhLFvL0N2NgI7xpeS7NaB6hGqmd5pVpGTDYvi4Q3w== +babel-plugin-jest-hoist@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz#aadbe943464182a8922c3c927c3067ff40d24626" + integrity sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg== dependencies: "@babel/template" "^7.3.3" "@babel/types" "^7.3.3" @@ -1056,7 +1164,7 @@ babel-plugin-jest-hoist@^29.5.0: babel-preset-current-node-syntax@^1.0.0: version "1.0.1" - resolved "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz" + resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz#b4399239b89b2a011f9ddbe3e4f401fc40cff73b" integrity sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ== dependencies: "@babel/plugin-syntax-async-generators" "^7.8.4" @@ -1072,22 +1180,36 @@ babel-preset-current-node-syntax@^1.0.0: "@babel/plugin-syntax-optional-chaining" "^7.8.3" "@babel/plugin-syntax-top-level-await" "^7.8.3" -babel-preset-jest@^29.5.0: - version "29.5.0" - resolved "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.5.0.tgz" - integrity sha512-JOMloxOqdiBSxMAzjRaH023/vvcaSaec49zvg+2LmNsktC7ei39LTJGw02J+9uUtTZUq6xbLyJ4dxe9sSmIuAg== +babel-preset-jest@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz#fa05fa510e7d493896d7b0dd2033601c840f171c" + integrity sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA== dependencies: - babel-plugin-jest-hoist "^29.5.0" + babel-plugin-jest-hoist "^29.6.3" babel-preset-current-node-syntax "^1.0.0" balanced-match@^1.0.0: version "1.0.2" - resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== +base64-js@^1.3.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + +bl@^4.0.3: + version "4.1.0" + resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" + integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w== + dependencies: + buffer "^5.5.0" + inherits "^2.0.4" + readable-stream "^3.4.0" + brace-expansion@^1.1.7: version "1.1.11" - resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== dependencies: balanced-match "^1.0.0" @@ -1095,50 +1217,58 @@ brace-expansion@^1.1.7: brace-expansion@^2.0.1: version "2.0.1" - resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== dependencies: balanced-match "^1.0.0" braces@^3.0.2: version "3.0.2" - resolved "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== dependencies: fill-range "^7.0.1" -browserslist@^4.21.3, "browserslist@>= 4.21.0": - version "4.21.5" - resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz" - integrity sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w== +browserslist@^4.21.9: + version "4.21.10" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.10.tgz#dbbac576628c13d3b2231332cb2ec5a46e015bb0" + integrity sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ== dependencies: - caniuse-lite "^1.0.30001449" - electron-to-chromium "^1.4.284" - node-releases "^2.0.8" - update-browserslist-db "^1.0.10" + caniuse-lite "^1.0.30001517" + electron-to-chromium "^1.4.477" + node-releases "^2.0.13" + update-browserslist-db "^1.0.11" bs-logger@0.x: version "0.2.6" - resolved "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz" + resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" integrity sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog== dependencies: fast-json-stable-stringify "2.x" bser@2.1.1: version "2.1.1" - resolved "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz" + resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== dependencies: node-int64 "^0.4.0" buffer-from@^1.0.0: version "1.1.2" - resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== +buffer@^5.5.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" + integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.1.13" + call-bind@^1.0.0, call-bind@^1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== dependencies: function-bind "^1.1.1" @@ -1146,17 +1276,17 @@ call-bind@^1.0.0, call-bind@^1.0.2: call-me-maybe@^1.0.1: version "1.0.2" - resolved "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.2.tgz" + resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.2.tgz#03f964f19522ba643b1b0693acb9152fe2074baa" integrity sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ== callsites@^3.0.0: version "3.1.0" - resolved "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== camel-case@^4.1.2: version "4.1.2" - resolved "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz" + resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-4.1.2.tgz#9728072a954f805228225a6deea6b38461e1bd5a" integrity sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw== dependencies: pascal-case "^3.1.2" @@ -1164,7 +1294,7 @@ camel-case@^4.1.2: camelcase-keys@^6.2.2: version "6.2.2" - resolved "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz" + resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-6.2.2.tgz#5e755d6ba51aa223ec7d3d52f25778210f9dc3c0" integrity sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg== dependencies: camelcase "^5.3.1" @@ -1173,40 +1303,31 @@ camelcase-keys@^6.2.2: camelcase@^5.3.1: version "5.3.1" - resolved "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== camelcase@^6.2.0: version "6.3.0" - resolved "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== -caniuse-lite@^1.0.30001449: - version "1.0.30001457" - resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001457.tgz" - integrity sha512-SDIV6bgE1aVbK6XyxdURbUE89zY7+k1BBBaOwYwkNCglXlel/E7mELiHC64HQ+W0xSKlqWhV9Wh7iHxUjMs4fA== +caniuse-lite@^1.0.30001517: + version "1.0.30001524" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001524.tgz#1e14bce4f43c41a7deaeb5ebfe86664fe8dadb80" + integrity sha512-Jj917pJtYg9HSJBF95HVX3Cdr89JUyLT4IZ8SvM5aDRni95swKgYi3TgYLH5hnGfPE/U1dg6IfZ50UsIlLkwSA== capital-case@^1.0.4: version "1.0.4" - resolved "https://registry.npmjs.org/capital-case/-/capital-case-1.0.4.tgz" + resolved "https://registry.yarnpkg.com/capital-case/-/capital-case-1.0.4.tgz#9d130292353c9249f6b00fa5852bee38a717e669" integrity sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A== dependencies: no-case "^3.0.4" tslib "^2.0.3" upper-case-first "^2.0.2" -chalk@^2.0.0: +chalk@^2.4.1, chalk@^2.4.2: version "2.4.2" - resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - -chalk@^2.4.1: - version "2.4.2" - resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== dependencies: ansi-styles "^3.2.1" @@ -1215,7 +1336,7 @@ chalk@^2.4.1: chalk@^4.0.0, chalk@^4.1.0: version "4.1.2" - resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== dependencies: ansi-styles "^4.1.0" @@ -1223,7 +1344,7 @@ chalk@^4.0.0, chalk@^4.1.0: change-case@^4.1.2: version "4.1.2" - resolved "https://registry.npmjs.org/change-case/-/change-case-4.1.2.tgz" + resolved "https://registry.yarnpkg.com/change-case/-/change-case-4.1.2.tgz#fedfc5f136045e2398c0410ee441f95704641e12" integrity sha512-bSxY2ws9OtviILG1EiY5K7NNxkqg/JnRnFxLtKQ96JaviiIxi7djMrSd0ECT9AC+lttClmYwKw53BWpOMblo7A== dependencies: camel-case "^4.1.2" @@ -1241,22 +1362,27 @@ change-case@^4.1.2: char-regex@^1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz" + resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== +chownr@^1.1.1: + version "1.1.4" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" + integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== + ci-info@^3.2.0: version "3.8.0" - resolved "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.8.0.tgz#81408265a5380c929f0bc665d62256628ce9ef91" integrity sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw== cjs-module-lexer@^1.0.0: version "1.2.3" - resolved "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz" + resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz#6c370ab19f8a3394e318fe682686ec0ac684d107" integrity sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ== cliui@^8.0.1: version "8.0.1" - resolved "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== dependencies: string-width "^4.2.0" @@ -1265,75 +1391,103 @@ cliui@^8.0.1: co@^4.6.0: version "4.6.0" - resolved "https://registry.npmjs.org/co/-/co-4.6.0.tgz" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" integrity sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ== +cohere-ai@^6.2.2: + version "6.2.2" + resolved "https://registry.yarnpkg.com/cohere-ai/-/cohere-ai-6.2.2.tgz#ea3a01d5bad839ffb006e8ec793c034a951cca7e" + integrity sha512-+Tq+4e8N/YWKJqFpWaULsfbZR/GOvGh8WWYFKR1bpipu8bCok3VcbTPnBmIToQiIqOgFpGk3HsA4b0guVyL3vg== + collect-v8-coverage@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz" - integrity sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg== + version "1.0.2" + resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz#c0b29bcd33bcd0779a1344c2136051e6afd3d9e9" + integrity sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q== color-convert@^1.9.0: version "1.9.3" - resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== dependencies: color-name "1.1.3" color-convert@^2.0.1: version "2.0.1" - resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== dependencies: color-name "~1.1.4" -color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - color-name@1.1.3: version "1.1.3" - resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== +color-name@^1.0.0, color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +color-string@^1.9.0: + version "1.9.1" + resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.9.1.tgz#4467f9146f036f855b764dfb5bf8582bf342c7a4" + integrity sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg== + dependencies: + color-name "^1.0.0" + simple-swizzle "^0.2.2" + +color@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/color/-/color-4.2.3.tgz#d781ecb5e57224ee43ea9627560107c0e0c6463a" + integrity sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A== + dependencies: + color-convert "^2.0.1" + color-string "^1.9.0" + +combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + +comlink@4.3.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/comlink/-/comlink-4.3.1.tgz#0c6b9d69bcd293715c907c33fe8fc45aecad13c5" + integrity sha512-+YbhUdNrpBZggBAHWcgQMLPLH1KDF3wJpeqrCKieWQ8RL7atmgsgTQko1XEBK6PsecfopWNntopJ+ByYG1lRaA== + concat-map@0.0.1: version "0.0.1" - resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== constant-case@^3.0.4: version "3.0.4" - resolved "https://registry.npmjs.org/constant-case/-/constant-case-3.0.4.tgz" + resolved "https://registry.yarnpkg.com/constant-case/-/constant-case-3.0.4.tgz#3b84a9aeaf4cf31ec45e6bf5de91bdfb0589faf1" integrity sha512-I2hSBi7Vvs7BEuJDr5dDHfzb/Ruj3FyvFyh7KLilAjNQw3Be+xgqUBA2W6scVEcL0hL1dwPRtIqEPVUCKkSsyQ== dependencies: no-case "^3.0.4" tslib "^2.0.3" upper-case "^2.0.2" -convert-source-map@^1.6.0: +convert-source-map@^1.6.0, convert-source-map@^1.7.0: version "1.9.0" - resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz" - integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A== - -convert-source-map@^1.7.0: - version "1.9.0" - resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.9.0.tgz#7faae62353fb4213366d0ca98358d22e8368b05f" integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A== convert-source-map@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== create-require@^1.1.0: version "1.1.1" - resolved "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz" + resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== cross-spawn@^6.0.5: version "6.0.5" - resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== dependencies: nice-try "^1.0.4" @@ -1342,18 +1496,9 @@ cross-spawn@^6.0.5: shebang-command "^1.2.0" which "^1.2.9" -cross-spawn@^7.0.0: - version "7.0.3" - resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz" - integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== - dependencies: - path-key "^3.1.0" - shebang-command "^2.0.0" - which "^2.0.1" - -cross-spawn@^7.0.3: +cross-spawn@^7.0.0, cross-spawn@^7.0.3: version "7.0.3" - resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== dependencies: path-key "^3.1.0" @@ -1362,14 +1507,14 @@ cross-spawn@^7.0.3: debug@^4.1.0, debug@^4.1.1: version "4.3.4" - resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== dependencies: ms "2.1.2" decamelize-keys@^1.1.0: version "1.1.1" - resolved "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.1.tgz" + resolved "https://registry.yarnpkg.com/decamelize-keys/-/decamelize-keys-1.1.1.tgz#04a2d523b2f18d80d0158a43b895d56dff8d19d8" integrity sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg== dependencies: decamelize "^1.1.0" @@ -1377,52 +1522,74 @@ decamelize-keys@^1.1.0: decamelize@^1.1.0, decamelize@^1.2.0: version "1.2.0" - resolved "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" integrity sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA== -dedent@^0.7.0: - version "0.7.0" - resolved "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz" - integrity sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA== +decompress-response@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-6.0.0.tgz#ca387612ddb7e104bd16d85aab00d5ecf09c66fc" + integrity sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ== + dependencies: + mimic-response "^3.1.0" + +dedent@^1.0.0: + version "1.5.1" + resolved "https://registry.yarnpkg.com/dedent/-/dedent-1.5.1.tgz#4f3fc94c8b711e9bb2800d185cd6ad20f2a90aff" + integrity sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg== + +deep-extend@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" + integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== deepmerge@^4.2.2: version "4.3.1" - resolved "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== -define-properties@^1.1.3, define-properties@^1.1.4: +define-properties@^1.1.3, define-properties@^1.1.4, define-properties@^1.2.0: version "1.2.0" - resolved "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.0.tgz#52988570670c9eacedd8064f4a990f2405849bd5" integrity sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA== dependencies: has-property-descriptors "^1.0.0" object-keys "^1.1.1" +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== + +detect-libc@^2.0.0, detect-libc@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.2.tgz#8ccf2ba9315350e1241b88d0ac3b0e1fbd99605d" + integrity sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw== + detect-newline@^3.0.0: version "3.1.0" - resolved "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz" + resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== -diff-sequences@^29.4.3: - version "29.4.3" - resolved "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.4.3.tgz" - integrity sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA== +diff-sequences@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.6.3.tgz#4deaf894d11407c51efc8418012f9e70b84ea921" + integrity sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q== diff@^4.0.1: version "4.0.2" - resolved "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz" + resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== dir-glob@^3.0.1: version "3.0.1" - resolved "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== dependencies: path-type "^4.0.0" dot-case@^3.0.4: version "3.0.4" - resolved "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz" + resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-3.0.4.tgz#9b2b670d00a431667a8a75ba29cd1b98809ce751" integrity sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w== dependencies: no-case "^3.0.4" @@ -1430,48 +1597,56 @@ dot-case@^3.0.4: eastasianwidth@^0.2.0: version "0.2.0" - resolved "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz" + resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== -electron-to-chromium@^1.4.284: - version "1.4.304" - resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.304.tgz" - integrity sha512-6c8M+ojPgDIXN2NyfGn8oHASXYnayj+gSEnGeLMKb9zjsySeVB/j7KkNAAG9yDcv8gNlhvFg5REa1N/kQU6pgA== +electron-to-chromium@^1.4.477: + version "1.4.506" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.506.tgz#59f64a211102db4c3ebae2f39cc0e8e1b12b3a07" + integrity sha512-xxGct4GPAKSRlrLBtJxJFYy74W11zX6PO9GyHgl/U+2s3Dp0ZEwAklDfNHXOWcvH7zWMpsmgbR0ggEuaYAVvHA== emittery@^0.13.1: version "0.13.1" - resolved "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz" + resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.13.1.tgz#c04b8c3457490e0847ae51fced3af52d338e3dad" integrity sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ== emoji-regex@^8.0.0: version "8.0.0" - resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== emoji-regex@^9.2.2: version "9.2.2" - resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== +end-of-stream@^1.1.0, end-of-stream@^1.4.1: + version "1.4.4" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" + integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== + dependencies: + once "^1.4.0" + error-ex@^1.3.1: version "1.3.2" - resolved "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== dependencies: is-arrayish "^0.2.1" -es-abstract@^1.19.0, es-abstract@^1.20.4: - version "1.21.1" - resolved "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.1.tgz" - integrity sha512-QudMsPOz86xYz/1dG1OuGBKOELjCh99IIWHLzy5znUB6j8xG2yMA7bfTV86VSqKF+Y/H08vQPR+9jyXpuC6hfg== +es-abstract@^1.20.4, es-abstract@^1.22.1: + version "1.22.1" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.22.1.tgz#8b4e5fc5cefd7f1660f0f8e1a52900dfbc9d9ccc" + integrity sha512-ioRRcXMO6OFyRpyzV3kE1IIBd4WG5/kltnzdxSCqoP8CMGs/Li+M1uF5o7lOkZVFjDs+NLesthnF66Pg/0q0Lw== dependencies: + array-buffer-byte-length "^1.0.0" + arraybuffer.prototype.slice "^1.0.1" available-typed-arrays "^1.0.5" call-bind "^1.0.2" es-set-tostringtag "^2.0.1" es-to-primitive "^1.2.1" - function-bind "^1.1.1" function.prototype.name "^1.1.5" - get-intrinsic "^1.1.3" + get-intrinsic "^1.2.1" get-symbol-description "^1.0.0" globalthis "^1.0.3" gopd "^1.0.1" @@ -1479,8 +1654,8 @@ es-abstract@^1.19.0, es-abstract@^1.20.4: has-property-descriptors "^1.0.0" has-proto "^1.0.1" has-symbols "^1.0.3" - internal-slot "^1.0.4" - is-array-buffer "^3.0.1" + internal-slot "^1.0.5" + is-array-buffer "^3.0.2" is-callable "^1.2.7" is-negative-zero "^2.0.2" is-regex "^1.1.4" @@ -1488,20 +1663,25 @@ es-abstract@^1.19.0, es-abstract@^1.20.4: is-string "^1.0.7" is-typed-array "^1.1.10" is-weakref "^1.0.2" - object-inspect "^1.12.2" + object-inspect "^1.12.3" object-keys "^1.1.1" object.assign "^4.1.4" - regexp.prototype.flags "^1.4.3" + regexp.prototype.flags "^1.5.0" + safe-array-concat "^1.0.0" safe-regex-test "^1.0.0" + string.prototype.trim "^1.2.7" string.prototype.trimend "^1.0.6" string.prototype.trimstart "^1.0.6" + typed-array-buffer "^1.0.0" + typed-array-byte-length "^1.0.0" + typed-array-byte-offset "^1.0.0" typed-array-length "^1.0.4" unbox-primitive "^1.0.2" - which-typed-array "^1.1.9" + which-typed-array "^1.1.10" es-set-tostringtag@^2.0.1: version "2.0.1" - resolved "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz" + resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz#338d502f6f674301d710b80c8592de8a15f09cd8" integrity sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg== dependencies: get-intrinsic "^1.1.3" @@ -1510,7 +1690,7 @@ es-set-tostringtag@^2.0.1: es-to-primitive@^1.2.1: version "1.2.1" - resolved "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== dependencies: is-callable "^1.1.4" @@ -1519,22 +1699,22 @@ es-to-primitive@^1.2.1: escalade@^3.1.1: version "3.1.1" - resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== escape-string-regexp@^1.0.5: version "1.0.5" - resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== escape-string-regexp@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== eslint-formatter-pretty@^4.1.0: version "4.1.0" - resolved "https://registry.npmjs.org/eslint-formatter-pretty/-/eslint-formatter-pretty-4.1.0.tgz" + resolved "https://registry.yarnpkg.com/eslint-formatter-pretty/-/eslint-formatter-pretty-4.1.0.tgz#7a6877c14ffe2672066c853587d89603e97c7708" integrity sha512-IsUTtGxF1hrH6lMWiSl1WbGaiP01eT6kzywdY1U+zLc0MP+nwEnUiS9UI8IaOTUhTeQJLlCEWIbXINBH4YJbBQ== dependencies: "@types/eslint" "^7.2.13" @@ -1548,17 +1728,17 @@ eslint-formatter-pretty@^4.1.0: eslint-rule-docs@^1.1.5: version "1.1.235" - resolved "https://registry.npmjs.org/eslint-rule-docs/-/eslint-rule-docs-1.1.235.tgz" + resolved "https://registry.yarnpkg.com/eslint-rule-docs/-/eslint-rule-docs-1.1.235.tgz#be6ef1fc3525f17b3c859ae2997fedadc89bfb9b" integrity sha512-+TQ+x4JdTnDoFEXXb3fDvfGOwnyNV7duH8fXWTPD1ieaBmB8omj7Gw/pMBBu4uI2uJCCU8APDaQJzWuXnTsH4A== esprima@^4.0.0: version "4.0.1" - resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== execa@^5.0.0: version "5.1.1" - resolved "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz" + resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== dependencies: cross-spawn "^7.0.3" @@ -1573,29 +1753,39 @@ execa@^5.0.0: exit@^0.1.2: version "0.1.2" - resolved "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz" + resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" integrity sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ== -expect@^29.0.0, expect@^29.5.0: - version "29.5.0" - resolved "https://registry.npmjs.org/expect/-/expect-29.5.0.tgz" - integrity sha512-yM7xqUrCO2JdpFo4XpM82t+PJBFybdqoQuJLDGeDX2ij8NZzqRHyu3Hp188/JX7SWqud+7t4MUdvcgGBICMHZg== +expand-template@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-2.0.3.tgz#6e14b3fcee0f3a6340ecb57d2e8918692052a47c" + integrity sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg== + +expect@^29.0.0, expect@^29.6.4: + version "29.6.4" + resolved "https://registry.yarnpkg.com/expect/-/expect-29.6.4.tgz#a6e6f66d4613717859b2fe3da98a739437b6f4b8" + integrity sha512-F2W2UyQ8XYyftHT57dtfg8Ue3X5qLgm2sSug0ivvLRH/VKNRL/pDxg/TH7zVzbQB0tu80clNFy6LU7OS/VSEKA== dependencies: - "@jest/expect-utils" "^29.5.0" - jest-get-type "^29.4.3" - jest-matcher-utils "^29.5.0" - jest-message-util "^29.5.0" - jest-util "^29.5.0" + "@jest/expect-utils" "^29.6.4" + jest-get-type "^29.6.3" + jest-matcher-utils "^29.6.4" + jest-message-util "^29.6.3" + jest-util "^29.6.3" fast-deep-equal@^3.1.1: version "3.1.3" - resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== +fast-fifo@^1.1.0, fast-fifo@^1.2.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/fast-fifo/-/fast-fifo-1.3.2.tgz#286e31de96eb96d38a97899815740ba2a4f3640c" + integrity sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ== + fast-glob@^3.2.9: - version "3.2.12" - resolved "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz" - integrity sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w== + version "3.3.1" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.1.tgz#784b4e897340f3dbbef17413b3f11acf03c874c4" + integrity sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg== dependencies: "@nodelib/fs.stat" "^2.0.2" "@nodelib/fs.walk" "^1.2.3" @@ -1603,112 +1793,142 @@ fast-glob@^3.2.9: merge2 "^1.3.0" micromatch "^4.0.4" -fast-json-stable-stringify@^2.1.0, fast-json-stable-stringify@2.x: +fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.1.0: version "2.1.0" - resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== fastq@^1.6.0: version "1.15.0" - resolved "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.15.0.tgz#d04d07c6a2a68fe4599fea8d2e103a937fae6b3a" integrity sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw== dependencies: reusify "^1.0.4" fb-watchman@^2.0.0: version "2.0.2" - resolved "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz" + resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.2.tgz#e9524ee6b5c77e9e5001af0f85f3adbb8623255c" integrity sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA== dependencies: bser "2.1.1" fill-range@^7.0.1: version "7.0.1" - resolved "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== dependencies: to-regex-range "^5.0.1" find-up@^4.0.0, find-up@^4.1.0: version "4.1.0" - resolved "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== dependencies: locate-path "^5.0.0" path-exists "^4.0.0" +flatbuffers@^1.12.0: + version "1.12.0" + resolved "https://registry.yarnpkg.com/flatbuffers/-/flatbuffers-1.12.0.tgz#72e87d1726cb1b216e839ef02658aa87dcef68aa" + integrity sha512-c7CZADjRcl6j0PlvFy0ZqXQ67qSEZfrVPynmnL+2zPc+NtMvrF8Y0QceMo7QqnSPc7+uWjUIAbvCQ5WIKlMVdQ== + +follow-redirects@^1.14.8: + version "1.15.2" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13" + integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== + for-each@^0.3.3: version "0.3.3" - resolved "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz" + resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== dependencies: is-callable "^1.1.3" foreground-child@^3.1.0: version "3.1.1" - resolved "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz" + resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.1.1.tgz#1d173e776d75d2772fed08efe4a0de1ea1b12d0d" integrity sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg== dependencies: cross-spawn "^7.0.0" signal-exit "^4.0.1" +form-data@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" + integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + +fs-constants@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" + integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== + fs.realpath@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== +fsevents@^2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + function-bind@^1.1.1: version "1.1.1" - resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== function.prototype.name@^1.1.5: - version "1.1.5" - resolved "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz" - integrity sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA== + version "1.1.6" + resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.6.tgz#cdf315b7d90ee77a4c6ee216c3c3362da07533fd" + integrity sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg== dependencies: call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.0" - functions-have-names "^1.2.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + functions-have-names "^1.2.3" -functions-have-names@^1.2.2: +functions-have-names@^1.2.3: version "1.2.3" - resolved "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz" + resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== gensync@^1.0.0-beta.2: version "1.0.0-beta.2" - resolved "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== get-caller-file@^2.0.5: version "2.0.5" - resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== -get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@^1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz" - integrity sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q== +get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@^1.2.0, get-intrinsic@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.1.tgz#d295644fed4505fc9cde952c37ee12b477a83d82" + integrity sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw== dependencies: function-bind "^1.1.1" has "^1.0.3" + has-proto "^1.0.1" has-symbols "^1.0.3" get-package-type@^0.1.0: version "0.1.0" - resolved "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz" + resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== get-stream@^6.0.0: version "6.0.1" - resolved "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== get-symbol-description@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" integrity sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw== dependencies: call-bind "^1.0.2" @@ -1716,49 +1936,42 @@ get-symbol-description@^1.0.0: getopts@^2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/getopts/-/getopts-2.3.0.tgz" + resolved "https://registry.yarnpkg.com/getopts/-/getopts-2.3.0.tgz#71e5593284807e03e2427449d4f6712a268666f4" integrity sha512-5eDf9fuSXwxBL6q5HX+dhDj+dslFGWzU5thZ9kNKUkcPtaPdatmUFKwHFrLb/uf/WpA4BHET+AX3Scl56cAjpA== +github-from-package@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/github-from-package/-/github-from-package-0.0.0.tgz#97fb5d96bfde8973313f20e8288ef9a167fa64ce" + integrity sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw== + glob-parent@^5.1.2: version "5.1.2" - resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== dependencies: is-glob "^4.0.1" glob-promise@^4.2.2: version "4.2.2" - resolved "https://registry.npmjs.org/glob-promise/-/glob-promise-4.2.2.tgz" + resolved "https://registry.yarnpkg.com/glob-promise/-/glob-promise-4.2.2.tgz#15f44bcba0e14219cd93af36da6bb905ff007877" integrity sha512-xcUzJ8NWN5bktoTIX7eOclO1Npxd/dyVqUJxlLIDasT4C7KZyqlPIwkdJ0Ypiy3p2ZKahTjK4M9uC3sNSfNMzw== dependencies: "@types/glob" "^7.1.3" glob@^10.2.5: - version "10.3.1" - resolved "https://registry.npmjs.org/glob/-/glob-10.3.1.tgz" - integrity sha512-9BKYcEeIs7QwlCYs+Y3GBvqAMISufUS0i2ELd11zpZjxI5V9iyRj0HgzB5/cLf2NY4vcYBTYzJ7GIui7j/4DOw== + version "10.3.4" + resolved "https://registry.yarnpkg.com/glob/-/glob-10.3.4.tgz#c85c9c7ab98669102b6defda76d35c5b1ef9766f" + integrity sha512-6LFElP3A+i/Q8XQKEvZjkEWEOTgAIALR9AO2rwT8bgPhDd1anmqDJDZ6lLddI4ehxxxR1S5RIqKe1uapMQfYaQ== dependencies: foreground-child "^3.1.0" jackspeak "^2.0.3" minimatch "^9.0.1" - minipass "^5.0.0 || ^6.0.2" - path-scurry "^1.10.0" + minipass "^5.0.0 || ^6.0.2 || ^7.0.0" + path-scurry "^1.10.1" -glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: - version "7.1.6" - resolved "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz" - integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - -glob@^7.2.0: +glob@^7.1.3, glob@^7.1.4, glob@^7.2.0: version "7.2.3" - resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== dependencies: fs.realpath "^1.0.0" @@ -1770,19 +1983,19 @@ glob@^7.2.0: globals@^11.1.0: version "11.12.0" - resolved "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== globalthis@^1.0.3: version "1.0.3" - resolved "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz" + resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.3.tgz#5852882a52b80dc301b0660273e1ed082f0b6ccf" integrity sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA== dependencies: define-properties "^1.1.3" globby@^11.0.1: version "11.1.0" - resolved "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== dependencies: array-union "^2.1.0" @@ -1794,23 +2007,28 @@ globby@^11.0.1: gopd@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== dependencies: get-intrinsic "^1.1.3" graceful-fs@^4.1.2, graceful-fs@^4.2.9: - version "4.2.10" - resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz" - integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== + version "4.2.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + +guid-typescript@^1.0.9: + version "1.0.9" + resolved "https://registry.yarnpkg.com/guid-typescript/-/guid-typescript-1.0.9.tgz#e35f77003535b0297ea08548f5ace6adb1480ddc" + integrity sha512-Y8T4vYhEfwJOTbouREvG+3XDsjr8E3kIr7uf+JZ0BYloFsttiHU0WfvANVsR7TxNUJa/WpCnw/Ino/p+DeBhBQ== handlebars@^4.7.7: - version "4.7.7" - resolved "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz" - integrity sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA== + version "4.7.8" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.8.tgz#41c42c18b1be2365439188c77c6afae71c0cd9e9" + integrity sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ== dependencies: minimist "^1.2.5" - neo-async "^2.6.0" + neo-async "^2.6.2" source-map "^0.6.1" wordwrap "^1.0.0" optionalDependencies: @@ -1818,58 +2036,58 @@ handlebars@^4.7.7: hard-rejection@^2.1.0: version "2.1.0" - resolved "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz" + resolved "https://registry.yarnpkg.com/hard-rejection/-/hard-rejection-2.1.0.tgz#1c6eda5c1685c63942766d79bb40ae773cecd883" integrity sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA== has-bigints@^1.0.1, has-bigints@^1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz" + resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ== has-flag@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== has-flag@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== has-property-descriptors@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz#610708600606d36961ed04c196193b6a607fa861" integrity sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ== dependencies: get-intrinsic "^1.1.1" has-proto@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz" + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.1.tgz#1885c1305538958aff469fef37937c22795408e0" integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg== has-symbols@^1.0.2, has-symbols@^1.0.3: version "1.0.3" - resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== has-tostringtag@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== dependencies: has-symbols "^1.0.2" has@^1.0.3: version "1.0.3" - resolved "https://registry.npmjs.org/has/-/has-1.0.3.tgz" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== dependencies: function-bind "^1.1.1" header-case@^2.0.4: version "2.0.4" - resolved "https://registry.npmjs.org/header-case/-/header-case-2.0.4.tgz" + resolved "https://registry.yarnpkg.com/header-case/-/header-case-2.0.4.tgz#5a42e63b55177349cf405beb8d775acabb92c063" integrity sha512-H/vuk5TEEVZwrR0lp2zed9OCo1uAILMlx0JEMgC26rzyJJ3N1v6XkwHHXJQdR2doSjcGPM6OKPYoJgf0plJ11Q== dependencies: capital-case "^1.0.4" @@ -1877,34 +2095,44 @@ header-case@^2.0.4: hosted-git-info@^2.1.4: version "2.8.9" - resolved "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9" integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw== hosted-git-info@^4.0.1: version "4.1.0" - resolved "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-4.1.0.tgz#827b82867e9ff1c8d0c4d9d53880397d2c86d224" integrity sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA== dependencies: lru-cache "^6.0.0" html-escaper@^2.0.0: version "2.0.2" - resolved "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz" + resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== human-signals@^2.1.0: version "2.1.0" - resolved "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== +ieee754@^1.1.13: + version "1.2.1" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== + ignore@^5.2.0: version "5.2.4" - resolved "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324" integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ== +immediate@~3.0.5: + version "3.0.6" + resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" + integrity sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ== + import-local@^3.0.2: version "3.1.0" - resolved "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.1.0.tgz#b4479df8a5fd44f6cdce24070675676063c95cb4" integrity sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg== dependencies: pkg-dir "^4.2.0" @@ -1912,30 +2140,35 @@ import-local@^3.0.2: imurmurhash@^0.1.4: version "0.1.4" - resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== indent-string@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== inflight@^1.0.4: version "1.0.6" - resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== dependencies: once "^1.3.0" wrappy "1" -inherits@2: +inherits@2, inherits@^2.0.3, inherits@^2.0.4: version "2.0.4" - resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== -internal-slot@^1.0.4: +ini@~1.3.0: + version "1.3.8" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" + integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== + +internal-slot@^1.0.5: version "1.0.5" - resolved "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.5.tgz#f2a2ee21f668f8627a4667f309dc0f4fb6674986" integrity sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ== dependencies: get-intrinsic "^1.2.0" @@ -1943,34 +2176,39 @@ internal-slot@^1.0.4: side-channel "^1.0.4" irregular-plurals@^3.2.0: - version "3.4.0" - resolved "https://registry.npmjs.org/irregular-plurals/-/irregular-plurals-3.4.0.tgz" - integrity sha512-YXxECO/W6N9aMBVKMKKZ8TXESgq7EFrp3emCGGUcrYY1cgJIeZjoB75MTu8qi+NAKntS9NwPU8VdcQ3r6E6aWQ== + version "3.5.0" + resolved "https://registry.yarnpkg.com/irregular-plurals/-/irregular-plurals-3.5.0.tgz#0835e6639aa8425bdc8b0d33d0dc4e89d9c01d2b" + integrity sha512-1ANGLZ+Nkv1ptFb2pa8oG8Lem4krflKuX/gINiHJHjJUKaJHk/SXk5x6K3J+39/p0h1RQ2saROclJJ+QLvETCQ== -is-array-buffer@^3.0.1: - version "3.0.1" - resolved "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.1.tgz" - integrity sha512-ASfLknmY8Xa2XtB4wmbz13Wu202baeA18cJBCeCy0wXUHZF0IPyVEXqKEcd+t2fNSLLL1vC6k7lxZEojNbISXQ== +is-array-buffer@^3.0.1, is-array-buffer@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.2.tgz#f2653ced8412081638ecb0ebbd0c41c6e0aecbbe" + integrity sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w== dependencies: call-bind "^1.0.2" - get-intrinsic "^1.1.3" + get-intrinsic "^1.2.0" is-typed-array "^1.1.10" is-arrayish@^0.2.1: version "0.2.1" - resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== +is-arrayish@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" + integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== + is-bigint@^1.0.1: version "1.0.4" - resolved "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz" + resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== dependencies: has-bigints "^1.0.1" is-boolean-object@^1.1.0: version "1.1.2" - resolved "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz" + resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== dependencies: call-bind "^1.0.2" @@ -1978,70 +2216,70 @@ is-boolean-object@^1.1.0: is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7: version "1.2.7" - resolved "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== -is-core-module@^2.5.0, is-core-module@^2.9.0: - version "2.11.0" - resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz" - integrity sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw== +is-core-module@^2.13.0, is-core-module@^2.5.0: + version "2.13.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.0.tgz#bb52aa6e2cbd49a30c2ba68c42bf3435ba6072db" + integrity sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ== dependencies: has "^1.0.3" is-date-object@^1.0.1: version "1.0.5" - resolved "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== dependencies: has-tostringtag "^1.0.0" is-extglob@^2.1.1: version "2.1.1" - resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== is-fullwidth-code-point@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== is-generator-fn@^2.0.0: version "2.1.0" - resolved "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz" + resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== is-glob@^4.0.1: version "4.0.3" - resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== dependencies: is-extglob "^2.1.1" is-negative-zero@^2.0.2: version "2.0.2" - resolved "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz" + resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== is-number-object@^1.0.4: version "1.0.7" - resolved "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz" + resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.7.tgz#59d50ada4c45251784e9904f5246c742f07a42fc" integrity sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ== dependencies: has-tostringtag "^1.0.0" is-number@^7.0.0: version "7.0.0" - resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== is-plain-obj@^1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" integrity sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg== is-regex@^1.1.4: version "1.1.4" - resolved "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== dependencies: call-bind "^1.0.2" @@ -2049,61 +2287,62 @@ is-regex@^1.1.4: is-shared-array-buffer@^1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz" + resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79" integrity sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA== dependencies: call-bind "^1.0.2" is-stream@^2.0.0: version "2.0.1" - resolved "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== is-string@^1.0.5, is-string@^1.0.7: version "1.0.7" - resolved "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz" + resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== dependencies: has-tostringtag "^1.0.0" is-symbol@^1.0.2, is-symbol@^1.0.3: version "1.0.4" - resolved "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== dependencies: has-symbols "^1.0.2" is-typed-array@^1.1.10, is-typed-array@^1.1.9: - version "1.1.10" - resolved "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz" - integrity sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A== + version "1.1.12" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.12.tgz#d0bab5686ef4a76f7a73097b95470ab199c57d4a" + integrity sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg== dependencies: - available-typed-arrays "^1.0.5" - call-bind "^1.0.2" - for-each "^0.3.3" - gopd "^1.0.1" - has-tostringtag "^1.0.0" + which-typed-array "^1.1.11" is-unicode-supported@^0.1.0: version "0.1.0" - resolved "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz" + resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== is-weakref@^1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz" + resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== dependencies: call-bind "^1.0.2" +isarray@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" + integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== + isexe@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== isomorphic-fetch@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-3.0.0.tgz" + resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-3.0.0.tgz#0267b005049046d2421207215d45d6a262b8b8b4" integrity sha512-qvUtwJ3j6qwsF3jLxkZ72qCgjMysPzDfeV240JHiGZsANBYd+EEuu35v7dfrJ9Up0Ak07D7GGSkGhCHTqg/5wA== dependencies: node-fetch "^2.6.1" @@ -2111,12 +2350,12 @@ isomorphic-fetch@^3.0.0: istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: version "3.2.0" - resolved "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz#189e7909d0a39fa5a3dfad5b03f71947770191d3" integrity sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw== -istanbul-lib-instrument@^5.0.4, istanbul-lib-instrument@^5.1.0: +istanbul-lib-instrument@^5.0.4: version "5.2.1" - resolved "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz#d10c8885c2125574e1c231cacadf955675e1ce3d" integrity sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg== dependencies: "@babel/core" "^7.12.3" @@ -2125,18 +2364,29 @@ istanbul-lib-instrument@^5.0.4, istanbul-lib-instrument@^5.1.0: istanbul-lib-coverage "^3.2.0" semver "^6.3.0" +istanbul-lib-instrument@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.0.tgz#7a8af094cbfff1d5bb280f62ce043695ae8dd5b8" + integrity sha512-x58orMzEVfzPUKqlbLd1hXCnySCxKdDKa6Rjg97CwuLLRI4g3FHTdnExu1OqffVFay6zeMW+T6/DowFLndWnIw== + dependencies: + "@babel/core" "^7.12.3" + "@babel/parser" "^7.14.7" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-coverage "^3.2.0" + semver "^7.5.4" + istanbul-lib-report@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz" - integrity sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw== + version "3.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz#908305bac9a5bd175ac6a74489eafd0fc2445a7d" + integrity sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw== dependencies: istanbul-lib-coverage "^3.0.0" - make-dir "^3.0.0" + make-dir "^4.0.0" supports-color "^7.1.0" istanbul-lib-source-maps@^4.0.0: version "4.0.1" - resolved "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz#895f3a709fcfba34c6de5a42939022f3e4358551" integrity sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw== dependencies: debug "^4.1.1" @@ -2144,391 +2394,389 @@ istanbul-lib-source-maps@^4.0.0: source-map "^0.6.1" istanbul-reports@^3.1.3: - version "3.1.5" - resolved "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz" - integrity sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w== + version "3.1.6" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.6.tgz#2544bcab4768154281a2f0870471902704ccaa1a" + integrity sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg== dependencies: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" jackspeak@^2.0.3: - version "2.2.1" - resolved "https://registry.npmjs.org/jackspeak/-/jackspeak-2.2.1.tgz" - integrity sha512-MXbxovZ/Pm42f6cDIDkl3xpwv1AGwObKwfmjs2nQePiy85tP3fatofl3FC1aBsOtP/6fq5SbtgHwWcMsLP+bDw== + version "2.3.1" + resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-2.3.1.tgz#ce2effa4c458e053640e61938865a5b5fae98456" + integrity sha512-4iSY3Bh1Htv+kLhiiZunUhQ+OYXIn0ze3ulq8JeWrFKmhPAJSySV2+kdtRh2pGcCeF0s6oR8Oc+pYZynJj4t8A== dependencies: "@isaacs/cliui" "^8.0.2" optionalDependencies: "@pkgjs/parseargs" "^0.11.0" -jest-changed-files@^29.5.0: - version "29.5.0" - resolved "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.5.0.tgz" - integrity sha512-IFG34IUMUaNBIxjQXF/iu7g6EcdMrGRRxaUSw92I/2g2YC6vCdTltl4nHvt7Ci5nSJwXIkCu8Ka1DKF+X7Z1Ag== +jest-changed-files@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-29.6.3.tgz#97cfdc93f74fb8af2a1acb0b78f836f1fb40c449" + integrity sha512-G5wDnElqLa4/c66ma5PG9eRjE342lIbF6SUnTJi26C3J28Fv2TVY2rOyKB9YGbSA5ogwevgmxc4j4aVjrEK6Yg== dependencies: execa "^5.0.0" + jest-util "^29.6.3" p-limit "^3.1.0" -jest-circus@^29.5.0: - version "29.5.0" - resolved "https://registry.npmjs.org/jest-circus/-/jest-circus-29.5.0.tgz" - integrity sha512-gq/ongqeQKAplVxqJmbeUOJJKkW3dDNPY8PjhJ5G0lBRvu0e3EWGxGy5cI4LAGA7gV2UHCtWBI4EMXK8c9nQKA== +jest-circus@^29.6.4: + version "29.6.4" + resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-29.6.4.tgz#f074c8d795e0cc0f2ebf0705086b1be6a9a8722f" + integrity sha512-YXNrRyntVUgDfZbjXWBMPslX1mQ8MrSG0oM/Y06j9EYubODIyHWP8hMUbjbZ19M3M+zamqEur7O80HODwACoJw== dependencies: - "@jest/environment" "^29.5.0" - "@jest/expect" "^29.5.0" - "@jest/test-result" "^29.5.0" - "@jest/types" "^29.5.0" + "@jest/environment" "^29.6.4" + "@jest/expect" "^29.6.4" + "@jest/test-result" "^29.6.4" + "@jest/types" "^29.6.3" "@types/node" "*" chalk "^4.0.0" co "^4.6.0" - dedent "^0.7.0" + dedent "^1.0.0" is-generator-fn "^2.0.0" - jest-each "^29.5.0" - jest-matcher-utils "^29.5.0" - jest-message-util "^29.5.0" - jest-runtime "^29.5.0" - jest-snapshot "^29.5.0" - jest-util "^29.5.0" + jest-each "^29.6.3" + jest-matcher-utils "^29.6.4" + jest-message-util "^29.6.3" + jest-runtime "^29.6.4" + jest-snapshot "^29.6.4" + jest-util "^29.6.3" p-limit "^3.1.0" - pretty-format "^29.5.0" + pretty-format "^29.6.3" pure-rand "^6.0.0" slash "^3.0.0" stack-utils "^2.0.3" -jest-cli@^29.5.0: - version "29.5.0" - resolved "https://registry.npmjs.org/jest-cli/-/jest-cli-29.5.0.tgz" - integrity sha512-L1KcP1l4HtfwdxXNFCL5bmUbLQiKrakMUriBEcc1Vfz6gx31ORKdreuWvmQVBit+1ss9NNR3yxjwfwzZNdQXJw== +jest-cli@^29.6.4: + version "29.6.4" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-29.6.4.tgz#ad52f2dfa1b0291de7ec7f8d7c81ac435521ede0" + integrity sha512-+uMCQ7oizMmh8ZwRfZzKIEszFY9ksjjEQnTEMTaL7fYiL3Kw4XhqT9bYh+A4DQKUb67hZn2KbtEnDuHvcgK4pQ== dependencies: - "@jest/core" "^29.5.0" - "@jest/test-result" "^29.5.0" - "@jest/types" "^29.5.0" + "@jest/core" "^29.6.4" + "@jest/test-result" "^29.6.4" + "@jest/types" "^29.6.3" chalk "^4.0.0" exit "^0.1.2" graceful-fs "^4.2.9" import-local "^3.0.2" - jest-config "^29.5.0" - jest-util "^29.5.0" - jest-validate "^29.5.0" + jest-config "^29.6.4" + jest-util "^29.6.3" + jest-validate "^29.6.3" prompts "^2.0.1" yargs "^17.3.1" -jest-config@^29.5.0: - version "29.5.0" - resolved "https://registry.npmjs.org/jest-config/-/jest-config-29.5.0.tgz" - integrity sha512-kvDUKBnNJPNBmFFOhDbm59iu1Fii1Q6SxyhXfvylq3UTHbg6o7j/g8k2dZyXWLvfdKB1vAPxNZnMgtKJcmu3kA== +jest-config@^29.6.4: + version "29.6.4" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-29.6.4.tgz#eff958ee41d4e1ee7a6106d02b74ad9fc427d79e" + integrity sha512-JWohr3i9m2cVpBumQFv2akMEnFEPVOh+9L2xIBJhJ0zOaci2ZXuKJj0tgMKQCBZAKA09H049IR4HVS/43Qb19A== dependencies: "@babel/core" "^7.11.6" - "@jest/test-sequencer" "^29.5.0" - "@jest/types" "^29.5.0" - babel-jest "^29.5.0" + "@jest/test-sequencer" "^29.6.4" + "@jest/types" "^29.6.3" + babel-jest "^29.6.4" chalk "^4.0.0" ci-info "^3.2.0" deepmerge "^4.2.2" glob "^7.1.3" graceful-fs "^4.2.9" - jest-circus "^29.5.0" - jest-environment-node "^29.5.0" - jest-get-type "^29.4.3" - jest-regex-util "^29.4.3" - jest-resolve "^29.5.0" - jest-runner "^29.5.0" - jest-util "^29.5.0" - jest-validate "^29.5.0" + jest-circus "^29.6.4" + jest-environment-node "^29.6.4" + jest-get-type "^29.6.3" + jest-regex-util "^29.6.3" + jest-resolve "^29.6.4" + jest-runner "^29.6.4" + jest-util "^29.6.3" + jest-validate "^29.6.3" micromatch "^4.0.4" parse-json "^5.2.0" - pretty-format "^29.5.0" + pretty-format "^29.6.3" slash "^3.0.0" strip-json-comments "^3.1.1" -jest-diff@^29.0.3, jest-diff@^29.5.0: - version "29.5.0" - resolved "https://registry.npmjs.org/jest-diff/-/jest-diff-29.5.0.tgz" - integrity sha512-LtxijLLZBduXnHSniy0WMdaHjmQnt3g5sa16W4p0HqukYTTsyTW3GD1q41TyGl5YFXj/5B2U6dlh5FM1LIMgxw== +jest-diff@^29.0.3, jest-diff@^29.6.4: + version "29.6.4" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.6.4.tgz#85aaa6c92a79ae8cd9a54ebae8d5b6d9a513314a" + integrity sha512-9F48UxR9e4XOEZvoUXEHSWY4qC4zERJaOfrbBg9JpbJOO43R1vN76REt/aMGZoY6GD5g84nnJiBIVlscegefpw== dependencies: chalk "^4.0.0" - diff-sequences "^29.4.3" - jest-get-type "^29.4.3" - pretty-format "^29.5.0" + diff-sequences "^29.6.3" + jest-get-type "^29.6.3" + pretty-format "^29.6.3" -jest-docblock@^29.4.3: - version "29.4.3" - resolved "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.4.3.tgz" - integrity sha512-fzdTftThczeSD9nZ3fzA/4KkHtnmllawWrXO69vtI+L9WjEIuXWs4AmyME7lN5hU7dB0sHhuPfcKofRsUb/2Fg== +jest-docblock@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-29.6.3.tgz#293dca5188846c9f7c0c2b1bb33e5b11f21645f2" + integrity sha512-2+H+GOTQBEm2+qFSQ7Ma+BvyV+waiIFxmZF5LdpBsAEjWX8QYjSCa4FrkIYtbfXUJJJnFCYrOtt6TZ+IAiTjBQ== dependencies: detect-newline "^3.0.0" -jest-each@^29.5.0: - version "29.5.0" - resolved "https://registry.npmjs.org/jest-each/-/jest-each-29.5.0.tgz" - integrity sha512-HM5kIJ1BTnVt+DQZ2ALp3rzXEl+g726csObrW/jpEGl+CDSSQpOJJX2KE/vEg8cxcMXdyEPu6U4QX5eruQv5hA== +jest-each@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-29.6.3.tgz#1956f14f5f0cb8ae0b2e7cabc10bb03ec817c142" + integrity sha512-KoXfJ42k8cqbkfshW7sSHcdfnv5agDdHCPA87ZBdmHP+zJstTJc0ttQaJ/x7zK6noAL76hOuTIJ6ZkQRS5dcyg== dependencies: - "@jest/types" "^29.5.0" + "@jest/types" "^29.6.3" chalk "^4.0.0" - jest-get-type "^29.4.3" - jest-util "^29.5.0" - pretty-format "^29.5.0" - -jest-environment-node@^29.5.0: - version "29.5.0" - resolved "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.5.0.tgz" - integrity sha512-ExxuIK/+yQ+6PRGaHkKewYtg6hto2uGCgvKdb2nfJfKXgZ17DfXjvbZ+jA1Qt9A8EQSfPnt5FKIfnOO3u1h9qw== - dependencies: - "@jest/environment" "^29.5.0" - "@jest/fake-timers" "^29.5.0" - "@jest/types" "^29.5.0" + jest-get-type "^29.6.3" + jest-util "^29.6.3" + pretty-format "^29.6.3" + +jest-environment-node@^29.6.4: + version "29.6.4" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-29.6.4.tgz#4ce311549afd815d3cafb49e60a1e4b25f06d29f" + integrity sha512-i7SbpH2dEIFGNmxGCpSc2w9cA4qVD+wfvg2ZnfQ7XVrKL0NA5uDVBIiGH8SR4F0dKEv/0qI5r+aDomDf04DpEQ== + dependencies: + "@jest/environment" "^29.6.4" + "@jest/fake-timers" "^29.6.4" + "@jest/types" "^29.6.3" "@types/node" "*" - jest-mock "^29.5.0" - jest-util "^29.5.0" + jest-mock "^29.6.3" + jest-util "^29.6.3" -jest-get-type@^29.4.3: - version "29.4.3" - resolved "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.4.3.tgz" - integrity sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg== +jest-get-type@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.6.3.tgz#36f499fdcea197c1045a127319c0481723908fd1" + integrity sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw== -jest-haste-map@^29.5.0: - version "29.5.0" - resolved "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.5.0.tgz" - integrity sha512-IspOPnnBro8YfVYSw6yDRKh/TiCdRngjxeacCps1cQ9cgVN6+10JUcuJ1EabrgYLOATsIAigxA0rLR9x/YlrSA== +jest-haste-map@^29.6.4: + version "29.6.4" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-29.6.4.tgz#97143ce833829157ea7025204b08f9ace609b96a" + integrity sha512-12Ad+VNTDHxKf7k+M65sviyynRoZYuL1/GTuhEVb8RYsNSNln71nANRb/faSyWvx0j+gHcivChXHIoMJrGYjog== dependencies: - "@jest/types" "^29.5.0" + "@jest/types" "^29.6.3" "@types/graceful-fs" "^4.1.3" "@types/node" "*" anymatch "^3.0.3" fb-watchman "^2.0.0" graceful-fs "^4.2.9" - jest-regex-util "^29.4.3" - jest-util "^29.5.0" - jest-worker "^29.5.0" + jest-regex-util "^29.6.3" + jest-util "^29.6.3" + jest-worker "^29.6.4" micromatch "^4.0.4" walker "^1.0.8" optionalDependencies: fsevents "^2.3.2" -jest-leak-detector@^29.5.0: - version "29.5.0" - resolved "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.5.0.tgz" - integrity sha512-u9YdeeVnghBUtpN5mVxjID7KbkKE1QU4f6uUwuxiY0vYRi9BUCLKlPEZfDGR67ofdFmDz9oPAy2G92Ujrntmow== +jest-leak-detector@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-29.6.3.tgz#b9661bc3aec8874e59aff361fa0c6d7cd507ea01" + integrity sha512-0kfbESIHXYdhAdpLsW7xdwmYhLf1BRu4AA118/OxFm0Ho1b2RcTmO4oF6aAMaxpxdxnJ3zve2rgwzNBD4Zbm7Q== dependencies: - jest-get-type "^29.4.3" - pretty-format "^29.5.0" + jest-get-type "^29.6.3" + pretty-format "^29.6.3" -jest-matcher-utils@^29.5.0: - version "29.5.0" - resolved "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.5.0.tgz" - integrity sha512-lecRtgm/rjIK0CQ7LPQwzCs2VwW6WAahA55YBuI+xqmhm7LAaxokSB8C97yJeYyT+HvQkH741StzpU41wohhWw== +jest-matcher-utils@^29.6.4: + version "29.6.4" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.6.4.tgz#327db7ababea49455df3b23e5d6109fe0c709d24" + integrity sha512-KSzwyzGvK4HcfnserYqJHYi7sZVqdREJ9DMPAKVbS98JsIAvumihaNUbjrWw0St7p9IY7A9UskCW5MYlGmBQFQ== dependencies: chalk "^4.0.0" - jest-diff "^29.5.0" - jest-get-type "^29.4.3" - pretty-format "^29.5.0" + jest-diff "^29.6.4" + jest-get-type "^29.6.3" + pretty-format "^29.6.3" -jest-message-util@^29.5.0: - version "29.5.0" - resolved "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.5.0.tgz" - integrity sha512-Kijeg9Dag6CKtIDA7O21zNTACqD5MD/8HfIV8pdD94vFyFuer52SigdC3IQMhab3vACxXMiFk+yMHNdbqtyTGA== +jest-message-util@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.6.3.tgz#bce16050d86801b165f20cfde34dc01d3cf85fbf" + integrity sha512-FtzaEEHzjDpQp51HX4UMkPZjy46ati4T5pEMyM6Ik48ztu4T9LQplZ6OsimHx7EuM9dfEh5HJa6D3trEftu3dA== dependencies: "@babel/code-frame" "^7.12.13" - "@jest/types" "^29.5.0" + "@jest/types" "^29.6.3" "@types/stack-utils" "^2.0.0" chalk "^4.0.0" graceful-fs "^4.2.9" micromatch "^4.0.4" - pretty-format "^29.5.0" + pretty-format "^29.6.3" slash "^3.0.0" stack-utils "^2.0.3" -jest-mock@^29.5.0: - version "29.5.0" - resolved "https://registry.npmjs.org/jest-mock/-/jest-mock-29.5.0.tgz" - integrity sha512-GqOzvdWDE4fAV2bWQLQCkujxYWL7RxjCnj71b5VhDAGOevB3qj3Ovg26A5NI84ZpODxyzaozXLOh2NCgkbvyaw== +jest-mock@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-29.6.3.tgz#433f3fd528c8ec5a76860177484940628bdf5e0a" + integrity sha512-Z7Gs/mOyTSR4yPsaZ72a/MtuK6RnC3JYqWONe48oLaoEcYwEDxqvbXz85G4SJrm2Z5Ar9zp6MiHF4AlFlRM4Pg== dependencies: - "@jest/types" "^29.5.0" + "@jest/types" "^29.6.3" "@types/node" "*" - jest-util "^29.5.0" + jest-util "^29.6.3" jest-pnp-resolver@^1.2.2: version "1.2.3" - resolved "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz" + resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz#930b1546164d4ad5937d5540e711d4d38d4cad2e" integrity sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w== -jest-regex-util@^29.4.3: - version "29.4.3" - resolved "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.4.3.tgz" - integrity sha512-O4FglZaMmWXbGHSQInfXewIsd1LMn9p3ZXB/6r4FOkyhX2/iP/soMG98jGvk/A3HAN78+5VWcBGO0BJAPRh4kg== +jest-regex-util@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-29.6.3.tgz#4a556d9c776af68e1c5f48194f4d0327d24e8a52" + integrity sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg== -jest-resolve-dependencies@^29.5.0: - version "29.5.0" - resolved "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.5.0.tgz" - integrity sha512-sjV3GFr0hDJMBpYeUuGduP+YeCRbd7S/ck6IvL3kQ9cpySYKqcqhdLLC2rFwrcL7tz5vYibomBrsFYWkIGGjOg== +jest-resolve-dependencies@^29.6.4: + version "29.6.4" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-29.6.4.tgz#20156b33c7eacbb6bb77aeba4bed0eab4a3f8734" + integrity sha512-7+6eAmr1ZBF3vOAJVsfLj1QdqeXG+WYhidfLHBRZqGN24MFRIiKG20ItpLw2qRAsW/D2ZUUmCNf6irUr/v6KHA== dependencies: - jest-regex-util "^29.4.3" - jest-snapshot "^29.5.0" + jest-regex-util "^29.6.3" + jest-snapshot "^29.6.4" -jest-resolve@*, jest-resolve@^29.5.0: - version "29.5.0" - resolved "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.5.0.tgz" - integrity sha512-1TzxJ37FQq7J10jPtQjcc+MkCkE3GBpBecsSUWJ0qZNJpmg6m0D9/7II03yJulm3H/fvVjgqLh/k2eYg+ui52w== +jest-resolve@^29.6.4: + version "29.6.4" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-29.6.4.tgz#e34cb06f2178b429c38455d98d1a07572ac9faa3" + integrity sha512-fPRq+0vcxsuGlG0O3gyoqGTAxasagOxEuyoxHeyxaZbc9QNek0AmJWSkhjlMG+mTsj+8knc/mWb3fXlRNVih7Q== dependencies: chalk "^4.0.0" graceful-fs "^4.2.9" - jest-haste-map "^29.5.0" + jest-haste-map "^29.6.4" jest-pnp-resolver "^1.2.2" - jest-util "^29.5.0" - jest-validate "^29.5.0" + jest-util "^29.6.3" + jest-validate "^29.6.3" resolve "^1.20.0" resolve.exports "^2.0.0" slash "^3.0.0" -jest-runner@^29.5.0: - version "29.5.0" - resolved "https://registry.npmjs.org/jest-runner/-/jest-runner-29.5.0.tgz" - integrity sha512-m7b6ypERhFghJsslMLhydaXBiLf7+jXy8FwGRHO3BGV1mcQpPbwiqiKUR2zU2NJuNeMenJmlFZCsIqzJCTeGLQ== +jest-runner@^29.6.4: + version "29.6.4" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-29.6.4.tgz#b3b8ccb85970fde0fae40c73ee11eb75adccfacf" + integrity sha512-SDaLrMmtVlQYDuG0iSPYLycG8P9jLI+fRm8AF/xPKhYDB2g6xDWjXBrR5M8gEWsK6KVFlebpZ4QsrxdyIX1Jaw== dependencies: - "@jest/console" "^29.5.0" - "@jest/environment" "^29.5.0" - "@jest/test-result" "^29.5.0" - "@jest/transform" "^29.5.0" - "@jest/types" "^29.5.0" + "@jest/console" "^29.6.4" + "@jest/environment" "^29.6.4" + "@jest/test-result" "^29.6.4" + "@jest/transform" "^29.6.4" + "@jest/types" "^29.6.3" "@types/node" "*" chalk "^4.0.0" emittery "^0.13.1" graceful-fs "^4.2.9" - jest-docblock "^29.4.3" - jest-environment-node "^29.5.0" - jest-haste-map "^29.5.0" - jest-leak-detector "^29.5.0" - jest-message-util "^29.5.0" - jest-resolve "^29.5.0" - jest-runtime "^29.5.0" - jest-util "^29.5.0" - jest-watcher "^29.5.0" - jest-worker "^29.5.0" + jest-docblock "^29.6.3" + jest-environment-node "^29.6.4" + jest-haste-map "^29.6.4" + jest-leak-detector "^29.6.3" + jest-message-util "^29.6.3" + jest-resolve "^29.6.4" + jest-runtime "^29.6.4" + jest-util "^29.6.3" + jest-watcher "^29.6.4" + jest-worker "^29.6.4" p-limit "^3.1.0" source-map-support "0.5.13" -jest-runtime@^29.5.0: - version "29.5.0" - resolved "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.5.0.tgz" - integrity sha512-1Hr6Hh7bAgXQP+pln3homOiEZtCDZFqwmle7Ew2j8OlbkIu6uE3Y/etJQG8MLQs3Zy90xrp2C0BRrtPHG4zryw== - dependencies: - "@jest/environment" "^29.5.0" - "@jest/fake-timers" "^29.5.0" - "@jest/globals" "^29.5.0" - "@jest/source-map" "^29.4.3" - "@jest/test-result" "^29.5.0" - "@jest/transform" "^29.5.0" - "@jest/types" "^29.5.0" +jest-runtime@^29.6.4: + version "29.6.4" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-29.6.4.tgz#b0bc495c9b6b12a0a7042ac34ca9bb85f8cd0ded" + integrity sha512-s/QxMBLvmwLdchKEjcLfwzP7h+jsHvNEtxGP5P+Fl1FMaJX2jMiIqe4rJw4tFprzCwuSvVUo9bn0uj4gNRXsbA== + dependencies: + "@jest/environment" "^29.6.4" + "@jest/fake-timers" "^29.6.4" + "@jest/globals" "^29.6.4" + "@jest/source-map" "^29.6.3" + "@jest/test-result" "^29.6.4" + "@jest/transform" "^29.6.4" + "@jest/types" "^29.6.3" "@types/node" "*" chalk "^4.0.0" cjs-module-lexer "^1.0.0" collect-v8-coverage "^1.0.0" glob "^7.1.3" graceful-fs "^4.2.9" - jest-haste-map "^29.5.0" - jest-message-util "^29.5.0" - jest-mock "^29.5.0" - jest-regex-util "^29.4.3" - jest-resolve "^29.5.0" - jest-snapshot "^29.5.0" - jest-util "^29.5.0" + jest-haste-map "^29.6.4" + jest-message-util "^29.6.3" + jest-mock "^29.6.3" + jest-regex-util "^29.6.3" + jest-resolve "^29.6.4" + jest-snapshot "^29.6.4" + jest-util "^29.6.3" slash "^3.0.0" strip-bom "^4.0.0" -jest-snapshot@^29.5.0: - version "29.5.0" - resolved "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.5.0.tgz" - integrity sha512-x7Wolra5V0tt3wRs3/ts3S6ciSQVypgGQlJpz2rsdQYoUKxMxPNaoHMGJN6qAuPJqS+2iQ1ZUn5kl7HCyls84g== +jest-snapshot@^29.6.4: + version "29.6.4" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-29.6.4.tgz#9833eb6b66ff1541c7fd8ceaa42d541f407b4876" + integrity sha512-VC1N8ED7+4uboUKGIDsbvNAZb6LakgIPgAF4RSpF13dN6YaMokfRqO+BaqK4zIh6X3JffgwbzuGqDEjHm/MrvA== dependencies: "@babel/core" "^7.11.6" "@babel/generator" "^7.7.2" "@babel/plugin-syntax-jsx" "^7.7.2" "@babel/plugin-syntax-typescript" "^7.7.2" - "@babel/traverse" "^7.7.2" "@babel/types" "^7.3.3" - "@jest/expect-utils" "^29.5.0" - "@jest/transform" "^29.5.0" - "@jest/types" "^29.5.0" - "@types/babel__traverse" "^7.0.6" - "@types/prettier" "^2.1.5" + "@jest/expect-utils" "^29.6.4" + "@jest/transform" "^29.6.4" + "@jest/types" "^29.6.3" babel-preset-current-node-syntax "^1.0.0" chalk "^4.0.0" - expect "^29.5.0" + expect "^29.6.4" graceful-fs "^4.2.9" - jest-diff "^29.5.0" - jest-get-type "^29.4.3" - jest-matcher-utils "^29.5.0" - jest-message-util "^29.5.0" - jest-util "^29.5.0" + jest-diff "^29.6.4" + jest-get-type "^29.6.3" + jest-matcher-utils "^29.6.4" + jest-message-util "^29.6.3" + jest-util "^29.6.3" natural-compare "^1.4.0" - pretty-format "^29.5.0" - semver "^7.3.5" + pretty-format "^29.6.3" + semver "^7.5.3" -jest-util@^29.0.0, jest-util@^29.5.0: - version "29.5.0" - resolved "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz" - integrity sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ== +jest-util@^29.0.0, jest-util@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.6.3.tgz#e15c3eac8716440d1ed076f09bc63ace1aebca63" + integrity sha512-QUjna/xSy4B32fzcKTSz1w7YYzgiHrjjJjevdRf61HYk998R5vVMMNmrHESYZVDS5DSWs+1srPLPKxXPkeSDOA== dependencies: - "@jest/types" "^29.5.0" + "@jest/types" "^29.6.3" "@types/node" "*" chalk "^4.0.0" ci-info "^3.2.0" graceful-fs "^4.2.9" picomatch "^2.2.3" -jest-validate@^29.5.0: - version "29.5.0" - resolved "https://registry.npmjs.org/jest-validate/-/jest-validate-29.5.0.tgz" - integrity sha512-pC26etNIi+y3HV8A+tUGr/lph9B18GnzSRAkPaaZJIE1eFdiYm6/CewuiJQ8/RlfHd1u/8Ioi8/sJ+CmbA+zAQ== +jest-validate@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-29.6.3.tgz#a75fca774cfb1c5758c70d035d30a1f9c2784b4d" + integrity sha512-e7KWZcAIX+2W1o3cHfnqpGajdCs1jSM3DkXjGeLSNmCazv1EeI1ggTeK5wdZhF+7N+g44JI2Od3veojoaumlfg== dependencies: - "@jest/types" "^29.5.0" + "@jest/types" "^29.6.3" camelcase "^6.2.0" chalk "^4.0.0" - jest-get-type "^29.4.3" + jest-get-type "^29.6.3" leven "^3.1.0" - pretty-format "^29.5.0" + pretty-format "^29.6.3" -jest-watcher@^29.5.0: - version "29.5.0" - resolved "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.5.0.tgz" - integrity sha512-KmTojKcapuqYrKDpRwfqcQ3zjMlwu27SYext9pt4GlF5FUgB+7XE1mcCnSm6a4uUpFyQIkb6ZhzZvHl+jiBCiA== +jest-watcher@^29.6.4: + version "29.6.4" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-29.6.4.tgz#633eb515ae284aa67fd6831f1c9d1b534cf0e0ba" + integrity sha512-oqUWvx6+On04ShsT00Ir9T4/FvBeEh2M9PTubgITPxDa739p4hoQweWPRGyYeaojgT0xTpZKF0Y/rSY1UgMxvQ== dependencies: - "@jest/test-result" "^29.5.0" - "@jest/types" "^29.5.0" + "@jest/test-result" "^29.6.4" + "@jest/types" "^29.6.3" "@types/node" "*" ansi-escapes "^4.2.1" chalk "^4.0.0" emittery "^0.13.1" - jest-util "^29.5.0" + jest-util "^29.6.3" string-length "^4.0.1" -jest-worker@^29.5.0: - version "29.5.0" - resolved "https://registry.npmjs.org/jest-worker/-/jest-worker-29.5.0.tgz" - integrity sha512-NcrQnevGoSp4b5kg+akIpthoAFHxPBcb5P6mYPY0fUNT+sSvmtu6jlkEle3anczUKIKEbMxFimk9oTP/tpIPgA== +jest-worker@^29.6.4: + version "29.6.4" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-29.6.4.tgz#f34279f4afc33c872b470d4af21b281ac616abd3" + integrity sha512-6dpvFV4WjcWbDVGgHTWo/aupl8/LbBx2NSKfiwqf79xC/yeJjKHT1+StcKy/2KTmW16hE68ccKVOtXf+WZGz7Q== dependencies: "@types/node" "*" - jest-util "^29.5.0" + jest-util "^29.6.3" merge-stream "^2.0.0" supports-color "^8.0.0" -jest@^29.0.0, jest@^29.5.0: - version "29.5.0" - resolved "https://registry.npmjs.org/jest/-/jest-29.5.0.tgz" - integrity sha512-juMg3he2uru1QoXX078zTa7pO85QyB9xajZc6bU+d9yEGwrKX6+vGmJQ3UdVZsvTEUARIdObzH68QItim6OSSQ== +jest@^29.5.0: + version "29.6.4" + resolved "https://registry.yarnpkg.com/jest/-/jest-29.6.4.tgz#7c48e67a445ba264b778253b5d78d4ebc9d0a622" + integrity sha512-tEFhVQFF/bzoYV1YuGyzLPZ6vlPrdfvDmmAxudA1dLEuiztqg2Rkx20vkKY32xiDROcD2KXlgZ7Cu8RPeEHRKw== dependencies: - "@jest/core" "^29.5.0" - "@jest/types" "^29.5.0" + "@jest/core" "^29.6.4" + "@jest/types" "^29.6.3" import-local "^3.0.2" - jest-cli "^29.5.0" + jest-cli "^29.6.4" js-tokens@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== js-yaml@^3.13.1: version "3.14.1" - resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== dependencies: argparse "^1.0.7" @@ -2536,59 +2784,66 @@ js-yaml@^3.13.1: js-yaml@^4.1.0: version "4.1.0" - resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== dependencies: argparse "^2.0.1" jsesc@^2.5.1: version "2.5.2" - resolved "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== json-parse-better-errors@^1.0.1: version "1.0.2" - resolved "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz" + resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== json-parse-even-better-errors@^2.3.0: version "2.3.1" - resolved "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== json-schema-traverse@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== -json5@^2.2.2, json5@^2.2.3: +json5@^2.2.3: version "2.2.3" - resolved "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== kind-of@^6.0.3: version "6.0.3" - resolved "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== kleur@^3.0.3: version "3.0.3" - resolved "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz" + resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== leven@^3.1.0: version "3.1.0" - resolved "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz" + resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== +lie@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/lie/-/lie-3.1.1.tgz#9a436b2cc7746ca59de7a41fa469b3efb76bd87e" + integrity sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw== + dependencies: + immediate "~3.0.5" + lines-and-columns@^1.1.6: version "1.2.4" - resolved "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== load-json-file@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b" integrity sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw== dependencies: graceful-fs "^4.1.2" @@ -2596,99 +2851,111 @@ load-json-file@^4.0.0: pify "^3.0.0" strip-bom "^3.0.0" +localforage@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/localforage/-/localforage-1.10.0.tgz#5c465dc5f62b2807c3a84c0c6a1b1b3212781dd4" + integrity sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg== + dependencies: + lie "3.1.1" + locate-path@^5.0.0: version "5.0.0" - resolved "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== dependencies: p-locate "^4.1.0" lodash.memoize@4.x: version "4.1.2" - resolved "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz" + resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag== lodash@^4.17.21: version "4.17.21" - resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== log-symbols@^4.0.0: version "4.1.0" - resolved "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== dependencies: chalk "^4.1.0" is-unicode-supported "^0.1.0" +long@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28" + integrity sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA== + lower-case@^2.0.2: version "2.0.2" - resolved "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz" + resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.2.tgz#6fa237c63dbdc4a82ca0fd882e4722dc5e634e28" integrity sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg== dependencies: tslib "^2.0.3" lru-cache@^5.1.1: version "5.1.1" - resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== dependencies: yallist "^3.0.2" lru-cache@^6.0.0: version "6.0.0" - resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== dependencies: yallist "^4.0.0" "lru-cache@^9.1.1 || ^10.0.0": - version "10.0.0" - resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-10.0.0.tgz" - integrity sha512-svTf/fzsKHffP42sujkO/Rjs37BCIsQVRCeNYIm9WN8rgT7ffoUnRtZCqU+6BqcSBdv8gwJeTz8knJpgACeQMw== + version "10.0.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.0.1.tgz#0a3be479df549cca0e5d693ac402ff19537a6b7a" + integrity sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g== -make-dir@^3.0.0: - version "3.1.0" - resolved "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz" - integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== +make-dir@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-4.0.0.tgz#c3c2307a771277cd9638305f915c29ae741b614e" + integrity sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw== dependencies: - semver "^6.0.0" + semver "^7.5.3" -make-error@^1.1.1, make-error@1.x: +make-error@1.x, make-error@^1.1.1: version "1.3.6" - resolved "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz" + resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== makeerror@1.0.12: version "1.0.12" - resolved "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz" + resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.12.tgz#3e5dd2079a82e812e983cc6610c4a2cb0eaa801a" integrity sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg== dependencies: tmpl "1.0.5" map-obj@^1.0.0: version "1.0.1" - resolved "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz" + resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" integrity sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg== map-obj@^4.0.0: version "4.3.0" - resolved "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz" + resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-4.3.0.tgz#9304f906e93faae70880da102a9f1df0ea8bb05a" integrity sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ== marked@^4.0.15: version "4.3.0" - resolved "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz" + resolved "https://registry.yarnpkg.com/marked/-/marked-4.3.0.tgz#796362821b019f734054582038b116481b456cf3" integrity sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A== memorystream@^0.3.1: version "0.3.1" - resolved "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz" + resolved "https://registry.yarnpkg.com/memorystream/-/memorystream-0.3.1.tgz#86d7090b30ce455d63fbae12dda51a47ddcaf9b2" integrity sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw== meow@^9.0.0: version "9.0.0" - resolved "https://registry.npmjs.org/meow/-/meow-9.0.0.tgz" + resolved "https://registry.yarnpkg.com/meow/-/meow-9.0.0.tgz#cd9510bc5cac9dee7d03c73ee1f9ad959f4ea364" integrity sha512-+obSblOQmRhcyBt62furQqRAQpNyWXo8BuQ5bN7dG8wmwQ+vwHKp/rCFD4CrTP8CsDQD1sjoZ94K417XEUk8IQ== dependencies: "@types/minimist" "^1.2.0" @@ -2706,118 +2973,157 @@ meow@^9.0.0: merge-stream@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== merge2@^1.3.0, merge2@^1.4.1: version "1.4.1" - resolved "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== micromatch@^4.0.4: version "4.0.5" - resolved "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== dependencies: braces "^3.0.2" picomatch "^2.3.1" +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@^2.1.12: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + mimic-fn@^2.1.0: version "2.1.0" - resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== +mimic-response@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9" + integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ== + min-indent@^1.0.0: version "1.0.1" - resolved "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz" + resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== minimatch@^3.0.4, minimatch@^3.1.1: version "3.1.2" - resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== dependencies: brace-expansion "^1.1.7" minimatch@^9.0.1: - version "9.0.2" - resolved "https://registry.npmjs.org/minimatch/-/minimatch-9.0.2.tgz" - integrity sha512-PZOT9g5v2ojiTL7r1xF6plNHLtOeTpSlDI007As2NlA2aYBMfVom17yqa6QzhmDP8QOhn7LjHTg7DFCVSSa6yg== + version "9.0.3" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825" + integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg== dependencies: brace-expansion "^2.0.1" minimist-options@4.1.0: version "4.1.0" - resolved "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz" + resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-4.1.0.tgz#c0655713c53a8a2ebd77ffa247d342c40f010619" integrity sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A== dependencies: arrify "^1.0.1" is-plain-obj "^1.1.0" kind-of "^6.0.3" -minimist@^1.2.5: +minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.5: version "1.2.8" - resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== -"minipass@^5.0.0 || ^6.0.2": - version "6.0.2" - resolved "https://registry.npmjs.org/minipass/-/minipass-6.0.2.tgz" - integrity sha512-MzWSV5nYVT7mVyWCwn2o7JH13w2TBRmmSqSRCKzTw+lmft9X4z+3wjvs06Tzijo5z4W/kahUCDpRXTF+ZrmF/w== +"minipass@^5.0.0 || ^6.0.2 || ^7.0.0": + version "7.0.3" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.0.3.tgz#05ea638da44e475037ed94d1c7efcc76a25e1974" + integrity sha512-LhbbwCfz3vsb12j/WkWQPZfKTsgqIe1Nf/ti1pKjYESGLHIVjWU96G9/ljLH4F9mWNVhlQOm0VySdAWzf05dpg== + +mkdirp-classic@^0.5.2, mkdirp-classic@^0.5.3: + version "0.5.3" + resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113" + integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A== ms@2.1.2: version "2.1.2" - resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== +napi-build-utils@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/napi-build-utils/-/napi-build-utils-1.0.2.tgz#b1fddc0b2c46e380a0b7a76f984dd47c41a13806" + integrity sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg== + natural-compare@^1.4.0: version "1.4.0" - resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== -neo-async@^2.6.0: +neo-async@^2.6.2: version "2.6.2" - resolved "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== nice-try@^1.0.4: version "1.0.5" - resolved "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz" + resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== no-case@^3.0.4: version "3.0.4" - resolved "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz" + resolved "https://registry.yarnpkg.com/no-case/-/no-case-3.0.4.tgz#d361fd5c9800f558551a8369fc0dcd4662b6124d" integrity sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg== dependencies: lower-case "^2.0.2" tslib "^2.0.3" +node-abi@^3.3.0: + version "3.47.0" + resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-3.47.0.tgz#6cbfa2916805ae25c2b7156ca640131632eb05e8" + integrity sha512-2s6B2CWZM//kPgwnuI0KrYwNjfdByE25zvAaEpq9IH4zcNsarH8Ihu/UuX6XMPEogDAxkuUFeZn60pXNHAqn3A== + dependencies: + semver "^7.3.5" + +node-addon-api@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-6.1.0.tgz#ac8470034e58e67d0c6f1204a18ae6995d9c0d76" + integrity sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA== + node-fetch@^2.6.1: - version "2.6.9" - resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.9.tgz" - integrity sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg== + version "2.7.0" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" + integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== dependencies: whatwg-url "^5.0.0" node-int64@^0.4.0: version "0.4.0" - resolved "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz" + resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== -node-releases@^2.0.8: - version "2.0.10" - resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz" - integrity sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w== +node-releases@^2.0.13: + version "2.0.13" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.13.tgz#d5ed1627c23e3461e819b02e57b75e4899b1c81d" + integrity sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ== node-watch@^0.7.3: - version "0.7.3" - resolved "https://registry.npmjs.org/node-watch/-/node-watch-0.7.3.tgz" - integrity sha512-3l4E8uMPY1HdMMryPRUAl+oIHtXtyiTlIiESNSVSNxcPfzAFzeTbXFQkZfAwBbo0B1qMSG8nUABx+Gd+YrbKrQ== + version "0.7.4" + resolved "https://registry.yarnpkg.com/node-watch/-/node-watch-0.7.4.tgz#34557106948cd4b8ddff9aa3d284774004548824" + integrity sha512-RinNxoz4W1cep1b928fuFhvAQ5ag/+1UlMDV7rbyGthBIgsiEouS4kvRayvvboxii4m8eolKOIBo3OjDqbc+uQ== normalize-package-data@^2.3.2, normalize-package-data@^2.5.0: version "2.5.0" - resolved "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== dependencies: hosted-git-info "^2.1.4" @@ -2827,7 +3133,7 @@ normalize-package-data@^2.3.2, normalize-package-data@^2.5.0: normalize-package-data@^3.0.0: version "3.0.3" - resolved "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-3.0.3.tgz#dbcc3e2da59509a0983422884cd172eefdfa525e" integrity sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA== dependencies: hosted-git-info "^4.0.1" @@ -2837,12 +3143,12 @@ normalize-package-data@^3.0.0: normalize-path@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== npm-run-all@^4.1.5: version "4.1.5" - resolved "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz" + resolved "https://registry.yarnpkg.com/npm-run-all/-/npm-run-all-4.1.5.tgz#04476202a15ee0e2e214080861bff12a51d98fba" integrity sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ== dependencies: ansi-styles "^3.2.1" @@ -2857,24 +3163,24 @@ npm-run-all@^4.1.5: npm-run-path@^4.0.1: version "4.0.1" - resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== dependencies: path-key "^3.0.0" -object-inspect@^1.12.2, object-inspect@^1.9.0: +object-inspect@^1.12.3, object-inspect@^1.9.0: version "1.12.3" - resolved "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9" integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g== object-keys@^1.1.1: version "1.1.1" - resolved "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== object.assign@^4.1.4: version "4.1.4" - resolved "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.4.tgz#9673c7c7c351ab8c4d0b516f4343ebf4dfb7799f" integrity sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ== dependencies: call-bind "^1.0.2" @@ -2882,23 +3188,67 @@ object.assign@^4.1.4: has-symbols "^1.0.3" object-keys "^1.1.1" -once@^1.3.0: +once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" - resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== dependencies: wrappy "1" onetime@^5.1.2: version "5.1.2" - resolved "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== dependencies: mimic-fn "^2.1.0" +onnx-proto@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/onnx-proto/-/onnx-proto-4.0.4.tgz#2431a25bee25148e915906dda0687aafe3b9e044" + integrity sha512-aldMOB3HRoo6q/phyB6QRQxSt895HNNw82BNyZ2CMh4bjeKv7g/c+VpAFtJuEMVfYLMbRx61hbuqnKceLeDcDA== + dependencies: + protobufjs "^6.8.8" + +onnxruntime-common@1.15.1: + version "1.15.1" + resolved "https://registry.yarnpkg.com/onnxruntime-common/-/onnxruntime-common-1.15.1.tgz#1b8af102409b5465811a7faef31cf438bded5425" + integrity sha512-Y89eJ8QmaRsPZPWLaX7mfqhj63ny47rSkQe80hIo+lvBQdrdXYR9VO362xvZulk9DFkCnXmGidprvgJ07bKsIQ== + +onnxruntime-common@~1.14.0: + version "1.14.0" + resolved "https://registry.yarnpkg.com/onnxruntime-common/-/onnxruntime-common-1.14.0.tgz#2bb5dac5261269779aa5fb6536ca379657de8bf6" + integrity sha512-3LJpegM2iMNRX2wUmtYfeX/ytfOzNwAWKSq1HbRrKc9+uqG/FsEA0bbKZl1btQeZaXhC26l44NWpNUeXPII7Ew== + +onnxruntime-node@1.14.0: + version "1.14.0" + resolved "https://registry.yarnpkg.com/onnxruntime-node/-/onnxruntime-node-1.14.0.tgz#c4ae6c355cfae7d83abaf36dd39a905c4a010217" + integrity sha512-5ba7TWomIV/9b6NH/1x/8QEeowsb+jBEvFzU6z0T4mNsFwdPqXeFUM7uxC6QeSRkEbWu3qEB0VMjrvzN/0S9+w== + dependencies: + onnxruntime-common "~1.14.0" + +onnxruntime-web@1.14.0: + version "1.14.0" + resolved "https://registry.yarnpkg.com/onnxruntime-web/-/onnxruntime-web-1.14.0.tgz#c8cee538781b1d4c1c6b043934f4a3e6ddf1466e" + integrity sha512-Kcqf43UMfW8mCydVGcX9OMXI2VN17c0p6XvR7IPSZzBf/6lteBzXHvcEVWDPmCKuGombl997HgLqj91F11DzXw== + dependencies: + flatbuffers "^1.12.0" + guid-typescript "^1.0.9" + long "^4.0.0" + onnx-proto "^4.0.4" + onnxruntime-common "~1.14.0" + platform "^1.3.6" + +openai@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/openai/-/openai-3.3.0.tgz#a6408016ad0945738e1febf43f2fccca83a3f532" + integrity sha512-uqxI/Au+aPRnsaQRe8CojU0eCR7I0mBiKjD3sNMzY6DaC1ZVrc85u98mtJW6voDug8fgGN+DIZmTDxTthxb7dQ== + dependencies: + axios "^0.26.0" + form-data "^4.0.0" + openapi-generator-plus@^2.6.0: version "2.6.0" - resolved "https://registry.npmjs.org/openapi-generator-plus/-/openapi-generator-plus-2.6.0.tgz" + resolved "https://registry.yarnpkg.com/openapi-generator-plus/-/openapi-generator-plus-2.6.0.tgz#797d7b25f682b2f764ed2a0e3f49efd7517d62a1" integrity sha512-DRdlJn7goQDDFGw1/9RhU3ibNXm9XMkSTg5cNmoz4d1vvM/CHeI+FzbPcStPgcshs0i0jYUZffmBpNhUEkb27g== dependencies: "@openapi-generator-plus/core" "2.6.0" @@ -2910,40 +3260,40 @@ openapi-generator-plus@^2.6.0: node-watch "^0.7.3" yaml "^2.0.1" -openapi-types@>=7: - version "12.1.3" - resolved "https://registry.npmjs.org/openapi-types/-/openapi-types-12.1.3.tgz" - integrity sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw== - p-limit@^2.2.0: version "2.3.0" - resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== dependencies: p-try "^2.0.0" p-limit@^3.1.0: version "3.1.0" - resolved "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== dependencies: yocto-queue "^0.1.0" p-locate@^4.1.0: version "4.1.0" - resolved "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== dependencies: p-limit "^2.2.0" p-try@^2.0.0: version "2.2.0" - resolved "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== +pako@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/pako/-/pako-2.1.0.tgz#266cc37f98c7d883545d11335c00fbd4062c9a86" + integrity sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug== + param-case@^3.0.4: version "3.0.4" - resolved "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz" + resolved "https://registry.yarnpkg.com/param-case/-/param-case-3.0.4.tgz#7d17fe4aa12bde34d4a77d91acfb6219caad01c5" integrity sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A== dependencies: dot-case "^3.0.4" @@ -2951,25 +3301,15 @@ param-case@^3.0.4: parse-json@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" integrity sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw== dependencies: error-ex "^1.3.1" json-parse-better-errors "^1.0.1" -parse-json@^5.0.0: - version "5.2.0" - resolved "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz" - integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== - dependencies: - "@babel/code-frame" "^7.0.0" - error-ex "^1.3.1" - json-parse-even-better-errors "^2.3.0" - lines-and-columns "^1.1.6" - -parse-json@^5.2.0: +parse-json@^5.0.0, parse-json@^5.2.0: version "5.2.0" - resolved "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== dependencies: "@babel/code-frame" "^7.0.0" @@ -2979,7 +3319,7 @@ parse-json@^5.2.0: pascal-case@^3.1.2: version "3.1.2" - resolved "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz" + resolved "https://registry.yarnpkg.com/pascal-case/-/pascal-case-3.1.2.tgz#b48e0ef2b98e205e7c1dae747d0b1508237660eb" integrity sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g== dependencies: no-case "^3.0.4" @@ -2987,7 +3327,7 @@ pascal-case@^3.1.2: path-case@^3.0.4: version "3.0.4" - resolved "https://registry.npmjs.org/path-case/-/path-case-3.0.4.tgz" + resolved "https://registry.yarnpkg.com/path-case/-/path-case-3.0.4.tgz#9168645334eb942658375c56f80b4c0cb5f82c6f" integrity sha512-qO4qCFjXqVTrcbPt/hQfhTQ+VhFsqNKOPtytgNKkKxSoEp3XPUQ8ObFuePylOIok5gjn69ry8XiULxCwot3Wfg== dependencies: dot-case "^3.0.4" @@ -2995,153 +3335,213 @@ path-case@^3.0.4: path-exists@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== path-is-absolute@^1.0.0: version "1.0.1" - resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== path-key@^2.0.1: version "2.0.1" - resolved "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" integrity sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw== -path-key@^3.0.0: - version "3.1.1" - resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz" - integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== - -path-key@^3.1.0: +path-key@^3.0.0, path-key@^3.1.0: version "3.1.1" - resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== path-parse@^1.0.7: version "1.0.7" - resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== -path-scurry@^1.10.0: - version "1.10.0" - resolved "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.0.tgz" - integrity sha512-tZFEaRQbMLjwrsmidsGJ6wDMv0iazJWk6SfIKnY4Xru8auXgmJkOBa5DUbYFcFD2Rzk2+KDlIiF0GVXNCbgC7g== +path-scurry@^1.10.1: + version "1.10.1" + resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.10.1.tgz#9ba6bf5aa8500fe9fd67df4f0d9483b2b0bfc698" + integrity sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ== dependencies: lru-cache "^9.1.1 || ^10.0.0" - minipass "^5.0.0 || ^6.0.2" + minipass "^5.0.0 || ^6.0.2 || ^7.0.0" path-type@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" integrity sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg== dependencies: pify "^3.0.0" path-type@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== picocolors@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== picomatch@^2.0.4, picomatch@^2.2.3, picomatch@^2.3.1: version "2.3.1" - resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== pidtree@^0.3.0: version "0.3.1" - resolved "https://registry.npmjs.org/pidtree/-/pidtree-0.3.1.tgz" + resolved "https://registry.yarnpkg.com/pidtree/-/pidtree-0.3.1.tgz#ef09ac2cc0533df1f3250ccf2c4d366b0d12114a" integrity sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA== pify@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz" + resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" integrity sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg== pirates@^4.0.4: - version "4.0.5" - resolved "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz" - integrity sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ== + version "4.0.6" + resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.6.tgz#3018ae32ecfcff6c29ba2267cbf21166ac1f36b9" + integrity sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg== pkg-dir@^4.2.0: version "4.2.0" - resolved "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== dependencies: find-up "^4.0.0" +platform@^1.3.6: + version "1.3.6" + resolved "https://registry.yarnpkg.com/platform/-/platform-1.3.6.tgz#48b4ce983164b209c2d45a107adb31f473a6e7a7" + integrity sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg== + plur@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/plur/-/plur-4.0.0.tgz" + resolved "https://registry.yarnpkg.com/plur/-/plur-4.0.0.tgz#729aedb08f452645fe8c58ef115bf16b0a73ef84" integrity sha512-4UGewrYgqDFw9vV6zNV+ADmPAUAfJPKtGvb/VdpQAx25X5f3xXdGdyOEVFwkl8Hl/tl7+xbeHqSEM+D5/TirUg== dependencies: irregular-plurals "^3.2.0" pluralize@^8.0.0: version "8.0.0" - resolved "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz" + resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-8.0.0.tgz#1a6fa16a38d12a1901e0320fa017051c539ce3b1" integrity sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA== +prebuild-install@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-7.1.1.tgz#de97d5b34a70a0c81334fd24641f2a1702352e45" + integrity sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw== + dependencies: + detect-libc "^2.0.0" + expand-template "^2.0.3" + github-from-package "0.0.0" + minimist "^1.2.3" + mkdirp-classic "^0.5.3" + napi-build-utils "^1.0.1" + node-abi "^3.3.0" + pump "^3.0.0" + rc "^1.2.7" + simple-get "^4.0.0" + tar-fs "^2.0.0" + tunnel-agent "^0.6.0" + prettier@2.8.7: version "2.8.7" - resolved "https://registry.npmjs.org/prettier/-/prettier-2.8.7.tgz" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.7.tgz#bb79fc8729308549d28fe3a98fce73d2c0656450" integrity sha512-yPngTo3aXUUmyuTjeTUT75txrf+aMh9FiD7q9ZE/i6r0bPb22g4FsE6Y338PQX1bmfy08i9QQCB7/rcUAVntfw== -pretty-format@^29.0.0, pretty-format@^29.5.0: - version "29.5.0" - resolved "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz" - integrity sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw== +pretty-format@^29.0.0, pretty-format@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.6.3.tgz#d432bb4f1ca6f9463410c3fb25a0ba88e594ace7" + integrity sha512-ZsBgjVhFAj5KeK+nHfF1305/By3lechHQSMWCTl8iHSbfOm2TN5nHEtFc/+W7fAyUeCs2n5iow72gld4gW0xDw== dependencies: - "@jest/schemas" "^29.4.3" + "@jest/schemas" "^29.6.3" ansi-styles "^5.0.0" react-is "^18.0.0" prompts@^2.0.1: version "2.4.2" - resolved "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz" + resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== dependencies: kleur "^3.0.3" sisteransi "^1.0.5" +protobufjs@^6.8.8: + version "6.11.4" + resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-6.11.4.tgz#29a412c38bf70d89e537b6d02d904a6f448173aa" + integrity sha512-5kQWPaJHi1WoCpjTGszzQ32PG2F4+wRY6BmAT4Vfw56Q2FZ4YZzK20xUYQH4YkfehY1e6QSICrJquM6xXZNcrw== + dependencies: + "@protobufjs/aspromise" "^1.1.2" + "@protobufjs/base64" "^1.1.2" + "@protobufjs/codegen" "^2.0.4" + "@protobufjs/eventemitter" "^1.1.0" + "@protobufjs/fetch" "^1.1.0" + "@protobufjs/float" "^1.0.2" + "@protobufjs/inquire" "^1.1.0" + "@protobufjs/path" "^1.1.2" + "@protobufjs/pool" "^1.1.0" + "@protobufjs/utf8" "^1.1.0" + "@types/long" "^4.0.1" + "@types/node" ">=13.7.0" + long "^4.0.0" + +pump@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" + integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + punycode@^2.1.0: version "2.3.0" - resolved "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f" integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA== pure-rand@^6.0.0: version "6.0.2" - resolved "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.2.tgz" + resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-6.0.2.tgz#a9c2ddcae9b68d736a8163036f088a2781c8b306" integrity sha512-6Yg0ekpKICSjPswYOuC5sku/TSWaRYlA0qsXqJgM/d/4pLPHPuTxK7Nbf7jFKzAeedUhR8C7K9Uv63FBsSo8xQ== querystringify@^2.1.1: version "2.2.0" - resolved "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz" + resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6" integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ== queue-microtask@^1.2.2: version "1.2.3" - resolved "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== +queue-tick@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/queue-tick/-/queue-tick-1.0.1.tgz#f6f07ac82c1fd60f82e098b417a80e52f1f4c142" + integrity sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag== + quick-lru@^4.0.1: version "4.0.1" - resolved "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz" + resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-4.0.1.tgz#5b8878f113a58217848c6482026c73e1ba57727f" integrity sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g== +rc@^1.2.7: + version "1.2.8" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" + integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== + dependencies: + deep-extend "^0.6.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~2.0.1" + react-is@^18.0.0: version "18.2.0" - resolved "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== read-pkg-up@^7.0.0, read-pkg-up@^7.0.1: version "7.0.1" - resolved "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507" integrity sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg== dependencies: find-up "^4.1.0" @@ -3150,7 +3550,7 @@ read-pkg-up@^7.0.0, read-pkg-up@^7.0.1: read-pkg@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389" integrity sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA== dependencies: load-json-file "^4.0.0" @@ -3159,7 +3559,7 @@ read-pkg@^3.0.0: read-pkg@^5.2.0: version "5.2.0" - resolved "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc" integrity sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg== dependencies: "@types/normalize-package-data" "^2.4.0" @@ -3167,169 +3567,188 @@ read-pkg@^5.2.0: parse-json "^5.0.0" type-fest "^0.6.0" +readable-stream@^3.1.1, readable-stream@^3.4.0: + version "3.6.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + redent@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz" + resolved "https://registry.yarnpkg.com/redent/-/redent-3.0.0.tgz#e557b7998316bb53c9f1f56fa626352c6963059f" integrity sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg== dependencies: indent-string "^4.0.0" strip-indent "^3.0.0" -regexp.prototype.flags@^1.4.3: - version "1.4.3" - resolved "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz" - integrity sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA== +regexp.prototype.flags@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz#fe7ce25e7e4cca8db37b6634c8a2c7009199b9cb" + integrity sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA== dependencies: call-bind "^1.0.2" - define-properties "^1.1.3" - functions-have-names "^1.2.2" + define-properties "^1.2.0" + functions-have-names "^1.2.3" require-directory@^2.1.1: version "2.1.1" - resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== require-from-string@^2.0.2: version "2.0.2" - resolved "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== requires-port@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== resolve-cwd@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== dependencies: resolve-from "^5.0.0" resolve-from@^5.0.0: version "5.0.0" - resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== resolve.exports@^2.0.0: version "2.0.2" - resolved "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz" + resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-2.0.2.tgz#f8c934b8e6a13f539e38b7098e2e36134f01e800" integrity sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg== resolve@^1.10.0, resolve@^1.20.0: - version "1.22.1" - resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz" - integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== + version "1.22.4" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.4.tgz#1dc40df46554cdaf8948a486a10f6ba1e2026c34" + integrity sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg== dependencies: - is-core-module "^2.9.0" + is-core-module "^2.13.0" path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" reusify@^1.0.4: version "1.0.4" - resolved "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== rimraf@^5.0.0: version "5.0.1" - resolved "https://registry.npmjs.org/rimraf/-/rimraf-5.0.1.tgz" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-5.0.1.tgz#0881323ab94ad45fec7c0221f27ea1a142f3f0d0" integrity sha512-OfFZdwtd3lZ+XZzYP/6gTACubwFcHdLRqS9UX3UwpU2dnGQYkPFISRwvM3w9IiB2w7bW5qGo/uAwE4SmXXSKvg== dependencies: glob "^10.2.5" run-parallel@^1.1.9: version "1.2.0" - resolved "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== dependencies: queue-microtask "^1.2.2" +safe-array-concat@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.0.0.tgz#2064223cba3c08d2ee05148eedbc563cd6d84060" + integrity sha512-9dVEFruWIsnie89yym+xWTAYASdpw3CJV7Li/6zBewGf9z2i1j31rP6jnY0pHEO4QZh6N0K11bFjWmdR8UGdPQ== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.2.0" + has-symbols "^1.0.3" + isarray "^2.0.5" + +safe-buffer@^5.0.1, safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + safe-regex-test@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.0.tgz#793b874d524eb3640d1873aad03596db2d4f2295" integrity sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA== dependencies: call-bind "^1.0.2" get-intrinsic "^1.1.3" is-regex "^1.1.4" -semver@^5.5.0, "semver@2 || 3 || 4 || 5": - version "5.7.1" - resolved "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz" - integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== - -semver@^6.0.0: - version "6.3.0" - resolved "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz" - integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== - -semver@^6.3.0: - version "6.3.0" - resolved "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz" - integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== - -semver@^7.3.4: - version "7.3.8" - resolved "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz" - integrity sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A== - dependencies: - lru-cache "^6.0.0" +"semver@2 || 3 || 4 || 5", semver@^5.5.0: + version "5.7.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" + integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== -semver@^7.3.5: - version "7.5.3" - resolved "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz" - integrity sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ== - dependencies: - lru-cache "^6.0.0" +semver@^6.3.0, semver@^6.3.1: + version "6.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== -semver@^7.5.3: - version "7.5.3" - resolved "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz" - integrity sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ== +semver@^7.3.4, semver@^7.3.5, semver@^7.5.3, semver@^7.5.4: + version "7.5.4" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" + integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== dependencies: lru-cache "^6.0.0" sentence-case@^3.0.4: version "3.0.4" - resolved "https://registry.npmjs.org/sentence-case/-/sentence-case-3.0.4.tgz" + resolved "https://registry.yarnpkg.com/sentence-case/-/sentence-case-3.0.4.tgz#3645a7b8c117c787fde8702056225bb62a45131f" integrity sha512-8LS0JInaQMCRoQ7YUytAo/xUu5W2XnQxV2HI/6uM6U7CITS1RqPElr30V6uIqyMKM9lJGRVFy5/4CuzcixNYSg== dependencies: no-case "^3.0.4" tslib "^2.0.3" upper-case-first "^2.0.2" +sharp@^0.32.0: + version "0.32.5" + resolved "https://registry.yarnpkg.com/sharp/-/sharp-0.32.5.tgz#9ddc78ead6446094f51e50355a2d4ec6e7220cd4" + integrity sha512-0dap3iysgDkNaPOaOL4X/0akdu0ma62GcdC2NBQ+93eqpePdDdr2/LM0sFdDSMmN7yS+odyZtPsb7tx/cYBKnQ== + dependencies: + color "^4.2.3" + detect-libc "^2.0.2" + node-addon-api "^6.1.0" + prebuild-install "^7.1.1" + semver "^7.5.4" + simple-get "^4.0.1" + tar-fs "^3.0.4" + tunnel-agent "^0.6.0" + shebang-command@^1.2.0: version "1.2.0" - resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" integrity sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg== dependencies: shebang-regex "^1.0.0" shebang-command@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== dependencies: shebang-regex "^3.0.0" shebang-regex@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" integrity sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ== shebang-regex@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== shell-quote@^1.6.1: - version "1.8.0" - resolved "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.0.tgz" - integrity sha512-QHsz8GgQIGKlRi24yFc6a6lN69Idnx634w49ay6+jA5yFh7a1UY+4Rp6HPx/L/1zcEDPEij8cIsiqR6bQsE5VQ== + version "1.8.1" + resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.8.1.tgz#6dbf4db75515ad5bac63b4f1894c3a154c766680" + integrity sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA== side-channel@^1.0.4: version "1.0.4" - resolved "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== dependencies: call-bind "^1.0.0" @@ -3338,27 +3757,48 @@ side-channel@^1.0.4: signal-exit@^3.0.3, signal-exit@^3.0.7: version "3.0.7" - resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== signal-exit@^4.0.1: - version "4.0.2" - resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-4.0.2.tgz" - integrity sha512-MY2/qGx4enyjprQnFaZsHib3Yadh3IXyV2C321GY0pjGfVBu4un0uDJkwgdxqO+Rdx8JMT8IfJIRwbYVz3Ob3Q== + version "4.1.0" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" + integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== + +simple-concat@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.1.tgz#f46976082ba35c2263f1c8ab5edfe26c41c9552f" + integrity sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q== + +simple-get@^4.0.0, simple-get@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-4.0.1.tgz#4a39db549287c979d352112fa03fd99fd6bc3543" + integrity sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA== + dependencies: + decompress-response "^6.0.0" + once "^1.3.1" + simple-concat "^1.0.0" + +simple-swizzle@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" + integrity sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg== + dependencies: + is-arrayish "^0.3.1" sisteransi@^1.0.5: version "1.0.5" - resolved "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz" + resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== slash@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== snake-case@^3.0.4: version "3.0.4" - resolved "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz" + resolved "https://registry.yarnpkg.com/snake-case/-/snake-case-3.0.4.tgz#4f2bbd568e9935abdfd593f34c691dadb49c452c" integrity sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg== dependencies: dot-case "^3.0.4" @@ -3366,7 +3806,7 @@ snake-case@^3.0.4: source-map-support@0.5.13: version "0.5.13" - resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932" integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w== dependencies: buffer-from "^1.0.0" @@ -3374,67 +3814,66 @@ source-map-support@0.5.13: source-map@^0.6.0, source-map@^0.6.1: version "0.6.1" - resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== spdx-correct@^3.0.0: - version "3.1.1" - resolved "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz" - integrity sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w== + version "3.2.0" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.2.0.tgz#4f5ab0668f0059e34f9c00dce331784a12de4e9c" + integrity sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA== dependencies: spdx-expression-parse "^3.0.0" spdx-license-ids "^3.0.0" spdx-exceptions@^2.1.0: version "2.3.0" - resolved "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz" + resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz#3f28ce1a77a00372683eade4a433183527a2163d" integrity sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A== spdx-expression-parse@^3.0.0: version "3.0.1" - resolved "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679" integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q== dependencies: spdx-exceptions "^2.1.0" spdx-license-ids "^3.0.0" spdx-license-ids@^3.0.0: - version "3.0.12" - resolved "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.12.tgz" - integrity sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA== + version "3.0.13" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz#7189a474c46f8d47c7b0da4b987bb45e908bd2d5" + integrity sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w== sprintf-js@~1.0.2: version "1.0.3" - resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== stack-utils@^2.0.3: version "2.0.6" - resolved "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz" + resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.6.tgz#aaf0748169c02fc33c8232abccf933f54a1cc34f" integrity sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ== dependencies: escape-string-regexp "^2.0.0" +streamx@^2.15.0: + version "2.15.1" + resolved "https://registry.yarnpkg.com/streamx/-/streamx-2.15.1.tgz#396ad286d8bc3eeef8f5cea3f029e81237c024c6" + integrity sha512-fQMzy2O/Q47rgwErk/eGeLu/roaFWV0jVsogDmrszM9uIw8L5OA+t+V93MgYlufNptfjmYR1tOMWhei/Eh7TQA== + dependencies: + fast-fifo "^1.1.0" + queue-tick "^1.0.1" + string-length@^4.0.1: version "4.0.2" - resolved "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz" + resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" integrity sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ== dependencies: char-regex "^1.0.2" strip-ansi "^6.0.0" -"string-width-cjs@npm:string-width@^4.2.0": - version "4.2.3" - resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" - resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== dependencies: emoji-regex "^8.0.0" @@ -3443,7 +3882,7 @@ string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: string-width@^5.0.1, string-width@^5.1.2: version "5.1.2" - resolved "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== dependencies: eastasianwidth "^0.2.0" @@ -3452,16 +3891,25 @@ string-width@^5.0.1, string-width@^5.1.2: string.prototype.padend@^3.0.0: version "3.1.4" - resolved "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.1.4.tgz" + resolved "https://registry.yarnpkg.com/string.prototype.padend/-/string.prototype.padend-3.1.4.tgz#2c43bb3a89eb54b6750de5942c123d6c98dd65b6" integrity sha512-67otBXoksdjsnXXRUq+KMVTdlVRZ2af422Y0aTyTjVaoQkGr3mxl2Bc5emi7dOQ3OGVVQQskmLEWwFXwommpNw== dependencies: call-bind "^1.0.2" define-properties "^1.1.4" es-abstract "^1.20.4" +string.prototype.trim@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz#a68352740859f6893f14ce3ef1bb3037f7a90533" + integrity sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + string.prototype.trimend@^1.0.6: version "1.0.6" - resolved "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz#c4a27fa026d979d79c04f17397f250a462944533" integrity sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ== dependencies: call-bind "^1.0.2" @@ -3470,85 +3918,90 @@ string.prototype.trimend@^1.0.6: string.prototype.trimstart@^1.0.6: version "1.0.6" - resolved "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz#e90ab66aa8e4007d92ef591bbf3cd422c56bdcf4" integrity sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA== dependencies: call-bind "^1.0.2" define-properties "^1.1.4" es-abstract "^1.20.4" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1": - version "6.0.1" - resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== dependencies: - ansi-regex "^5.0.1" + safe-buffer "~5.2.0" -strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" - resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== dependencies: ansi-regex "^5.0.1" strip-ansi@^7.0.1: version "7.1.0" - resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== dependencies: ansi-regex "^6.0.1" strip-bom@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== strip-bom@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== strip-final-newline@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== strip-indent@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz" + resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-3.0.0.tgz#c32e1cee940b6b3432c771bc2c54bcce73cd3001" integrity sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ== dependencies: min-indent "^1.0.0" strip-json-comments@^3.1.1: version "3.1.1" - resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== +strip-json-comments@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + integrity sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ== + supports-color@^5.3.0: version "5.5.0" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== dependencies: has-flag "^3.0.0" supports-color@^7.0.0, supports-color@^7.1.0: version "7.2.0" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== dependencies: has-flag "^4.0.0" supports-color@^8.0.0: version "8.1.1" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== dependencies: has-flag "^4.0.0" supports-hyperlinks@^2.0.0: version "2.3.0" - resolved "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz" + resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz#3943544347c1ff90b15effb03fc14ae45ec10624" integrity sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA== dependencies: has-flag "^4.0.0" @@ -3556,12 +4009,51 @@ supports-hyperlinks@^2.0.0: supports-preserve-symlinks-flag@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== +tar-fs@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.1.1.tgz#489a15ab85f1f0befabb370b7de4f9eb5cbe8784" + integrity sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng== + dependencies: + chownr "^1.1.1" + mkdirp-classic "^0.5.2" + pump "^3.0.0" + tar-stream "^2.1.4" + +tar-fs@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-3.0.4.tgz#a21dc60a2d5d9f55e0089ccd78124f1d3771dbbf" + integrity sha512-5AFQU8b9qLfZCX9zp2duONhPmZv0hGYiBPJsyUdqMjzq/mqVpy/rEUSeHk1+YitmxugaptgBh5oDGU3VsAJq4w== + dependencies: + mkdirp-classic "^0.5.2" + pump "^3.0.0" + tar-stream "^3.1.5" + +tar-stream@^2.1.4: + version "2.2.0" + resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287" + integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ== + dependencies: + bl "^4.0.3" + end-of-stream "^1.4.1" + fs-constants "^1.0.0" + inherits "^2.0.3" + readable-stream "^3.1.1" + +tar-stream@^3.1.5: + version "3.1.6" + resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-3.1.6.tgz#6520607b55a06f4a2e2e04db360ba7d338cc5bab" + integrity sha512-B/UyjYwPpMBv+PaFSWAmtYjwdrlEaZQEhMIBFNC5oEG8lpiW8XjcSdmEaClj28ArfKScKHs2nshz3k2le6crsg== + dependencies: + b4a "^1.6.4" + fast-fifo "^1.2.0" + streamx "^2.15.0" + test-exclude@^6.0.0: version "6.0.0" - resolved "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz" + resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== dependencies: "@istanbuljs/schema" "^0.1.2" @@ -3570,34 +4062,34 @@ test-exclude@^6.0.0: tmpl@1.0.5: version "1.0.5" - resolved "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz" + resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== to-fast-properties@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== to-regex-range@^5.0.1: version "5.0.1" - resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== dependencies: is-number "^7.0.0" tr46@~0.0.3: version "0.0.3" - resolved "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== trim-newlines@^3.0.0: version "3.0.1" - resolved "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz" + resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-3.0.1.tgz#260a5d962d8b752425b32f3a7db0dcacd176c144" integrity sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw== ts-jest@^29.1.0: version "29.1.1" - resolved "https://registry.npmjs.org/ts-jest/-/ts-jest-29.1.1.tgz" + resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-29.1.1.tgz#f58fe62c63caf7bfcc5cc6472082f79180f0815b" integrity sha512-D6xjnnbP17cC85nliwGiL+tpoKN0StpgE0TeOjXQTU6MVCfsB4v7aW05CgQ/1OywGb0x/oy9hHFnN+sczTiRaA== dependencies: bs-logger "0.x" @@ -3609,9 +4101,9 @@ ts-jest@^29.1.0: semver "^7.5.3" yargs-parser "^21.0.1" -ts-node@^10.9.1, ts-node@>=9.0.0: +ts-node@^10.9.1: version "10.9.1" - resolved "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.1.tgz#e73de9102958af9e1f0b168a6ff320e25adcff4b" integrity sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw== dependencies: "@cspotcode/source-map-support" "^0.8.0" @@ -3630,7 +4122,7 @@ ts-node@^10.9.1, ts-node@>=9.0.0: tsd@^0.28.1: version "0.28.1" - resolved "https://registry.npmjs.org/tsd/-/tsd-0.28.1.tgz" + resolved "https://registry.yarnpkg.com/tsd/-/tsd-0.28.1.tgz#a470bd88a80ff138496c71606072893fe5820e62" integrity sha512-FeYrfJ05QgEMW/qOukNCr4fAJHww4SaKnivAXRv4g5kj4FeLpNV7zH4dorzB9zAfVX4wmA7zWu/wQf7kkcvfbw== dependencies: "@tsd/typescript" "~5.0.2" @@ -3642,57 +4134,94 @@ tsd@^0.28.1: read-pkg-up "^7.0.0" tslib@^2.0.3: - version "2.3.1" - resolved "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz" - integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== + version "2.6.2" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" + integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== + +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + integrity sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w== + dependencies: + safe-buffer "^5.0.1" type-detect@4.0.8: version "4.0.8" - resolved "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== type-fest@^0.18.0: version "0.18.1" - resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.18.1.tgz#db4bc151a4a2cf4eebf9add5db75508db6cc841f" integrity sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw== type-fest@^0.21.3: version "0.21.3" - resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== type-fest@^0.6.0: version "0.6.0" - resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b" integrity sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg== type-fest@^0.8.1: version "0.8.1" - resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== +typed-array-buffer@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz#18de3e7ed7974b0a729d3feecb94338d1472cd60" + integrity sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.2.1" + is-typed-array "^1.1.10" + +typed-array-byte-length@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz#d787a24a995711611fb2b87a4052799517b230d0" + integrity sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA== + dependencies: + call-bind "^1.0.2" + for-each "^0.3.3" + has-proto "^1.0.1" + is-typed-array "^1.1.10" + +typed-array-byte-offset@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz#cbbe89b51fdef9cd6aaf07ad4707340abbc4ea0b" + integrity sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg== + dependencies: + available-typed-arrays "^1.0.5" + call-bind "^1.0.2" + for-each "^0.3.3" + has-proto "^1.0.1" + is-typed-array "^1.1.10" + typed-array-length@^1.0.4: version "1.0.4" - resolved "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz" + resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.4.tgz#89d83785e5c4098bec72e08b319651f0eac9c1bb" integrity sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng== dependencies: call-bind "^1.0.2" for-each "^0.3.3" is-typed-array "^1.1.9" -typescript@^5.0.4, typescript@>=2.7, "typescript@>=4.3 <6": - version "5.1.6" - resolved "https://registry.npmjs.org/typescript/-/typescript-5.1.6.tgz" - integrity sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA== +typescript@^5.0.4: + version "5.2.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.2.2.tgz#5ebb5e5a5b75f085f22bc3f8460fba308310fa78" + integrity sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w== uglify-js@^3.1.4: version "3.17.4" - resolved "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.17.4.tgz#61678cf5fa3f5b7eb789bb345df29afb8257c22c" integrity sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g== unbox-primitive@^1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz" + resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e" integrity sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw== dependencies: call-bind "^1.0.2" @@ -3700,51 +4229,56 @@ unbox-primitive@^1.0.2: has-symbols "^1.0.3" which-boxed-primitive "^1.0.2" -update-browserslist-db@^1.0.10: - version "1.0.10" - resolved "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz" - integrity sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ== +update-browserslist-db@^1.0.11: + version "1.0.11" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz#9a2a641ad2907ae7b3616506f4b977851db5b940" + integrity sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA== dependencies: escalade "^3.1.1" picocolors "^1.0.0" upper-case-first@^2.0.2: version "2.0.2" - resolved "https://registry.npmjs.org/upper-case-first/-/upper-case-first-2.0.2.tgz" + resolved "https://registry.yarnpkg.com/upper-case-first/-/upper-case-first-2.0.2.tgz#992c3273f882abd19d1e02894cc147117f844324" integrity sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg== dependencies: tslib "^2.0.3" upper-case@^2.0.2: version "2.0.2" - resolved "https://registry.npmjs.org/upper-case/-/upper-case-2.0.2.tgz" + resolved "https://registry.yarnpkg.com/upper-case/-/upper-case-2.0.2.tgz#d89810823faab1df1549b7d97a76f8662bae6f7a" integrity sha512-KgdgDGJt2TpuwBUIjgG6lzw2GWFRCW9Qkfkiv0DxqHHLYJHmtmdUIKcZd8rHgFSjopVTlw6ggzCm1b8MFQwikg== dependencies: tslib "^2.0.3" uri-js@^4.2.2: version "4.4.1" - resolved "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== dependencies: punycode "^2.1.0" url-parse@^1.5.10: version "1.5.10" - resolved "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.10.tgz#9d3c2f736c1d75dd3bd2be507dcc111f1e2ea9c1" integrity sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ== dependencies: querystringify "^2.1.1" requires-port "^1.0.0" +util-deprecate@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== + v8-compile-cache-lib@^3.0.1: version "3.0.1" - resolved "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz" + resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== v8-to-istanbul@^9.0.1: version "9.1.0" - resolved "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz" + resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz#1b83ed4e397f58c85c266a570fc2558b5feb9265" integrity sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA== dependencies: "@jridgewell/trace-mapping" "^0.3.12" @@ -3753,7 +4287,7 @@ v8-to-istanbul@^9.0.1: validate-npm-package-license@^3.0.1: version "3.0.4" - resolved "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz" + resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== dependencies: spdx-correct "^3.0.0" @@ -3761,24 +4295,24 @@ validate-npm-package-license@^3.0.1: walker@^1.0.8: version "1.0.8" - resolved "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz" + resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== dependencies: makeerror "1.0.12" webidl-conversions@^3.0.0: version "3.0.1" - resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== whatwg-fetch@^3.4.1: - version "3.6.2" - resolved "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz" - integrity sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA== + version "3.6.18" + resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.6.18.tgz#2f640cdee315abced7daeaed2309abd1e44e62d4" + integrity sha512-ltN7j66EneWn5TFDO4L9inYC1D+Czsxlrw2SalgjMmEMkLfA5SIZxEFdE6QtHFiiM6Q7WL32c7AkI3w6yxM84Q== whatwg-url@^5.0.0: version "5.0.0" - resolved "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== dependencies: tr46 "~0.0.3" @@ -3786,7 +4320,7 @@ whatwg-url@^5.0.0: which-boxed-primitive@^1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz" + resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== dependencies: is-bigint "^1.0.1" @@ -3795,49 +4329,39 @@ which-boxed-primitive@^1.0.2: is-string "^1.0.5" is-symbol "^1.0.3" -which-typed-array@^1.1.9: - version "1.1.9" - resolved "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz" - integrity sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA== +which-typed-array@^1.1.10, which-typed-array@^1.1.11: + version "1.1.11" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.11.tgz#99d691f23c72aab6768680805a271b69761ed61a" + integrity sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew== dependencies: available-typed-arrays "^1.0.5" call-bind "^1.0.2" for-each "^0.3.3" gopd "^1.0.1" has-tostringtag "^1.0.0" - is-typed-array "^1.1.10" which@^1.2.9: version "1.3.1" - resolved "https://registry.npmjs.org/which/-/which-1.3.1.tgz" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== dependencies: isexe "^2.0.0" which@^2.0.1: version "2.0.2" - resolved "https://registry.npmjs.org/which/-/which-2.0.2.tgz" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== dependencies: isexe "^2.0.0" wordwrap@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q== -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: version "7.0.0" - resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== dependencies: ansi-styles "^4.0.0" @@ -3846,7 +4370,7 @@ wrap-ansi@^7.0.0: wrap-ansi@^8.1.0: version "8.1.0" - resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== dependencies: ansi-styles "^6.1.0" @@ -3855,12 +4379,12 @@ wrap-ansi@^8.1.0: wrappy@1: version "1.0.2" - resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== write-file-atomic@^4.0.2: version "4.0.2" - resolved "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-4.0.2.tgz#a9df01ae5b77858a027fd2e80768ee433555fcfd" integrity sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg== dependencies: imurmurhash "^0.1.4" @@ -3868,42 +4392,37 @@ write-file-atomic@^4.0.2: y18n@^5.0.5: version "5.0.8" - resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== yallist@^3.0.2: version "3.1.1" - resolved "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== yallist@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== yaml@^2.0.1: - version "2.3.1" - resolved "https://registry.npmjs.org/yaml/-/yaml-2.3.1.tgz" - integrity sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ== + version "2.3.2" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.2.tgz#f522db4313c671a0ca963a75670f1c12ea909144" + integrity sha512-N/lyzTPaJasoDmfV7YTrYCI0G/3ivm/9wdG0aHuheKowWQwGTsK0Eoiw6utmzAnI6pkJa0DUVygvp3spqqEKXg== yargs-parser@^20.2.3: version "20.2.9" - resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== -yargs-parser@^21.0.1: - version "21.1.1" - resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz" - integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== - -yargs-parser@^21.1.1: +yargs-parser@^21.0.1, yargs-parser@^21.1.1: version "21.1.1" - resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== yargs@^17.3.1: version "17.7.2" - resolved "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== dependencies: cliui "^8.0.1" @@ -3916,10 +4435,10 @@ yargs@^17.3.1: yn@3.1.1: version "3.1.1" - resolved "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz" + resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== yocto-queue@^0.1.0: version "0.1.0" - resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== diff --git a/clients/python/pyproject.toml b/clients/python/pyproject.toml index 73623598f106..3afff14f4bec 100644 --- a/clients/python/pyproject.toml +++ b/clients/python/pyproject.toml @@ -16,7 +16,7 @@ classifiers = [ ] dependencies = [ 'requests >= 2.28', - 'pydantic >= 1.9', + 'pydantic>=1.9,<2.0', 'numpy >= 1.21.6', 'posthog >= 2.4.0', 'typing_extensions >= 4.5.0', diff --git a/docker-compose.cluster.yml b/docker-compose.cluster.yml new file mode 100644 index 000000000000..d36ed16906f8 --- /dev/null +++ b/docker-compose.cluster.yml @@ -0,0 +1,66 @@ +# This docker compose file is not meant to be used. It is a work in progress +# for the distributed version of Chroma. It is not yet functional. + +version: '3.9' + +networks: + net: + driver: bridge + +services: + server: + image: server + build: + context: . + dockerfile: Dockerfile + volumes: + - ./:/chroma + - index_data:/index_data + command: uvicorn chromadb.app:app --reload --workers 1 --host 0.0.0.0 --port 8000 --log-config log_config.yml + environment: + - IS_PERSISTENT=TRUE + - CHROMA_PRODUCER_IMPL=chromadb.ingest.impl.pulsar.PulsarProducer + - CHROMA_CONSUMER_IMPL=chromadb.ingest.impl.pulsar.PulsarConsumer + - PULSAR_BROKER_URL=pulsar + - PULSAR_BROKER_PORT=6650 + - PULSAR_ADMIN_PORT=8080 + ports: + - 8000:8000 + depends_on: + pulsar: + condition: service_healthy + networks: + - net + + pulsar: + image: apachepulsar/pulsar + volumes: + - pulsardata:/pulsar/data + - pulsarconf:/pulsar/conf + command: bin/pulsar standalone + ports: + - 6650:6650 + - 8080:8080 + networks: + - net + healthcheck: + test: + [ + "CMD", + "curl", + "-f", + "localhost:8080/admin/v2/brokers/health" + ] + interval: 3s + timeout: 1m + retries: 10 + +volumes: + index_data: + driver: local + backups: + driver: local + pulsardata: + driver: local + pulsarconf: + driver: local diff --git a/docker-compose.server.example.yml b/docker-compose.server.example.yml index 5c575fe0eadd..2c8228fad06f 100644 --- a/docker-compose.server.example.yml +++ b/docker-compose.server.example.yml @@ -7,14 +7,16 @@ services: server: image: ghcr.io/chroma-core/chroma:latest volumes: - - index_data:/chroma/.chroma/index + # Default configuration for persist_directory in chromadb/config.py + # Currently it's located in "/chroma/chroma/" + - chroma_persistent_folder:/chroma/chroma/ ports: - 8000:8000 networks: - net volumes: - index_data: - driver: local backups: driver: local + chroma_persistent_folder: + driver: local diff --git a/docker-compose.test-auth.yml b/docker-compose.test-auth.yml new file mode 100644 index 000000000000..c66cfc8202bb --- /dev/null +++ b/docker-compose.test-auth.yml @@ -0,0 +1,34 @@ +version: '3.9' + +networks: + test_net: + driver: bridge + +services: + test_server: + build: + context: . + dockerfile: Dockerfile + volumes: + - ./:/chroma + - test_index_data:/index_data + command: uvicorn chromadb.app:app --workers 1 --host 0.0.0.0 --port 8000 --log-config chromadb/log_config.yml + environment: + - ANONYMIZED_TELEMETRY=False + - ALLOW_RESET=True + - IS_PERSISTENT=TRUE + - CHROMA_SERVER_AUTH_CREDENTIALS_FILE=${CHROMA_SERVER_AUTH_CREDENTIALS_FILE} + - CHROMA_SERVER_AUTH_CREDENTIALS=${CHROMA_SERVER_AUTH_CREDENTIALS} + - CHROMA_SERVER_AUTH_CREDENTIALS_PROVIDER=${CHROMA_SERVER_AUTH_CREDENTIALS_PROVIDER} + - CHROMA_SERVER_AUTH_PROVIDER=${CHROMA_SERVER_AUTH_PROVIDER} + - CHROMA_SERVER_AUTH_TOKEN_TRANSPORT_HEADER=${CHROMA_SERVER_AUTH_TOKEN_TRANSPORT_HEADER} + ports: + - ${CHROMA_PORT}:8000 + networks: + - test_net + +volumes: + test_index_data: + driver: local + test_backups: + driver: local diff --git a/docker-compose.test.yml b/docker-compose.test.yml index eb65303ebd6a..514047257303 100644 --- a/docker-compose.test.yml +++ b/docker-compose.test.yml @@ -12,7 +12,7 @@ services: volumes: - ./:/chroma - test_index_data:/index_data - command: uvicorn chromadb.app:app --workers 1 --host 0.0.0.0 --port 8000 --log-config log_config.yml + command: uvicorn chromadb.app:app --workers 1 --host 0.0.0.0 --port 8000 --log-config chromadb/log_config.yml environment: - ANONYMIZED_TELEMETRY=False - ALLOW_RESET=True diff --git a/docker-compose.yml b/docker-compose.yml index 5f298f1e741e..93581dd23c7b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -12,17 +12,21 @@ services: dockerfile: Dockerfile volumes: - ./:/chroma - - index_data:/index_data - command: uvicorn chromadb.app:app --reload --workers 1 --host 0.0.0.0 --port 8000 --log-config log_config.yml + # Be aware that indexed data are located in "/chroma/chroma/" + # Default configuration for persist_directory in chromadb/config.py + command: uvicorn chromadb.app:app --reload --workers 1 --host 0.0.0.0 --port 8000 --log-config chromadb/log_config.yml environment: - IS_PERSISTENT=TRUE + - CHROMA_SERVER_AUTH_PROVIDER=${CHROMA_SERVER_AUTH_PROVIDER} + - CHROMA_SERVER_AUTH_CREDENTIALS_FILE=${CHROMA_SERVER_AUTH_CREDENTIALS_FILE} + - CHROMA_SERVER_AUTH_CREDENTIALS=${CHROMA_SERVER_AUTH_CREDENTIALS} + - CHROMA_SERVER_AUTH_CREDENTIALS_PROVIDER=${CHROMA_SERVER_AUTH_CREDENTIALS_PROVIDER} + - PERSIST_DIRECTORY=${PERSIST_DIRECTORY:-/chroma/chroma} ports: - 8000:8000 networks: - net volumes: - index_data: - driver: local backups: driver: local diff --git a/docs/CIP_2_Auth_Providers_Proposal.md b/docs/CIP_2_Auth_Providers_Proposal.md new file mode 100644 index 000000000000..95df2d9b6c38 --- /dev/null +++ b/docs/CIP_2_Auth_Providers_Proposal.md @@ -0,0 +1,190 @@ +# CIP-2: Auth Providers Proposal + +## Status + +Current Status: `Accepted` + +## **Motivation** + +Currently, Chroma does not provide any authentication mechanism. This CIP proposes to +to add authentication abstractions and basic authentication mechanisms to Chroma. + +There are intrinsic and extrinsic motivations for this CIP. The intrinsic motivation +is to provide a secure way to access Chroma as adoption grows and the team is gearing up to release a cloud offering. +The extrinsic motivation is driven by the community which is deploying Chroma in both public and private clouds and +in test and production environments. The community has expressed the need for authentication and authorization. + +> Observation: We consider the Auth to be applicable to client-server mode. + +## **Public Interfaces** + +Changes to the public interface are related to the `Settings` class where we introduce new optional attributes to +control server and client-side auth providers. + +## **Proposed Changes** + +We propose two abstraction groups, one for the server-side and another for the client-side. In +addition we also introduce a FastAPI/startlette middleware adapter which will allow using the server-side abstractions +in the context of FastAPI. For client-side we rely on `requests` + +### Architecture Overview + +Architecture Overview: + +![cip-2-arch.png](assets/cip-2-arch.png) + +Request Sequence: + +![cip-2-seq.png](assets/cip-2-seq.png) + +### Constraints + +This section provides teh architectural constraints for the authentication framework. The constraints are set of +restrictions we impose to make the design simpler and more robust. + +- There must be at most one active client-side auth provider +- There must be at most one active client-side credentials provider +- There must be at most one active server-side auth provider +- There must be at most one active server-side auth configuration provider +- There must be at most one active server-side auth credentials provider + +### Core Concepts + +- Auth Provider - an abstraction that provides authentication functionality for either client or server-side. The + provider is responsible for validating client credentials using (if available) configuration and credentials + providers. The auth provider is also responsible for carrying the Chroma-leg of any authentication flow. +- Auth Configuration Provider - an abstraction that provides configuration for auth providers. The configuration can be + loaded from a file, env vars or programmatically. The configuration is used for validating and/or accessing user + credentials. Examples: secret key for JWT token based auth, DB URL for DB based auth, etc. Depending on sensitivity of + the information stored in the configuration, the provider should implement the necessary interfaces to access such + information in a secure way. +- Auth Credentials Provider - an abstraction that provides credentials for auth providers. The credentials can be + loaded from a file, env vars or programmatically. The credentials are used for validating client-side credentials (for + sever-side auth) and retrieving or generating client-side credentials (for client-side auth). + +#### Abstractions + +##### Server-Side + +We suggest multiple abstractions on the server-side to allow for easy integration with different auth providers. +We suggest the following abstractions: + +> Note: All abstractions are defined under `chromadb.auth` package + +- `ServerAuthProvider` - this is the base server auth provider abstraction that allows any server implementation of + Chroma to support variety of auth providers. The main responsibility of the auth provider is to orchestrate the auth + flow by gluing together the auth configuration and credentials providers. +- `ChromaAuthMiddleware` - The auth middleware is effectively an adapter responsible for providing server specific + implementation of the auth middleware. This includes three general types of operations - forwarding authentication to + the auth provider, instrumenting the server if needed to support a specific auth flow, ignore certain + actions/operations (e.g. in REST this would be verb+path) that should not be authenticated. +- `ServerAuthenticationRequest` - An abstraction for querying for authentication data from server specific + implementation. +- `ServerAuthenticationResponse` - An abstraction for returning authentication data to server specific implementation. +- `ServerAuthConfigurationProvider` - this is the base abstraction for auth configuration providers. The provider is + responsible for loading auth configuration from a file, env vars or programmatically. +- `AbstractCredentials` - base abstraction for credentials encapsulation from server to Auth Credentials Provider. +- `ServerAuthCredentialsProvider` - this is the base abstraction for auth credentials providers. The provider is + responsible for verifying client credentials. + +##### Client-Side + +We suggest multiple abstractions on the client-side to allow for easy integration with different auth providers. + +- `ClientAuthProvider` - this is the base client auth provider abstraction that allows any client implementation of + Chroma to support variety of auth providers. The main responsibility of the auth provider is to orchestrate the auth + flow by gluing together the auth configuration and credentials providers, and any possible auth workflows (e.g. OAuth) +- `ClientAuthConfigurationProvider` - this is the base abstraction for auth configuration providers. The provider is + responsible for loading auth configuration from a file, env vars or programmatically. +- `ClientAuthCredentialsProvider` - this is the base abstraction for auth credentials providers. The provider is + responsible for verifying client credentials. +- `AbstractCredentials` - base abstraction for credentials encapsulation from client to Auth Credentials Provider. +- `ClientAuthProtocolAdapter` - this is an abstraction that allows for client-side auth providers to communicate with + backends using variety of protocols and libraries (e.g. `requests`, `gRPC` etc). The adapter is responsible for + translating the auth requests to generated by the credentials provider to a protocol specific message. + +#### Workflows + +##### Server-Side + +![cip-2-server-side-wf.png](assets/cip-2-server-side-wf.png) + +##### Client-Side + +![cip-2-client-side-wf.png](assets/cip-2-client-side-wf.png) + +### Configuration + +#### Server-side + +TBD + +#### Client-side + + + +### Reasoning + +- Server-side abstraction - it is very useful as the intention is to support a variety of auth providers. +- Client-side abstraction - similar reasoning but from client's perspective. It will allow for both standard and + non-standard auth provider plugins to be added without further impacting the client side +- Backend (fastAPI) adapter - this is a backend-specific way of loading server-side auth provider plugins. It will also + serve as a template/blueprint when it comes to introducing the auth plugins to another backend framework (e.g. Flask) + +We also propose that each auth provider on either side must be configurable via three main methods depending on +developer preference: + +- File-base - a configuration file that provides the requisite config and credentials (recommended for production) +- Env - configuration through environment variables (this can also apply for the file-based config, which can be + specified in env var) +- Programmatically - provide requisite configuration through CLI or directly in code (it is left for the developer to + decide how such configuration is loaded and made available to the auth provider) - this is possibly the least secure + and should be used for testing + +The intention is to start with two minimal but useful Auth providers: + +- Basic Auth - base64 encoded user and password credentials. The credentials will be static in nature and defined via + auth provider config +- Token - A simple static token implementation + +Both of the above providers will rely on the `Authorization` header to achieve their functionality. + +> Both initial providers are there to help introduce a bear minimum security but are not recommended for production use + +Further work: + +- Introduction of JWT and mTLS auth providers +- API Keys +- Chroma managed user store - this would be similar to what standard DBMS’ are doing today - maintain a table with users + and salted password hashes +- K8s RBAC integration (for cloud-native deployments) +- GCP service accounts? +- SPIFFE and SPIRE integrations +- Go and Java client-side auth providers (for other impl like Rust and Ruby, we need to discuss with respective + maintainers) + +> Note: this CIP intentionally does not tackle authZ but acknowledges that authN and authZ must work in tandem in future +> releases + +## **Compatibility, Deprecation, and Migration Plan** + +This change, introducing a pluggable auth framework is no impacting compatibility of existing deployments and users can +upgrade and use the new framework without the need for migration. + +No deprecations. + +## **Test Plan** + +We will introduce a new set of tests to verify both client and server-side auth providers. + +## **Rejected Alternatives** + +We have considered direct middleware Auth or existing third-party libraries for FastAPI integration with auth providers, +but that will create a dependency for Chroma on FastAPI itself. + +We have also considered using OAuth 2.0 or OIDC however the challenge there is that both of these protocols are +generally intended for User (human) auth whereas in our case we have a system-to-system auth. That said there still +might be room for either of these protocols, but further more in-depth use case analysis is required. + +Relying entirely on external providers, while this is possible not providing out-of-the-box integrated auth capabilities +is a non-starter for many enterprise customers. diff --git a/docs/CIP_4_In_Nin_Metadata_Filters.md b/docs/CIP_4_In_Nin_Metadata_Filters.md new file mode 100644 index 000000000000..e9a0911e69e6 --- /dev/null +++ b/docs/CIP_4_In_Nin_Metadata_Filters.md @@ -0,0 +1,61 @@ +# CIP-4: In and Not In Metadata Filters Proposal + +## Status + +Current Status: `Under Discussion` + +## **Motivation** + +Currently, Chroma does not provide a way to filter metadata through `in` and `not in`. This appears to be a frequent ask +from community members. + +## **Public Interfaces** + +The changes will affect the following public interfaces: + +- `Where` and `OperatorExpression` + classes - https://github.com/chroma-core/chroma/blob/48700dd07f14bcfd8b206dc3b2e2795d5531094d/chromadb/types.py#L125-L129 +- `collection.get()` +- `collection.query()` + +## **Proposed Changes** + +We suggest the introduction of two new operators `$in` and `$nin` that will be used to filter metadata. We call these +operators `InclusionExclusionOperator`. + +We suggest the following new operator definition: + +```python +InclusionExclusionOperator = Union[Literal["$in"], Literal["$nin"]] +``` + +Additionally, we suggest that those operators are added to `OperatorExpression` for seamless integration with +existing `Where` semantics: + +```python +OperatorExpression = Union[ + Dict[Union[WhereOperator, LogicalOperator], LiteralValue], + Dict[InclusionExclusionOperator, List[LiteralValue]], +] +``` + +An example of a query using the new operators would be: + +```python +collection.query(query_texts=query, + where={"$and": [{"author": {'$in': ['john', 'jill']}}, {"article_type": {"$eq": "blog"}}]}, + n_results=3) +``` + +## **Compatibility, Deprecation, and Migration Plan** + +The change is compatible with existing release 0.4.x. + +## **Test Plan** + +Property tests will be updated to ensure boundary conditions are covered as well as interoperability with existing `Where` +operators. + +## **Rejected Alternatives** + +N/A diff --git a/docs/CIP_5_Large_Batch_Handling_Improvements.md b/docs/CIP_5_Large_Batch_Handling_Improvements.md new file mode 100644 index 000000000000..9b03d080f0f8 --- /dev/null +++ b/docs/CIP_5_Large_Batch_Handling_Improvements.md @@ -0,0 +1,59 @@ +# CIP-5: Large Batch Handling Improvements Proposal + +## Status + +Current Status: `Under Discussion` + +## **Motivation** + +As users start putting Chroma in its paces and storing ever-increasing datasets, we must ensure that errors +related to significant and potentially expensive batches are handled gracefully. This CIP proposes to add a new +setting, `max_batch_size` API, on the local segment API and use it to split large batches into smaller ones. + +## **Public Interfaces** + +The following interfaces are impacted: + +- New Server API endpoint - `/pre-flight-checks` +- New `max_batch_size` property on the `API` interface +- Updated `_add`, `_update` and `_upsert` methods on `chromadb.api.segment.SegmentAPI` +- Updated `_add`, `_update` and `_upsert` methods on `chromadb.api.fastapi.FastAPI` +- New utility library `batch_utils.py` +- New exception raised when batch size exceeds `max_batch_size` + +## **Proposed Changes** + +We propose the following changes: + +- The new `max_batch_size` property is now available in the `API` interface. The property relies on the + underlying `Producer` class + to fetch the actual value. The property will be implemented by both `chromadb.api.segment.SegmentAPI` + and `chromadb.api.fastapi.FastAPI` +- `chromadb.api.segment.SegmentAPI` will implement the `max_batch_size` property by fetching the value from the + `Producer` class. +- `chromadb.api.fastapi.FastAPI` will implement the `max_batch_size` by fetching it from a new `/pre-flight-checks` + endpoint on the Server. +- New `/pre-flight-checks` endpoint on the Server will return a dictionary with pre-flight checks the client must + fulfil to integrate with the server side. For now, we propose using this only for `max_batch_size`, but we can + add more checks in the future. The pre-flight checks will be only fetched once per client and cached for the duration + of the client's lifetime. +- Updated `_add`, `_update` and `_upsert` method on `chromadb.api.segment.SegmentAPI` to validate batch size. +- Updated `_add`, `_update` and `_upsert` method on `chromadb.api.fastapi.FastAPI` to validate batch size (client-side + validation) +- New utility library `batch_utils.py` will contain the logic for splitting batches into smaller ones. + +## **Compatibility, Deprecation, and Migration Plan** + +The change will be fully compatible with existing implementations. The changes will be transparent to the user. + +## **Test Plan** + +New tests: + +- Batch splitting tests for `chromadb.api.segment.SegmentAPI` +- Batch splitting tests for `chromadb.api.fastapi.FastAPI` +- Tests for `/pre-flight-checks` endpoint + +## **Rejected Alternatives** + +N/A diff --git a/docs/assets/cip-2-arch.png b/docs/assets/cip-2-arch.png new file mode 100644 index 000000000000..68f30ac6c5cd Binary files /dev/null and b/docs/assets/cip-2-arch.png differ diff --git a/docs/assets/cip-2-client-side-wf.png b/docs/assets/cip-2-client-side-wf.png new file mode 100644 index 000000000000..82d49898f880 Binary files /dev/null and b/docs/assets/cip-2-client-side-wf.png differ diff --git a/docs/assets/cip-2-seq.png b/docs/assets/cip-2-seq.png new file mode 100644 index 000000000000..a42dc8ec7c45 Binary files /dev/null and b/docs/assets/cip-2-seq.png differ diff --git a/docs/assets/cip-2-server-side-wf.png b/docs/assets/cip-2-server-side-wf.png new file mode 100644 index 000000000000..a4acb6d8893a Binary files /dev/null and b/docs/assets/cip-2-server-side-wf.png differ diff --git a/docs/cip/CIP-1_Allow_Filtering_for_Collections.md b/docs/cip/CIP-1_Allow_Filtering_for_Collections.md new file mode 100644 index 000000000000..6671390fc909 --- /dev/null +++ b/docs/cip/CIP-1_Allow_Filtering_for_Collections.md @@ -0,0 +1,54 @@ +# CIP-1 Allow Filtering for Collections + +## Status + +Current Status: Under Discussion + +## Motivation + +Currently operations on getting collections does not yet support filtering based on its +metadata, as a result, users have to perform filtering after getting the collection. +This is inconvenient to the users as they have to perform the filtering in the +application and inefficient as extra bandwidth are consumed when transferring data +between client and server. + +We should allow for getting a collection based on a filtering of its metadata. For +example, users could handle cases like wanting to get all collections belonging to a +specific id or a specific collection metadata field value. + +## Public Interfaces + +The public facing change is on the `list_collection` API. Specifically, we would like to +change the following API to add an optional `where` parameter in the API class. + +```python +def list_collections(self) -> Sequence[Collection]: # original +def list_collections(self, where: Optional[Where] = {}) # after the change +``` + +## Proposed Changes + +The proposed changes are mentioned in the public interfaces. + +## Compatibility, Deprecation, and Migration Plan + +This change is backward compatible. + +## Test Plan + +We plan to modify unit tests to accommodate the change and use system tests to verify +this API change is backward compatible. + +## Rejected Alternatives + +- An alternative solution would be adding new APIs similar to + +```python +def get_collection( +self, +name: str, +embedding_function: Optional[EmbeddingFunction] = ef.DefaultEmbeddingFunction(), +) -> Collection: +``` + +We decided to not go with it to reduce the user's burden to learn new APIs. diff --git a/examples/basic_functionality/assets/auh-sequence.png b/examples/basic_functionality/assets/auh-sequence.png new file mode 100644 index 000000000000..d674328f6882 Binary files /dev/null and b/examples/basic_functionality/assets/auh-sequence.png differ diff --git a/examples/basic_functionality/assets/auth-architecture.png b/examples/basic_functionality/assets/auth-architecture.png new file mode 100644 index 000000000000..33d049acdd36 Binary files /dev/null and b/examples/basic_functionality/assets/auth-architecture.png differ diff --git a/examples/basic_functionality/client_auth.ipynb b/examples/basic_functionality/client_auth.ipynb new file mode 100644 index 000000000000..b856a9f95821 --- /dev/null +++ b/examples/basic_functionality/client_auth.ipynb @@ -0,0 +1,394 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "source": [ + "# Chroma Authentication\n", + "\n", + "This tutorial aims to explain how authentication can be setup in Chroma.\n", + "\n", + "> **Important**: The concept of authentication is only applicable to Client/Server deployments. If you are using Chroma in a standalone mode, authentication is not applicable.\n", + "\n", + "## Concepts\n", + "\n", + "### Architecture Overview\n", + "\n", + "![Authentication Architecture](assets/auth-architecture.png \"Authentication Architecture\")\n", + "\n", + "### Authentication Flow (Sequence)\n", + "\n", + "The authentication sequence is applied for every request. It is important to understand that credential computation or retrieval (e.g. from external auth providers) is only done once for the first authenticated request. Subsequent requests will use the same credentials.\n", + "\n", + "The authentication flow is as follows:\n", + "\n", + "![Authentication Flow](assets/auh-sequence.png \"Authentication Flow\")\n", + "\n", + "### Preemptive Authentication\n", + "\n", + "In its current release the authentication in Chroma works in a preemptive mode. This means that the client is responsible for sending the authentication information on every request. The server will not challenge the client for authentication.\n", + "\n", + "> **Warning**: There are security risks involved with preemptive authentication in that the client might unintentionally send credentials to malicious or unintended server. When deploying authentication users are encouraged to use HTTPS (always verify server certs), to use secure providers (e.g. JWT) \n", + "> and apply good security practices.\n", + "\n", + "### Authentication Provider\n", + "\n", + "Authentication in Chroma is handled by Authentication Providers. Providers are pluggable modules that allow Chroma to abstract the authentication mechanism from the rest of the system.\n", + "\n", + "Chroma ships with the following build-in providers:\n", + "- Basic Authentication\n", + "- JWT Authentication (work in progress)\n", + "\n", + "### Client-side Authentication\n", + "\n", + "Client-side authentication refers to the process of preparing and communicating credentials information on the client-side and sending that information the Chroma server.\n", + "\n", + "### Server-side Authentication\n", + "\n", + "Server-side authentication refers to the process of validating the credentials information received from the client and authenticating the client.\n" + ], + "metadata": { + "collapsed": false + }, + "id": "eae631e46b4c1115" + }, + { + "cell_type": "markdown", + "source": [ + "## Configuration\n", + "\n", + "### Server Configuration\n", + "\n", + "In order for the server to provide auth it needs several pieces of information and depending on the authentication provider you may or may not need to provide all of them.\n", + "\n", + "- `CHROMA_SERVER_AUTH_PROVIDER` - It indicates the authentication provider class to use. In this case we are using the `chromadb.auth.basic.BasicAuthServerProvider` class (it is also possible to use `basic` as a shorthand).\n", + "- `CHROMA_SERVER_AUTH_CREDENTIALS_PROVIDER` - The credentials provider is a way for the server to validate the provided auth information from the client. You can use `chromadb.auth.providers.HtpasswdFileServerAuthCredentialsProvider` to validate against a file in htpasswd format (user:password) - single line with bcrypt hash for password. Alternatively you can use a shorthand to load providers (e.g. `htpasswd_file` for `chromadb.auth.providers.HtpasswdFileServerAuthCredentialsProvider`).\n", + "- `CHROMA_SERVER_AUTH_CREDENTIALS_FILE` - The path to the credentials file in case the credentials provider requires it. In this case we are using the `chromadb.auth.providers.HtpasswdFileServerAuthCredentialsProvider` provider which requires a file path.\n", + "\n", + "\n", + "### Client Configuration\n", + "\n", + "Similarly on the client side we need to provide the following configuration parameters:\n", + "\n", + "- `CHROMA_CLIENT_AUTH_PROVIDER` - It indicates the authentication provider class to use. In this case we are using the `chromadb.auth.basic.BasicAuthClientProvider` class or `basic` shorthand.\n", + "- `CHROMA_CLIENT_AUTH_CREDENTIALS` - The auth credentials to be passed to the provider. In this case we are using the `admin:admin` credentials as we'll be using Basic Auth.\n" + ], + "metadata": { + "collapsed": false + }, + "id": "87d45f79aed65e21" + }, + { + "cell_type": "markdown", + "source": [ + "## Setting Up\n", + "\n", + "### Before You Begin\n", + "\n", + "Make sure you have either `chromadb` or `chromadb-client` installed. You can do that by running the following command:\n", + "\n", + "```bash\n", + "pip install chromadb\n", + "```\n", + "or\n", + "\n", + "```bash\n", + "pip install chromadb-client\n", + "```\n", + "\n", + "Make sure Chroma Server is running. Use one of the following methods to start the server:\n", + "\n", + "From the command line:\n", + "\n", + "> Note: The below options will configure the server to use Basic Authentication with the username `admin` and password `admin`.\n", + "\n", + "```bash\n", + "export CHROMA_USER=admin\n", + "export CHROMA_PASSWORD=admin\n", + "docker run --rm --entrypoint htpasswd httpd:2 -Bbn ${CHROMA_USER} ${CHROMA_PASSWORD} > server.htpasswd\n", + "CHROMA_SERVER_AUTH_CREDENTIALS_FILE=\"./server.htpasswd\" \\\n", + "CHROMA_SERVER_AUTH_CREDENTIALS_PROVIDER='chromadb.auth.providers.HtpasswdFileServerAuthCredentialsProvider' \\\n", + "CHROMA_SERVER_AUTH_PROVIDER='chromadb.auth.basic.BasicAuthServerProvider' \\\n", + "uvicorn chromadb.app:app --workers 1 --host 0.0.0.0 --port 8000 --proxy-headers --log-config log_config.yml\n", + "```\n", + "\n", + "With Docker Compose:\n", + "\n", + "> Note: You need to clone the git repository first and run the command from the repository root.\n", + "\n", + "```bash\n", + "export CHROMA_USER=admin\n", + "export CHROMA_PASSWORD=admin\n", + "docker run --rm --entrypoint htpasswd httpd:2 -Bbn ${CHROMA_USER} ${CHROMA_PASSWORD} > server.htpasswd\n", + "cat << EOF > .env\n", + "CHROMA_SERVER_AUTH_CREDENTIALS_FILE=\"/chroma/server.htpasswd\"\n", + "CHROMA_SERVER_AUTH_CREDENTIALS_PROVIDER='chromadb.auth.providers.HtpasswdFileServerAuthCredentialsProvider'\n", + "CHROMA_SERVER_AUTH_PROVIDER='chromadb.auth.basic.BasicAuthServerProvider'\n", + "EOF\n", + "docker-compose up -d --build \n", + "```\n" + ], + "metadata": { + "collapsed": false + }, + "id": "af49d8c78f2f7347" + }, + { + "cell_type": "markdown", + "source": [ + "## Basic Authentication" + ], + "metadata": { + "collapsed": false + }, + "id": "fc77d909233f2645" + }, + { + "cell_type": "code", + "execution_count": 2, + "outputs": [ + { + "data": { + "text/plain": "[]" + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import chromadb\n", + "from chromadb import Settings\n", + "\n", + "client = chromadb.HttpClient(\n", + " settings=Settings(chroma_client_auth_provider=\"chromadb.auth.basic.BasicAuthClientProvider\",\n", + " chroma_client_auth_credentials=\"admin:admin\"))\n", + "client.heartbeat() # this should work with or without authentication - it is a public endpoint\n", + "\n", + "client.get_version() # this should work with or without authentication - it is a public endpoint\n", + "\n", + "client.list_collections() # this is a protected endpoint and requires authentication\n", + "\n" + ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2023-08-22T00:33:16.354523Z", + "start_time": "2023-08-22T00:33:15.715736Z" + } + }, + "id": "8f9307acce25f672" + }, + { + "cell_type": "markdown", + "source": [ + "#### Verifying Authentication (Negative Test)" + ], + "metadata": { + "collapsed": false + }, + "id": "6b75f04e59cb1d42" + }, + { + "cell_type": "code", + "execution_count": 3, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "As expected, you are not authorized to access protected endpoints.\n" + ] + } + ], + "source": [ + "# Try to access a protected endpoint without authentication\n", + "import sys\n", + "\n", + "client = chromadb.HttpClient()\n", + "try:\n", + " client.list_collections()\n", + "except Exception as e:\n", + " if \"Unauthorized\" in str(e):\n", + " print(\"As expected, you are not authorized to access protected endpoints.\", file=sys.stderr)\n", + " else:\n", + " raise e" + ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2023-08-22T00:33:19.119718Z", + "start_time": "2023-08-22T00:33:19.097558Z" + } + }, + "id": "c0c3240ed4d70a79" + }, + { + "cell_type": "markdown", + "source": [ + "## Token Authentication\n", + "\n", + "> Note: Tokens must be valid ASCII strings.\n", + "\n", + "### Default Token (`Authorization` with `Bearer`)" + ], + "metadata": { + "collapsed": false + }, + "id": "390aed41f019649b" + }, + { + "cell_type": "code", + "execution_count": 3, + "outputs": [ + { + "ename": "ConnectionError", + "evalue": "HTTPConnectionPool(host='localhost', port=8000): Max retries exceeded with url: /api/v1 (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 61] Connection refused'))", + "output_type": "error", + "traceback": [ + "\u001B[0;31m---------------------------------------------------------------------------\u001B[0m", + "\u001B[0;31mConnectionRefusedError\u001B[0m Traceback (most recent call last)", + "File \u001B[0;32m~/PycharmProjects/chroma-core/venv/lib/python3.10/site-packages/urllib3/connection.py:174\u001B[0m, in \u001B[0;36mHTTPConnection._new_conn\u001B[0;34m(self)\u001B[0m\n\u001B[1;32m 173\u001B[0m \u001B[38;5;28;01mtry\u001B[39;00m:\n\u001B[0;32m--> 174\u001B[0m conn \u001B[38;5;241m=\u001B[39m \u001B[43mconnection\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mcreate_connection\u001B[49m\u001B[43m(\u001B[49m\n\u001B[1;32m 175\u001B[0m \u001B[43m \u001B[49m\u001B[43m(\u001B[49m\u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43m_dns_host\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mport\u001B[49m\u001B[43m)\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mtimeout\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;241;43m*\u001B[39;49m\u001B[38;5;241;43m*\u001B[39;49m\u001B[43mextra_kw\u001B[49m\n\u001B[1;32m 176\u001B[0m \u001B[43m \u001B[49m\u001B[43m)\u001B[49m\n\u001B[1;32m 178\u001B[0m \u001B[38;5;28;01mexcept\u001B[39;00m SocketTimeout:\n", + "File \u001B[0;32m~/PycharmProjects/chroma-core/venv/lib/python3.10/site-packages/urllib3/util/connection.py:95\u001B[0m, in \u001B[0;36mcreate_connection\u001B[0;34m(address, timeout, source_address, socket_options)\u001B[0m\n\u001B[1;32m 94\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m err \u001B[38;5;129;01mis\u001B[39;00m \u001B[38;5;129;01mnot\u001B[39;00m \u001B[38;5;28;01mNone\u001B[39;00m:\n\u001B[0;32m---> 95\u001B[0m \u001B[38;5;28;01mraise\u001B[39;00m err\n\u001B[1;32m 97\u001B[0m \u001B[38;5;28;01mraise\u001B[39;00m socket\u001B[38;5;241m.\u001B[39merror(\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mgetaddrinfo returns an empty list\u001B[39m\u001B[38;5;124m\"\u001B[39m)\n", + "File \u001B[0;32m~/PycharmProjects/chroma-core/venv/lib/python3.10/site-packages/urllib3/util/connection.py:85\u001B[0m, in \u001B[0;36mcreate_connection\u001B[0;34m(address, timeout, source_address, socket_options)\u001B[0m\n\u001B[1;32m 84\u001B[0m sock\u001B[38;5;241m.\u001B[39mbind(source_address)\n\u001B[0;32m---> 85\u001B[0m \u001B[43msock\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mconnect\u001B[49m\u001B[43m(\u001B[49m\u001B[43msa\u001B[49m\u001B[43m)\u001B[49m\n\u001B[1;32m 86\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m sock\n", + "\u001B[0;31mConnectionRefusedError\u001B[0m: [Errno 61] Connection refused", + "\nDuring handling of the above exception, another exception occurred:\n", + "\u001B[0;31mNewConnectionError\u001B[0m Traceback (most recent call last)", + "File \u001B[0;32m~/PycharmProjects/chroma-core/venv/lib/python3.10/site-packages/urllib3/connectionpool.py:714\u001B[0m, in \u001B[0;36mHTTPConnectionPool.urlopen\u001B[0;34m(self, method, url, body, headers, retries, redirect, assert_same_host, timeout, pool_timeout, release_conn, chunked, body_pos, **response_kw)\u001B[0m\n\u001B[1;32m 713\u001B[0m \u001B[38;5;66;03m# Make the request on the httplib connection object.\u001B[39;00m\n\u001B[0;32m--> 714\u001B[0m httplib_response \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43m_make_request\u001B[49m\u001B[43m(\u001B[49m\n\u001B[1;32m 715\u001B[0m \u001B[43m \u001B[49m\u001B[43mconn\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 716\u001B[0m \u001B[43m \u001B[49m\u001B[43mmethod\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 717\u001B[0m \u001B[43m \u001B[49m\u001B[43murl\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 718\u001B[0m \u001B[43m \u001B[49m\u001B[43mtimeout\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mtimeout_obj\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 719\u001B[0m \u001B[43m \u001B[49m\u001B[43mbody\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mbody\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 720\u001B[0m \u001B[43m \u001B[49m\u001B[43mheaders\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mheaders\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 721\u001B[0m \u001B[43m \u001B[49m\u001B[43mchunked\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mchunked\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 722\u001B[0m \u001B[43m\u001B[49m\u001B[43m)\u001B[49m\n\u001B[1;32m 724\u001B[0m \u001B[38;5;66;03m# If we're going to release the connection in ``finally:``, then\u001B[39;00m\n\u001B[1;32m 725\u001B[0m \u001B[38;5;66;03m# the response doesn't need to know about the connection. Otherwise\u001B[39;00m\n\u001B[1;32m 726\u001B[0m \u001B[38;5;66;03m# it will also try to release it and we'll have a double-release\u001B[39;00m\n\u001B[1;32m 727\u001B[0m \u001B[38;5;66;03m# mess.\u001B[39;00m\n", + "File \u001B[0;32m~/PycharmProjects/chroma-core/venv/lib/python3.10/site-packages/urllib3/connectionpool.py:415\u001B[0m, in \u001B[0;36mHTTPConnectionPool._make_request\u001B[0;34m(self, conn, method, url, timeout, chunked, **httplib_request_kw)\u001B[0m\n\u001B[1;32m 414\u001B[0m \u001B[38;5;28;01melse\u001B[39;00m:\n\u001B[0;32m--> 415\u001B[0m \u001B[43mconn\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mrequest\u001B[49m\u001B[43m(\u001B[49m\u001B[43mmethod\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43murl\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;241;43m*\u001B[39;49m\u001B[38;5;241;43m*\u001B[39;49m\u001B[43mhttplib_request_kw\u001B[49m\u001B[43m)\u001B[49m\n\u001B[1;32m 417\u001B[0m \u001B[38;5;66;03m# We are swallowing BrokenPipeError (errno.EPIPE) since the server is\u001B[39;00m\n\u001B[1;32m 418\u001B[0m \u001B[38;5;66;03m# legitimately able to close the connection after sending a valid response.\u001B[39;00m\n\u001B[1;32m 419\u001B[0m \u001B[38;5;66;03m# With this behaviour, the received response is still readable.\u001B[39;00m\n", + "File \u001B[0;32m~/PycharmProjects/chroma-core/venv/lib/python3.10/site-packages/urllib3/connection.py:244\u001B[0m, in \u001B[0;36mHTTPConnection.request\u001B[0;34m(self, method, url, body, headers)\u001B[0m\n\u001B[1;32m 243\u001B[0m headers[\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mUser-Agent\u001B[39m\u001B[38;5;124m\"\u001B[39m] \u001B[38;5;241m=\u001B[39m _get_default_user_agent()\n\u001B[0;32m--> 244\u001B[0m \u001B[38;5;28;43msuper\u001B[39;49m\u001B[43m(\u001B[49m\u001B[43mHTTPConnection\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;28;43mself\u001B[39;49m\u001B[43m)\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mrequest\u001B[49m\u001B[43m(\u001B[49m\u001B[43mmethod\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43murl\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mbody\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mbody\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mheaders\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mheaders\u001B[49m\u001B[43m)\u001B[49m\n", + "File \u001B[0;32m~/.pyenv/versions/3.10.10/lib/python3.10/http/client.py:1282\u001B[0m, in \u001B[0;36mHTTPConnection.request\u001B[0;34m(self, method, url, body, headers, encode_chunked)\u001B[0m\n\u001B[1;32m 1281\u001B[0m \u001B[38;5;250m\u001B[39m\u001B[38;5;124;03m\"\"\"Send a complete request to the server.\"\"\"\u001B[39;00m\n\u001B[0;32m-> 1282\u001B[0m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43m_send_request\u001B[49m\u001B[43m(\u001B[49m\u001B[43mmethod\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43murl\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mbody\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mheaders\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mencode_chunked\u001B[49m\u001B[43m)\u001B[49m\n", + "File \u001B[0;32m~/.pyenv/versions/3.10.10/lib/python3.10/http/client.py:1328\u001B[0m, in \u001B[0;36mHTTPConnection._send_request\u001B[0;34m(self, method, url, body, headers, encode_chunked)\u001B[0m\n\u001B[1;32m 1327\u001B[0m body \u001B[38;5;241m=\u001B[39m _encode(body, \u001B[38;5;124m'\u001B[39m\u001B[38;5;124mbody\u001B[39m\u001B[38;5;124m'\u001B[39m)\n\u001B[0;32m-> 1328\u001B[0m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mendheaders\u001B[49m\u001B[43m(\u001B[49m\u001B[43mbody\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mencode_chunked\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mencode_chunked\u001B[49m\u001B[43m)\u001B[49m\n", + "File \u001B[0;32m~/.pyenv/versions/3.10.10/lib/python3.10/http/client.py:1277\u001B[0m, in \u001B[0;36mHTTPConnection.endheaders\u001B[0;34m(self, message_body, encode_chunked)\u001B[0m\n\u001B[1;32m 1276\u001B[0m \u001B[38;5;28;01mraise\u001B[39;00m CannotSendHeader()\n\u001B[0;32m-> 1277\u001B[0m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43m_send_output\u001B[49m\u001B[43m(\u001B[49m\u001B[43mmessage_body\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mencode_chunked\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mencode_chunked\u001B[49m\u001B[43m)\u001B[49m\n", + "File \u001B[0;32m~/.pyenv/versions/3.10.10/lib/python3.10/http/client.py:1037\u001B[0m, in \u001B[0;36mHTTPConnection._send_output\u001B[0;34m(self, message_body, encode_chunked)\u001B[0m\n\u001B[1;32m 1036\u001B[0m \u001B[38;5;28;01mdel\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_buffer[:]\n\u001B[0;32m-> 1037\u001B[0m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43msend\u001B[49m\u001B[43m(\u001B[49m\u001B[43mmsg\u001B[49m\u001B[43m)\u001B[49m\n\u001B[1;32m 1039\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m message_body \u001B[38;5;129;01mis\u001B[39;00m \u001B[38;5;129;01mnot\u001B[39;00m \u001B[38;5;28;01mNone\u001B[39;00m:\n\u001B[1;32m 1040\u001B[0m \n\u001B[1;32m 1041\u001B[0m \u001B[38;5;66;03m# create a consistent interface to message_body\u001B[39;00m\n", + "File \u001B[0;32m~/.pyenv/versions/3.10.10/lib/python3.10/http/client.py:975\u001B[0m, in \u001B[0;36mHTTPConnection.send\u001B[0;34m(self, data)\u001B[0m\n\u001B[1;32m 974\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mauto_open:\n\u001B[0;32m--> 975\u001B[0m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mconnect\u001B[49m\u001B[43m(\u001B[49m\u001B[43m)\u001B[49m\n\u001B[1;32m 976\u001B[0m \u001B[38;5;28;01melse\u001B[39;00m:\n", + "File \u001B[0;32m~/PycharmProjects/chroma-core/venv/lib/python3.10/site-packages/urllib3/connection.py:205\u001B[0m, in \u001B[0;36mHTTPConnection.connect\u001B[0;34m(self)\u001B[0m\n\u001B[1;32m 204\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21mconnect\u001B[39m(\u001B[38;5;28mself\u001B[39m):\n\u001B[0;32m--> 205\u001B[0m conn \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43m_new_conn\u001B[49m\u001B[43m(\u001B[49m\u001B[43m)\u001B[49m\n\u001B[1;32m 206\u001B[0m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_prepare_conn(conn)\n", + "File \u001B[0;32m~/PycharmProjects/chroma-core/venv/lib/python3.10/site-packages/urllib3/connection.py:186\u001B[0m, in \u001B[0;36mHTTPConnection._new_conn\u001B[0;34m(self)\u001B[0m\n\u001B[1;32m 185\u001B[0m \u001B[38;5;28;01mexcept\u001B[39;00m SocketError \u001B[38;5;28;01mas\u001B[39;00m e:\n\u001B[0;32m--> 186\u001B[0m \u001B[38;5;28;01mraise\u001B[39;00m NewConnectionError(\n\u001B[1;32m 187\u001B[0m \u001B[38;5;28mself\u001B[39m, \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mFailed to establish a new connection: \u001B[39m\u001B[38;5;132;01m%s\u001B[39;00m\u001B[38;5;124m\"\u001B[39m \u001B[38;5;241m%\u001B[39m e\n\u001B[1;32m 188\u001B[0m )\n\u001B[1;32m 190\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m conn\n", + "\u001B[0;31mNewConnectionError\u001B[0m: : Failed to establish a new connection: [Errno 61] Connection refused", + "\nDuring handling of the above exception, another exception occurred:\n", + "\u001B[0;31mMaxRetryError\u001B[0m Traceback (most recent call last)", + "File \u001B[0;32m~/PycharmProjects/chroma-core/venv/lib/python3.10/site-packages/requests/adapters.py:489\u001B[0m, in \u001B[0;36mHTTPAdapter.send\u001B[0;34m(self, request, stream, timeout, verify, cert, proxies)\u001B[0m\n\u001B[1;32m 488\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;129;01mnot\u001B[39;00m chunked:\n\u001B[0;32m--> 489\u001B[0m resp \u001B[38;5;241m=\u001B[39m \u001B[43mconn\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43murlopen\u001B[49m\u001B[43m(\u001B[49m\n\u001B[1;32m 490\u001B[0m \u001B[43m \u001B[49m\u001B[43mmethod\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mrequest\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mmethod\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 491\u001B[0m \u001B[43m \u001B[49m\u001B[43murl\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43murl\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 492\u001B[0m \u001B[43m \u001B[49m\u001B[43mbody\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mrequest\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mbody\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 493\u001B[0m \u001B[43m \u001B[49m\u001B[43mheaders\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mrequest\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mheaders\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 494\u001B[0m \u001B[43m \u001B[49m\u001B[43mredirect\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;28;43;01mFalse\u001B[39;49;00m\u001B[43m,\u001B[49m\n\u001B[1;32m 495\u001B[0m \u001B[43m \u001B[49m\u001B[43massert_same_host\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;28;43;01mFalse\u001B[39;49;00m\u001B[43m,\u001B[49m\n\u001B[1;32m 496\u001B[0m \u001B[43m \u001B[49m\u001B[43mpreload_content\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;28;43;01mFalse\u001B[39;49;00m\u001B[43m,\u001B[49m\n\u001B[1;32m 497\u001B[0m \u001B[43m \u001B[49m\u001B[43mdecode_content\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;28;43;01mFalse\u001B[39;49;00m\u001B[43m,\u001B[49m\n\u001B[1;32m 498\u001B[0m \u001B[43m \u001B[49m\u001B[43mretries\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mmax_retries\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 499\u001B[0m \u001B[43m \u001B[49m\u001B[43mtimeout\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mtimeout\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 500\u001B[0m \u001B[43m \u001B[49m\u001B[43m)\u001B[49m\n\u001B[1;32m 502\u001B[0m \u001B[38;5;66;03m# Send the request.\u001B[39;00m\n\u001B[1;32m 503\u001B[0m \u001B[38;5;28;01melse\u001B[39;00m:\n", + "File \u001B[0;32m~/PycharmProjects/chroma-core/venv/lib/python3.10/site-packages/urllib3/connectionpool.py:798\u001B[0m, in \u001B[0;36mHTTPConnectionPool.urlopen\u001B[0;34m(self, method, url, body, headers, retries, redirect, assert_same_host, timeout, pool_timeout, release_conn, chunked, body_pos, **response_kw)\u001B[0m\n\u001B[1;32m 796\u001B[0m e \u001B[38;5;241m=\u001B[39m ProtocolError(\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mConnection aborted.\u001B[39m\u001B[38;5;124m\"\u001B[39m, e)\n\u001B[0;32m--> 798\u001B[0m retries \u001B[38;5;241m=\u001B[39m \u001B[43mretries\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mincrement\u001B[49m\u001B[43m(\u001B[49m\n\u001B[1;32m 799\u001B[0m \u001B[43m \u001B[49m\u001B[43mmethod\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43murl\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43merror\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43me\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43m_pool\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;28;43mself\u001B[39;49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43m_stacktrace\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43msys\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mexc_info\u001B[49m\u001B[43m(\u001B[49m\u001B[43m)\u001B[49m\u001B[43m[\u001B[49m\u001B[38;5;241;43m2\u001B[39;49m\u001B[43m]\u001B[49m\n\u001B[1;32m 800\u001B[0m \u001B[43m\u001B[49m\u001B[43m)\u001B[49m\n\u001B[1;32m 801\u001B[0m retries\u001B[38;5;241m.\u001B[39msleep()\n", + "File \u001B[0;32m~/PycharmProjects/chroma-core/venv/lib/python3.10/site-packages/urllib3/util/retry.py:592\u001B[0m, in \u001B[0;36mRetry.increment\u001B[0;34m(self, method, url, response, error, _pool, _stacktrace)\u001B[0m\n\u001B[1;32m 591\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m new_retry\u001B[38;5;241m.\u001B[39mis_exhausted():\n\u001B[0;32m--> 592\u001B[0m \u001B[38;5;28;01mraise\u001B[39;00m MaxRetryError(_pool, url, error \u001B[38;5;129;01mor\u001B[39;00m ResponseError(cause))\n\u001B[1;32m 594\u001B[0m log\u001B[38;5;241m.\u001B[39mdebug(\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mIncremented Retry for (url=\u001B[39m\u001B[38;5;124m'\u001B[39m\u001B[38;5;132;01m%s\u001B[39;00m\u001B[38;5;124m'\u001B[39m\u001B[38;5;124m): \u001B[39m\u001B[38;5;132;01m%r\u001B[39;00m\u001B[38;5;124m\"\u001B[39m, url, new_retry)\n", + "\u001B[0;31mMaxRetryError\u001B[0m: HTTPConnectionPool(host='localhost', port=8000): Max retries exceeded with url: /api/v1 (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 61] Connection refused'))", + "\nDuring handling of the above exception, another exception occurred:\n", + "\u001B[0;31mConnectionError\u001B[0m Traceback (most recent call last)", + "Cell \u001B[0;32mIn[3], line 6\u001B[0m\n\u001B[1;32m 2\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01mchromadb\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m Settings\n\u001B[1;32m 4\u001B[0m client \u001B[38;5;241m=\u001B[39m chromadb\u001B[38;5;241m.\u001B[39mHttpClient(\n\u001B[1;32m 5\u001B[0m settings\u001B[38;5;241m=\u001B[39mSettings(chroma_client_auth_provider\u001B[38;5;241m=\u001B[39m\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mtoken\u001B[39m\u001B[38;5;124m\"\u001B[39m, chroma_client_auth_credentials\u001B[38;5;241m=\u001B[39m\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mtest-token\u001B[39m\u001B[38;5;124m\"\u001B[39m))\n\u001B[0;32m----> 6\u001B[0m \u001B[43mclient\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mheartbeat\u001B[49m\u001B[43m(\u001B[49m\u001B[43m)\u001B[49m \u001B[38;5;66;03m# this should work with or without authentication - it is a public endpoint\u001B[39;00m\n\u001B[1;32m 8\u001B[0m client\u001B[38;5;241m.\u001B[39mget_version() \u001B[38;5;66;03m# this should work with or without authentication - it is a public endpoint\u001B[39;00m\n\u001B[1;32m 10\u001B[0m client\u001B[38;5;241m.\u001B[39mlist_collections() \u001B[38;5;66;03m# this is a protected endpoint and requires authentication\u001B[39;00m\n", + "File \u001B[0;32m~/PycharmProjects/chroma-core/chromadb/api/fastapi.py:84\u001B[0m, in \u001B[0;36mFastAPI.heartbeat\u001B[0;34m(self)\u001B[0m\n\u001B[1;32m 81\u001B[0m \u001B[38;5;129m@override\u001B[39m\n\u001B[1;32m 82\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21mheartbeat\u001B[39m(\u001B[38;5;28mself\u001B[39m) \u001B[38;5;241m-\u001B[39m\u001B[38;5;241m>\u001B[39m \u001B[38;5;28mint\u001B[39m:\n\u001B[1;32m 83\u001B[0m \u001B[38;5;250m \u001B[39m\u001B[38;5;124;03m\"\"\"Returns the current server time in nanoseconds to check if the server is alive\"\"\"\u001B[39;00m\n\u001B[0;32m---> 84\u001B[0m resp \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43m_session\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mget\u001B[49m\u001B[43m(\u001B[49m\u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43m_api_url\u001B[49m\u001B[43m)\u001B[49m\n\u001B[1;32m 85\u001B[0m raise_chroma_error(resp)\n\u001B[1;32m 86\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28mint\u001B[39m(resp\u001B[38;5;241m.\u001B[39mjson()[\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mnanosecond heartbeat\u001B[39m\u001B[38;5;124m\"\u001B[39m])\n", + "File \u001B[0;32m~/PycharmProjects/chroma-core/venv/lib/python3.10/site-packages/requests/sessions.py:600\u001B[0m, in \u001B[0;36mSession.get\u001B[0;34m(self, url, **kwargs)\u001B[0m\n\u001B[1;32m 592\u001B[0m \u001B[38;5;250m\u001B[39m\u001B[38;5;124mr\u001B[39m\u001B[38;5;124;03m\"\"\"Sends a GET request. Returns :class:`Response` object.\u001B[39;00m\n\u001B[1;32m 593\u001B[0m \n\u001B[1;32m 594\u001B[0m \u001B[38;5;124;03m:param url: URL for the new :class:`Request` object.\u001B[39;00m\n\u001B[1;32m 595\u001B[0m \u001B[38;5;124;03m:param \\*\\*kwargs: Optional arguments that ``request`` takes.\u001B[39;00m\n\u001B[1;32m 596\u001B[0m \u001B[38;5;124;03m:rtype: requests.Response\u001B[39;00m\n\u001B[1;32m 597\u001B[0m \u001B[38;5;124;03m\"\"\"\u001B[39;00m\n\u001B[1;32m 599\u001B[0m kwargs\u001B[38;5;241m.\u001B[39msetdefault(\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mallow_redirects\u001B[39m\u001B[38;5;124m\"\u001B[39m, \u001B[38;5;28;01mTrue\u001B[39;00m)\n\u001B[0;32m--> 600\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mrequest\u001B[49m\u001B[43m(\u001B[49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[38;5;124;43mGET\u001B[39;49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43murl\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;241;43m*\u001B[39;49m\u001B[38;5;241;43m*\u001B[39;49m\u001B[43mkwargs\u001B[49m\u001B[43m)\u001B[49m\n", + "File \u001B[0;32m~/PycharmProjects/chroma-core/venv/lib/python3.10/site-packages/requests/sessions.py:587\u001B[0m, in \u001B[0;36mSession.request\u001B[0;34m(self, method, url, params, data, headers, cookies, files, auth, timeout, allow_redirects, proxies, hooks, stream, verify, cert, json)\u001B[0m\n\u001B[1;32m 582\u001B[0m send_kwargs \u001B[38;5;241m=\u001B[39m {\n\u001B[1;32m 583\u001B[0m \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mtimeout\u001B[39m\u001B[38;5;124m\"\u001B[39m: timeout,\n\u001B[1;32m 584\u001B[0m \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mallow_redirects\u001B[39m\u001B[38;5;124m\"\u001B[39m: allow_redirects,\n\u001B[1;32m 585\u001B[0m }\n\u001B[1;32m 586\u001B[0m send_kwargs\u001B[38;5;241m.\u001B[39mupdate(settings)\n\u001B[0;32m--> 587\u001B[0m resp \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43msend\u001B[49m\u001B[43m(\u001B[49m\u001B[43mprep\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;241;43m*\u001B[39;49m\u001B[38;5;241;43m*\u001B[39;49m\u001B[43msend_kwargs\u001B[49m\u001B[43m)\u001B[49m\n\u001B[1;32m 589\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m resp\n", + "File \u001B[0;32m~/PycharmProjects/chroma-core/chromadb/auth/providers.py:123\u001B[0m, in \u001B[0;36mRequestsClientAuthProtocolAdapter._Session.send\u001B[0;34m(self, request, **kwargs)\u001B[0m\n\u001B[1;32m 118\u001B[0m \u001B[38;5;129m@override\u001B[39m\n\u001B[1;32m 119\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21msend\u001B[39m(\n\u001B[1;32m 120\u001B[0m \u001B[38;5;28mself\u001B[39m, request: requests\u001B[38;5;241m.\u001B[39mPreparedRequest, \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs: Any\n\u001B[1;32m 121\u001B[0m ) \u001B[38;5;241m-\u001B[39m\u001B[38;5;241m>\u001B[39m requests\u001B[38;5;241m.\u001B[39mResponse:\n\u001B[1;32m 122\u001B[0m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_protocol_adapter\u001B[38;5;241m.\u001B[39minject_credentials(request)\n\u001B[0;32m--> 123\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28;43msuper\u001B[39;49m\u001B[43m(\u001B[49m\u001B[43m)\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43msend\u001B[49m\u001B[43m(\u001B[49m\u001B[43mrequest\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;241;43m*\u001B[39;49m\u001B[38;5;241;43m*\u001B[39;49m\u001B[43mkwargs\u001B[49m\u001B[43m)\u001B[49m\n", + "File \u001B[0;32m~/PycharmProjects/chroma-core/venv/lib/python3.10/site-packages/requests/sessions.py:701\u001B[0m, in \u001B[0;36mSession.send\u001B[0;34m(self, request, **kwargs)\u001B[0m\n\u001B[1;32m 698\u001B[0m start \u001B[38;5;241m=\u001B[39m preferred_clock()\n\u001B[1;32m 700\u001B[0m \u001B[38;5;66;03m# Send the request\u001B[39;00m\n\u001B[0;32m--> 701\u001B[0m r \u001B[38;5;241m=\u001B[39m \u001B[43madapter\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43msend\u001B[49m\u001B[43m(\u001B[49m\u001B[43mrequest\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;241;43m*\u001B[39;49m\u001B[38;5;241;43m*\u001B[39;49m\u001B[43mkwargs\u001B[49m\u001B[43m)\u001B[49m\n\u001B[1;32m 703\u001B[0m \u001B[38;5;66;03m# Total elapsed time of the request (approximately)\u001B[39;00m\n\u001B[1;32m 704\u001B[0m elapsed \u001B[38;5;241m=\u001B[39m preferred_clock() \u001B[38;5;241m-\u001B[39m start\n", + "File \u001B[0;32m~/PycharmProjects/chroma-core/venv/lib/python3.10/site-packages/requests/adapters.py:565\u001B[0m, in \u001B[0;36mHTTPAdapter.send\u001B[0;34m(self, request, stream, timeout, verify, cert, proxies)\u001B[0m\n\u001B[1;32m 561\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;28misinstance\u001B[39m(e\u001B[38;5;241m.\u001B[39mreason, _SSLError):\n\u001B[1;32m 562\u001B[0m \u001B[38;5;66;03m# This branch is for urllib3 v1.22 and later.\u001B[39;00m\n\u001B[1;32m 563\u001B[0m \u001B[38;5;28;01mraise\u001B[39;00m SSLError(e, request\u001B[38;5;241m=\u001B[39mrequest)\n\u001B[0;32m--> 565\u001B[0m \u001B[38;5;28;01mraise\u001B[39;00m \u001B[38;5;167;01mConnectionError\u001B[39;00m(e, request\u001B[38;5;241m=\u001B[39mrequest)\n\u001B[1;32m 567\u001B[0m \u001B[38;5;28;01mexcept\u001B[39;00m ClosedPoolError \u001B[38;5;28;01mas\u001B[39;00m e:\n\u001B[1;32m 568\u001B[0m \u001B[38;5;28;01mraise\u001B[39;00m \u001B[38;5;167;01mConnectionError\u001B[39;00m(e, request\u001B[38;5;241m=\u001B[39mrequest)\n", + "\u001B[0;31mConnectionError\u001B[0m: HTTPConnectionPool(host='localhost', port=8000): Max retries exceeded with url: /api/v1 (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 61] Connection refused'))" + ] + } + ], + "source": [ + "import chromadb\n", + "from chromadb import Settings\n", + "\n", + "client = chromadb.HttpClient(\n", + " settings=Settings(chroma_client_auth_provider=\"token\", chroma_client_auth_credentials=\"test-token\"))\n", + "client.heartbeat() # this should work with or without authentication - it is a public endpoint\n", + "\n", + "client.get_version() # this should work with or without authentication - it is a public endpoint\n", + "\n", + "client.list_collections() # this is a protected endpoint and requires authentication\n" + ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2023-08-28T16:44:30.289045Z", + "start_time": "2023-08-28T16:44:29.878090Z" + } + }, + "id": "b218beb03ae1582e" + }, + { + "cell_type": "markdown", + "source": [ + "### X-Chroma-Token" + ], + "metadata": { + "collapsed": false + }, + "id": "c8234687c5afe521" + }, + { + "cell_type": "code", + "execution_count": 2, + "outputs": [ + { + "ename": "Exception", + "evalue": "{\"error\":\"Unauthorized\"}", + "output_type": "error", + "traceback": [ + "\u001B[0;31m---------------------------------------------------------------------------\u001B[0m", + "\u001B[0;31mHTTPError\u001B[0m Traceback (most recent call last)", + "File \u001B[0;32m~/PycharmProjects/chroma-core/chromadb/api/fastapi.py:410\u001B[0m, in \u001B[0;36mraise_chroma_error\u001B[0;34m(resp)\u001B[0m\n\u001B[1;32m 409\u001B[0m \u001B[38;5;28;01mtry\u001B[39;00m:\n\u001B[0;32m--> 410\u001B[0m \u001B[43mresp\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mraise_for_status\u001B[49m\u001B[43m(\u001B[49m\u001B[43m)\u001B[49m\n\u001B[1;32m 411\u001B[0m \u001B[38;5;28;01mexcept\u001B[39;00m requests\u001B[38;5;241m.\u001B[39mHTTPError:\n", + "File \u001B[0;32m~/PycharmProjects/chroma-core/venv/lib/python3.10/site-packages/requests/models.py:1021\u001B[0m, in \u001B[0;36mResponse.raise_for_status\u001B[0;34m(self)\u001B[0m\n\u001B[1;32m 1020\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m http_error_msg:\n\u001B[0;32m-> 1021\u001B[0m \u001B[38;5;28;01mraise\u001B[39;00m HTTPError(http_error_msg, response\u001B[38;5;241m=\u001B[39m\u001B[38;5;28mself\u001B[39m)\n", + "\u001B[0;31mHTTPError\u001B[0m: 401 Client Error: Unauthorized for url: http://localhost:8000/api/v1/collections", + "\nDuring handling of the above exception, another exception occurred:\n", + "\u001B[0;31mException\u001B[0m Traceback (most recent call last)", + "Cell \u001B[0;32mIn[2], line 11\u001B[0m\n\u001B[1;32m 7\u001B[0m client\u001B[38;5;241m.\u001B[39mheartbeat() \u001B[38;5;66;03m# this should work with or without authentication - it is a public endpoint\u001B[39;00m\n\u001B[1;32m 9\u001B[0m client\u001B[38;5;241m.\u001B[39mget_version() \u001B[38;5;66;03m# this should work with or without authentication - it is a public endpoint\u001B[39;00m\n\u001B[0;32m---> 11\u001B[0m \u001B[43mclient\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mlist_collections\u001B[49m\u001B[43m(\u001B[49m\u001B[43m)\u001B[49m \u001B[38;5;66;03m# this is a protected endpoint and requires authentication\u001B[39;00m\n", + "File \u001B[0;32m~/PycharmProjects/chroma-core/chromadb/api/fastapi.py:92\u001B[0m, in \u001B[0;36mFastAPI.list_collections\u001B[0;34m(self)\u001B[0m\n\u001B[1;32m 90\u001B[0m \u001B[38;5;250m\u001B[39m\u001B[38;5;124;03m\"\"\"Returns a list of all collections\"\"\"\u001B[39;00m\n\u001B[1;32m 91\u001B[0m resp \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_session\u001B[38;5;241m.\u001B[39mget(\u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_api_url \u001B[38;5;241m+\u001B[39m \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124m/collections\u001B[39m\u001B[38;5;124m\"\u001B[39m)\n\u001B[0;32m---> 92\u001B[0m \u001B[43mraise_chroma_error\u001B[49m\u001B[43m(\u001B[49m\u001B[43mresp\u001B[49m\u001B[43m)\u001B[49m\n\u001B[1;32m 93\u001B[0m json_collections \u001B[38;5;241m=\u001B[39m resp\u001B[38;5;241m.\u001B[39mjson()\n\u001B[1;32m 94\u001B[0m collections \u001B[38;5;241m=\u001B[39m []\n", + "File \u001B[0;32m~/PycharmProjects/chroma-core/chromadb/api/fastapi.py:412\u001B[0m, in \u001B[0;36mraise_chroma_error\u001B[0;34m(resp)\u001B[0m\n\u001B[1;32m 410\u001B[0m resp\u001B[38;5;241m.\u001B[39mraise_for_status()\n\u001B[1;32m 411\u001B[0m \u001B[38;5;28;01mexcept\u001B[39;00m requests\u001B[38;5;241m.\u001B[39mHTTPError:\n\u001B[0;32m--> 412\u001B[0m \u001B[38;5;28;01mraise\u001B[39;00m (\u001B[38;5;167;01mException\u001B[39;00m(resp\u001B[38;5;241m.\u001B[39mtext))\n", + "\u001B[0;31mException\u001B[0m: {\"error\":\"Unauthorized\"}" + ] + } + ], + "source": [ + "import chromadb\n", + "from chromadb import Settings\n", + "\n", + "client = chromadb.HttpClient(\n", + " settings=Settings(chroma_client_auth_provider=\"token\", chroma_client_auth_credentials=\"test-token\",\n", + " chroma_client_auth_token_transport_header=\"X_CHROMA_TOKEN\"))\n", + "client.heartbeat() # this should work with or without authentication - it is a public endpoint\n", + "\n", + "client.get_version() # this should work with or without authentication - it is a public endpoint\n", + "\n", + "client.list_collections() # this is a protected endpoint and requires authentication" + ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2023-08-28T14:25:12.858416Z", + "start_time": "2023-08-28T14:25:12.629618Z" + } + }, + "id": "93485c3175d1e2c7" + }, + { + "cell_type": "code", + "execution_count": null, + "outputs": [], + "source": [], + "metadata": { + "collapsed": false + }, + "id": "29d28a25e85f95af" + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.6" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/examples/basic_functionality/in_not_in_filtering.ipynb b/examples/basic_functionality/in_not_in_filtering.ipynb new file mode 100644 index 000000000000..3076d4a3585c --- /dev/null +++ b/examples/basic_functionality/in_not_in_filtering.ipynb @@ -0,0 +1,149 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "initial_id", + "metadata": { + "collapsed": true, + "ExecuteTime": { + "end_time": "2023-08-30T12:48:38.227653Z", + "start_time": "2023-08-30T12:48:27.744069Z" + } + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Number of requested results 10 is greater than number of elements in index 3, updating n_results = 3\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'ids': [['1', '3']], 'distances': [[0.28824201226234436, 1.017508625984192]], 'metadatas': [[{'author': 'john'}, {'author': 'jill'}]], 'embeddings': None, 'documents': [['Article by john', 'Article by Jill']]}\n", + "{'ids': ['1', '3'], 'embeddings': None, 'metadatas': [{'author': 'john'}, {'author': 'jill'}], 'documents': ['Article by john', 'Article by Jill']}\n" + ] + } + ], + "source": [ + "import chromadb\n", + "\n", + "from chromadb.utils import embedding_functions\n", + "\n", + "sentence_transformer_ef = embedding_functions.SentenceTransformerEmbeddingFunction(model_name=\"all-MiniLM-L6-v2\")\n", + "\n", + "\n", + "client = chromadb.Client()\n", + "# client.heartbeat()\n", + "# client.reset()\n", + "collection = client.get_or_create_collection(\"test-where-list\", embedding_function=sentence_transformer_ef)\n", + "collection.add(documents=[\"Article by john\", \"Article by Jack\", \"Article by Jill\"],\n", + " metadatas=[{\"author\": \"john\"}, {\"author\": \"jack\"}, {\"author\": \"jill\"}], ids=[\"1\", \"2\", \"3\"])\n", + "\n", + "query = [\"Give me articles by john\"]\n", + "res = collection.query(query_texts=query,where={'author': {'$in': ['john', 'jill']}}, n_results=10)\n", + "print(res)\n", + "\n", + "res_get = collection.get(where={'author': {'$in': ['john', 'jill']}})\n", + "print(res_get)\n" + ] + }, + { + "cell_type": "markdown", + "source": [ + "# Interactions with existing Where operators" + ], + "metadata": { + "collapsed": false + }, + "id": "752cef843ba2f900" + }, + { + "cell_type": "code", + "execution_count": 2, + "outputs": [ + { + "data": { + "text/plain": "{'ids': [['1']],\n 'distances': [[0.28824201226234436]],\n 'metadatas': [[{'article_type': 'blog', 'author': 'john'}]],\n 'embeddings': None,\n 'documents': [['Article by john']]}" + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "collection.upsert(documents=[\"Article by john\", \"Article by Jack\", \"Article by Jill\"],\n", + " metadatas=[{\"author\": \"john\",\"article_type\":\"blog\"}, {\"author\": \"jack\",\"article_type\":\"social\"}, {\"author\": \"jill\",\"article_type\":\"paper\"}], ids=[\"1\", \"2\", \"3\"])\n", + "\n", + "collection.query(query_texts=query,where={\"$and\":[{\"author\": {'$in': ['john', 'jill']}},{\"article_type\":{\"$eq\":\"blog\"}}]}, n_results=3)" + ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2023-08-30T12:48:49.974353Z", + "start_time": "2023-08-30T12:48:49.938985Z" + } + }, + "id": "ca56cda318f9e94d" + }, + { + "cell_type": "code", + "execution_count": 3, + "outputs": [ + { + "data": { + "text/plain": "{'ids': [['1', '3']],\n 'distances': [[0.28824201226234436, 1.017508625984192]],\n 'metadatas': [[{'article_type': 'blog', 'author': 'john'},\n {'article_type': 'paper', 'author': 'jill'}]],\n 'embeddings': None,\n 'documents': [['Article by john', 'Article by Jill']]}" + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "collection.query(query_texts=query,where={\"$or\":[{\"author\": {'$in': ['john']}},{\"article_type\":{\"$in\":[\"paper\"]}}]}, n_results=3)" + ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2023-08-30T12:48:53.501431Z", + "start_time": "2023-08-30T12:48:53.481571Z" + } + }, + "id": "f10e79ec90c797c1" + }, + { + "cell_type": "code", + "execution_count": null, + "outputs": [], + "source": [], + "metadata": { + "collapsed": false + }, + "id": "d97b8b6dd96261d0" + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.6" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/examples/deployments/aws-terraform/README.md b/examples/deployments/aws-terraform/README.md new file mode 100644 index 000000000000..dc47929821a1 --- /dev/null +++ b/examples/deployments/aws-terraform/README.md @@ -0,0 +1,155 @@ +# AWS EC2 Basic Deployment + +This is an example deployment to AWS EC2 Compute using [terraform](https://www.terraform.io/). + +This deployment will do the following: + +- Create a security group with required ports open (22 and 8000) +- Create EC2 instance with Ubuntu 22 and deploy Chroma using docker compose +- Create a data volume for Chroma data +- Mount the data volume to the EC2 instance +- Format the data volume with ext4 +- Start Chroma + +## Requirements + +- [Terraform CLI v1.3.4+](https://developer.hashicorp.com/terraform/tutorials/gcp-get-started/install-cli) + +## Deployment with terraform + +This deployment uses Ubuntu 22 as foundation, but you'd like to use a different AMI (non-Debian based image) you may have to adjust the startup script. + +To find AWS EC2 AMIs you can use: + +```bash +# 099720109477 is Canonical +aws ec2 describe-images \ + --owners 099720109477 \ + --filters 'Name=name,Values=ubuntu/images/*/ubuntu-jammy*' \ + --query 'sort_by(Images,&CreationDate)[-1].ImageId' +``` + +### 2. Init your terraform state +```bash +terraform init +``` + +### 3. Deploy your application + +Generate SSH key to use with your chroma instance (so you can login to the EC2): + +> Note: This is optional. You can use your own existing SSH key if you prefer. + +```bash +ssh-keygen -t RSA -b 4096 -C "Chroma AWS Key" -N "" -f ./chroma-aws && chmod 400 ./chroma-aws +``` + +Set up your Terraform variables and deploy your instance: + +```bash +export TF_VAR_AWS_ACCESS_KEY= #take note of this as it must be present in all of the subsequent steps +export TF_VAR_AWS_SECRET_ACCESS_KEY= #take note of this as it must be present in all of the subsequent steps +export TF_ssh_public_key="./chroma-aws.pub" #path to the public key you generated above (or can be different if you want to use your own key) +export TF_ssh_private_key="./chroma-aws" #path to the private key you generated above (or can be different if you want to use your own key) - used for formatting the Chroma data volume +export TF_VAR_chroma_release=0.4.8 #set the chroma release to deploy +export TF_VAR_region="us-west-1" # AWS region to deploy the chroma instance to +export TF_VAR_public_access="true" #enable public access to the chroma instance on port 8000 +export TF_VAR_enable_auth="true" #enable basic auth for the chroma instance +export TF_VAR_auth_type="token" #The auth type to use for the chroma instance (token or basic) +terraform apply -auto-approve +``` +> Note: Basic Auth is supported by Chroma v0.4.7+ + +### 4. Check your public IP and that Chroma is running + +Get the public IP of your instance + +```bash +terraform output instance_public_ip +``` + +Check that chroma is running (It should take up several minutes for the instance to be ready) + +```bash +export instance_public_ip=$(terraform output instance_public_ip | sed 's/"//g') +curl -v http://$instance_public_ip:8000/api/v1/heartbeat +``` + +#### 4.1 Checking Auth + +##### Basic +When basic auth is enabled you can check the get the credentials from Terraform state by running: + +```bash +terraform output chroma_auth_basic +``` + +You should see something of the form: + +```bash +chroma:VuA8I}QyNrm0@QLq +``` + +You can then export these credentials: + +```bash +export CHROMA_AUTH=$(terraform output chroma_auth_basic | sed 's/"//g') +``` + +Using the credentials: + +```bash +curl -v http://$instance_public_ip:8000/api/v1/collections -u "${CHROMA_AUTH}" +``` + +> Note: Without `-u` you should be getting 401 Unauthorized response + + +##### Token +When token auth is enabled you can check the get the credentials from Terraform state by running: + +```bash +terraform output chroma_auth_token +``` + +You should see something of the form: + +```bash +PVcQ4qUUnmahXwUgAf3UuYZoMlos6MnF +``` + +You can then export these credentials: + +```bash +export CHROMA_AUTH=$(terraform output chroma_auth_token | sed 's/"//g') +``` + +Using the credentials: + +```bash +curl -v http://$instance_public_ip:8000/api/v1/collections -H "Authorization: Bearer ${CHROMA_AUTH}" +``` + +#### 4.2 SSH to your instance + + +To SSH to your instance: + +```bash +ssh -i ./chroma-aws ubuntu@$instance_public_ip +``` + +### 5. Destroy your Chroma instance +```bash +terraform destroy -auto-approve +``` + +## Extras + +You can visualize your infrastructure with: + +```bash +terraform graph | dot -Tsvg > graph.svg +``` + +>Note: You will need graphviz installed for this to work diff --git a/examples/deployments/aws-terraform/chroma.tf b/examples/deployments/aws-terraform/chroma.tf new file mode 100644 index 000000000000..5f0db03ed51f --- /dev/null +++ b/examples/deployments/aws-terraform/chroma.tf @@ -0,0 +1,161 @@ +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = "~> 5.0" + } + } +} + +# Define provider +variable "AWS_ACCESS_KEY" {} +variable "AWS_SECRET_ACCESS_KEY" {} + +provider "aws" { + access_key = var.AWS_ACCESS_KEY + secret_key = var.AWS_SECRET_ACCESS_KEY + region = var.region +} + +# Create security group +resource "aws_security_group" "chroma_sg" { + name = "chroma-cluster-sg" + description = "Security group for the cluster nodes" + + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + + dynamic "ingress" { + for_each = var.public_access ? [1] : [] + content { + from_port = 8000 + to_port = 8000 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + } + + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + ipv6_cidr_blocks = ["::/0"] + } + + tags = { + Name = "chroma" + } +} + +resource "aws_key_pair" "chroma-keypair" { + key_name = "chroma-keypair" # Replace with your desired key pair name + public_key = file(var.ssh_public_key) # Replace with the path to your public key file +} + +data "aws_ami" "ubuntu" { + most_recent = true + + filter { + name = "name" + values = ["ubuntu/images/hvm-ssd/ubuntu-jammy*"] + } + + filter { + name = "virtualization-type" + values = ["hvm"] + } + filter { + name = "architecture" + values = ["x86_64"] + } + + owners = ["099720109477"] # Canonical +} +# Create EC2 instances +resource "aws_instance" "chroma_instance" { + ami = data.aws_ami.ubuntu.id + instance_type = var.instance_type + key_name = "chroma-keypair" + security_groups = [aws_security_group.chroma_sg.name] + + user_data = templatefile("${path.module}/startup.sh", { + chroma_release = var.chroma_release, + enable_auth = var.enable_auth, + auth_type = var.auth_type, + basic_auth_credentials = "${local.basic_auth_credentials.username}:${local.basic_auth_credentials.password}", + token_auth_credentials = random_password.chroma_token.result, + }) + + tags = { + Name = "chroma" + } + + ebs_block_device { + device_name = "/dev/sda1" + volume_size = var.chroma_instance_volume_size # size in GBs + } +} + + +resource "aws_ebs_volume" "chroma-volume" { + availability_zone = aws_instance.chroma_instance.availability_zone + size = var.chroma_data_volume_size + + tags = { + Name = "chroma" + } + + lifecycle { + prevent_destroy = var.prevent_chroma_data_volume_delete # size in GBs + } +} + +locals { + cleaned_volume_id = replace(aws_ebs_volume.chroma-volume.id, "-", "") +} + +resource "aws_volume_attachment" "chroma_volume_attachment" { + device_name = "/dev/sdh" + volume_id = aws_ebs_volume.chroma-volume.id + instance_id = aws_instance.chroma_instance.id + provisioner "remote-exec" { + inline = [ + "export VOLUME_ID=${local.cleaned_volume_id} && sudo mkfs -t ext4 /dev/$(lsblk -o +SERIAL | grep $VOLUME_ID | awk '{print $1}')", + "sudo mkdir /chroma-data", + "export VOLUME_ID=${local.cleaned_volume_id} && sudo mount /dev/$(lsblk -o +SERIAL | grep $VOLUME_ID | awk '{print $1}') /chroma-data" + ] + + connection { + host = aws_instance.chroma_instance.public_ip + type = "ssh" + user = "ubuntu" + private_key = file(var.ssh_private_key) + } + } + depends_on = [aws_instance.chroma_instance, aws_ebs_volume.chroma-volume] +} + + +output "instance_public_ip" { + value = aws_instance.chroma_instance.public_ip +} + +output "instance_private_ip" { + value = aws_instance.chroma_instance.private_ip +} + +output "chroma_auth_token" { + value = random_password.chroma_token.result + sensitive = true +} + + +output "chroma_auth_basic" { + value = "${local.basic_auth_credentials.username}:${local.basic_auth_credentials.password}" + sensitive = true +} diff --git a/examples/deployments/aws-terraform/startup.sh b/examples/deployments/aws-terraform/startup.sh new file mode 100644 index 000000000000..a6e5b3134f30 --- /dev/null +++ b/examples/deployments/aws-terraform/startup.sh @@ -0,0 +1,53 @@ +#! /bin/bash + +# Note: This is run as root + +cd ~ +export enable_auth="${enable_auth}" +export basic_auth_credentials="${basic_auth_credentials}" +export auth_type="${auth_type}" +export token_auth_credentials="${token_auth_credentials}" +apt-get update -y +apt-get install -y ca-certificates curl gnupg lsb-release +mkdir -m 0755 -p /etc/apt/keyrings +curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg +echo \ + "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \ + $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null +apt-get update -y +chmod a+r /etc/apt/keyrings/docker.gpg +apt-get update -y +apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin git +usermod -aG docker ubuntu +git clone https://github.com/chroma-core/chroma.git && cd chroma +git fetch --tags +git checkout tags/${chroma_release} + +if [ "$${enable_auth}" = "true" ] && [ "$${auth_type}" = "basic" ] && [ ! -z "$${basic_auth_credentials}" ]; then + username=$(echo $basic_auth_credentials | cut -d: -f1) + password=$(echo $basic_auth_credentials | cut -d: -f2) + docker run --rm --entrypoint htpasswd httpd:2 -Bbn $username $password > server.htpasswd + cat < .env +CHROMA_SERVER_AUTH_CREDENTIALS_FILE="/chroma/server.htpasswd" +CHROMA_SERVER_AUTH_CREDENTIALS_PROVIDER='chromadb.auth.providers.HtpasswdFileServerAuthCredentialsProvider' +CHROMA_SERVER_AUTH_PROVIDER='chromadb.auth.basic.BasicAuthServerProvider' +EOF +fi + +if [ "$${enable_auth}" = "true" ] && [ "$${auth_type}" = "token" ] && [ ! -z "$${token_auth_credentials}" ]; then + cat < .env +CHROMA_SERVER_AUTH_CREDENTIALS="$${token_auth_credentials}" \ +CHROMA_SERVER_AUTH_CREDENTIALS_PROVIDER='chromadb.auth.token.TokenConfigServerAuthCredentialsProvider' +CHROMA_SERVER_AUTH_PROVIDER='chromadb.auth.token.TokenAuthServerProvider' +EOF +fi + +cat < docker-compose.override.yaml +version: '3.8' +services: + server: + volumes: + - /chroma-data:/chroma/chroma +EOF + +COMPOSE_PROJECT_NAME=chroma docker compose up -d --build diff --git a/examples/deployments/aws-terraform/variables.tf b/examples/deployments/aws-terraform/variables.tf new file mode 100644 index 000000000000..84e086116b5a --- /dev/null +++ b/examples/deployments/aws-terraform/variables.tf @@ -0,0 +1,94 @@ +variable "chroma_release" { + description = "The chroma release to deploy" + type = string + default = "0.4.8" +} + +variable "region" { + description = "AWS Region" + type = string + default = "us-west-1" +} + +variable "instance_type" { + description = "AWS EC2 Instance Type" + type = string + default = "t3.medium" +} + + +variable "public_access" { + description = "Enable public ingress on port 8000" + type = bool + default = true // or true depending on your needs +} + +variable "enable_auth" { + description = "Enable authentication" + type = bool + default = true // or false depending on your needs +} + +variable "auth_type" { + description = "Authentication type" + type = string + default = "token" // or token depending on your needs + validation { + condition = contains(["basic", "token"], var.auth_type) + error_message = "The auth type must be either basic or token" + } +} + +resource "random_password" "chroma_password" { + length = 16 + special = true + lower = true + upper = true +} + +resource "random_password" "chroma_token" { + length = 32 + special = false + lower = true + upper = true +} + + +locals { + basic_auth_credentials = { + username = "chroma" + password = random_password.chroma_password.result + } + token_auth_credentials = { + token = random_password.chroma_token.result + } +} + +variable "ssh_public_key" { + description = "SSH Public Key" + type = string + default = "./chroma-aws.pub" +} +variable "ssh_private_key" { + description = "SSH Private Key" + type = string + default = "./chroma-aws" +} + +variable "chroma_instance_volume_size" { + description = "The size of the instance volume - the root volume" + type = number + default = 30 +} + +variable "chroma_data_volume_size" { + description = "EBS Volume Size of the attached data volume where your chroma data is stored" + type = number + default = 20 +} + +variable "prevent_chroma_data_volume_delete" { + description = "Prevent the chroma data volume from being deleted when the instance is terminated" + type = bool + default = false +} diff --git a/examples/deployments/google-cloud-compute/README.md b/examples/deployments/google-cloud-compute/README.md index 8da1af830de9..ea25613baf46 100644 --- a/examples/deployments/google-cloud-compute/README.md +++ b/examples/deployments/google-cloud-compute/README.md @@ -3,43 +3,135 @@ This is an example deployment to Google Cloud Compute using [terraform](https://www.terraform.io/) ## Requirements + - [gcloud CLI](https://cloud.google.com/sdk/gcloud) - [Terraform CLI v1.3.4+](https://developer.hashicorp.com/terraform/tutorials/gcp-get-started/install-cli) +- [Terraform GCP provider](https://registry.terraform.io/providers/hashicorp/google/latest/docs) ## Deployment with terraform ### 1. Auth to your Google Cloud project + ```bash gcloud auth application-default login ``` ### 2. Init your terraform state + ```bash terraform init ``` ### 3. Deploy your application + +> **WARNING**: GCP Terraform provider does not allow use of variables in the lifecycle of the volume. By default, the +> template does not prevent deletion of the volume however if you plan to use this template for production deployment you +> may consider change the value of `prevent_destroy` to `true` in `chroma.tf` file. + +Generate SSH key to use with your chroma instance (so you can SSH to the GCP VM): + +> Note: This is optional. You can use your own existing SSH key if you prefer. + +```bash +ssh-keygen -t RSA -b 4096 -C "Chroma AWS Key" -N "" -f ./chroma-aws && chmod 400 ./chroma-aws +``` + ```bash export TF_VAR_project_id= #take note of this as it must be present in all of the subsequent steps -export TF_VAR_chroma_release=0.4.5 #set the chroma release to deploy +export TF_ssh_public_key="./chroma-aws.pub" #path to the public key you generated above (or can be different if you want to use your own key) +export TF_ssh_private_key="./chroma-aws" #path to the private key you generated above (or can be different if you want to use your own key) - used for formatting the Chroma data volume +export TF_VAR_chroma_release="0.4.9" #set the chroma release to deploy +export TF_VAR_zone="us-central1-a" # AWS region to deploy the chroma instance to +export TF_VAR_public_access="true" #enable public access to the chroma instance on port 8000 +export TF_VAR_enable_auth="true" #enable basic auth for the chroma instance +export TF_VAR_auth_type="token" #The auth type to use for the chroma instance (token or basic) terraform apply -auto-approve ``` ### 4. Check your public IP and that Chroma is running -Get the public IP of your instance +> Note: Depending on your instance type it might take a few minutes for the instance to be ready + +Get the public IP of your instance (it should also be printed out after successful `terraform apply`): ```bash terraform output instance_public_ip ``` -Check that chroma is running +Check that chroma is running: + ```bash export instance_public_ip=$(terraform output instance_public_ip | sed 's/"//g') curl -v http://$instance_public_ip:8000/api/v1/heartbeat ``` +#### 4.1 Checking Auth + +##### Token + +When token auth is enabled (this is the default option) you can check the get the credentials from Terraform state by +running: + +```bash +terraform output chroma_auth_token +``` + +You should see something of the form: + +```bash +PVcQ4qUUnmahXwUgAf3UuYZoMlos6MnF +``` + +You can then export these credentials: + +```bash +export CHROMA_AUTH=$(terraform output chroma_auth_token | sed 's/"//g') +``` + +Using the credentials: + +```bash +curl -v http://$instance_public_ip:8000/api/v1/collections -H "Authorization: Bearer ${CHROMA_AUTH}" +``` + +##### Basic + +When basic auth is enabled you can check the get the credentials from Terraform state by running: + +```bash +terraform output chroma_auth_basic +``` + +You should see something of the form: + +```bash +chroma:VuA8I}QyNrm0@QLq +``` + +You can then export these credentials: + +```bash +export CHROMA_AUTH=$(terraform output chroma_auth_basic | sed 's/"//g') +``` + +Using the credentials: + +```bash +curl -v http://$instance_public_ip:8000/api/v1/collections -u "${CHROMA_AUTH}" +``` + +> Note: Without `-u` you should be getting 401 Unauthorized response + +#### 4.2 SSH to your instance + +To SSH to your instance: + +```bash +ssh -i ./chroma-aws debian@$instance_public_ip +``` + ### 5. Destroy your application + ```bash terraform destroy -auto-approve ``` diff --git a/examples/deployments/google-cloud-compute/chroma.tf b/examples/deployments/google-cloud-compute/chroma.tf index 7ed41b417a28..f49fc59cfe37 100644 --- a/examples/deployments/google-cloud-compute/chroma.tf +++ b/examples/deployments/google-cloud-compute/chroma.tf @@ -1,18 +1,36 @@ -resource "google_compute_instance" "chroma1" { +terraform { + required_providers { + google = { + source = "hashicorp/google" + version = "~> 4.80.0" + } + } +} + +resource "google_compute_instance" "chroma" { project = var.project_id name = "chroma-1" machine_type = var.machine_type zone = var.zone - tags = ["chroma"] + tags = local.tags + + labels = var.labels + boot_disk { initialize_params { - image = "debian-cloud/debian-11" - size = 20 + image = var.image + size = var.chroma_instance_volume_size #size in GB } } + attached_disk { + source = google_compute_disk.chroma.id + device_name = var.chroma_data_volume_device_name + mode = "READ_WRITE" + } + network_interface { network = "default" @@ -21,30 +39,91 @@ resource "google_compute_instance" "chroma1" { } } - metadata_startup_script = templatefile("${path.module}/startup.sh", { chroma_release = var.chroma_release }) + metadata = { + ssh-keys = "${var.vm_user}:${file(var.ssh_public_key)}" + } + + metadata_startup_script = templatefile("${path.module}/startup.sh", { + chroma_release = var.chroma_release, + enable_auth = var.enable_auth, + auth_type = var.auth_type, + basic_auth_credentials = "${local.basic_auth_credentials.username}:${local.basic_auth_credentials.password}", + token_auth_credentials = random_password.chroma_token.result, + }) + + provisioner "remote-exec" { + inline = [ + "export VOLUME_ID=${var.chroma_data_volume_device_name} && sudo mkfs -t ext4 /dev/$(lsblk -o +SERIAL | grep $VOLUME_ID | awk '{print $1}')", + "sudo mkdir /chroma-data", + "export VOLUME_ID=${var.chroma_data_volume_device_name} && sudo mount /dev/$(lsblk -o +SERIAL | grep $VOLUME_ID | awk '{print $1}') /chroma-data" + ] + + connection { + host = google_compute_instance.chroma.network_interface[0].access_config[0].nat_ip + type = "ssh" + user = var.vm_user + private_key = file(var.ssh_private_key) + } + } } + +resource "google_compute_disk" "chroma" { + project = var.project_id + name = "chroma-data" + type = var.disk_type + zone = var.zone + labels = var.labels + size = var.chroma_data_volume_size #size in GB + + lifecycle { + prevent_destroy = false #WARNING: You need to configure this manually as the provider does not support it yet + } +} + +#resource "google_compute_attached_disk" "vm_attached_disk" { +# disk = google_compute_disk.chroma.id +# instance = google_compute_instance.chroma.self_link +# +#} + + + resource "google_compute_firewall" "default" { project = var.project_id name = "chroma-firewall" network = "default" allow { - protocol = "icmp" + protocol = "icmp" #allow ping } - allow { - protocol = "tcp" - ports = ["8000"] + dynamic "allow" { + for_each = var.public_access ? [1] : [] + content { + protocol = "tcp" + ports = [var.chroma_port] + } } - source_ranges = ["0.0.0.0/0"] + source_ranges = var.source_ranges - target_tags = ["chroma"] + target_tags = local.tags } output "instance_public_ip" { description = "The public IP address of the instance." - value = google_compute_instance.chroma1.network_interface[0].access_config[0].nat_ip -} \ No newline at end of file + value = google_compute_instance.chroma.network_interface[0].access_config[0].nat_ip +} + +output "chroma_auth_token" { + value = random_password.chroma_token.result + sensitive = true +} + + +output "chroma_auth_basic" { + value = "${local.basic_auth_credentials.username}:${local.basic_auth_credentials.password}" + sensitive = true +} diff --git a/examples/deployments/google-cloud-compute/main.tf b/examples/deployments/google-cloud-compute/main.tf index a73c37765429..e69de29bb2d1 100644 --- a/examples/deployments/google-cloud-compute/main.tf +++ b/examples/deployments/google-cloud-compute/main.tf @@ -1,8 +0,0 @@ -terraform { - required_providers { - google = { - source = "hashicorp/google" - version = "~> 4.47.0" - } - } -} diff --git a/examples/deployments/google-cloud-compute/startup.sh b/examples/deployments/google-cloud-compute/startup.sh index d0140670cb43..1d93e46c3e23 100644 --- a/examples/deployments/google-cloud-compute/startup.sh +++ b/examples/deployments/google-cloud-compute/startup.sh @@ -1,7 +1,12 @@ #! /bin/bash -cd ~ +# Note: This is run as root +cd ~ +export enable_auth="${enable_auth}" +export basic_auth_credentials="${basic_auth_credentials}" +export auth_type="${auth_type}" +export token_auth_credentials="${token_auth_credentials}" apt-get update -y apt-get install -y ca-certificates curl gnupg lsb-release mkdir -m 0755 -p /etc/apt/keyrings @@ -13,10 +18,36 @@ apt-get update -y chmod a+r /etc/apt/keyrings/docker.gpg apt-get update -y apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin git - -git clone https://github.com/chroma-core/chroma.git -cd chroma +usermod -aG docker debian +git clone https://github.com/chroma-core/chroma.git && cd chroma git fetch --tags git checkout tags/${chroma_release} +if [ "$${enable_auth}" = "true" ] && [ "$${auth_type}" = "basic" ] && [ ! -z "$${basic_auth_credentials}" ]; then + username=$(echo $basic_auth_credentials | cut -d: -f1) + password=$(echo $basic_auth_credentials | cut -d: -f2) + docker run --rm --entrypoint htpasswd httpd:2 -Bbn $username $password > server.htpasswd + cat < .env +CHROMA_SERVER_AUTH_CREDENTIALS_FILE="/chroma/server.htpasswd" +CHROMA_SERVER_AUTH_CREDENTIALS_PROVIDER='chromadb.auth.providers.HtpasswdFileServerAuthCredentialsProvider' +CHROMA_SERVER_AUTH_PROVIDER='chromadb.auth.basic.BasicAuthServerProvider' +EOF +fi + +if [ "$${enable_auth}" = "true" ] && [ "$${auth_type}" = "token" ] && [ ! -z "$${token_auth_credentials}" ]; then + cat < .env +CHROMA_SERVER_AUTH_CREDENTIALS="$${token_auth_credentials}" \ +CHROMA_SERVER_AUTH_CREDENTIALS_PROVIDER='chromadb.auth.token.TokenConfigServerAuthCredentialsProvider' +CHROMA_SERVER_AUTH_PROVIDER='chromadb.auth.token.TokenAuthServerProvider' +EOF +fi + +cat < docker-compose.override.yaml +version: '3.8' +services: + server: + volumes: + - /chroma-data:/chroma/chroma +EOF + COMPOSE_PROJECT_NAME=chroma docker compose up -d --build diff --git a/examples/deployments/google-cloud-compute/variables.tf b/examples/deployments/google-cloud-compute/variables.tf index a3bca24654bf..0147ce49aa42 100644 --- a/examples/deployments/google-cloud-compute/variables.tf +++ b/examples/deployments/google-cloud-compute/variables.tf @@ -1,10 +1,11 @@ variable "project_id" { - type = string + type = string + description = "The project id to deploy to" } variable "chroma_release" { description = "The chroma release to deploy" type = string - default = "0.4.5" + default = "0.4.9" } variable "zone" { @@ -12,7 +13,130 @@ variable "zone" { default = "us-central1-a" } +variable "image" { + default = "debian-cloud/debian-11" + description = "The image to use for the instance" + type = string +} + +variable "vm_user" { + default = "debian" + description = "The user to use for connecting to the instance. This is usually the default image user" + type = string +} + variable "machine_type" { type = string default = "e2-small" } + +variable "public_access" { + description = "Enable public ingress on port 8000" + type = bool + default = true // or true depending on your needs +} + +variable "enable_auth" { + description = "Enable authentication" + type = bool + default = true // or false depending on your needs +} + +variable "auth_type" { + description = "Authentication type" + type = string + default = "token" // or token depending on your needs + validation { + condition = contains(["basic", "token"], var.auth_type) + error_message = "The auth type must be either basic or token" + } +} + +resource "random_password" "chroma_password" { + length = 16 + special = true + lower = true + upper = true +} + +resource "random_password" "chroma_token" { + length = 32 + special = false + lower = true + upper = true +} + + +locals { + basic_auth_credentials = { + username = "chroma" + password = random_password.chroma_password.result + } + token_auth_credentials = { + token = random_password.chroma_token.result + } + tags = [ + "chroma", + "release-${replace(var.chroma_release, ".", "")}", + ] +} + +variable "ssh_public_key" { + description = "SSH Public Key" + type = string + default = "./chroma-aws.pub" +} +variable "ssh_private_key" { + description = "SSH Private Key" + type = string + default = "./chroma-aws" +} + +variable "chroma_instance_volume_size" { + description = "The size of the instance volume - the root volume" + type = number + default = 30 +} + +variable "chroma_data_volume_size" { + description = "Volume Size of the attached data volume where your chroma data is stored" + type = number + default = 20 +} + +variable "chroma_data_volume_device_name" { + default = "chroma-disk-0" + description = "The device name of the chroma data volume" + type = string +} + +variable "prevent_chroma_data_volume_delete" { + description = "Prevent the chroma data volume from being deleted when the instance is terminated" + type = bool + default = false +} + +variable "disk_type" { + default = "pd-ssd" + description = "The type of disk to use for the instance. Can be either pd-standard or pd-ssd" +} + +variable "labels" { + default = { + environment = "dev" + } + description = "Labels to apply to all resources in this example" + type = map(string) +} + +variable "chroma_port" { + default = "8000" + description = "The port that chroma listens on" + type = string +} + +variable "source_ranges" { + default = ["0.0.0.0/0"] + type = list(string) + description = "List of CIDR ranges to allow through the firewall" +} diff --git a/examples/use_with/cohere/cohere_js.js b/examples/use_with/cohere/cohere_js.js index 585e383c3716..7fe866916029 100644 --- a/examples/use_with/cohere/cohere_js.js +++ b/examples/use_with/cohere/cohere_js.js @@ -7,7 +7,7 @@ First run Chroma ``` git clone git@github.com:chroma-core/chroma.git cd chroma -docker-compose up -d --build +chroma run --path /chroma_db_path ``` Then install chroma and cohere @@ -61,20 +61,20 @@ const main = async () => { }); // # 나는 오렌지를 좋아한다 is "I like oranges" in Korean - multilingual_texts = [ 'Hello from Cohere!', 'مرحبًا من كوهير!', - 'Hallo von Cohere!', 'Bonjour de Cohere!', - '¡Hola desde Cohere!', 'Olá do Cohere!', - 'Ciao da Cohere!', '您好,来自 Cohere!', - 'कोहेरे से नमस्ते!', '나는 오렌지를 좋아한다' ] + multilingual_texts = ['Hello from Cohere!', 'مرحبًا من كوهير!', + 'Hallo von Cohere!', 'Bonjour de Cohere!', + '¡Hola desde Cohere!', 'Olá do Cohere!', + 'Ciao da Cohere!', '您好,来自 Cohere!', + 'कोहेरे से नमस्ते!', '나는 오렌지를 좋아한다'] let ids = Array.from({ length: multilingual_texts.length }, (_, i) => String(i)); await collection.add({ - ids:ids, - documents:multilingual_texts -}) + ids: ids, + documents: multilingual_texts + }) - console.log(await collection.query({queryTexts:["citrus"], nResults:1})) + console.log(await collection.query({ queryTexts: ["citrus"], nResults: 1 })) } diff --git a/log_config.yml b/log_config.yml deleted file mode 100644 index e8da3c2c7de6..000000000000 --- a/log_config.yml +++ /dev/null @@ -1,23 +0,0 @@ -version: 1 -disable_existing_loggers: False -formatters: - default: - format: '%(asctime)s %(levelname)-8s %(name)-15s %(message)s' - datefmt: '%Y-%m-%d %H:%M:%S' -handlers: - console: - class: logging.StreamHandler - stream: ext://sys.stdout - formatter: default - file: - class : logging.handlers.RotatingFileHandler - filename: chroma.log - formatter: default -loggers: - root: - level: WARN - handlers: [console, file] - chromadb: - level: DEBUG - uvicorn: - level: INFO diff --git a/pyproject.toml b/pyproject.toml index 4f8d34c760d4..8fc60673607e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,10 +17,11 @@ classifiers = [ dependencies = [ 'requests >= 2.28', 'pydantic>=1.9,<2.0', - 'chroma-hnswlib==0.7.2', + 'chroma-hnswlib==0.7.3', 'fastapi>=0.95.2, <0.100.0', 'uvicorn[standard] >= 0.18.3', - 'numpy >= 1.21.6', + 'numpy == 1.21.6; python_version < "3.8"', + 'numpy >= 1.22.5; python_version >= "3.8"', 'posthog >= 2.4.0', 'typing_extensions >= 4.5.0', 'pulsar-client>=3.1.0', @@ -30,7 +31,9 @@ dependencies = [ 'tqdm >= 4.65.0', 'overrides >= 7.3.1', 'importlib-resources', - 'graphlib_backport >= 1.0.3; python_version < "3.9"' + 'graphlib_backport >= 1.0.3; python_version < "3.9"', + 'bcrypt >= 4.0.1', + 'typer >= 0.9.0', ] [tool.black] @@ -41,6 +44,9 @@ target-version = ['py36', 'py37', 'py38', 'py39', 'py310'] [tool.pytest.ini_options] pythonpath = ["."] +[project.scripts] +chroma = "chromadb.cli.cli:app" + [project.urls] "Homepage" = "https://github.com/chroma-core/chroma" "Bug Tracker" = "https://github.com/chroma-core/chroma/issues" @@ -54,3 +60,6 @@ local_scheme="no-local-version" [tool.setuptools] packages = ["chromadb"] + +[tool.setuptools.package-data] +chromadb = ["*.yml"] diff --git a/requirements.txt b/requirements.txt index 04387f95cd0d..9a9fdcc295c7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,8 +1,10 @@ -chroma-hnswlib==0.7.2 +bcrypt==4.0.1 +chroma-hnswlib==0.7.3 fastapi>=0.95.2, <0.100.0 graphlib_backport==1.0.3; python_version < '3.9' importlib-resources -numpy==1.21.6 +numpy==1.21.6; python_version < '3.8' +numpy==1.22.4; python_version >= '3.8' onnxruntime==1.14.1 overrides==7.3.1 posthog==2.4.0 @@ -12,5 +14,6 @@ pypika==0.48.9 requests==2.28.1 tokenizers==0.13.2 tqdm==4.65.0 +typer>=0.9.0 typing_extensions==4.5.0 uvicorn[standard]==0.18.3 diff --git a/requirements_dev.txt b/requirements_dev.txt index 68546b27796a..9354d39b7255 100644 --- a/requirements_dev.txt +++ b/requirements_dev.txt @@ -3,8 +3,10 @@ build httpx hypothesis hypothesis[numpy] +mypy-protobuf pre-commit pytest pytest-asyncio setuptools_scm +types-protobuf types-requests==2.30.0.0