diff --git a/.env.example b/.env.example index 3871841c0..e8f9b747b 100644 --- a/.env.example +++ b/.env.example @@ -1,21 +1,19 @@ # Keys -# Required keys for platform encryption/decryption ops -PRIVATE_KEY=replace_with_nacl_sk -PUBLIC_KEY=replace_with_nacl_pk -ENCRYPTION_KEY=replace_with_lengthy_secure_hex +# Required key for platform encryption/decryption ops +ENCRYPTION_KEY=6c1fe4e407b8911c104518103505b218 # JWT # Required secrets to sign JWT tokens -JWT_SIGNUP_SECRET=replace_with_lengthy_secure_hex -JWT_REFRESH_SECRET=replace_with_lengthy_secure_hex -JWT_AUTH_SECRET=replace_with_lengthy_secure_hex +JWT_SIGNUP_SECRET=3679e04ca949f914c03332aaaeba805a +JWT_REFRESH_SECRET=5f2f3c8f0159068dc2bbb3a652a716ff +JWT_AUTH_SECRET=4be6ba5602e0fa0ac6ac05c3cd4d247f +JWT_SERVICE_SECRET=f32f716d70a42c5703f4656015e76200 # JWT lifetime # Optional lifetimes for JWT tokens expressed in seconds or a string # describing a time span (e.g. 60, "2 days", "10h", "7d") JWT_AUTH_LIFETIME= JWT_REFRESH_LIFETIME= -JWT_SERVICE_SECRET= JWT_SIGNUP_LIFETIME= # Optional lifetimes for OTP expressed in seconds @@ -33,22 +31,28 @@ MONGO_PASSWORD=example # Website URL # Required - SITE_URL=http://localhost:8080 # Mail/SMTP -# Required to send emails -# By default, SMTP_HOST is set to smtp.gmail.com -SMTP_HOST=smtp.gmail.com +SMTP_HOST= # required +SMTP_USERNAME= # required +SMTP_PASSWORD= # required SMTP_PORT=587 -SMTP_NAME=Team -SMTP_USERNAME=team@infisical.com -SMTP_PASSWORD= +SMTP_SECURE=false +SMTP_FROM_ADDRESS= # required +SMTP_FROM_NAME=Infisical # Integration # Optional only if integration is used -OAUTH_CLIENT_SECRET_HEROKU= -OAUTH_TOKEN_URL_HEROKU= +CLIENT_ID_HEROKU= +CLIENT_ID_VERCEL= +CLIENT_ID_NETLIFY= +CLIENT_ID_GITHUB= +CLIENT_SECRET_HEROKU= +CLIENT_SECRET_VERCEL= +CLIENT_SECRET_NETLIFY= +CLIENT_SECRET_GITHUB= +CLIENT_SLUG_VERCEL= # Sentry (optional) for monitoring errors SENTRY_DSN= @@ -60,7 +64,7 @@ POSTHOG_PROJECT_API_KEY= STRIPE_SECRET_KEY= STRIPE_PUBLISHABLE_KEY= STRIPE_WEBHOOK_SECRET= -STRIPE_PRODUCT_CARD_AUTH= -STRIPE_PRODUCT_PRO= STRIPE_PRODUCT_STARTER= +STRIPE_PRODUCT_TEAM= +STRIPE_PRODUCT_PRO= NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY= \ No newline at end of file diff --git a/.eslintignore b/.eslintignore index 7a3d61558..1e484b986 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,3 +1,4 @@ node_modules built healthcheck.js +tailwind.config.js \ No newline at end of file diff --git a/.github/values.yaml b/.github/values.yaml new file mode 100644 index 000000000..5fd38b031 --- /dev/null +++ b/.github/values.yaml @@ -0,0 +1,93 @@ +##### +# INFISICAL K8 DEFAULT VALUES FILE +# PLEASE REPLACE VALUES/EDIT AS REQUIRED +##### + +nameOverride: "" + +frontend: + name: frontend + podAnnotations: {} + deploymentAnnotations: + secrets.infisical.com/auto-reload: "true" + replicaCount: 2 + image: + repository: infisical/frontend + pullPolicy: Always + tag: "latest" + kubeSecretRef: managed-secret-frontend + service: + # type of the frontend service + type: ClusterIP + # define the nodePort if service type is NodePort + # nodePort: + annotations: {} + +backend: + name: backend + podAnnotations: {} + deploymentAnnotations: + secrets.infisical.com/auto-reload: "true" + replicaCount: 2 + image: + repository: infisical/backend + pullPolicy: Always + tag: "latest" + kubeSecretRef: managed-backend-secret + service: + annotations: {} + +mongodb: + name: mongodb + podAnnotations: {} + image: + repository: mongo + pullPolicy: IfNotPresent + tag: "latest" + service: + annotations: {} + +# By default the backend will be connected to a Mongo instance in the cluster. +# However, it is recommended to add a managed document DB connection string because the DB instance in the cluster does not have persistence yet ( data will be deleted on next deploy). +# Learn about connection string type here https://www.mongodb.com/docs/manual/reference/connection-string/ +mongodbConnection: {} + # externalMongoDBConnectionString: <> + +ingress: + enabled: true + annotations: + kubernetes.io/ingress.class: "nginx" + hostName: gamma.infisical.com # replace with your domain + frontend: + path: / + pathType: Prefix + backend: + path: /api + pathType: Prefix + tls: [] + + +## Complete Ingress example +# ingress: +# enabled: true +# annotations: +# kubernetes.io/ingress.class: "nginx" +# cert-manager.io/issuer: letsencrypt-nginx +# hostName: k8.infisical.com +# frontend: +# path: / +# pathType: Prefix +# backend: +# path: /api +# pathType: Prefix +# tls: +# - secretName: letsencrypt-nginx +# hosts: +# - k8.infisical.com + +### +### YOU MUST FILL IN ALL SECRETS BELOW +### +backendEnvironmentVariables: {} + +frontendEnvironmentVariables: {} diff --git a/.github/workflows/be-test-report.yml b/.github/workflows/be-test-report.yml new file mode 100644 index 000000000..bd57b377e --- /dev/null +++ b/.github/workflows/be-test-report.yml @@ -0,0 +1,41 @@ +name: "Backend Test Report" + +on: + workflow_run: + workflows: ["Check Backend Pull Request"] + types: + - completed + +jobs: + be-report: + name: Backend test report + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: ๐Ÿ“ Download test results + id: download-artifact + uses: dawidd6/action-download-artifact@v2 + with: + name: be-test-results + path: backend + workflow: check-be-pull-request.yml + workflow_conclusion: success + - name: ๐Ÿ“‹ Publish test results + uses: dorny/test-reporter@v1 + with: + name: Test Results + path: reports/jest-*.xml + reporter: jest-junit + working-directory: backend + - name: ๐Ÿ“‹ Publish coverage + uses: ArtiomTr/jest-coverage-report-action@v2 + id: coverage + with: + output: comment, report-markdown + coverage-file: coverage/report.json + github-token: ${{ secrets.GITHUB_TOKEN }} + working-directory: backend + - uses: marocchino/sticky-pull-request-comment@v2 + with: + message: ${{ steps.coverage.outputs.report }} diff --git a/.github/workflows/check-be-pull-request.yml b/.github/workflows/check-be-pull-request.yml index f17d8c5c8..3cb010e8c 100644 --- a/.github/workflows/check-be-pull-request.yml +++ b/.github/workflows/check-be-pull-request.yml @@ -1,41 +1,42 @@ -name: Check Backend Pull Request +name: "Check Backend Pull Request" on: pull_request: - types: [ opened, synchronize ] + types: [opened, synchronize] paths: - - 'backend/**' - - '!backend/README.md' - - '!backend/.*' - - 'backend/.eslintrc.js' - + - "backend/**" + - "!backend/README.md" + - "!backend/.*" + - "backend/.eslintrc.js" jobs: - check-be-pr: name: Check runs-on: ubuntu-latest steps: - - - name: โ˜๏ธ Checkout source + - name: โ˜๏ธ Checkout source uses: actions/checkout@v3 - - - name: ๐Ÿ”ง Setup Node 16 + - name: ๐Ÿ”ง Setup Node 16 uses: actions/setup-node@v3 with: - node-version: '16' - cache: 'npm' + node-version: "16" + cache: "npm" cache-dependency-path: backend/package-lock.json - - - name: ๐Ÿ“ฆ Install dependencies - run: npm ci --only-production --ignore-scripts + - name: ๐Ÿ“ฆ Install dependencies + run: npm ci --only-production working-directory: backend - # - - # name: ๐Ÿงช Run tests - # run: npm run test:ci - # working-directory: backend - - - name: ๐Ÿ—๏ธ Run build + - name: ๐Ÿงช Run tests + run: npm run test:ci + working-directory: backend + - name: ๐Ÿ“ Upload test results + uses: actions/upload-artifact@v3 + if: always() + with: + name: be-test-results + path: | + ./backend/reports + ./backend/coverage + - name: ๐Ÿ—๏ธ Run build run: npm run build working-directory: backend diff --git a/.github/workflows/close_inactive_issues.yml b/.github/workflows/close_inactive_issues.yml deleted file mode 100644 index 315c9e929..000000000 --- a/.github/workflows/close_inactive_issues.yml +++ /dev/null @@ -1,22 +0,0 @@ -name: Close inactive issues -on: - schedule: - - cron: "30 1 * * *" - -jobs: - close-issues: - runs-on: ubuntu-latest - permissions: - issues: write - pull-requests: write - steps: - - uses: actions/stale@v4 - with: - days-before-issue-stale: 30 - days-before-issue-close: 14 - stale-issue-label: "stale" - stale-issue-message: "This issue is stale because it has been open for 30 days with no activity." - close-issue-message: "This issue was closed because it has been inactive for 14 days since being marked as stale." - days-before-pr-stale: -1 - days-before-pr-close: -1 - repo-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index 1e836a178..b4f9546ae 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -1,5 +1,4 @@ -name: Push to Docker Hub - +name: Build, Publish and Deploy to Gamma on: [workflow_dispatch] jobs: @@ -10,8 +9,9 @@ jobs: steps: - name: โ˜๏ธ Checkout source uses: actions/checkout@v3 - - name: ๐Ÿ”ง Set up QEMU - uses: docker/setup-qemu-action@v2 + - name: Save commit hashes for tag + id: commit + uses: pr-mpt/actions-commit-hash@v2 - name: ๐Ÿ”ง Set up Docker Buildx uses: docker/setup-buildx-action@v2 - name: ๐Ÿ‹ Login to Docker Hub @@ -19,9 +19,13 @@ jobs: with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: Set up Depot CLI + uses: depot/setup-action@v1 - name: ๐Ÿ“ฆ Build backend and export to Docker - uses: docker/build-push-action@v3 + uses: depot/build-push-action@v1 with: + project: 64mmf0n610 + token: ${{ secrets.DEPOT_PROJECT_TOKEN }} load: true context: backend tags: infisical/backend:test @@ -35,11 +39,14 @@ jobs: run: | docker compose -f .github/resources/docker-compose.be-test.yml down - name: ๐Ÿ—๏ธ Build backend and push - uses: docker/build-push-action@v3 + uses: depot/build-push-action@v1 with: + project: 64mmf0n610 + token: ${{ secrets.DEPOT_PROJECT_TOKEN }} push: true context: backend - tags: infisical/backend:latest + tags: infisical/backend:${{ steps.commit.outputs.short }}, + infisical/backend:latest platforms: linux/amd64,linux/arm64 frontend-image: @@ -49,8 +56,9 @@ jobs: steps: - name: โ˜๏ธ Checkout source uses: actions/checkout@v3 - - name: ๐Ÿ”ง Set up QEMU - uses: docker/setup-qemu-action@v2 + - name: Save commit hashes for tag + id: commit + uses: pr-mpt/actions-commit-hash@v2 - name: ๐Ÿ”ง Set up Docker Buildx uses: docker/setup-buildx-action@v2 - name: ๐Ÿ‹ Login to Docker Hub @@ -58,10 +66,14 @@ jobs: with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: Set up Depot CLI + uses: depot/setup-action@v1 - name: ๐Ÿ“ฆ Build frontend and export to Docker - uses: docker/build-push-action@v3 + uses: depot/build-push-action@v1 with: load: true + token: ${{ secrets.DEPOT_PROJECT_TOKEN }} + project: 64mmf0n610 context: frontend tags: infisical/frontend:test build-args: | @@ -76,11 +88,51 @@ jobs: run: | docker stop infisical-frontend-test - name: ๐Ÿ—๏ธ Build frontend and push - uses: docker/build-push-action@v3 + uses: depot/build-push-action@v1 with: + project: 64mmf0n610 push: true + token: ${{ secrets.DEPOT_PROJECT_TOKEN }} context: frontend - tags: infisical/frontend:latest + tags: infisical/frontend:${{ steps.commit.outputs.short }}, + infisical/frontend:latest platforms: linux/amd64,linux/arm64 build-args: | POSTHOG_API_KEY=${{ secrets.PUBLIC_POSTHOG_API_KEY }} + gamma-deployment: + name: Deploy to gamma + runs-on: ubuntu-latest + needs: [frontend-image, backend-image] + steps: + - name: โ˜๏ธ Checkout source + uses: actions/checkout@v3 + - name: Install Helm + uses: azure/setup-helm@v3 + with: + version: v3.10.0 + - name: Install infisical helm chart + run: | + helm repo add infisical-helm-charts 'https://dl.cloudsmith.io/public/infisical/helm-charts/helm/charts/' + helm repo update + - name: Install kubectl + uses: azure/setup-kubectl@v3 + - name: Install doctl + uses: digitalocean/action-doctl@v2 + with: + token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }} + - name: Save DigitalOcean kubeconfig with short-lived credentials + run: doctl kubernetes cluster kubeconfig save --expiry-seconds 600 k8s-1-25-4-do-0-nyc1-1670645170179 + - name: switch to gamma namespace + run: kubectl config set-context --current --namespace=gamma + - name: test kubectl + run: kubectl get ingress + - name: Download helm values to file and upgrade gamma deploy + run: | + wget https://raw.githubusercontent.com/Infisical/infisical/main/.github/values.yaml + helm upgrade infisical infisical-helm-charts/infisical --values values.yaml --recreate-pods + if [[ $(helm status infisical) == *"FAILED"* ]]; then + echo "Helm upgrade failed" + exit 1 + else + echo "Helm upgrade was successful" + fi \ No newline at end of file diff --git a/.github/workflows/release_build.yml b/.github/workflows/release_build.yml index 695b0ea24..3d11a1157 100644 --- a/.github/workflows/release_build.yml +++ b/.github/workflows/release_build.yml @@ -1,4 +1,4 @@ -name: Go releaser +name: Build and release CLI on: push: @@ -13,25 +13,36 @@ permissions: jobs: goreleaser: - runs-on: ubuntu-latest + runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v3 with: fetch-depth: 0 - run: git fetch --force --tags + - run: echo "Ref name ${{github.ref_name}}" - uses: actions/setup-go@v3 with: go-version: '>=1.19.3' cache: true cache-dependency-path: cli/go.sum - - uses: goreleaser/goreleaser-action@v2 + - name: libssl1.1 => libssl1.0-dev for OSXCross + run: | + echo 'deb http://security.ubuntu.com/ubuntu bionic-security main' | sudo tee -a /etc/apt/sources.list + sudo apt update && apt-cache policy libssl1.0-dev + sudo apt-get install libssl1.0-dev + - name: OSXCross for CGO Support + run: | + mkdir ../../osxcross + git clone https://github.com/plentico/osxcross-target.git ../../osxcross/target + - uses: goreleaser/goreleaser-action@v4 with: distribution: goreleaser version: latest - args: release --rm-dist + args: release --clean env: GITHUB_TOKEN: ${{ secrets.GO_RELEASER_GITHUB_TOKEN }} FURY_TOKEN: ${{ secrets.FURYPUSHTOKEN }} + AUR_KEY: ${{ secrets.AUR_KEY }} - uses: actions/setup-python@v4 - run: pip install --upgrade cloudsmith-cli - name: Publish to CloudSmith diff --git a/.github/workflows/release_docker_k8_operator.yaml b/.github/workflows/release_docker_k8_operator.yaml index 01aa3b625..788d414b6 100644 --- a/.github/workflows/release_docker_k8_operator.yaml +++ b/.github/workflows/release_docker_k8_operator.yaml @@ -26,13 +26,4 @@ jobs: context: k8-operator push: true platforms: linux/amd64,linux/arm64 - tags: infisical/kubernetes-operator:latest - - - uses: actions/setup-go@v2 - - - name: Upload CRD manifest - uses: svenstaro/upload-release-action@v2 - with: - repo_token: ${{ secrets.GITHUB_TOKEN }} - file: dist/install-secrets-operator.yaml - tag: ${{ github.ref }} \ No newline at end of file + tags: infisical/kubernetes-operator:latest \ No newline at end of file diff --git a/.gitignore b/.gitignore index f32a51384..b8341e81b 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,8 @@ node_modules .DS_Store /dist +/completions/ +/manpages/ # frontend @@ -25,7 +27,9 @@ node_modules .env # testing -/coverage +coverage +reports +junit.xml # next.js /.next/ diff --git a/.goreleaser.yaml b/.goreleaser.yaml index e83973397..fc39224aa 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -6,43 +6,76 @@ # - cd cli && go mod tidy # # you may remove this if you don't need go generate # - cd cli && go generate ./... +before: + hooks: + - ./cli/scripts/completions.sh + - ./cli/scripts/manpages.sh + builds: - - env: - - CGO_ENABLED=0 + - id: darwin-build binary: infisical - id: infisical + ldflags: -X github.com/Infisical/infisical-merge/packages/util.CLI_VERSION={{ .Version }} + flags: + - -trimpath + env: + - CGO_ENABLED=1 + - CC=/home/runner/work/osxcross/target/bin/o64-clang + - CXX=/home/runner/work/osxcross/target/bin/o64-clang++ goos: - darwin + ignore: + - goos: darwin + goarch: "386" + dir: ./cli + + - id: all-other-builds + env: + - CGO_ENABLED=0 + binary: infisical + ldflags: -X github.com/Infisical/infisical-merge/packages/util.CLI_VERSION={{ .Version }} + flags: + - -trimpath + goos: - freebsd - linux - netbsd - openbsd - windows goarch: - - 386 + - "386" - amd64 - arm - arm64 goarm: - - 6 - - 7 + - "6" + - "7" ignore: - - goos: darwin - goarch: "386" - goos: windows goarch: "386" - goos: freebsd goarch: "386" dir: ./cli +archives: + - format_overrides: + - goos: windows + format: zip + files: + - README* + - LICENSE* + - manpages/* + - completions/* + release: replace_existing_draft: true mode: 'replace' checksum: name_template: 'checksums.txt' + snapshot: - name_template: "{{ incpatch .Version }}" + name_template: "{{ incpatch .Version }}-devel" + changelog: sort: asc filters: @@ -56,6 +89,7 @@ changelog: # - infisical # dir: "{{ dir .ArtifactPath }}" # cmd: curl -F package=@{{ .ArtifactName }} https://{{ .Env.FURY_TOKEN }}@push.fury.io/infisical/ + brews: - name: infisical tap: @@ -67,21 +101,39 @@ brews: folder: Formula homepage: "https://infisical.com" description: "The official Infisical CLI" + install: |- + bin.install "infisical" + bash_completion.install "completions/infisical.bash" => "infisical" + zsh_completion.install "completions/infisical.zsh" => "_infisical" + fish_completion.install "completions/infisical.fish" + man1.install "manpages/infisical.1.gz" + nfpms: - id: infisical package_name: infisical builds: - - infisical + - all-other-builds vendor: Infisical, Inc homepage: https://infisical.com/ maintainer: Infisical, Inc description: The offical Infisical CLI - license: Apache 2.0 + license: MIT formats: - rpm - deb - apk + - archlinux bindir: /usr/bin + contents: + - src: ./completions/infisical.bash + dst: /etc/bash_completion.d/infisical + - src: ./completions/infisical.fish + dst: /usr/share/fish/vendor_completions.d/infisical.fish + - src: ./completions/infisical.zsh + dst: /usr/share/zsh/site-functions/_infisical + - src: ./manpages/infisical.1.gz + dst: /usr/share/man/man1/infisical.1.gz + scoop: bucket: owner: Infisical @@ -91,7 +143,32 @@ scoop: email: ai@infisical.com homepage: "https://infisical.com" description: "The official Infisical CLI" - license: Apache-2.0 + license: MIT + +aurs: + - + name: infisical-bin + homepage: "https://infisical.com" + description: "The official Infisical CLI" + maintainers: + - Infisical, Inc + license: MIT + private_key: '{{ .Env.AUR_KEY }}' + git_url: 'ssh://aur@aur.archlinux.org/infisical-bin.git' + package: |- + # bin + install -Dm755 "./infisical" "${pkgdir}/usr/bin/infisical" + # license + install -Dm644 "./LICENSE" "${pkgdir}/usr/share/licenses/infisical/LICENSE" + # completions + mkdir -p "${pkgdir}/usr/share/bash-completion/completions/" + mkdir -p "${pkgdir}/usr/share/zsh/site-functions/" + mkdir -p "${pkgdir}/usr/share/fish/vendor_completions.d/" + install -Dm644 "./completions/infisical.bash" "${pkgdir}/usr/share/bash-completion/completions/infisical" + install -Dm644 "./completions/infisical.zsh" "${pkgdir}/usr/share/zsh/site-functions/infisical" + install -Dm644 "./completions/infisical.fish" "${pkgdir}/usr/share/fish/vendor_completions.d/infisical.fish" + # man pages + install -Dm644 "./manpages/infisical.1.gz" "${pkgdir}/usr/share/man/man1/infisical.1.gz" # dockers: # - dockerfile: goreleaser.dockerfile # goos: linux diff --git a/.prettierrc b/.prettierrc deleted file mode 100644 index fa81e63de..000000000 --- a/.prettierrc +++ /dev/null @@ -1,7 +0,0 @@ -{ - "semi": true, - "trailingComma": "none", - "singleQuote": true, - "printWidth": 80, - "useTabs": false -} diff --git a/Makefile b/Makefile index 266eaf9b5..7ef83d948 100644 --- a/Makefile +++ b/Makefile @@ -7,6 +7,9 @@ push: up-dev: docker-compose -f docker-compose.dev.yml up --build +i-dev: + infisical run -- docker-compose -f docker-compose.dev.yml up --build + up-prod: docker-compose -f docker-compose.yml up --build diff --git a/README.md b/README.md index ba76997f1..1ec8cff50 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ infisical

-

Open-source, E2EE, simple tool to manage and sync environment variables across your team and infrastructure.

+

Open-source, E2EE, simple tool to manage secrets and configs across your team and infrastructure.

@@ -21,30 +21,45 @@ PRs welcome! - + git commit activity + + Cloudsmith downloads + Slack community channel + + Infisical Twitter +

Dashboard -**[Infisical](https://infisical.com)** is an open source, E2EE tool to help teams manage and sync environment variables across their development workflow and infrastructure. It's designed to be simple and take minutes to get going. -- **[User-Friendly Dashboard](https://infisical.com/docs/getting-started/dashboard/project)** to manage your team's environment variables within projects -- **[Language-Agnostic CLI](https://infisical.com/docs/cli/overview)** that pulls and injects environment variables into your local workflow +**Read this in other languages**: [English language](i18n/README.en.md) +[Spanish language](i18n/README.es.md) +[Korean language](i18n/README.ko.md) +[Turkish language](i18n/README.tr.md) + +**[Infisical](https://infisical.com)** is an open source, E2EE tool to help teams manage and sync secrets and configs across their development workflow and infrastructure. It's designed to be simple and take minutes to get going. + +- **[User-Friendly Dashboard](https://infisical.com/docs/getting-started/dashboard/project)** to manage your team's secrets and configs within projects +- **[Language-Agnostic CLI](https://infisical.com/docs/cli/overview)** that pulls and injects esecrets and configs into your local workflow - **[Complete control over your data](https://infisical.com/docs/self-hosting/overview)** - host it yourself on any infrastructure - **Navigate Multiple Environments** per project (e.g. development, staging, production, etc.) -- **Personal/Shared** scoping for environment variables -- **[Integrations](https://infisical.com/docs/integrations/overview)** with CI/CD and production infrastructure (Heroku available, more coming soon) +- **Personal overrides** for secrets and configs +- **[Integrations](https://infisical.com/docs/integrations/overview)** with CI/CD and production infrastructure +- **[Infisical API](https://infisical.com/docs/api-reference/overview/introduction)** - manage secrets via HTTPS requests to the platform +- **[Secret Versioning](https://infisical.com/docs/getting-started/dashboard/versioning)** to view the change history for any secret +- **[Activity Logs](https://infisical.com/docs/getting-started/dashboard/audit-logs)** to record every action taken in a project +- **[Point-in-time Secrets Recovery](https://infisical.com/docs/getting-started/dashboard/pit-recovery)** for rolling back to any snapshot of your secrets +- **Role-based Access Controls** per environment +- ๐Ÿ”œ **2FA** (next week) - ๐Ÿ”œ **1-Click Deploy** to Digital Ocean and Heroku -- ๐Ÿ”œ **Authentication/Authorization** for projects (read/write controls soon) - ๐Ÿ”œ **Automatic Secret Rotation** -- ๐Ÿ”œ **2FA** -- ๐Ÿ”œ **Access Logs** -- ๐Ÿ”œ **Slack Integration & MS Teams** integrations +- ๐Ÿ”œ **Slack & MS Teams** integrations And more. @@ -62,7 +77,7 @@ To quickly get started, visit our [get started guide](https://infisical.com/docs Infisical makes secret management simple and end-to-end encrypted by default. We're on a mission to make it more accessible to all developers, not just security teams. -According to a [report](https://www.ekransystem.com/en/blog/secrets-management) in 2019, only 10% of organizations use secret management solutions despite all using digital secrets to some extent. +According to a [report](https://www.ekransystem.com/en/blog/secrets-management), only 10% of organizations use secret management solutions despite all using digital secrets to some extent. If you care about efficiency and security, then Infisical is right for you. @@ -84,21 +99,13 @@ Not sure where to get started? You can: - [GitHub Issues](https://github.com/Infisical/infisical-cli/issues) (For any bugs and errors you encounter using Infisical) - [Twitter](https://twitter.com/infisical) (Get news fast) -## ๐Ÿฅ Status +## ๐ŸŒ„ Status -- [x] Public Alpha: Anyone can sign up over at [infisical.com](https://infisical.com) but go easy on us, there are kinks and we're just getting started. +- [x] Public Alpha: Anyone can sign up over at [infisical.com](https://infisical.com) but there are some minor kinks. - [ ] Public Beta: Stable enough for most non-enterprise use-cases. - [ ] Public: Production-ready. -We're currently in Public Alpha. - -## ๐Ÿšจ Stay Up-to-Date - -Infisical officially launched as v.1.0 on November 21st, 2022. However, a lot of new features are coming very quickly. Watch **releases** of this repository to be notified about future updates: - -![infisical-star-github](https://github.com/Infisical/infisical/blob/main/.github/images/star-infisical.gif?raw=true) - -## ๐Ÿ”Œ Integrations +## ๏ฟฝ๐Ÿ”Œ Integrations We're currently setting the foundation and building [integrations](https://infisical.com/docs/integrations/overview) so secrets can be synced everywhere. Any help is welcome! :) @@ -131,35 +138,43 @@ We're currently setting the foundation and building [integrations](https://infis - ๐Ÿ”œ Vercel (https://github.com/Infisical/infisical/issues/60) + + โœ”๏ธ Vercel + - ๐Ÿ”œ GitLab CI/CD + + โœ”๏ธ Kubernetes + - ๐Ÿ”œ Fly.io + + โœ”๏ธ Fly.io + - ๐Ÿ”œ AWS + ๐Ÿ”œ AWS PS (https://github.com/Infisical/infisical/issues/286) - ๐Ÿ”œ GitHub Actions (https://github.com/Infisical/infisical/issues/54) + + โœ”๏ธ GitHub Actions + - ๐Ÿ”œ Railway + ๐Ÿ”œ Railway (https://github.com/Infisical/infisical/issues/271) - ๐Ÿ”œ GCP + ๐Ÿ”œ GCP SM (https://github.com/Infisical/infisical/issues/285) - ๐Ÿ”œ Kubernetes + ๐Ÿ”œ GitLab CI/CD (https://github.com/Infisical/infisical/issues/134) - ๐Ÿ”œ CircleCI + ๐Ÿ”œ CircleCI (https://github.com/Infisical/infisical/issues/91) @@ -178,10 +193,12 @@ We're currently setting the foundation and building [integrations](https://infis ๐Ÿ”œ TravisCI - ๐Ÿ”œ Netlify (https://github.com/Infisical/infisical/issues/55) + + โœ”๏ธ Netlify + - ๐Ÿ”œ Railway + ๐Ÿ”œ Forge @@ -191,9 +208,22 @@ We're currently setting the foundation and building [integrations](https://infis ๐Ÿ”œ Supabase + + + โœ”๏ธ Render + + + + + + ๐Ÿ”œ BuddyCI + ๐Ÿ”œ Serverless + + ๐Ÿ”œ AWS Lambda + @@ -265,13 +295,13 @@ We're currently setting the foundation and building [integrations](https://infis - - โœ”๏ธ Ruby on Rails + + โœ”๏ธ Vue - - โœ”๏ธ Vue + + โœ”๏ธ Ruby on Rails @@ -287,6 +317,16 @@ We're currently setting the foundation and building [integrations](https://infis + + + + โœ”๏ธ .NET + + + + And more... + + @@ -302,6 +342,12 @@ This repo is entirely MIT licensed, with the exception of the `ee` directory whi Looking to report a security vulnerability? Please don't post about it in GitHub issue. Instead, refer to our [SECURITY.md](./SECURITY.md) file. +## ๐Ÿšจ Stay Up-to-Date + +Infisical officially launched as v.1.0 on November 21st, 2022. There are a lot of new features coming very frequently. Watch **releases** of this repository to be notified about future updates: + +![infisical-star-github](https://github.com/Infisical/infisical/blob/main/.github/images/star-infisical.gif?raw=true) + ## ๐Ÿฆธ Contributors [//]: contributor-faces @@ -310,4 +356,10 @@ Looking to report a security vulnerability? Please don't post about it in GitHub - + + +## ๐ŸŒŽ Translations + +Infisical is currently available in English, Korean, French, and Portuguese (Brazil). Help us translate Infisical to your language! + +You can find all the info in [this issue](https://github.com/Infisical/infisical/issues/181). diff --git a/backend/.eslintrc b/backend/.eslintrc index 7fe198901..c1ca1a1eb 100644 --- a/backend/.eslintrc +++ b/backend/.eslintrc @@ -1,11 +1,10 @@ { "parser": "@typescript-eslint/parser", - "plugins": ["@typescript-eslint", "prettier"], + "plugins": ["@typescript-eslint"], "extends": [ "eslint:recommended", "plugin:@typescript-eslint/eslint-recommended", - "plugin:@typescript-eslint/recommended", - "prettier" + "plugin:@typescript-eslint/recommended" ], "rules": { "no-console": 2 diff --git a/backend/Dockerfile b/backend/Dockerfile index ccc76e66e..e4d283a77 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -4,12 +4,15 @@ WORKDIR /app COPY package.json package-lock.json ./ +# RUN npm ci --only-production --ignore-scripts +# "prepare": "cd .. && npm install" + RUN npm ci --only-production COPY . . HEALTHCHECK --interval=10s --timeout=3s --start-period=10s \ - CMD node healthcheck.js + CMD node healthcheck.js CMD ["npm", "run", "start"] diff --git a/backend/__tests__/healthcheck.test.ts b/backend/__tests__/healthcheck.test.ts new file mode 100644 index 000000000..234d2d8eb --- /dev/null +++ b/backend/__tests__/healthcheck.test.ts @@ -0,0 +1,19 @@ +import { server } from '../src/app'; +import { describe, expect, it, beforeAll, afterAll } from '@jest/globals'; +import supertest from 'supertest'; +import { setUpHealthEndpoint } from '../src/services/health'; + +const requestWithSupertest = supertest(server); +describe('Healthcheck endpoint', () => { + beforeAll(async () => { + setUpHealthEndpoint(server); + }); + afterAll(async () => { + server.close(); + }); + + it('GET /healthcheck should return OK', async () => { + const res = await requestWithSupertest.get('/healthcheck'); + expect(res.status).toEqual(200); + }); +}); diff --git a/backend/environment.d.ts b/backend/environment.d.ts index 33827fb2b..8012416f6 100644 --- a/backend/environment.d.ts +++ b/backend/environment.d.ts @@ -3,8 +3,10 @@ export {}; declare global { namespace NodeJS { interface ProcessEnv { + PORT: string; EMAIL_TOKEN_LIFETIME: string; ENCRYPTION_KEY: string; + SALT_ROUNDS: string; JWT_AUTH_LIFETIME: string; JWT_AUTH_SECRET: string; JWT_REFRESH_LIFETIME: string; @@ -14,24 +16,36 @@ declare global { JWT_SIGNUP_SECRET: string; MONGO_URL: string; NODE_ENV: 'development' | 'staging' | 'testing' | 'production'; - OAUTH_CLIENT_SECRET_HEROKU: string; - OAUTH_TOKEN_URL_HEROKU: string; + VERBOSE_ERROR_OUTPUT: string; + LOKI_HOST: string; + CLIENT_ID_HEROKU: string; + CLIENT_ID_VERCEL: string; + CLIENT_ID_NETLIFY: string; + CLIENT_ID_GITHUB: string; + CLIENT_SECRET_HEROKU: string; + CLIENT_SECRET_VERCEL: string; + CLIENT_SECRET_NETLIFY: string; + CLIENT_SECRET_GITHUB: string; + CLIENT_SLUG_VERCEL: string; POSTHOG_HOST: string; POSTHOG_PROJECT_API_KEY: string; - PRIVATE_KEY: string; - PUBLIC_KEY: string; SENTRY_DSN: string; SITE_URL: string; SMTP_HOST: string; - SMTP_NAME: string; - SMTP_PASSWORD: string; + SMTP_SECURE: string; + SMTP_PORT: string; SMTP_USERNAME: string; - STRIPE_PRODUCT_CARD_AUTH: string; - STRIPE_PRODUCT_PRO: string; + SMTP_PASSWORD: string; + SMTP_FROM_ADDRESS: string; + SMTP_FROM_NAME: string; STRIPE_PRODUCT_STARTER: string; + STRIPE_PRODUCT_TEAM: string; + STRIPE_PRODUCT_PRO: string; STRIPE_PUBLISHABLE_KEY: string; STRIPE_SECRET_KEY: string; STRIPE_WEBHOOK_SECRET: string; + TELEMETRY_ENABLED: string; + LICENSE_KEY: string; } } } diff --git a/backend/package-lock.json b/backend/package-lock.json index c85f9155d..6703e198f 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -11,10 +11,15 @@ "dependencies": { "@godaddy/terminus": "^4.11.2", "@sentry/node": "^7.21.1", - "@sentry/tracing": "^7.19.0", + "@octokit/rest": "^19.0.5", + "@sentry/tracing": "^7.21.1", "@types/crypto-js": "^4.1.1", - "axios": "^1.1.3", + "axios": "^1.2.0", + "@types/libsodium-wrappers": "^0.7.10", + "await-to-js": "^3.0.0", + "bcrypt": "^5.1.0", "bigint-conversion": "^2.2.2", + "builder-pattern": "^2.2.0", "cookie-parser": "^1.4.6", "cors": "^2.8.5", "crypto-js": "^4.1.1", @@ -24,38 +29,54 @@ "express-validator": "^6.14.2", "handlebars": "^4.7.7", "helmet": "^5.1.1", - "jsonwebtoken": "^8.5.1", + "js-yaml": "^4.1.0", + "jsonwebtoken": "^9.0.0", "jsrp": "^0.2.4", - "mongoose": "^6.7.2", + "mongoose": "^6.7.3", + "libsodium-wrappers": "^0.7.10", + "lodash": "^4.17.21", "nodemailer": "^6.8.0", - "posthog-node": "^2.1.0", + "posthog-node": "^2.2.2", "query-string": "^7.1.3", + "request-ip": "^3.3.0", "rimraf": "^3.0.2", "stripe": "^10.7.0", + "swagger-autogen": "^2.22.0", + "swagger-ui-express": "^4.6.0", "tweetnacl": "^1.0.3", "tweetnacl-util": "^0.15.1", - "typescript": "^4.9.3" + "typescript": "^4.9.3", + "utility-types": "^3.10.0", + "winston": "^3.8.2", + "winston-loki": "^6.0.6" }, "devDependencies": { + "@jest/globals": "^29.3.1", "@posthog/plugin-scaffold": "^1.3.4", + "@types/bcrypt": "^5.0.0", + "@types/bcryptjs": "^2.4.2", "@types/cookie-parser": "^1.4.3", "@types/cors": "^2.8.12", "@types/express": "^4.17.14", + "@types/jest": "^29.2.4", "@types/jsonwebtoken": "^8.5.9", + "@types/lodash": "^4.14.191", "@types/node": "^18.11.3", "@types/nodemailer": "^6.4.6", + "@types/supertest": "^2.0.12", "@types/swagger-jsdoc": "^6.0.1", "@types/swagger-ui-express": "^4.1.3", "@typescript-eslint/eslint-plugin": "^5.40.1", "@typescript-eslint/parser": "^5.40.1", + "cross-env": "^7.0.3", "eslint": "^8.26.0", - "eslint-config-prettier": "^8.5.0", - "eslint-plugin-prettier": "^4.2.1", "install": "^0.13.0", "jest": "^29.3.1", + "jest-junit": "^15.0.0", "nodemon": "^2.0.19", "npm": "^8.19.3", - "prettier": "^2.7.1", + "supertest": "^6.3.3", + "ts-jest": "^29.0.3", "ts-node": "^10.9.1" } }, @@ -1076,6 +1097,7 @@ "version": "3.188.0", "resolved": "https://registry.npmjs.org/@aws-sdk/util-base64-browser/-/util-base64-browser-3.188.0.tgz", "integrity": "sha512-qlH+5NZBLiyKziL335BEPedYxX6j+p7KFRWXvDQox9S+s+gLCayednpK+fteOhBenCcR9fUZOVuAPScy1I8qCg==", + "deprecated": "The package @aws-sdk/util-base64-browser has been renamed to @aws-sdk/util-base64. Please install the renamed package.", "optional": true, "dependencies": { "tslib": "^2.3.1" @@ -1091,6 +1113,7 @@ "version": "3.201.0", "resolved": "https://registry.npmjs.org/@aws-sdk/util-base64-node/-/util-base64-node-3.201.0.tgz", "integrity": "sha512-ydZqNpB3l5kiicInpPDExPb5xHI7uyVIa1vMupnuIrJ412iNb0F2+K8LlFynzw6fSJShVKnqFcWOYRA96z1iIw==", + "deprecated": "The package @aws-sdk/util-base64-node has been renamed to @aws-sdk/util-base64. Please install the renamed package.", "optional": true, "dependencies": { "@aws-sdk/util-buffer-from": "3.201.0", @@ -1994,6 +2017,14 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "engines": { + "node": ">=0.1.90" + } + }, "node_modules/@cspotcode/source-map-support": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", @@ -2006,6 +2037,16 @@ "node": ">=12" } }, + "node_modules/@dabh/diagnostics": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", + "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", + "dependencies": { + "colorspace": "1.1.x", + "enabled": "2.0.x", + "kuler": "^2.0.0" + } + }, "node_modules/@eslint/eslintrc": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.3.tgz", @@ -2547,6 +2588,39 @@ "resolved": "https://registry.npmjs.org/@juanelas/base64/-/base64-1.0.5.tgz", "integrity": "sha512-gTIElNo4ohMcYUZzol/Hb6DYJzphxl0b1B4egJJ+JiqxqcOcWx4XLMAB+lhWuMsMX3uR1oc5hwPusU3lgc1FkQ==" }, + "node_modules/@mapbox/node-pre-gyp": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.10.tgz", + "integrity": "sha512-4ySo4CjzStuprMwk35H5pPbkymjv1SF3jGLj6rAHp/xT/RF7TL7bd9CTm1xDY49K2qF7jmR/g7k+SkLETP6opA==", + "dependencies": { + "detect-libc": "^2.0.0", + "https-proxy-agent": "^5.0.0", + "make-dir": "^3.1.0", + "node-fetch": "^2.6.7", + "nopt": "^5.0.0", + "npmlog": "^5.0.1", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.11" + }, + "bin": { + "node-pre-gyp": "bin/node-pre-gyp" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/@maxmind/geoip2-node": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/@maxmind/geoip2-node/-/geoip2-node-3.5.0.tgz", @@ -2558,6 +2632,21 @@ "maxmind": "^4.2.0" } }, + "node_modules/@napi-rs/snappy-darwin-arm64": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/snappy-darwin-arm64/-/snappy-darwin-arm64-7.1.1.tgz", + "integrity": "sha512-3LZyoAw3Qa5F7sCCTkSkhmGlydwUKU6L3Jl46eKHO2Ctm8Gcjxww6T7MfwlwGZ6JqAM6d1d++WLzUZPCGXVmag==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -2593,6 +2682,153 @@ "node": ">= 8" } }, + "node_modules/@octokit/auth-token": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-3.0.2.tgz", + "integrity": "sha512-pq7CwIMV1kmzkFTimdwjAINCXKTajZErLB4wMLYapR2nuB/Jpr66+05wOTZMSCBXP6n4DdDWT2W19Bm17vU69Q==", + "dependencies": { + "@octokit/types": "^8.0.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@octokit/core": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@octokit/core/-/core-4.1.0.tgz", + "integrity": "sha512-Czz/59VefU+kKDy+ZfDwtOIYIkFjExOKf+HA92aiTZJ6EfWpFzYQWw0l54ji8bVmyhc+mGaLUbSUmXazG7z5OQ==", + "dependencies": { + "@octokit/auth-token": "^3.0.0", + "@octokit/graphql": "^5.0.0", + "@octokit/request": "^6.0.0", + "@octokit/request-error": "^3.0.0", + "@octokit/types": "^8.0.0", + "before-after-hook": "^2.2.0", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@octokit/endpoint": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-7.0.3.tgz", + "integrity": "sha512-57gRlb28bwTsdNXq+O3JTQ7ERmBTuik9+LelgcLIVfYwf235VHbN9QNo4kXExtp/h8T423cR5iJThKtFYxC7Lw==", + "dependencies": { + "@octokit/types": "^8.0.0", + "is-plain-object": "^5.0.0", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@octokit/graphql": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-5.0.4.tgz", + "integrity": "sha512-amO1M5QUQgYQo09aStR/XO7KAl13xpigcy/kI8/N1PnZYSS69fgte+xA4+c2DISKqUZfsh0wwjc2FaCt99L41A==", + "dependencies": { + "@octokit/request": "^6.0.0", + "@octokit/types": "^8.0.0", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@octokit/openapi-types": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-14.0.0.tgz", + "integrity": "sha512-HNWisMYlR8VCnNurDU6os2ikx0s0VyEjDYHNS/h4cgb8DeOxQ0n72HyinUtdDVxJhFy3FWLGl0DJhfEWk3P5Iw==" + }, + "node_modules/@octokit/plugin-paginate-rest": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-5.0.1.tgz", + "integrity": "sha512-7A+rEkS70pH36Z6JivSlR7Zqepz3KVucEFVDnSrgHXzG7WLAzYwcHZbKdfTXHwuTHbkT1vKvz7dHl1+HNf6Qyw==", + "dependencies": { + "@octokit/types": "^8.0.0" + }, + "engines": { + "node": ">= 14" + }, + "peerDependencies": { + "@octokit/core": ">=4" + } + }, + "node_modules/@octokit/plugin-request-log": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.4.tgz", + "integrity": "sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA==", + "peerDependencies": { + "@octokit/core": ">=3" + } + }, + "node_modules/@octokit/plugin-rest-endpoint-methods": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-6.7.0.tgz", + "integrity": "sha512-orxQ0fAHA7IpYhG2flD2AygztPlGYNAdlzYz8yrD8NDgelPfOYoRPROfEyIe035PlxvbYrgkfUZIhSBKju/Cvw==", + "dependencies": { + "@octokit/types": "^8.0.0", + "deprecation": "^2.3.1" + }, + "engines": { + "node": ">= 14" + }, + "peerDependencies": { + "@octokit/core": ">=3" + } + }, + "node_modules/@octokit/request": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-6.2.2.tgz", + "integrity": "sha512-6VDqgj0HMc2FUX2awIs+sM6OwLgwHvAi4KCK3mT2H2IKRt6oH9d0fej5LluF5mck1lRR/rFWN0YIDSYXYSylbw==", + "dependencies": { + "@octokit/endpoint": "^7.0.0", + "@octokit/request-error": "^3.0.0", + "@octokit/types": "^8.0.0", + "is-plain-object": "^5.0.0", + "node-fetch": "^2.6.7", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@octokit/request-error": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-3.0.2.tgz", + "integrity": "sha512-WMNOFYrSaX8zXWoJg9u/pKgWPo94JXilMLb2VManNOby9EZxrQaBe/QSC4a1TzpAlpxofg2X/jMnCyZgL6y7eg==", + "dependencies": { + "@octokit/types": "^8.0.0", + "deprecation": "^2.0.0", + "once": "^1.4.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@octokit/rest": { + "version": "19.0.5", + "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-19.0.5.tgz", + "integrity": "sha512-+4qdrUFq2lk7Va+Qff3ofREQWGBeoTKNqlJO+FGjFP35ZahP+nBenhZiGdu8USSgmq4Ky3IJ/i4u0xbLqHaeow==", + "dependencies": { + "@octokit/core": "^4.1.0", + "@octokit/plugin-paginate-rest": "^5.0.0", + "@octokit/plugin-request-log": "^1.0.4", + "@octokit/plugin-rest-endpoint-methods": "^6.7.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@octokit/types": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-8.0.0.tgz", + "integrity": "sha512-65/TPpOJP1i3K4lBJMnWqPUJ6zuOtzhtagDvydAWbEXpbFYA0oMKKyLb95NFZZP0lSh/4b6K+DQlzvYQJQQePg==", + "dependencies": { + "@octokit/openapi-types": "^14.0.0" + } + }, "node_modules/@posthog/plugin-scaffold": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/@posthog/plugin-scaffold/-/plugin-scaffold-1.3.4.tgz", @@ -2615,6 +2851,90 @@ "node": ">=8" } }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==" + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" + }, + "node_modules/@sentry/node": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@sentry/node/-/node-7.19.0.tgz", + "integrity": "sha512-yG7Tx32WqOkEHVotFLrumCcT9qlaSDTkFNZ+yLSvZXx74ifsE781DzBA9W7K7bBdYO3op+p2YdsOKzf3nPpAyQ==", + "dependencies": { + "@sentry/core": "7.19.0", + "@sentry/types": "7.19.0", + "@sentry/utils": "7.19.0", + "cookie": "^0.4.1", + "https-proxy-agent": "^5.0.0", + "lru_map": "^0.3.3", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@sentry/node/node_modules/@sentry/core": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.19.0.tgz", + "integrity": "sha512-YF9cTBcAnO4R44092BJi5Wa2/EO02xn2ziCtmNgAVTN2LD31a/YVGxGBt/FDr4Y6yeuVehaqijVVvtpSmXrGJw==", + "dependencies": { + "@sentry/types": "7.21.1", + "@sentry/utils": "7.21.1", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/@sentry/node": { "version": "7.21.1", "resolved": "https://registry.npmjs.org/@sentry/node/-/node-7.21.1.tgz", @@ -2633,46 +2953,33 @@ } }, "node_modules/@sentry/tracing": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-7.19.0.tgz", - "integrity": "sha512-SWY17M3TsgBePaGowUcSqBwaT0TJQzuNexVnLojuU0k6F57L9hubvP9zaoosoCfARXQ/3NypAFWnlJyf570rFQ==", + "version": "7.21.1", + "resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-7.21.1.tgz", + "integrity": "sha512-b1BTPsRaNQpohzegoz59KGuBl+To651vEq0vMS4tCzSyIdxkYso3JCrjDdEqW/2MliQYANNVrUai2bmwmU9h1g==", "dependencies": { - "@sentry/core": "7.19.0", - "@sentry/types": "7.19.0", - "@sentry/utils": "7.19.0", + "@sentry/core": "7.21.1", + "@sentry/types": "7.21.1", + "@sentry/utils": "7.21.1", "tslib": "^1.9.3" }, "engines": { "node": ">=8" } }, - "node_modules/@sentry/tracing/node_modules/@sentry/core": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.19.0.tgz", - "integrity": "sha512-YF9cTBcAnO4R44092BJi5Wa2/EO02xn2ziCtmNgAVTN2LD31a/YVGxGBt/FDr4Y6yeuVehaqijVVvtpSmXrGJw==", - "dependencies": { - "@sentry/types": "7.19.0", - "@sentry/utils": "7.19.0", - "tslib": "^1.9.3" - }, + "node_modules/@sentry/types": { + "version": "7.21.1", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.21.1.tgz", + "integrity": "sha512-3/IKnd52Ol21amQvI+kz+WB76s8/LR5YvFJzMgIoI2S8d82smIr253zGijRXxHPEif8kMLX4Yt+36VzrLxg6+A==", "engines": { "node": ">=8" } }, - "node_modules/@sentry/tracing/node_modules/@sentry/types": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.19.0.tgz", - "integrity": "sha512-oGRAT6lfzoKrxO1mvxiSj0XHxWPd6Gd1wpPGuu6iJo03xgWDS+MIlD1h2unqL4N5fAzLjzmbC2D2lUw50Kn2pA==", - "engines": { - "node": ">=8" - } - }, - "node_modules/@sentry/tracing/node_modules/@sentry/utils": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.19.0.tgz", - "integrity": "sha512-2L6lq+c9Ol2uiRxQDdcgoapmHJp24MhMN0gIkn2alSfMJ+ls6bGXzQHx6JAIdoOiwFQXRZHKL9ecfAc8O+vItA==", + "node_modules/@sentry/utils": { + "version": "7.21.1", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.21.1.tgz", + "integrity": "sha512-F0W0AAi8tgtTx6ApZRI2S9HbXEA9ENX1phTZgdNNWcMFm1BNbc21XEwLqwXBNjub5nlA6CE8xnjXRgdZKx4kzQ==", "dependencies": { - "@sentry/types": "7.19.0", + "@sentry/types": "7.21.1", "tslib": "^1.9.3" }, "engines": { @@ -2788,6 +3095,21 @@ "@babel/types": "^7.3.0" } }, + "node_modules/@types/bcrypt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/bcrypt/-/bcrypt-5.0.0.tgz", + "integrity": "sha512-agtcFKaruL8TmcvqbndlqHPSJgsolhf/qPWchFlgnW1gECTN/nKbFcoFnvKAQRFfKbh+BO6A3SWdJu9t+xF3Lw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/bcryptjs": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@types/bcryptjs/-/bcryptjs-2.4.2.tgz", + "integrity": "sha512-LiMQ6EOPob/4yUL66SZzu6Yh77cbzJFYll+ZfaPiPPFswtIlA/Fs1MzdKYA7JApHU49zQTbJGX3PDmCpIdDBRQ==", + "dev": true + }, "node_modules/@types/body-parser": { "version": "1.19.2", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", @@ -2816,6 +3138,12 @@ "@types/express": "*" } }, + "node_modules/@types/cookiejar": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@types/cookiejar/-/cookiejar-2.1.2.tgz", + "integrity": "sha512-t73xJJrvdTjXrn4jLS9VSGRbz0nUY3cl2DMGDU48lKl+HR9dbbjW2A9r3g40VA++mQpy6uuHg33gy7du2BKpog==", + "dev": true + }, "node_modules/@types/cors": { "version": "2.8.12", "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.12.tgz", @@ -2883,6 +3211,16 @@ "@types/istanbul-lib-report": "*" } }, + "node_modules/@types/jest": { + "version": "29.2.4", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.2.4.tgz", + "integrity": "sha512-PipFB04k2qTRPePduVLTRiPzQfvMeLwUN3Z21hsAKaB/W9IIzgB2pizCL466ftJlcyZqnHoC9ZHpxLGl3fS86A==", + "dev": true, + "dependencies": { + "expect": "^29.0.0", + "pretty-format": "^29.0.0" + } + }, "node_modules/@types/json-schema": { "version": "7.0.11", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", @@ -2898,6 +3236,22 @@ "@types/node": "*" } }, + "node_modules/@types/libsodium-wrappers": { + "version": "0.7.10", + "resolved": "https://registry.npmjs.org/@types/libsodium-wrappers/-/libsodium-wrappers-0.7.10.tgz", + "integrity": "sha512-BqI9B92u+cM3ccp8mpHf+HzJ8fBlRwdmyd6+fz3p99m3V6ifT5O3zmOMi612PGkpeFeG/G6loxUnzlDNhfjPSA==" + }, + "node_modules/@types/lodash": { + "version": "4.14.191", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.191.tgz", + "integrity": "sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ==", + "dev": true + }, + "node_modules/@types/long": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz", + "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==" + }, "node_modules/@types/mime": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", @@ -2919,9 +3273,9 @@ } }, "node_modules/@types/prettier": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.1.tgz", - "integrity": "sha512-ri0UmynRRvZiiUJdiz38MmIblKK+oH30MztdBVR95dv/Ubw6neWSb8u1XpRb72L4qsZOhz+L+z9JD40SJmfWow==", + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.2.tgz", + "integrity": "sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg==", "dev": true }, "node_modules/@types/qs": { @@ -2958,6 +3312,25 @@ "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", "dev": true }, + "node_modules/@types/superagent": { + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/@types/superagent/-/superagent-4.1.16.tgz", + "integrity": "sha512-tLfnlJf6A5mB6ddqF159GqcDizfzbMUB1/DeT59/wBNqzRTNNKsaw79A/1TZ84X+f/EwWH8FeuSkjlCLyqS/zQ==", + "dev": true, + "dependencies": { + "@types/cookiejar": "*", + "@types/node": "*" + } + }, + "node_modules/@types/supertest": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/@types/supertest/-/supertest-2.0.12.tgz", + "integrity": "sha512-X3HPWTwXRerBZS7Mo1k6vMVR1Z6zmJcDVn5O/31whe0tnjE4te6ZJSJGq1RiqHPjzPdMTfjCFogDJmwng9xHaQ==", + "dev": true, + "dependencies": { + "@types/superagent": "*" + } + }, "node_modules/@types/swagger-jsdoc": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/@types/swagger-jsdoc/-/swagger-jsdoc-6.0.1.tgz", @@ -3193,8 +3566,7 @@ "node_modules/abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" }, "node_modules/accepts": { "version": "1.3.8", @@ -3296,7 +3668,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, "engines": { "node": ">=8" } @@ -3329,6 +3700,23 @@ "node": ">= 8" } }, + "node_modules/aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==" + }, + "node_modules/are-we-there-yet": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", + "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/arg": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", @@ -3338,8 +3726,7 @@ "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, "node_modules/array-flatten": { "version": "1.1.1", @@ -3355,6 +3742,12 @@ "node": ">=8" } }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "dev": true + }, "node_modules/assert-plus": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", @@ -3364,15 +3757,36 @@ "node": ">=0.8" } }, + "node_modules/async": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", + "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==" + }, + "node_modules/async-exit-hook": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/async-exit-hook/-/async-exit-hook-2.0.1.tgz", + "integrity": "sha512-NW2cX8m1Q7KPA7a5M2ULQeZ2wR5qI5PAbw5L0UOMxdioVk9PMZ0h1TmyZEkPYrCvYjDlFICusOu1dlEKAAeXBw==", + "engines": { + "node": ">=0.12.0" + } + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, + "node_modules/await-to-js": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/await-to-js/-/await-to-js-3.0.0.tgz", + "integrity": "sha512-zJAaP9zxTcvTHRlejau3ZOY4V7SRpiByf3/dxx2uyKxxor19tpmpV2QRsTKikckwhaPmr2dVpxxMr7jOCYVp5g==", + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/axios": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.1.3.tgz", - "integrity": "sha512-00tXVRwKx/FZr/IDVFt4C+f9FYairX517WoGCL6dpOntqLkZofjhu43F/Xl44UOpqa+9sLFDrG/XAnFsUYgkDA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.2.0.tgz", + "integrity": "sha512-zT7wZyNYu3N5Bu0wuZ6QccIf93Qk1eV8LOewxgjOZFd2DenOs98cJ7+Y6703d0wkaXGY6/nZd4EweJaHz9uzQw==", "dependencies": { "follow-redirects": "^1.15.0", "form-data": "^4.0.0", @@ -3494,6 +3908,24 @@ } ] }, + "node_modules/bcrypt": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-5.1.0.tgz", + "integrity": "sha512-RHBS7HI5N5tEnGTmtR/pppX0mmDSBpQ4aCBsj7CEQfYXDcO74A8sIBYcJMuCsis2E81zDxeENYhv66oZwLiA+Q==", + "hasInstallScript": true, + "dependencies": { + "@mapbox/node-pre-gyp": "^1.0.10", + "node-addon-api": "^5.0.0" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/before-after-hook": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz", + "integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==" + }, "node_modules/bigint-conversion": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/bigint-conversion/-/bigint-conversion-2.2.2.tgz", @@ -3602,6 +4034,18 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, + "dependencies": { + "fast-json-stable-stringify": "2.x" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/bser": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", @@ -3622,6 +4066,17 @@ "node": ">=6.9.0" } }, + "node_modules/btoa": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/btoa/-/btoa-1.2.1.tgz", + "integrity": "sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g==", + "bin": { + "btoa": "bin/btoa.js" + }, + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/buffer": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", @@ -3656,6 +4111,11 @@ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, + "node_modules/builder-pattern": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/builder-pattern/-/builder-pattern-2.2.0.tgz", + "integrity": "sha512-cES3qdeBzA4QyJi7rV/l/kAhIFX6AKo3vK66ZPXLNpjcQWCS8sjLKscly8imlfW2YPTo/hquMRMnaWpZ80Kj+g==" + }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -3795,6 +4255,14 @@ "node": ">= 6" } }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "engines": { + "node": ">=10" + } + }, "node_modules/ci-info": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.5.0.tgz", @@ -3846,6 +4314,15 @@ "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", "dev": true }, + "node_modules/color": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", + "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", + "dependencies": { + "color-convert": "^1.9.3", + "color-string": "^1.6.0" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -3861,8 +4338,46 @@ "node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "bin": { + "color-support": "bin.js" + } + }, + "node_modules/color/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/colorspace": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", + "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", + "dependencies": { + "color": "^3.1.3", + "text-hex": "1.0.x" + } }, "node_modules/combined-stream": { "version": "1.0.8", @@ -3875,11 +4390,22 @@ "node": ">= 0.8" } }, + "node_modules/component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", + "dev": true + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==" + }, "node_modules/content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", @@ -3938,6 +4464,12 @@ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" }, + "node_modules/cookiejar": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz", + "integrity": "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==", + "dev": true + }, "node_modules/core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", @@ -3974,6 +4506,24 @@ "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", "dev": true }, + "node_modules/cross-env": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", + "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.1" + }, + "bin": { + "cross-env": "src/bin/cross-env.js", + "cross-env-shell": "src/bin/cross-env-shell.js" + }, + "engines": { + "node": ">=10.14", + "npm": ">=6", + "yarn": ">=1" + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -4033,7 +4583,6 @@ "version": "4.2.2", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -4046,6 +4595,11 @@ "node": ">=0.4.0" } }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==" + }, "node_modules/denque": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", @@ -4062,6 +4616,11 @@ "node": ">= 0.8" } }, + "node_modules/deprecation": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", + "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==" + }, "node_modules/destroy": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", @@ -4071,6 +4630,14 @@ "npm": "1.2.8000 || >= 1.4.16" } }, + "node_modules/detect-libc": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz", + "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==", + "engines": { + "node": ">=8" + } + }, "node_modules/detect-newline": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", @@ -4080,6 +4647,16 @@ "node": ">=8" } }, + "node_modules/dezalgo": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", + "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", + "dev": true, + "dependencies": { + "asap": "^2.0.0", + "wrappy": "1" + } + }, "node_modules/diff": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", @@ -4164,8 +4741,12 @@ "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/enabled": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" }, "node_modules/encodeurl": { "version": "1.0.2", @@ -4175,6 +4756,29 @@ "node": ">= 0.8" } }, + "node_modules/encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "optional": true, + "peer": true, + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, + "node_modules/encoding/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "optional": true, + "peer": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -4266,39 +4870,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint-config-prettier": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz", - "integrity": "sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==", - "dev": true, - "bin": { - "eslint-config-prettier": "bin/cli.js" - }, - "peerDependencies": { - "eslint": ">=7.0.0" - } - }, - "node_modules/eslint-plugin-prettier": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz", - "integrity": "sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==", - "dev": true, - "dependencies": { - "prettier-linter-helpers": "^1.0.0" - }, - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "eslint": ">=7.28.0", - "prettier": ">=2.0.0" - }, - "peerDependenciesMeta": { - "eslint-config-prettier": { - "optional": true - } - } - }, "node_modules/eslint-scope": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", @@ -4616,12 +5187,6 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true }, - "node_modules/fast-diff": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", - "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", - "dev": true - }, "node_modules/fast-glob": { "version": "3.2.12", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", @@ -4662,6 +5227,12 @@ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, + "node_modules/fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", + "dev": true + }, "node_modules/fast-xml-parser": { "version": "4.0.11", "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.0.11.tgz", @@ -4696,6 +5267,11 @@ "bser": "2.1.1" } }, + "node_modules/fecha": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", + "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==" + }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -4793,6 +5369,11 @@ "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "dev": true }, + "node_modules/fn.name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" + }, "node_modules/follow-redirects": { "version": "1.15.2", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", @@ -4825,6 +5406,21 @@ "node": ">= 6" } }, + "node_modules/formidable": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-2.1.1.tgz", + "integrity": "sha512-0EcS9wCFEzLvfiks7omJ+SiYJAiD+TzK4Pcw1UlUoGnhUxDcMKjt0P7x8wEb0u6OHu8Nb98WG3nxtlF5C7bvUQ==", + "dev": true, + "dependencies": { + "dezalgo": "^1.0.4", + "hexoid": "^1.0.0", + "once": "^1.4.0", + "qs": "^6.11.0" + }, + "funding": { + "url": "https://ko-fi.com/tunnckoCore/commissions" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -4841,6 +5437,28 @@ "node": ">= 0.6" } }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -4865,6 +5483,25 @@ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, + "node_modules/gauge": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -5058,6 +5695,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==" + }, "node_modules/hash-base": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", @@ -5079,6 +5721,15 @@ "node": ">=12.0.0" } }, + "node_modules/hexoid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hexoid/-/hexoid-1.0.0.tgz", + "integrity": "sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", @@ -5299,7 +5950,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, "engines": { "node": ">=8" } @@ -5343,11 +5993,18 @@ "node": ">=8" } }, + "node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, "engines": { "node": ">=8" }, @@ -5678,6 +6335,21 @@ "fsevents": "^2.3.2" } }, + "node_modules/jest-junit": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/jest-junit/-/jest-junit-15.0.0.tgz", + "integrity": "sha512-Z5sVX0Ag3HZdMUnD5DFlG+1gciIFSy7yIVPhOdGUi8YJaI9iLvvBb530gtQL2CHmv0JJeiwRZenr0VrSR7frvg==", + "dev": true, + "dependencies": { + "mkdirp": "^1.0.4", + "strip-ansi": "^6.0.1", + "uuid": "^8.3.2", + "xml": "^1.0.1" + }, + "engines": { + "node": ">=10.12.0" + } + }, "node_modules/jest-leak-detector": { "version": "29.3.1", "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.3.1.tgz", @@ -5998,7 +6670,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, "dependencies": { "argparse": "^2.0.1" }, @@ -6048,10 +6719,9 @@ "dev": true }, "node_modules/json5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", - "dev": true, + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "bin": { "json5": "lib/cli.js" }, @@ -6060,32 +6730,18 @@ } }, "node_modules/jsonwebtoken": { - "version": "8.5.1", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", - "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz", + "integrity": "sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw==", "dependencies": { "jws": "^3.2.2", - "lodash.includes": "^4.3.0", - "lodash.isboolean": "^3.0.3", - "lodash.isinteger": "^4.0.4", - "lodash.isnumber": "^3.0.3", - "lodash.isplainobject": "^4.0.6", - "lodash.isstring": "^4.0.1", - "lodash.once": "^4.0.0", + "lodash": "^4.17.21", "ms": "^2.1.1", - "semver": "^5.6.0" + "semver": "^7.3.8" }, "engines": { - "node": ">=4", - "npm": ">=1.4.28" - } - }, - "node_modules/jsonwebtoken/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "bin": { - "semver": "bin/semver" + "node": ">=12", + "npm": ">=6" } }, "node_modules/jsprim": { @@ -6146,6 +6802,11 @@ "node": ">=6" } }, + "node_modules/kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" + }, "node_modules/leven": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", @@ -6168,6 +6829,19 @@ "node": ">= 0.8.0" } }, + "node_modules/libsodium": { + "version": "0.7.10", + "resolved": "https://registry.npmjs.org/libsodium/-/libsodium-0.7.10.tgz", + "integrity": "sha512-eY+z7hDrDKxkAK+QKZVNv92A5KYkxfvIshtBJkmg5TSiCnYqZP3i9OO9whE79Pwgm4jGaoHgkM4ao/b9Cyu4zQ==" + }, + "node_modules/libsodium-wrappers": { + "version": "0.7.10", + "resolved": "https://registry.npmjs.org/libsodium-wrappers/-/libsodium-wrappers-0.7.10.tgz", + "integrity": "sha512-pO3F1Q9NPLB/MWIhehim42b/Fwb30JNScCNh8TcQ/kIc+qGLQch8ag8wb0keK3EP5kbGakk1H8Wwo7v+36rNQg==", + "dependencies": { + "libsodium": "^0.7.0" + } + }, "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", @@ -6194,35 +6868,11 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, - "node_modules/lodash.includes": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", - "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" - }, - "node_modules/lodash.isboolean": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", - "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" - }, - "node_modules/lodash.isinteger": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", - "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" - }, - "node_modules/lodash.isnumber": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", - "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" - }, - "node_modules/lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" - }, - "node_modules/lodash.isstring": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", - "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "dev": true }, "node_modules/lodash.merge": { "version": "4.6.2", @@ -6230,10 +6880,22 @@ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, - "node_modules/lodash.once": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", - "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" + "node_modules/logform": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.4.2.tgz", + "integrity": "sha512-W4c9himeAwXEdZ05dQNerhFz2XG80P9Oj0loPUMV23VC2it0orMHQhJm4hdnnor3rd1HsGf6a2lPwBM1zeXHGw==", + "dependencies": { + "@colors/colors": "1.5.0", + "fecha": "^4.2.0", + "ms": "^2.1.1", + "safe-stable-stringify": "^2.3.1", + "triple-beam": "^1.3.0" + } + }, + "node_modules/long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" }, "node_modules/lru_map": { "version": "0.3.3", @@ -6244,7 +6906,6 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, "dependencies": { "yallist": "^4.0.0" }, @@ -6256,7 +6917,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, "dependencies": { "semver": "^6.0.0" }, @@ -6271,7 +6931,6 @@ "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, "bin": { "semver": "bin/semver.js" } @@ -6440,6 +7099,51 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/minipass": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.0.0.tgz", + "integrity": "sha512-g2Uuh2jEKoht+zvO6vJqXmYpflPqzRBT+Th2h01DKh5z7wbY/AZ2gCQ78cP70YoHPyFdY30YBV5WxgLOEwOykw==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/mmdb-lib": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/mmdb-lib/-/mmdb-lib-2.0.2.tgz", @@ -6478,9 +7182,9 @@ } }, "node_modules/mongoose": { - "version": "6.7.2", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-6.7.2.tgz", - "integrity": "sha512-lrP2V5U1qhaf+z33fiIn7aYAZZ1fVDly+TkFRjTujNBF/FIHESATj2RbgAOSlWqv32fsZXkXejXzeVfjbv35Ow==", + "version": "6.7.3", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-6.7.3.tgz", + "integrity": "sha512-bLC2Pt6Vpoov+1kBYvQgJXG/2DWXbfIvfK4Gh68kCdYGh6CVO31YxYuIGz70hyGwX2g4DmSzbs5IA8Px2neMCQ==", "dependencies": { "bson": "^4.7.0", "kareem": "2.4.1", @@ -6552,6 +7256,49 @@ "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" }, + "node_modules/node-addon-api": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.0.0.tgz", + "integrity": "sha512-CvkDw2OEnme7ybCykJpVcKH+uAOLV2qLqiyla128dN9TkEWfrYmxG6C2boDe5KcNQqZF3orkqzGgOMvZ/JNekA==" + }, + "node_modules/node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-fetch/node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/node-fetch/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/node-fetch/node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -6740,129 +7487,7 @@ "treeverse", "validate-npm-package-name", "which", - "write-file-atomic", - "@colors/colors", - "@gar/promisify", - "@npmcli/disparity-colors", - "@npmcli/git", - "@npmcli/installed-package-contents", - "@npmcli/metavuln-calculator", - "@npmcli/move-file", - "@npmcli/name-from-folder", - "@npmcli/node-gyp", - "@npmcli/promise-spawn", - "@npmcli/query", - "@tootallnate/once", - "agent-base", - "agentkeepalive", - "aggregate-error", - "ansi-regex", - "ansi-styles", - "aproba", - "are-we-there-yet", - "asap", - "balanced-match", - "bin-links", - "binary-extensions", - "brace-expansion", - "builtins", - "cidr-regex", - "clean-stack", - "clone", - "cmd-shim", - "color-convert", - "color-name", - "color-support", - "common-ancestor-path", - "concat-map", - "console-control-strings", - "cssesc", - "debug", - "debuglog", - "defaults", - "delegates", - "depd", - "dezalgo", - "diff", - "emoji-regex", - "encoding", - "env-paths", - "err-code", - "fs.realpath", - "function-bind", - "gauge", - "has", - "has-flag", - "has-unicode", - "http-cache-semantics", - "http-proxy-agent", - "https-proxy-agent", - "humanize-ms", - "iconv-lite", - "ignore-walk", - "imurmurhash", - "indent-string", - "infer-owner", - "inflight", - "inherits", - "ip", - "ip-regex", - "is-core-module", - "is-fullwidth-code-point", - "is-lambda", - "isexe", - "json-stringify-nice", - "jsonparse", - "just-diff", - "just-diff-apply", - "lru-cache", - "minipass-collect", - "minipass-fetch", - "minipass-flush", - "minipass-json-stream", - "minipass-sized", - "minizlib", - "mute-stream", - "negotiator", - "normalize-package-data", - "npm-bundled", - "npm-normalize-package-bin", - "npm-packlist", - "once", - "path-is-absolute", - "postcss-selector-parser", - "promise-all-reject-late", - "promise-call-limit", - "promise-inflight", - "promise-retry", - "promzard", - "read-cmd-shim", - "readable-stream", - "retry", - "safe-buffer", - "safer-buffer", - "set-blocking", - "signal-exit", - "smart-buffer", - "socks", - "socks-proxy-agent", - "spdx-correct", - "spdx-exceptions", - "spdx-expression-parse", - "spdx-license-ids", - "string_decoder", - "string-width", - "strip-ansi", - "supports-color", - "unique-filename", - "unique-slug", - "util-deprecate", - "validate-npm-package-license", - "walk-up-path", - "wcwidth", - "wide-align", - "wrappy", - "yallist" + "write-file-atomic" ], "dev": true, "dependencies": { @@ -9363,6 +9988,17 @@ "inBundle": true, "license": "ISC" }, + "node_modules/npmlog": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", + "dependencies": { + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" + } + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -9398,6 +10034,14 @@ "wrappy": "1" } }, + "node_modules/one-time": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", + "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "dependencies": { + "fn.name": "1.x.x" + } + }, "node_modules/onetime": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", @@ -9645,9 +10289,9 @@ } }, "node_modules/posthog-node": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/posthog-node/-/posthog-node-2.1.0.tgz", - "integrity": "sha512-xr56mZRQo7rnL2YdwbipcxTZeyi5dcI6IM4++wIN7JLYwinrJYcQv01nan4gU4kMy33Qz5qT6boWMQRwpKZJVQ==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/posthog-node/-/posthog-node-2.2.3.tgz", + "integrity": "sha512-dYlLZhrDus+uRov/Hh+EiRlMoMhRKchNjNa7mNE2iWmKg/ryOTipf0XYKS9UKdki7aU1NzWFhnLe11HF615XuA==", "dependencies": { "axios": "^0.27.0" }, @@ -9673,33 +10317,6 @@ "node": ">= 0.8.0" } }, - "node_modules/prettier": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz", - "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==", - "dev": true, - "bin": { - "prettier": "bin-prettier.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/prettier-linter-helpers": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", - "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", - "dev": true, - "dependencies": { - "fast-diff": "^1.1.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/pretty-format": { "version": "29.3.1", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.3.1.tgz", @@ -9739,6 +10356,31 @@ "node": ">= 6" } }, + "node_modules/protobufjs": { + "version": "6.11.3", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.3.tgz", + "integrity": "sha512-xL96WDdCZYdU7Slin569tFX712BxsxslWwAfAhCYjQKGTq7dAU91Lomy6nLLhh/dyGhk/YH4TwTSRxTzhuHyZg==", + "hasInstallScript": true, + "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" + }, + "bin": { + "pbjs": "bin/pbjs", + "pbts": "bin/pbts" + } + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -9906,6 +10548,11 @@ "url": "https://github.com/sponsors/mysticatea" } }, + "node_modules/request-ip": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/request-ip/-/request-ip-3.3.0.tgz", + "integrity": "sha512-cA6Xh6e0fDBBBwH77SLJaJPBmD3nWVAcF9/XAcsrIHdjhFzFiB5aNQFytdjCGPezU3ROwrR11IddKAM08vohxA==" + }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -10046,6 +10693,14 @@ } ] }, + "node_modules/safe-stable-stringify": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.1.tgz", + "integrity": "sha512-dVHE6bMtS/bnL2mwualjc6IxEv1F+OCUpA46pKUj6F8uDbUM0jCCulPqRNPSnWwGNKx5etqMjZYdXtrm5KJZGA==", + "engines": { + "node": ">=10" + } + }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -10067,7 +10722,6 @@ "version": "7.3.8", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, "dependencies": { "lru-cache": "^6.0.0" }, @@ -10133,6 +10787,11 @@ "node": ">= 0.8.0" } }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" + }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", @@ -10192,8 +10851,20 @@ "node_modules/signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/simple-swizzle/node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" }, "node_modules/simple-update-notifier": { "version": "1.0.7", @@ -10240,6 +10911,34 @@ "npm": ">= 3.0.0" } }, + "node_modules/snappy": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/snappy/-/snappy-7.1.1.tgz", + "integrity": "sha512-mL7GGPJ+WdsaFT5aR/uEqCq8cPg2VbhyifDEP7AeqIVDsAC8LBGYbZP1Qzoa2Ym84OW7JEQXqIpwqFp1EQw5BA==", + "optional": true, + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "optionalDependencies": { + "@napi-rs/snappy-android-arm-eabi": "7.1.1", + "@napi-rs/snappy-android-arm64": "7.1.1", + "@napi-rs/snappy-darwin-arm64": "7.1.1", + "@napi-rs/snappy-darwin-x64": "7.1.1", + "@napi-rs/snappy-freebsd-x64": "7.1.1", + "@napi-rs/snappy-linux-arm-gnueabihf": "7.1.1", + "@napi-rs/snappy-linux-arm64-gnu": "7.1.1", + "@napi-rs/snappy-linux-arm64-musl": "7.1.1", + "@napi-rs/snappy-linux-x64-gnu": "7.1.1", + "@napi-rs/snappy-linux-x64-musl": "7.1.1", + "@napi-rs/snappy-win32-arm64-msvc": "7.1.1", + "@napi-rs/snappy-win32-ia32-msvc": "7.1.1", + "@napi-rs/snappy-win32-x64-msvc": "7.1.1" + } + }, "node_modules/socks": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", @@ -10294,6 +10993,14 @@ "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", "dev": true }, + "node_modules/stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", + "engines": { + "node": "*" + } + }, "node_modules/stack-utils": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", @@ -10365,7 +11072,6 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -10379,7 +11085,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -10435,6 +11140,52 @@ "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==", "optional": true }, + "node_modules/superagent": { + "version": "8.0.6", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-8.0.6.tgz", + "integrity": "sha512-HqSe6DSIh3hEn6cJvCkaM1BLi466f1LHi4yubR0tpewlMpk4RUFFy35bKz8SsPBwYfIIJy5eclp+3tCYAuX0bw==", + "dev": true, + "dependencies": { + "component-emitter": "^1.3.0", + "cookiejar": "^2.1.3", + "debug": "^4.3.4", + "fast-safe-stringify": "^2.1.1", + "form-data": "^4.0.0", + "formidable": "^2.1.1", + "methods": "^1.1.2", + "mime": "2.6.0", + "qs": "^6.11.0", + "semver": "^7.3.8" + }, + "engines": { + "node": ">=6.4.0 <13 || >=14" + } + }, + "node_modules/superagent/node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/supertest": { + "version": "6.3.3", + "resolved": "https://registry.npmjs.org/supertest/-/supertest-6.3.3.tgz", + "integrity": "sha512-EMCG6G8gDu5qEqRQ3JjjPs6+FYT1a7Hv5ApHvtSghmOFJYtsU5S+pSb6Y2EUeCEY3CmEL3mmQ8YWlPOzQomabA==", + "dev": true, + "dependencies": { + "methods": "^1.1.2", + "superagent": "^8.0.5" + }, + "engines": { + "node": ">=6.4.0" + } + }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -10459,6 +11210,63 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/swagger-autogen": { + "version": "2.22.0", + "resolved": "https://registry.npmjs.org/swagger-autogen/-/swagger-autogen-2.22.0.tgz", + "integrity": "sha512-MPdtwgx/RL3og0RjFVV9hPoQv3x+c3ZRhS0Vjp9k94DLV7iUgIuCg8H+uAT8oD5w48ATTRT1VjcOHlCGH62pdA==", + "dependencies": { + "acorn": "^7.4.1", + "deepmerge": "^4.2.2", + "glob": "^7.1.7", + "json5": "^2.2.1" + } + }, + "node_modules/swagger-autogen/node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/swagger-ui-dist": { + "version": "4.15.5", + "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-4.15.5.tgz", + "integrity": "sha512-V3eIa28lwB6gg7/wfNvAbjwJYmDXy1Jo1POjyTzlB6wPcHiGlRxq39TSjYGVjQrUSAzpv+a7nzp7mDxgNy57xA==" + }, + "node_modules/swagger-ui-express": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/swagger-ui-express/-/swagger-ui-express-4.6.0.tgz", + "integrity": "sha512-ZxpQFp1JR2RF8Ar++CyJzEDdvufa08ujNUJgMVTMWPi86CuQeVdBtvaeO/ysrz6dJAYXf9kbVNhWD7JWocwqsA==", + "dependencies": { + "swagger-ui-dist": ">=4.11.0" + }, + "engines": { + "node": ">= v0.10.32" + }, + "peerDependencies": { + "express": ">=4.0.0" + } + }, + "node_modules/tar": { + "version": "6.1.13", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.13.tgz", + "integrity": "sha512-jdIBIN6LTIe2jqzay/2vtYLlBHa3JF42ot3h1dW8Q0PaAG4v8rm0cvpVePtau5C6OKXGGcgO9q2AMNSWxiLqKw==", + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^4.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", @@ -10473,6 +11281,11 @@ "node": ">=8" } }, + "node_modules/text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -10546,6 +11359,54 @@ "node": ">=12" } }, + "node_modules/triple-beam": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", + "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==" + }, + "node_modules/ts-jest": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.0.3.tgz", + "integrity": "sha512-Ibygvmuyq1qp/z3yTh9QTwVVAbFdDy/+4BtIQR2sp6baF2SJU/8CKK/hhnGIDY2L90Az2jIqTwZPnN2p+BweiQ==", + "dev": true, + "dependencies": { + "bs-logger": "0.x", + "fast-json-stable-stringify": "2.x", + "jest-util": "^29.0.0", + "json5": "^2.2.1", + "lodash.memoize": "4.x", + "make-error": "1.x", + "semver": "7.x", + "yargs-parser": "^21.0.1" + }, + "bin": { + "ts-jest": "cli.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": ">=7.0.0-beta.0 <8", + "@jest/types": "^29.0.0", + "babel-jest": "^29.0.0", + "jest": "^29.0.0", + "typescript": ">=4.3" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "@jest/types": { + "optional": true + }, + "babel-jest": { + "optional": true + }, + "esbuild": { + "optional": true + } + } + }, "node_modules/ts-node": { "version": "10.9.1", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", @@ -10694,6 +11555,11 @@ "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", "dev": true }, + "node_modules/universal-user-agent": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz", + "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==" + }, "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", @@ -10742,6 +11608,14 @@ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, + "node_modules/utility-types": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.10.0.tgz", + "integrity": "sha512-O11mqxmi7wMKCo6HKFt5AhO4BwY3VV68YU07tgxfz8zJTIxr4BpsezN49Ffwy9j3ZpwwJp4fkRwjRzq3uWE6Rg==", + "engines": { + "node": ">= 4" + } + }, "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", @@ -10754,7 +11628,7 @@ "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "optional": true, + "devOptional": true, "bin": { "uuid": "dist/bin/uuid" } @@ -10869,6 +11743,62 @@ "node": ">= 8" } }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "node_modules/winston": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.8.2.tgz", + "integrity": "sha512-MsE1gRx1m5jdTTO9Ld/vND4krP2To+lgDoMEHGGa4HIlAUyXJtfc7CxQcGXVyz2IBpw5hbFkj2b/AtUdQwyRew==", + "dependencies": { + "@colors/colors": "1.5.0", + "@dabh/diagnostics": "^2.0.2", + "async": "^3.2.3", + "is-stream": "^2.0.0", + "logform": "^2.4.0", + "one-time": "^1.0.0", + "readable-stream": "^3.4.0", + "safe-stable-stringify": "^2.3.1", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.5.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/winston-loki": { + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/winston-loki/-/winston-loki-6.0.6.tgz", + "integrity": "sha512-cll+nv5T/b9uJXqca0N2WKL1JJNuJND9E6WOOAuSGkZ44L9VQ/QK9F+/5VKbv6LIP9p0nvPSOYxtACCDb/9iWw==", + "dependencies": { + "async-exit-hook": "2.0.1", + "btoa": "^1.2.1", + "protobufjs": "^6.8.8", + "winston-transport": "^4.3.0" + }, + "optionalDependencies": { + "snappy": "7.1.1" + } + }, + "node_modules/winston-transport": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.5.0.tgz", + "integrity": "sha512-YpZzcUzBedhlTAfJg6vJDlyEai/IFMIVcaEZZyl3UXIl4gmqRpU7AE89AHLkbzLUsv0NVmw7ts+iztqKxxPW1Q==", + "dependencies": { + "logform": "^2.3.2", + "readable-stream": "^3.6.0", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 6.4.0" + } + }, "node_modules/word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", @@ -10918,6 +11848,12 @@ "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, + "node_modules/xml": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz", + "integrity": "sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw==", + "dev": true + }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", @@ -10930,8 +11866,7 @@ "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/yargs": { "version": "17.6.2", @@ -12721,6 +13656,11 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, + "@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==" + }, "@cspotcode/source-map-support": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", @@ -12730,6 +13670,16 @@ "@jridgewell/trace-mapping": "0.3.9" } }, + "@dabh/diagnostics": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", + "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", + "requires": { + "colorspace": "1.1.x", + "enabled": "2.0.x", + "kuler": "^2.0.0" + } + }, "@eslint/eslintrc": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.3.tgz", @@ -13166,6 +14116,32 @@ "resolved": "https://registry.npmjs.org/@juanelas/base64/-/base64-1.0.5.tgz", "integrity": "sha512-gTIElNo4ohMcYUZzol/Hb6DYJzphxl0b1B4egJJ+JiqxqcOcWx4XLMAB+lhWuMsMX3uR1oc5hwPusU3lgc1FkQ==" }, + "@mapbox/node-pre-gyp": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.10.tgz", + "integrity": "sha512-4ySo4CjzStuprMwk35H5pPbkymjv1SF3jGLj6rAHp/xT/RF7TL7bd9CTm1xDY49K2qF7jmR/g7k+SkLETP6opA==", + "requires": { + "detect-libc": "^2.0.0", + "https-proxy-agent": "^5.0.0", + "make-dir": "^3.1.0", + "node-fetch": "^2.6.7", + "nopt": "^5.0.0", + "npmlog": "^5.0.1", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.11" + }, + "dependencies": { + "nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "requires": { + "abbrev": "1" + } + } + } + }, "@maxmind/geoip2-node": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/@maxmind/geoip2-node/-/geoip2-node-3.5.0.tgz", @@ -13177,6 +14153,12 @@ "maxmind": "^4.2.0" } }, + "@napi-rs/snappy-darwin-arm64": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/snappy-darwin-arm64/-/snappy-darwin-arm64-7.1.1.tgz", + "integrity": "sha512-3LZyoAw3Qa5F7sCCTkSkhmGlydwUKU6L3Jl46eKHO2Ctm8Gcjxww6T7MfwlwGZ6JqAM6d1d++WLzUZPCGXVmag==", + "optional": true + }, "@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -13203,6 +14185,118 @@ "fastq": "^1.6.0" } }, + "@octokit/auth-token": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-3.0.2.tgz", + "integrity": "sha512-pq7CwIMV1kmzkFTimdwjAINCXKTajZErLB4wMLYapR2nuB/Jpr66+05wOTZMSCBXP6n4DdDWT2W19Bm17vU69Q==", + "requires": { + "@octokit/types": "^8.0.0" + } + }, + "@octokit/core": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@octokit/core/-/core-4.1.0.tgz", + "integrity": "sha512-Czz/59VefU+kKDy+ZfDwtOIYIkFjExOKf+HA92aiTZJ6EfWpFzYQWw0l54ji8bVmyhc+mGaLUbSUmXazG7z5OQ==", + "requires": { + "@octokit/auth-token": "^3.0.0", + "@octokit/graphql": "^5.0.0", + "@octokit/request": "^6.0.0", + "@octokit/request-error": "^3.0.0", + "@octokit/types": "^8.0.0", + "before-after-hook": "^2.2.0", + "universal-user-agent": "^6.0.0" + } + }, + "@octokit/endpoint": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-7.0.3.tgz", + "integrity": "sha512-57gRlb28bwTsdNXq+O3JTQ7ERmBTuik9+LelgcLIVfYwf235VHbN9QNo4kXExtp/h8T423cR5iJThKtFYxC7Lw==", + "requires": { + "@octokit/types": "^8.0.0", + "is-plain-object": "^5.0.0", + "universal-user-agent": "^6.0.0" + } + }, + "@octokit/graphql": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-5.0.4.tgz", + "integrity": "sha512-amO1M5QUQgYQo09aStR/XO7KAl13xpigcy/kI8/N1PnZYSS69fgte+xA4+c2DISKqUZfsh0wwjc2FaCt99L41A==", + "requires": { + "@octokit/request": "^6.0.0", + "@octokit/types": "^8.0.0", + "universal-user-agent": "^6.0.0" + } + }, + "@octokit/openapi-types": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-14.0.0.tgz", + "integrity": "sha512-HNWisMYlR8VCnNurDU6os2ikx0s0VyEjDYHNS/h4cgb8DeOxQ0n72HyinUtdDVxJhFy3FWLGl0DJhfEWk3P5Iw==" + }, + "@octokit/plugin-paginate-rest": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-5.0.1.tgz", + "integrity": "sha512-7A+rEkS70pH36Z6JivSlR7Zqepz3KVucEFVDnSrgHXzG7WLAzYwcHZbKdfTXHwuTHbkT1vKvz7dHl1+HNf6Qyw==", + "requires": { + "@octokit/types": "^8.0.0" + } + }, + "@octokit/plugin-request-log": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.4.tgz", + "integrity": "sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA==", + "requires": {} + }, + "@octokit/plugin-rest-endpoint-methods": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-6.7.0.tgz", + "integrity": "sha512-orxQ0fAHA7IpYhG2flD2AygztPlGYNAdlzYz8yrD8NDgelPfOYoRPROfEyIe035PlxvbYrgkfUZIhSBKju/Cvw==", + "requires": { + "@octokit/types": "^8.0.0", + "deprecation": "^2.3.1" + } + }, + "@octokit/request": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-6.2.2.tgz", + "integrity": "sha512-6VDqgj0HMc2FUX2awIs+sM6OwLgwHvAi4KCK3mT2H2IKRt6oH9d0fej5LluF5mck1lRR/rFWN0YIDSYXYSylbw==", + "requires": { + "@octokit/endpoint": "^7.0.0", + "@octokit/request-error": "^3.0.0", + "@octokit/types": "^8.0.0", + "is-plain-object": "^5.0.0", + "node-fetch": "^2.6.7", + "universal-user-agent": "^6.0.0" + } + }, + "@octokit/request-error": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-3.0.2.tgz", + "integrity": "sha512-WMNOFYrSaX8zXWoJg9u/pKgWPo94JXilMLb2VManNOby9EZxrQaBe/QSC4a1TzpAlpxofg2X/jMnCyZgL6y7eg==", + "requires": { + "@octokit/types": "^8.0.0", + "deprecation": "^2.0.0", + "once": "^1.4.0" + } + }, + "@octokit/rest": { + "version": "19.0.5", + "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-19.0.5.tgz", + "integrity": "sha512-+4qdrUFq2lk7Va+Qff3ofREQWGBeoTKNqlJO+FGjFP35ZahP+nBenhZiGdu8USSgmq4Ky3IJ/i4u0xbLqHaeow==", + "requires": { + "@octokit/core": "^4.1.0", + "@octokit/plugin-paginate-rest": "^5.0.0", + "@octokit/plugin-request-log": "^1.0.4", + "@octokit/plugin-rest-endpoint-methods": "^6.7.0" + } + }, + "@octokit/types": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-8.0.0.tgz", + "integrity": "sha512-65/TPpOJP1i3K4lBJMnWqPUJ6zuOtzhtagDvydAWbEXpbFYA0oMKKyLb95NFZZP0lSh/4b6K+DQlzvYQJQQePg==", + "requires": { + "@octokit/openapi-types": "^14.0.0" + } + }, "@posthog/plugin-scaffold": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/@posthog/plugin-scaffold/-/plugin-scaffold-1.3.4.tgz", @@ -13222,6 +14316,60 @@ "tslib": "^1.9.3" } }, + "@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==" + }, + "@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" + }, + "@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" + }, + "@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==" + }, + "@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "requires": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==" + }, + "@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==" + }, + "@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==" + }, + "@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==" + }, + "@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" + }, "@sentry/node": { "version": "7.21.1", "resolved": "https://registry.npmjs.org/@sentry/node/-/node-7.21.1.tgz", @@ -13237,40 +14385,28 @@ } }, "@sentry/tracing": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-7.19.0.tgz", - "integrity": "sha512-SWY17M3TsgBePaGowUcSqBwaT0TJQzuNexVnLojuU0k6F57L9hubvP9zaoosoCfARXQ/3NypAFWnlJyf570rFQ==", + "version": "7.21.1", + "resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-7.21.1.tgz", + "integrity": "sha512-b1BTPsRaNQpohzegoz59KGuBl+To651vEq0vMS4tCzSyIdxkYso3JCrjDdEqW/2MliQYANNVrUai2bmwmU9h1g==", "requires": { - "@sentry/core": "7.19.0", - "@sentry/types": "7.19.0", - "@sentry/utils": "7.19.0", + "@sentry/core": "7.21.1", + "@sentry/types": "7.21.1", + "@sentry/utils": "7.21.1", + "tslib": "^1.9.3" + } + }, + "@sentry/types": { + "version": "7.21.1", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.21.1.tgz", + "integrity": "sha512-3/IKnd52Ol21amQvI+kz+WB76s8/LR5YvFJzMgIoI2S8d82smIr253zGijRXxHPEif8kMLX4Yt+36VzrLxg6+A==" + }, + "@sentry/utils": { + "version": "7.21.1", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.21.1.tgz", + "integrity": "sha512-F0W0AAi8tgtTx6ApZRI2S9HbXEA9ENX1phTZgdNNWcMFm1BNbc21XEwLqwXBNjub5nlA6CE8xnjXRgdZKx4kzQ==", + "requires": { + "@sentry/types": "7.21.1", "tslib": "^1.9.3" - }, - "dependencies": { - "@sentry/core": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.19.0.tgz", - "integrity": "sha512-YF9cTBcAnO4R44092BJi5Wa2/EO02xn2ziCtmNgAVTN2LD31a/YVGxGBt/FDr4Y6yeuVehaqijVVvtpSmXrGJw==", - "requires": { - "@sentry/types": "7.19.0", - "@sentry/utils": "7.19.0", - "tslib": "^1.9.3" - } - }, - "@sentry/types": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.19.0.tgz", - "integrity": "sha512-oGRAT6lfzoKrxO1mvxiSj0XHxWPd6Gd1wpPGuu6iJo03xgWDS+MIlD1h2unqL4N5fAzLjzmbC2D2lUw50Kn2pA==" - }, - "@sentry/utils": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.19.0.tgz", - "integrity": "sha512-2L6lq+c9Ol2uiRxQDdcgoapmHJp24MhMN0gIkn2alSfMJ+ls6bGXzQHx6JAIdoOiwFQXRZHKL9ecfAc8O+vItA==", - "requires": { - "@sentry/types": "7.19.0", - "tslib": "^1.9.3" - } - } } }, "@sentry/types": { @@ -13376,6 +14512,21 @@ "@babel/types": "^7.3.0" } }, + "@types/bcrypt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/bcrypt/-/bcrypt-5.0.0.tgz", + "integrity": "sha512-agtcFKaruL8TmcvqbndlqHPSJgsolhf/qPWchFlgnW1gECTN/nKbFcoFnvKAQRFfKbh+BO6A3SWdJu9t+xF3Lw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/bcryptjs": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@types/bcryptjs/-/bcryptjs-2.4.2.tgz", + "integrity": "sha512-LiMQ6EOPob/4yUL66SZzu6Yh77cbzJFYll+ZfaPiPPFswtIlA/Fs1MzdKYA7JApHU49zQTbJGX3PDmCpIdDBRQ==", + "dev": true + }, "@types/body-parser": { "version": "1.19.2", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", @@ -13404,6 +14555,12 @@ "@types/express": "*" } }, + "@types/cookiejar": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@types/cookiejar/-/cookiejar-2.1.2.tgz", + "integrity": "sha512-t73xJJrvdTjXrn4jLS9VSGRbz0nUY3cl2DMGDU48lKl+HR9dbbjW2A9r3g40VA++mQpy6uuHg33gy7du2BKpog==", + "dev": true + }, "@types/cors": { "version": "2.8.12", "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.12.tgz", @@ -13471,6 +14628,16 @@ "@types/istanbul-lib-report": "*" } }, + "@types/jest": { + "version": "29.2.4", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.2.4.tgz", + "integrity": "sha512-PipFB04k2qTRPePduVLTRiPzQfvMeLwUN3Z21hsAKaB/W9IIzgB2pizCL466ftJlcyZqnHoC9ZHpxLGl3fS86A==", + "dev": true, + "requires": { + "expect": "^29.0.0", + "pretty-format": "^29.0.0" + } + }, "@types/json-schema": { "version": "7.0.11", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", @@ -13486,6 +14653,22 @@ "@types/node": "*" } }, + "@types/libsodium-wrappers": { + "version": "0.7.10", + "resolved": "https://registry.npmjs.org/@types/libsodium-wrappers/-/libsodium-wrappers-0.7.10.tgz", + "integrity": "sha512-BqI9B92u+cM3ccp8mpHf+HzJ8fBlRwdmyd6+fz3p99m3V6ifT5O3zmOMi612PGkpeFeG/G6loxUnzlDNhfjPSA==" + }, + "@types/lodash": { + "version": "4.14.191", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.191.tgz", + "integrity": "sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ==", + "dev": true + }, + "@types/long": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz", + "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==" + }, "@types/mime": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", @@ -13507,9 +14690,9 @@ } }, "@types/prettier": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.1.tgz", - "integrity": "sha512-ri0UmynRRvZiiUJdiz38MmIblKK+oH30MztdBVR95dv/Ubw6neWSb8u1XpRb72L4qsZOhz+L+z9JD40SJmfWow==", + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.2.tgz", + "integrity": "sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg==", "dev": true }, "@types/qs": { @@ -13546,6 +14729,25 @@ "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", "dev": true }, + "@types/superagent": { + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/@types/superagent/-/superagent-4.1.16.tgz", + "integrity": "sha512-tLfnlJf6A5mB6ddqF159GqcDizfzbMUB1/DeT59/wBNqzRTNNKsaw79A/1TZ84X+f/EwWH8FeuSkjlCLyqS/zQ==", + "dev": true, + "requires": { + "@types/cookiejar": "*", + "@types/node": "*" + } + }, + "@types/supertest": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/@types/supertest/-/supertest-2.0.12.tgz", + "integrity": "sha512-X3HPWTwXRerBZS7Mo1k6vMVR1Z6zmJcDVn5O/31whe0tnjE4te6ZJSJGq1RiqHPjzPdMTfjCFogDJmwng9xHaQ==", + "dev": true, + "requires": { + "@types/superagent": "*" + } + }, "@types/swagger-jsdoc": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/@types/swagger-jsdoc/-/swagger-jsdoc-6.0.1.tgz", @@ -13692,8 +14894,7 @@ "abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" }, "accepts": { "version": "1.3.8", @@ -13763,8 +14964,7 @@ "ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" }, "ansi-styles": { "version": "4.3.0", @@ -13785,6 +14985,20 @@ "picomatch": "^2.0.4" } }, + "aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==" + }, + "are-we-there-yet": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", + "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + } + }, "arg": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", @@ -13794,8 +15008,7 @@ "argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, "array-flatten": { "version": "1.1.1", @@ -13808,21 +15021,42 @@ "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "dev": true }, + "asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "dev": true + }, "assert-plus": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", "dev": true }, + "async": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", + "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==" + }, + "async-exit-hook": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/async-exit-hook/-/async-exit-hook-2.0.1.tgz", + "integrity": "sha512-NW2cX8m1Q7KPA7a5M2ULQeZ2wR5qI5PAbw5L0UOMxdioVk9PMZ0h1TmyZEkPYrCvYjDlFICusOu1dlEKAAeXBw==" + }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, + "await-to-js": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/await-to-js/-/await-to-js-3.0.0.tgz", + "integrity": "sha512-zJAaP9zxTcvTHRlejau3ZOY4V7SRpiByf3/dxx2uyKxxor19tpmpV2QRsTKikckwhaPmr2dVpxxMr7jOCYVp5g==" + }, "axios": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.1.3.tgz", - "integrity": "sha512-00tXVRwKx/FZr/IDVFt4C+f9FYairX517WoGCL6dpOntqLkZofjhu43F/Xl44UOpqa+9sLFDrG/XAnFsUYgkDA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.2.0.tgz", + "integrity": "sha512-zT7wZyNYu3N5Bu0wuZ6QccIf93Qk1eV8LOewxgjOZFd2DenOs98cJ7+Y6703d0wkaXGY6/nZd4EweJaHz9uzQw==", "requires": { "follow-redirects": "^1.15.0", "form-data": "^4.0.0", @@ -13909,6 +15143,20 @@ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" }, + "bcrypt": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-5.1.0.tgz", + "integrity": "sha512-RHBS7HI5N5tEnGTmtR/pppX0mmDSBpQ4aCBsj7CEQfYXDcO74A8sIBYcJMuCsis2E81zDxeENYhv66oZwLiA+Q==", + "requires": { + "@mapbox/node-pre-gyp": "^1.0.10", + "node-addon-api": "^5.0.0" + } + }, + "before-after-hook": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz", + "integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==" + }, "bigint-conversion": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/bigint-conversion/-/bigint-conversion-2.2.2.tgz", @@ -13993,6 +15241,15 @@ "update-browserslist-db": "^1.0.9" } }, + "bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, + "requires": { + "fast-json-stable-stringify": "2.x" + } + }, "bser": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", @@ -14010,6 +15267,11 @@ "buffer": "^5.6.0" } }, + "btoa": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/btoa/-/btoa-1.2.1.tgz", + "integrity": "sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g==" + }, "buffer": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", @@ -14030,6 +15292,11 @@ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, + "builder-pattern": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/builder-pattern/-/builder-pattern-2.2.0.tgz", + "integrity": "sha512-cES3qdeBzA4QyJi7rV/l/kAhIFX6AKo3vK66ZPXLNpjcQWCS8sjLKscly8imlfW2YPTo/hquMRMnaWpZ80Kj+g==" + }, "bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -14117,6 +15384,11 @@ } } }, + "chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==" + }, "ci-info": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.5.0.tgz", @@ -14161,6 +15433,30 @@ "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", "dev": true }, + "color": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", + "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", + "requires": { + "color-convert": "^1.9.3", + "color-string": "^1.6.0" + }, + "dependencies": { + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + } + } + }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -14173,8 +15469,30 @@ "color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "requires": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==" + }, + "colorspace": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", + "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", + "requires": { + "color": "^3.1.3", + "text-hex": "1.0.x" + } }, "combined-stream": { "version": "1.0.8", @@ -14184,11 +15502,22 @@ "delayed-stream": "~1.0.0" } }, + "component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", + "dev": true + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==" + }, "content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", @@ -14234,6 +15563,12 @@ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" }, + "cookiejar": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz", + "integrity": "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==", + "dev": true + }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", @@ -14267,6 +15602,15 @@ "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", "dev": true }, + "cross-env": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", + "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.1" + } + }, "cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -14311,14 +15655,18 @@ "deepmerge": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", - "dev": true + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==" }, "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==" + }, "denque": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", @@ -14329,17 +15677,37 @@ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" }, + "deprecation": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", + "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==" + }, "destroy": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" }, + "detect-libc": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz", + "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==" + }, "detect-newline": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", "dev": true }, + "dezalgo": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", + "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", + "dev": true, + "requires": { + "asap": "^2.0.0", + "wrappy": "1" + } + }, "diff": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", @@ -14403,14 +15771,40 @@ "emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "enabled": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" }, "encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" }, + "encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "optional": true, + "peer": true, + "requires": { + "iconv-lite": "^0.6.2" + }, + "dependencies": { + "iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "optional": true, + "peer": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + } + } + }, "error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -14502,22 +15896,6 @@ } } }, - "eslint-config-prettier": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz", - "integrity": "sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==", - "dev": true, - "requires": {} - }, - "eslint-plugin-prettier": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz", - "integrity": "sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==", - "dev": true, - "requires": { - "prettier-linter-helpers": "^1.0.0" - } - }, "eslint-scope": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", @@ -14740,12 +16118,6 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true }, - "fast-diff": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", - "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", - "dev": true - }, "fast-glob": { "version": "3.2.12", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", @@ -14782,6 +16154,12 @@ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, + "fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", + "dev": true + }, "fast-xml-parser": { "version": "4.0.11", "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.0.11.tgz", @@ -14809,6 +16187,11 @@ "bser": "2.1.1" } }, + "fecha": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", + "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==" + }, "file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -14887,6 +16270,11 @@ "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "dev": true }, + "fn.name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" + }, "follow-redirects": { "version": "1.15.2", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", @@ -14902,6 +16290,18 @@ "mime-types": "^2.1.12" } }, + "formidable": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-2.1.1.tgz", + "integrity": "sha512-0EcS9wCFEzLvfiks7omJ+SiYJAiD+TzK4Pcw1UlUoGnhUxDcMKjt0P7x8wEb0u6OHu8Nb98WG3nxtlF5C7bvUQ==", + "dev": true, + "requires": { + "dezalgo": "^1.0.4", + "hexoid": "^1.0.0", + "once": "^1.4.0", + "qs": "^6.11.0" + } + }, "forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -14912,6 +16312,24 @@ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" }, + "fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "requires": { + "minipass": "^3.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "requires": { + "yallist": "^4.0.0" + } + } + } + }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -14929,6 +16347,22 @@ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, + "gauge": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", + "requires": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" + } + }, "gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -15059,6 +16493,11 @@ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==" + }, "hash-base": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", @@ -15074,6 +16513,12 @@ "resolved": "https://registry.npmjs.org/helmet/-/helmet-5.1.1.tgz", "integrity": "sha512-/yX0oVZBggA9cLJh8aw3PPCfedBnbd7J2aowjzsaWwZh7/UFY0nccn/aHAggIgWUFfnykX8GKd3a1pSbrmlcVQ==" }, + "hexoid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hexoid/-/hexoid-1.0.0.tgz", + "integrity": "sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g==", + "dev": true + }, "html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", @@ -15231,8 +16676,7 @@ "is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" }, "is-generator-fn": { "version": "2.1.0", @@ -15261,11 +16705,15 @@ "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", "dev": true }, + "is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==" + }, "is-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==" }, "isexe": { "version": "2.0.0", @@ -15505,6 +16953,18 @@ "walker": "^1.0.8" } }, + "jest-junit": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/jest-junit/-/jest-junit-15.0.0.tgz", + "integrity": "sha512-Z5sVX0Ag3HZdMUnD5DFlG+1gciIFSy7yIVPhOdGUi8YJaI9iLvvBb530gtQL2CHmv0JJeiwRZenr0VrSR7frvg==", + "dev": true, + "requires": { + "mkdirp": "^1.0.4", + "strip-ansi": "^6.0.1", + "uuid": "^8.3.2", + "xml": "^1.0.1" + } + }, "jest-leak-detector": { "version": "29.3.1", "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.3.1.tgz", @@ -15769,7 +17229,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, "requires": { "argparse": "^2.0.1" } @@ -15810,33 +17269,19 @@ "dev": true }, "json5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", - "dev": true + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==" }, "jsonwebtoken": { - "version": "8.5.1", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", - "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz", + "integrity": "sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw==", "requires": { "jws": "^3.2.2", - "lodash.includes": "^4.3.0", - "lodash.isboolean": "^3.0.3", - "lodash.isinteger": "^4.0.4", - "lodash.isnumber": "^3.0.3", - "lodash.isplainobject": "^4.0.6", - "lodash.isstring": "^4.0.1", - "lodash.once": "^4.0.0", + "lodash": "^4.17.21", "ms": "^2.1.1", - "semver": "^5.6.0" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" - } + "semver": "^7.3.8" } }, "jsprim": { @@ -15891,6 +17336,11 @@ "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", "dev": true }, + "kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" + }, "leven": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", @@ -15907,6 +17357,19 @@ "type-check": "~0.4.0" } }, + "libsodium": { + "version": "0.7.10", + "resolved": "https://registry.npmjs.org/libsodium/-/libsodium-0.7.10.tgz", + "integrity": "sha512-eY+z7hDrDKxkAK+QKZVNv92A5KYkxfvIshtBJkmg5TSiCnYqZP3i9OO9whE79Pwgm4jGaoHgkM4ao/b9Cyu4zQ==" + }, + "libsodium-wrappers": { + "version": "0.7.10", + "resolved": "https://registry.npmjs.org/libsodium-wrappers/-/libsodium-wrappers-0.7.10.tgz", + "integrity": "sha512-pO3F1Q9NPLB/MWIhehim42b/Fwb30JNScCNh8TcQ/kIc+qGLQch8ag8wb0keK3EP5kbGakk1H8Wwo7v+36rNQg==", + "requires": { + "libsodium": "^0.7.0" + } + }, "lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", @@ -15927,35 +17390,11 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, - "lodash.includes": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", - "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" - }, - "lodash.isboolean": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", - "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" - }, - "lodash.isinteger": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", - "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" - }, - "lodash.isnumber": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", - "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" - }, - "lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" - }, - "lodash.isstring": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", - "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" + "lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "dev": true }, "lodash.merge": { "version": "4.6.2", @@ -15963,10 +17402,22 @@ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, - "lodash.once": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", - "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" + "logform": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.4.2.tgz", + "integrity": "sha512-W4c9himeAwXEdZ05dQNerhFz2XG80P9Oj0loPUMV23VC2it0orMHQhJm4hdnnor3rd1HsGf6a2lPwBM1zeXHGw==", + "requires": { + "@colors/colors": "1.5.0", + "fecha": "^4.2.0", + "ms": "^2.1.1", + "safe-stable-stringify": "^2.3.1", + "triple-beam": "^1.3.0" + } + }, + "long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" }, "lru_map": { "version": "0.3.3", @@ -15977,7 +17428,6 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, "requires": { "yallist": "^4.0.0" } @@ -15986,7 +17436,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, "requires": { "semver": "^6.0.0" }, @@ -15994,8 +17443,7 @@ "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" } } }, @@ -16120,6 +17568,38 @@ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==" }, + "minipass": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.0.0.tgz", + "integrity": "sha512-g2Uuh2jEKoht+zvO6vJqXmYpflPqzRBT+Th2h01DKh5z7wbY/AZ2gCQ78cP70YoHPyFdY30YBV5WxgLOEwOykw==", + "requires": { + "yallist": "^4.0.0" + } + }, + "minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "requires": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" + }, "mmdb-lib": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/mmdb-lib/-/mmdb-lib-2.0.2.tgz", @@ -16149,9 +17629,9 @@ } }, "mongoose": { - "version": "6.7.2", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-6.7.2.tgz", - "integrity": "sha512-lrP2V5U1qhaf+z33fiIn7aYAZZ1fVDly+TkFRjTujNBF/FIHESATj2RbgAOSlWqv32fsZXkXejXzeVfjbv35Ow==", + "version": "6.7.3", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-6.7.3.tgz", + "integrity": "sha512-bLC2Pt6Vpoov+1kBYvQgJXG/2DWXbfIvfK4Gh68kCdYGh6CVO31YxYuIGz70hyGwX2g4DmSzbs5IA8Px2neMCQ==", "requires": { "bson": "^4.7.0", "kareem": "2.4.1", @@ -16209,6 +17689,40 @@ "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" }, + "node-addon-api": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.0.0.tgz", + "integrity": "sha512-CvkDw2OEnme7ybCykJpVcKH+uAOLV2qLqiyla128dN9TkEWfrYmxG6C2boDe5KcNQqZF3orkqzGgOMvZ/JNekA==" + }, + "node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "requires": { + "whatwg-url": "^5.0.0" + }, + "dependencies": { + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + } + } + }, "node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -18089,6 +19603,17 @@ "path-key": "^3.0.0" } }, + "npmlog": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", + "requires": { + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" + } + }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -18115,6 +19640,14 @@ "wrappy": "1" } }, + "one-time": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", + "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "requires": { + "fn.name": "1.x.x" + } + }, "onetime": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", @@ -18289,9 +19822,9 @@ } }, "posthog-node": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/posthog-node/-/posthog-node-2.1.0.tgz", - "integrity": "sha512-xr56mZRQo7rnL2YdwbipcxTZeyi5dcI6IM4++wIN7JLYwinrJYcQv01nan4gU4kMy33Qz5qT6boWMQRwpKZJVQ==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/posthog-node/-/posthog-node-2.2.3.tgz", + "integrity": "sha512-dYlLZhrDus+uRov/Hh+EiRlMoMhRKchNjNa7mNE2iWmKg/ryOTipf0XYKS9UKdki7aU1NzWFhnLe11HF615XuA==", "requires": { "axios": "^0.27.0" }, @@ -18313,21 +19846,6 @@ "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true }, - "prettier": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz", - "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==", - "dev": true - }, - "prettier-linter-helpers": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", - "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", - "dev": true, - "requires": { - "fast-diff": "^1.1.2" - } - }, "pretty-format": { "version": "29.3.1", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.3.1.tgz", @@ -18357,6 +19875,26 @@ "sisteransi": "^1.0.5" } }, + "protobufjs": { + "version": "6.11.3", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.3.tgz", + "integrity": "sha512-xL96WDdCZYdU7Slin569tFX712BxsxslWwAfAhCYjQKGTq7dAU91Lomy6nLLhh/dyGhk/YH4TwTSRxTzhuHyZg==", + "requires": { + "@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" + } + }, "proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -18468,6 +20006,11 @@ "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", "dev": true }, + "request-ip": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/request-ip/-/request-ip-3.3.0.tgz", + "integrity": "sha512-cA6Xh6e0fDBBBwH77SLJaJPBmD3nWVAcF9/XAcsrIHdjhFzFiB5aNQFytdjCGPezU3ROwrR11IddKAM08vohxA==" + }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -18551,6 +20094,11 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" }, + "safe-stable-stringify": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.1.tgz", + "integrity": "sha512-dVHE6bMtS/bnL2mwualjc6IxEv1F+OCUpA46pKUj6F8uDbUM0jCCulPqRNPSnWwGNKx5etqMjZYdXtrm5KJZGA==" + }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -18569,7 +20117,6 @@ "version": "7.3.8", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, "requires": { "lru-cache": "^6.0.0" } @@ -18627,6 +20174,11 @@ "send": "0.18.0" } }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" + }, "setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", @@ -18674,8 +20226,22 @@ "signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, + "simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "requires": { + "is-arrayish": "^0.3.1" + }, + "dependencies": { + "is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + } + } }, "simple-update-notifier": { "version": "1.0.7", @@ -18711,6 +20277,27 @@ "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==" }, + "snappy": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/snappy/-/snappy-7.1.1.tgz", + "integrity": "sha512-mL7GGPJ+WdsaFT5aR/uEqCq8cPg2VbhyifDEP7AeqIVDsAC8LBGYbZP1Qzoa2Ym84OW7JEQXqIpwqFp1EQw5BA==", + "optional": true, + "requires": { + "@napi-rs/snappy-android-arm-eabi": "7.1.1", + "@napi-rs/snappy-android-arm64": "7.1.1", + "@napi-rs/snappy-darwin-arm64": "7.1.1", + "@napi-rs/snappy-darwin-x64": "7.1.1", + "@napi-rs/snappy-freebsd-x64": "7.1.1", + "@napi-rs/snappy-linux-arm-gnueabihf": "7.1.1", + "@napi-rs/snappy-linux-arm64-gnu": "7.1.1", + "@napi-rs/snappy-linux-arm64-musl": "7.1.1", + "@napi-rs/snappy-linux-x64-gnu": "7.1.1", + "@napi-rs/snappy-linux-x64-musl": "7.1.1", + "@napi-rs/snappy-win32-arm64-msvc": "7.1.1", + "@napi-rs/snappy-win32-ia32-msvc": "7.1.1", + "@napi-rs/snappy-win32-x64-msvc": "7.1.1" + } + }, "socks": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", @@ -18755,6 +20342,11 @@ "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", "dev": true }, + "stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==" + }, "stack-utils": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", @@ -18809,7 +20401,6 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, "requires": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -18820,7 +20411,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "requires": { "ansi-regex": "^5.0.1" } @@ -18858,6 +20448,42 @@ "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==", "optional": true }, + "superagent": { + "version": "8.0.6", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-8.0.6.tgz", + "integrity": "sha512-HqSe6DSIh3hEn6cJvCkaM1BLi466f1LHi4yubR0tpewlMpk4RUFFy35bKz8SsPBwYfIIJy5eclp+3tCYAuX0bw==", + "dev": true, + "requires": { + "component-emitter": "^1.3.0", + "cookiejar": "^2.1.3", + "debug": "^4.3.4", + "fast-safe-stringify": "^2.1.1", + "form-data": "^4.0.0", + "formidable": "^2.1.1", + "methods": "^1.1.2", + "mime": "2.6.0", + "qs": "^6.11.0", + "semver": "^7.3.8" + }, + "dependencies": { + "mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true + } + } + }, + "supertest": { + "version": "6.3.3", + "resolved": "https://registry.npmjs.org/supertest/-/supertest-6.3.3.tgz", + "integrity": "sha512-EMCG6G8gDu5qEqRQ3JjjPs6+FYT1a7Hv5ApHvtSghmOFJYtsU5S+pSb6Y2EUeCEY3CmEL3mmQ8YWlPOzQomabA==", + "dev": true, + "requires": { + "methods": "^1.1.2", + "superagent": "^8.0.5" + } + }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -18873,6 +20499,50 @@ "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "dev": true }, + "swagger-autogen": { + "version": "2.22.0", + "resolved": "https://registry.npmjs.org/swagger-autogen/-/swagger-autogen-2.22.0.tgz", + "integrity": "sha512-MPdtwgx/RL3og0RjFVV9hPoQv3x+c3ZRhS0Vjp9k94DLV7iUgIuCg8H+uAT8oD5w48ATTRT1VjcOHlCGH62pdA==", + "requires": { + "acorn": "^7.4.1", + "deepmerge": "^4.2.2", + "glob": "^7.1.7", + "json5": "^2.2.1" + }, + "dependencies": { + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==" + } + } + }, + "swagger-ui-dist": { + "version": "4.15.5", + "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-4.15.5.tgz", + "integrity": "sha512-V3eIa28lwB6gg7/wfNvAbjwJYmDXy1Jo1POjyTzlB6wPcHiGlRxq39TSjYGVjQrUSAzpv+a7nzp7mDxgNy57xA==" + }, + "swagger-ui-express": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/swagger-ui-express/-/swagger-ui-express-4.6.0.tgz", + "integrity": "sha512-ZxpQFp1JR2RF8Ar++CyJzEDdvufa08ujNUJgMVTMWPi86CuQeVdBtvaeO/ysrz6dJAYXf9kbVNhWD7JWocwqsA==", + "requires": { + "swagger-ui-dist": ">=4.11.0" + } + }, + "tar": { + "version": "6.1.13", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.13.tgz", + "integrity": "sha512-jdIBIN6LTIe2jqzay/2vtYLlBHa3JF42ot3h1dW8Q0PaAG4v8rm0cvpVePtau5C6OKXGGcgO9q2AMNSWxiLqKw==", + "requires": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^4.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + } + }, "test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", @@ -18884,6 +20554,11 @@ "minimatch": "^3.0.4" } }, + "text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" + }, "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -18939,6 +20614,27 @@ "punycode": "^2.1.1" } }, + "triple-beam": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", + "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==" + }, + "ts-jest": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.0.3.tgz", + "integrity": "sha512-Ibygvmuyq1qp/z3yTh9QTwVVAbFdDy/+4BtIQR2sp6baF2SJU/8CKK/hhnGIDY2L90Az2jIqTwZPnN2p+BweiQ==", + "dev": true, + "requires": { + "bs-logger": "0.x", + "fast-json-stable-stringify": "2.x", + "jest-util": "^29.0.0", + "json5": "^2.2.1", + "lodash.memoize": "4.x", + "make-error": "1.x", + "semver": "7.x", + "yargs-parser": "^21.0.1" + } + }, "ts-node": { "version": "10.9.1", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", @@ -19031,6 +20727,11 @@ "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", "dev": true }, + "universal-user-agent": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz", + "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==" + }, "unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", @@ -19060,6 +20761,11 @@ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, + "utility-types": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.10.0.tgz", + "integrity": "sha512-O11mqxmi7wMKCo6HKFt5AhO4BwY3VV68YU07tgxfz8zJTIxr4BpsezN49Ffwy9j3ZpwwJp4fkRwjRzq3uWE6Rg==" + }, "utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", @@ -19069,7 +20775,7 @@ "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "optional": true + "devOptional": true }, "v8-compile-cache-lib": { "version": "3.0.1", @@ -19159,6 +20865,54 @@ "isexe": "^2.0.0" } }, + "wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "requires": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "winston": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.8.2.tgz", + "integrity": "sha512-MsE1gRx1m5jdTTO9Ld/vND4krP2To+lgDoMEHGGa4HIlAUyXJtfc7CxQcGXVyz2IBpw5hbFkj2b/AtUdQwyRew==", + "requires": { + "@colors/colors": "1.5.0", + "@dabh/diagnostics": "^2.0.2", + "async": "^3.2.3", + "is-stream": "^2.0.0", + "logform": "^2.4.0", + "one-time": "^1.0.0", + "readable-stream": "^3.4.0", + "safe-stable-stringify": "^2.3.1", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.5.0" + } + }, + "winston-loki": { + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/winston-loki/-/winston-loki-6.0.6.tgz", + "integrity": "sha512-cll+nv5T/b9uJXqca0N2WKL1JJNuJND9E6WOOAuSGkZ44L9VQ/QK9F+/5VKbv6LIP9p0nvPSOYxtACCDb/9iWw==", + "requires": { + "async-exit-hook": "2.0.1", + "btoa": "^1.2.1", + "protobufjs": "^6.8.8", + "snappy": "7.1.1", + "winston-transport": "^4.3.0" + } + }, + "winston-transport": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.5.0.tgz", + "integrity": "sha512-YpZzcUzBedhlTAfJg6vJDlyEai/IFMIVcaEZZyl3UXIl4gmqRpU7AE89AHLkbzLUsv0NVmw7ts+iztqKxxPW1Q==", + "requires": { + "logform": "^2.3.2", + "readable-stream": "^3.6.0", + "triple-beam": "^1.3.0" + } + }, "word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", @@ -19196,6 +20950,12 @@ "signal-exit": "^3.0.7" } }, + "xml": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz", + "integrity": "sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw==", + "dev": true + }, "y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", @@ -19205,8 +20965,7 @@ "yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "yargs": { "version": "17.6.2", diff --git a/backend/package.json b/backend/package.json index 86c8b2b80..f2a2710c9 100644 --- a/backend/package.json +++ b/backend/package.json @@ -2,9 +2,9 @@ "dependencies": { "@godaddy/terminus": "^4.11.2", "@sentry/node": "^7.21.1", - "@sentry/tracing": "^7.19.0", + "@sentry/tracing": "^7.21.1", "@types/crypto-js": "^4.1.1", - "axios": "^1.1.3", + "axios": "^1.2.0", "bigint-conversion": "^2.2.2", "cookie-parser": "^1.4.6", "cors": "^2.8.5", @@ -17,7 +17,7 @@ "helmet": "^5.1.1", "jsonwebtoken": "^8.5.1", "jsrp": "^0.2.4", - "mongoose": "^6.7.2", + "mongoose": "^6.7.3", "nodemailer": "^6.8.0", "posthog-node": "^2.1.0", "query-string": "^7.1.3", @@ -33,11 +33,15 @@ "scripts": { "start": "npm run build && node build/index.js", "dev": "nodemon", - "build": "rimraf ./build && tsc && cp -R ./src/templates ./src/json ./build", + "swagger-autogen": "node ./swagger/index.ts", + "build": "rimraf ./build && tsc && cp -R ./src/templates ./build", "lint": "eslint . --ext .ts", "lint-and-fix": "eslint . --ext .ts --fix", - "prettier-format": "prettier --config .prettierrc 'src/**/*.ts' --write", - "lint-staged": "lint-staged" + "lint-staged": "lint-staged", + "pretest": "docker compose -f test-resources/docker-compose.test.yml up -d", + "test": "cross-env NODE_ENV=test jest --testTimeout=10000 --detectOpenHandles", + "test:ci": "npm test -- --watchAll=false --ci --reporters=default --reporters=jest-junit --reporters=github-actions --coverage --testLocationInResults --json --outputFile=coverage/report.json", + "posttest": "docker compose -f test-resources/docker-compose.test.yml down" }, "repository": { "type": "git", @@ -51,25 +55,94 @@ "homepage": "https://github.com/Infisical/infisical-api#readme", "description": "", "devDependencies": { + "@jest/globals": "^29.3.1", "@posthog/plugin-scaffold": "^1.3.4", + "@types/bcrypt": "^5.0.0", + "@types/bcryptjs": "^2.4.2", "@types/cookie-parser": "^1.4.3", "@types/cors": "^2.8.12", "@types/express": "^4.17.14", + "@types/jest": "^29.2.4", "@types/jsonwebtoken": "^8.5.9", + "@types/lodash": "^4.14.191", "@types/node": "^18.11.3", "@types/nodemailer": "^6.4.6", + "@types/supertest": "^2.0.12", "@types/swagger-jsdoc": "^6.0.1", "@types/swagger-ui-express": "^4.1.3", "@typescript-eslint/eslint-plugin": "^5.40.1", "@typescript-eslint/parser": "^5.40.1", + "cross-env": "^7.0.3", "eslint": "^8.26.0", - "eslint-config-prettier": "^8.5.0", - "eslint-plugin-prettier": "^4.2.1", "install": "^0.13.0", "jest": "^29.3.1", + "jest-junit": "^15.0.0", "nodemon": "^2.0.19", "npm": "^8.19.3", - "prettier": "^2.7.1", + "supertest": "^6.3.3", + "ts-jest": "^29.0.3", "ts-node": "^10.9.1" + }, + "jest": { + "preset": "ts-jest", + "testEnvironment": "node", + "collectCoverageFrom": [ + "src/*.{js,ts}", + "!**/node_modules/**" + ], + "setupFiles": [ + "/test-resources/env-vars.js" + ] + }, + "jest-junit": { + "outputDirectory": "reports", + "outputName": "jest-junit.xml", + "ancestorSeparator": " โ€บ ", + "uniqueOutputName": "false", + "suiteNameTemplate": "{filepath}", + "classNameTemplate": "{classname}", + "titleTemplate": "{title}" + }, + "dependencies": { + "@godaddy/terminus": "^4.11.2", + "@octokit/rest": "^19.0.5", + "@sentry/node": "^7.14.0", + "@sentry/tracing": "^7.19.0", + "@types/crypto-js": "^4.1.1", + "@types/libsodium-wrappers": "^0.7.10", + "await-to-js": "^3.0.0", + "axios": "^1.1.3", + "bcrypt": "^5.1.0", + "bigint-conversion": "^2.2.2", + "builder-pattern": "^2.2.0", + "cookie-parser": "^1.4.6", + "cors": "^2.8.5", + "crypto-js": "^4.1.1", + "dotenv": "^16.0.1", + "express": "^4.18.1", + "express-rate-limit": "^6.7.0", + "express-validator": "^6.14.2", + "handlebars": "^4.7.7", + "helmet": "^5.1.1", + "js-yaml": "^4.1.0", + "jsonwebtoken": "^9.0.0", + "jsrp": "^0.2.4", + "libsodium-wrappers": "^0.7.10", + "lodash": "^4.17.21", + "mongoose": "^6.7.2", + "nodemailer": "^6.8.0", + "posthog-node": "^2.2.2", + "query-string": "^7.1.3", + "request-ip": "^3.3.0", + "rimraf": "^3.0.2", + "stripe": "^10.7.0", + "swagger-autogen": "^2.22.0", + "swagger-ui-express": "^4.6.0", + "tweetnacl": "^1.0.3", + "tweetnacl-util": "^0.15.1", + "typescript": "^4.9.3", + "utility-types": "^3.10.0", + "winston": "^3.8.2", + "winston-loki": "^6.0.6" } } diff --git a/backend/spec.json b/backend/spec.json new file mode 100644 index 000000000..0b0e275b6 --- /dev/null +++ b/backend/spec.json @@ -0,0 +1,4146 @@ +{ + "openapi": "3.0.0", + "info": { + "title": "Infisical API", + "description": "List of all available APIs that can be consumed", + "version": "1.0.0" + }, + "servers": [ + { + "url": "https://infisical.com", + "description": "Production server" + }, + { + "url": "http://localhost:8080", + "description": "Local server" + } + ], + "paths": { + "/api/v1/secret/{secretId}/secret-versions": { + "get": { + "summary": "Return secret versions", + "description": "Return secret versions", + "parameters": [ + { + "name": "secretId", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "ID of secret" + }, + { + "name": "offset", + "description": "Number of versions to skip", + "required": false, + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "limit", + "description": "Maximum number of versions to return", + "required": false, + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "secretVersions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SecretVersion" + }, + "description": "Secret versions" + } + } + } + } + } + }, + "400": { + "description": "Bad Request" + } + }, + "security": [ + { + "apiKeyAuth": [] + } + ] + } + }, + "/api/v1/secret/{secretId}/secret-versions/rollback": { + "post": { + "summary": "Roll back secret to a version.", + "description": "Roll back secret to a version.", + "parameters": [ + { + "name": "secretId", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "ID of secret" + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "secret": { + "type": "object", + "$ref": "#/components/schemas/Secret", + "description": "Secret rolled back to" + } + } + } + } + } + }, + "400": { + "description": "Bad Request" + } + }, + "security": [ + { + "apiKeyAuth": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "version": { + "type": "integer", + "description": "Version of secret to roll back to" + } + } + } + } + } + } + } + }, + "/api/v1/secret-snapshot/{secretSnapshotId}": { + "get": { + "description": "", + "parameters": [ + { + "name": "secretSnapshotId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + }, + "/api/v1/workspace/{workspaceId}/secret-snapshots": { + "get": { + "summary": "Return project secret snapshot ids", + "description": "Return project secret snapshots ids", + "parameters": [ + { + "name": "workspaceId", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "ID of project" + }, + { + "name": "offset", + "description": "Number of secret snapshots to skip", + "required": false, + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "limit", + "description": "Maximum number of secret snapshots to return", + "required": false, + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "secretSnapshots": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SecretSnapshot" + }, + "description": "Project secret snapshots" + } + } + } + } + } + }, + "400": { + "description": "Bad Request" + } + }, + "security": [ + { + "apiKeyAuth": [] + } + ] + } + }, + "/api/v1/workspace/{workspaceId}/secret-snapshots/count": { + "get": { + "description": "", + "parameters": [ + { + "name": "workspaceId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + }, + "/api/v1/workspace/{workspaceId}/secret-snapshots/rollback": { + "post": { + "summary": "Roll back project secrets to those captured in a secret snapshot version.", + "description": "Roll back project secrets to those captured in a secret snapshot version.", + "parameters": [ + { + "name": "workspaceId", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "ID of project" + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "secrets": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Secret" + }, + "description": "Secrets rolled back to" + } + } + } + } + } + }, + "400": { + "description": "Bad Request" + } + }, + "security": [ + { + "apiKeyAuth": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "version": { + "type": "integer", + "description": "Version of secret snapshot to roll back to" + } + } + } + } + } + } + } + }, + "/api/v1/workspace/{workspaceId}/logs": { + "get": { + "summary": "Return project (audit) logs", + "description": "Return project (audit) logs", + "parameters": [ + { + "name": "workspaceId", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "ID of project" + }, + { + "name": "userId", + "description": "ID of project member", + "required": false, + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "offset", + "description": "Number of logs to skip", + "required": false, + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "limit", + "description": "Maximum number of logs to return", + "required": false, + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "sortBy", + "description": "Order to sort the logs by", + "schema": { + "type": "string", + "enum": [ + "oldest", + "recent" + ] + }, + "required": false, + "in": "query" + }, + { + "name": "actionNames", + "description": "Names of log actions (comma-separated)", + "required": false, + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "logs": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Log" + }, + "description": "Project logs" + } + } + } + } + } + }, + "400": { + "description": "Bad Request" + } + }, + "security": [ + { + "apiKeyAuth": [] + } + ] + } + }, + "/api/v1/action/{actionId}": { + "get": { + "description": "", + "parameters": [ + { + "name": "actionId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/signup/email/signup": { + "post": { + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + }, + "403": { + "description": "Forbidden" + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "email": { + "example": "any" + } + } + } + } + } + } + } + }, + "/api/v1/signup/email/verify": { + "post": { + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + }, + "403": { + "description": "Forbidden" + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "email": { + "example": "any" + }, + "code": { + "example": "any" + } + } + } + } + } + } + } + }, + "/api/v1/signup/complete-account/signup": { + "post": { + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + }, + "403": { + "description": "Forbidden" + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "email": { + "example": "any" + }, + "firstName": { + "example": "any" + }, + "lastName": { + "example": "any" + }, + "publicKey": { + "example": "any" + }, + "encryptedPrivateKey": { + "example": "any" + }, + "iv": { + "example": "any" + }, + "tag": { + "example": "any" + }, + "salt": { + "example": "any" + }, + "verifier": { + "example": "any" + }, + "organizationName": { + "example": "any" + } + } + } + } + } + } + } + }, + "/api/v1/signup/complete-account/invite": { + "post": { + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + }, + "403": { + "description": "Forbidden" + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "email": { + "example": "any" + }, + "firstName": { + "example": "any" + }, + "lastName": { + "example": "any" + }, + "publicKey": { + "example": "any" + }, + "encryptedPrivateKey": { + "example": "any" + }, + "iv": { + "example": "any" + }, + "tag": { + "example": "any" + }, + "salt": { + "example": "any" + }, + "verifier": { + "example": "any" + } + } + } + } + } + } + } + }, + "/api/v1/auth/token": { + "post": { + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + }, + "/api/v1/auth/login1": { + "post": { + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "email": { + "example": "any" + }, + "clientPublicKey": { + "example": "any" + } + } + } + } + } + } + } + }, + "/api/v1/auth/login2": { + "post": { + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "email": { + "example": "any" + }, + "clientProof": { + "example": "any" + } + } + } + } + } + } + } + }, + "/api/v1/auth/logout": { + "post": { + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + }, + "/api/v1/auth/checkAuth": { + "post": { + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/bot/{workspaceId}": { + "get": { + "description": "", + "parameters": [ + { + "name": "workspaceId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + }, + "/api/v1/bot/{botId}/active": { + "patch": { + "description": "", + "parameters": [ + { + "name": "botId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "isActive": { + "example": "any" + }, + "botKey": { + "example": "any" + } + } + } + } + } + } + } + }, + "/api/v1/user/": { + "get": { + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/user-action/": { + "post": { + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "action": { + "example": "any" + } + } + } + } + } + } + }, + "get": { + "description": "", + "parameters": [ + { + "name": "action", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + }, + "/api/v1/organization/": { + "get": { + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + }, + "post": { + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "organizationName": { + "example": "any" + } + } + } + } + } + } + } + }, + "/api/v1/organization/{organizationId}": { + "get": { + "description": "", + "parameters": [ + { + "name": "organizationId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + }, + "/api/v1/organization/{organizationId}/users": { + "get": { + "description": "", + "parameters": [ + { + "name": "organizationId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + }, + "/api/v1/organization/{organizationId}/my-workspaces": { + "get": { + "description": "", + "parameters": [ + { + "name": "organizationId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + }, + "/api/v1/organization/{organizationId}/name": { + "patch": { + "description": "", + "parameters": [ + { + "name": "organizationId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { + "example": "any" + } + } + } + } + } + } + } + }, + "/api/v1/organization/{organizationId}/incidentContactOrg": { + "get": { + "description": "", + "parameters": [ + { + "name": "organizationId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + }, + "post": { + "description": "", + "parameters": [ + { + "name": "organizationId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "email": { + "example": "any" + } + } + } + } + } + } + }, + "delete": { + "description": "", + "parameters": [ + { + "name": "organizationId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "email": { + "example": "any" + } + } + } + } + } + } + } + }, + "/api/v1/organization/{organizationId}/customer-portal-session": { + "post": { + "description": "", + "parameters": [ + { + "name": "organizationId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + }, + "/api/v1/organization/{organizationId}/subscriptions": { + "get": { + "description": "", + "parameters": [ + { + "name": "organizationId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + }, + "/api/v1/workspace/{workspaceId}/keys": { + "get": { + "description": "", + "parameters": [ + { + "name": "workspaceId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + }, + "/api/v1/workspace/{workspaceId}/users": { + "get": { + "description": "", + "parameters": [ + { + "name": "workspaceId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + }, + "/api/v1/workspace/": { + "get": { + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + }, + "post": { + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "workspaceName": { + "example": "any" + }, + "organizationId": { + "example": "any" + } + } + } + } + } + } + } + }, + "/api/v1/workspace/{workspaceId}": { + "get": { + "description": "", + "parameters": [ + { + "name": "workspaceId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + }, + "delete": { + "description": "", + "parameters": [ + { + "name": "workspaceId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + }, + "/api/v1/workspace/{workspaceId}/name": { + "post": { + "description": "", + "parameters": [ + { + "name": "workspaceId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { + "example": "any" + } + } + } + } + } + } + } + }, + "/api/v1/workspace/{workspaceId}/invite-signup": { + "post": { + "description": "", + "parameters": [ + { + "name": "workspaceId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "email": { + "example": "any" + } + } + } + } + } + } + } + }, + "/api/v1/workspace/{workspaceId}/integrations": { + "get": { + "description": "", + "parameters": [ + { + "name": "workspaceId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + }, + "/api/v1/workspace/{workspaceId}/authorizations": { + "get": { + "description": "", + "parameters": [ + { + "name": "workspaceId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + }, + "/api/v1/workspace/{workspaceId}/service-tokens": { + "get": { + "description": "", + "parameters": [ + { + "name": "workspaceId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + }, + "/api/v1/membership-org/membershipOrg/{membershipOrgId}/change-role": { + "post": { + "description": "", + "parameters": [ + { + "name": "membershipOrgId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/membership-org/{membershipOrgId}": { + "delete": { + "description": "", + "parameters": [ + { + "name": "membershipOrgId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "400": { + "description": "Bad Request" + } + } + } + }, + "/api/v1/membership/{workspaceId}/connect": { + "get": { + "description": "", + "parameters": [ + { + "name": "workspaceId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + }, + "/api/v1/membership/{membershipId}": { + "delete": { + "description": "", + "parameters": [ + { + "name": "membershipId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + }, + "/api/v1/membership/{membershipId}/change-role": { + "post": { + "description": "", + "parameters": [ + { + "name": "membershipId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "role": { + "example": "any" + } + } + } + } + } + } + } + }, + "/api/v1/key/{workspaceId}": { + "post": { + "description": "", + "parameters": [ + { + "name": "workspaceId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "key": { + "example": "any" + } + } + } + } + } + } + } + }, + "/api/v1/key/{workspaceId}/latest": { + "get": { + "description": "", + "parameters": [ + { + "name": "workspaceId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + }, + "/api/v1/invite-org/signup": { + "post": { + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "organizationId": { + "example": "any" + }, + "inviteeEmail": { + "example": "any" + } + } + } + } + } + } + } + }, + "/api/v1/invite-org/verify": { + "post": { + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "email": { + "example": "any" + }, + "code": { + "example": "any" + } + } + } + } + } + } + } + }, + "/api/v1/secret/{workspaceId}": { + "post": { + "description": "", + "parameters": [ + { + "name": "workspaceId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "secrets": { + "example": "any" + }, + "keys": { + "example": "any" + }, + "environment": { + "example": "any" + }, + "channel": { + "example": "any" + } + } + } + } + } + } + }, + "get": { + "description": "", + "parameters": [ + { + "name": "workspaceId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "environment", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "channel", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + }, + "/api/v1/secret/{workspaceId}/service-token": { + "get": { + "description": "", + "parameters": [ + { + "name": "workspaceId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "environment", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "channel", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + }, + "/api/v1/service-token/": { + "get": { + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "OK" + } + } + }, + "post": { + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { + "example": "any" + }, + "workspaceId": { + "example": "any" + }, + "environment": { + "example": "any" + }, + "expiresIn": { + "example": "any" + }, + "publicKey": { + "example": "any" + }, + "encryptedKey": { + "example": "any" + }, + "nonce": { + "example": "any" + } + } + } + } + } + } + } + }, + "/api/v1/password/srp1": { + "post": { + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "clientPublicKey": { + "example": "any" + } + } + } + } + } + } + } + }, + "/api/v1/password/change-password": { + "post": { + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "clientProof": { + "example": "any" + }, + "encryptedPrivateKey": { + "example": "any" + }, + "iv": { + "example": "any" + }, + "tag": { + "example": "any" + }, + "salt": { + "example": "any" + }, + "verifier": { + "example": "any" + } + } + } + } + } + } + } + }, + "/api/v1/password/email/password-reset": { + "post": { + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + }, + "403": { + "description": "Forbidden" + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "email": { + "example": "any" + } + } + } + } + } + } + } + }, + "/api/v1/password/email/password-reset-verify": { + "post": { + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + }, + "403": { + "description": "Forbidden" + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "email": { + "example": "any" + }, + "code": { + "example": "any" + } + } + } + } + } + } + } + }, + "/api/v1/password/backup-private-key": { + "get": { + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + }, + "post": { + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "clientProof": { + "example": "any" + }, + "encryptedPrivateKey": { + "example": "any" + }, + "iv": { + "example": "any" + }, + "tag": { + "example": "any" + }, + "salt": { + "example": "any" + }, + "verifier": { + "example": "any" + } + } + } + } + } + } + } + }, + "/api/v1/password/password-reset": { + "post": { + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "encryptedPrivateKey": { + "example": "any" + }, + "iv": { + "example": "any" + }, + "tag": { + "example": "any" + }, + "salt": { + "example": "any" + }, + "verifier": { + "example": "any" + } + } + } + } + } + } + } + }, + "/api/v1/stripe/webhook": { + "post": { + "description": "", + "parameters": [ + { + "name": "stripe-signature", + "in": "header", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + }, + "/api/v1/integration/{integrationId}": { + "patch": { + "description": "", + "parameters": [ + { + "name": "integrationId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "app": { + "example": "any" + }, + "environment": { + "example": "any" + }, + "isActive": { + "example": "any" + }, + "target": { + "example": "any" + }, + "context": { + "example": "any" + }, + "siteId": { + "example": "any" + } + } + } + } + } + } + }, + "delete": { + "description": "", + "parameters": [ + { + "name": "integrationId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + }, + "/api/v1/integration-auth/integration-options": { + "get": { + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/integration-auth/oauth-token": { + "post": { + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "workspaceId": { + "example": "any" + }, + "code": { + "example": "any" + }, + "integration": { + "example": "any" + } + } + } + } + } + } + } + }, + "/api/v1/integration-auth/{integrationAuthId}/apps": { + "get": { + "description": "", + "parameters": [ + { + "name": "integrationAuthId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + }, + "/api/v1/integration-auth/{integrationAuthId}": { + "delete": { + "description": "", + "parameters": [ + { + "name": "integrationAuthId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + }, + "/api/v2/users/me": { + "get": { + "summary": "Retrieve the current user on the request", + "description": "Retrieve the current user on the request", + "parameters": [], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "user": { + "type": "object", + "$ref": "#/components/schemas/CurrentUser", + "description": "Current user on request" + } + } + } + } + } + }, + "400": { + "description": "Bad Request" + } + }, + "security": [ + { + "apiKeyAuth": [] + } + ] + } + }, + "/api/v2/users/me/organizations": { + "get": { + "summary": "Return organizations that current user is part of", + "description": "Return organizations that current user is part of", + "parameters": [], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "organizations": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Organization" + }, + "description": "Organizations that user is part of" + } + } + } + } + } + }, + "400": { + "description": "Bad Request" + } + }, + "security": [ + { + "apiKeyAuth": [] + } + ] + } + }, + "/api/v2/organizations/{organizationId}/memberships": { + "get": { + "summary": "Return organization memberships", + "description": "Return organization memberships", + "parameters": [ + { + "name": "organizationId", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "ID of organization" + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "memberships": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MembershipOrg" + }, + "description": "Memberships of organization" + } + } + } + } + } + }, + "400": { + "description": "Bad Request" + } + }, + "security": [ + { + "apiKeyAuth": [] + } + ] + } + }, + "/api/v2/organizations/{organizationId}/memberships/{membershipId}": { + "patch": { + "summary": "Update organization membership", + "description": "Update organization membership", + "parameters": [ + { + "name": "organizationId", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "ID of organization" + }, + { + "name": "membershipId", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "ID of organization membership to update" + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "membership": { + "$ref": "#/components/schemas/MembershipOrg", + "description": "Updated organization membership" + } + } + } + } + } + }, + "400": { + "description": "Bad Request" + } + }, + "security": [ + { + "apiKeyAuth": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "role": { + "type": "string", + "description": "Role of organization membership - either owner, admin, or member" + } + } + } + } + } + } + }, + "delete": { + "summary": "Delete organization membership", + "description": "Delete organization membership", + "parameters": [ + { + "name": "organizationId", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "ID of organization" + }, + { + "name": "membershipId", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "ID of organization membership to delete" + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "membership": { + "$ref": "#/components/schemas/MembershipOrg", + "description": "Deleted organization membership" + } + } + } + } + } + }, + "400": { + "description": "Bad Request" + } + }, + "security": [ + { + "apiKeyAuth": [] + } + ] + } + }, + "/api/v2/organizations/{organizationId}/workspaces": { + "get": { + "summary": "Return projects in organization that user is part of", + "description": "Return projects in organization that user is part of", + "parameters": [ + { + "name": "organizationId", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "ID of organization" + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "workspaces": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Project" + }, + "description": "Projects of organization" + } + } + } + } + } + }, + "400": { + "description": "Bad Request" + } + }, + "security": [ + { + "apiKeyAuth": [] + } + ] + } + }, + "/api/v2/workspace/{workspaceId}/environments": { + "post": { + "description": "", + "parameters": [ + { + "name": "workspaceId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "environmentName": { + "example": "any" + }, + "environmentSlug": { + "example": "any" + } + } + } + } + } + } + }, + "put": { + "description": "", + "parameters": [ + { + "name": "workspaceId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "environmentName": { + "example": "any" + }, + "environmentSlug": { + "example": "any" + }, + "oldEnvironmentSlug": { + "example": "any" + } + } + } + } + } + } + }, + "delete": { + "description": "", + "parameters": [ + { + "name": "workspaceId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "environmentSlug": { + "example": "any" + } + } + } + } + } + } + } + }, + "/api/v2/workspace/{workspaceId}/secrets": { + "post": { + "description": "", + "parameters": [ + { + "name": "workspaceId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "secrets": { + "example": "any" + }, + "keys": { + "example": "any" + }, + "environment": { + "example": "any" + }, + "channel": { + "example": "any" + } + } + } + } + } + } + }, + "get": { + "description": "", + "parameters": [ + { + "name": "workspaceId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "environment", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "channel", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + }, + "/api/v2/workspace/{workspaceId}/encrypted-key": { + "get": { + "summary": "Return encrypted project key", + "description": "Return encrypted project key", + "parameters": [ + { + "name": "workspaceId", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "ID of project" + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ProjectKey" + }, + "description": "Encrypted project key for the given project" + } + } + } + }, + "400": { + "description": "Bad Request" + } + }, + "security": [ + { + "apiKeyAuth": [] + } + ] + } + }, + "/api/v2/workspace/{workspaceId}/service-token-data": { + "get": { + "description": "", + "parameters": [ + { + "name": "workspaceId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + }, + "/api/v2/workspace/{workspaceId}/memberships": { + "get": { + "summary": "Return project memberships", + "description": "Return project memberships", + "parameters": [ + { + "name": "workspaceId", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "ID of project" + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "memberships": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Membership" + }, + "description": "Memberships of project" + } + } + } + } + } + }, + "400": { + "description": "Bad Request" + } + }, + "security": [ + { + "apiKeyAuth": [] + } + ] + } + }, + "/api/v2/workspace/{workspaceId}/memberships/{membershipId}": { + "patch": { + "summary": "Update project membership", + "description": "Update project membership", + "parameters": [ + { + "name": "workspaceId", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "ID of project" + }, + { + "name": "membershipId", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "ID of project membership to update" + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "membership": { + "$ref": "#/components/schemas/Membership", + "description": "Updated membership" + } + } + } + } + } + }, + "400": { + "description": "Bad Request" + } + }, + "security": [ + { + "apiKeyAuth": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "role": { + "type": "string", + "description": "Role of membership - either admin or member" + } + } + } + } + } + } + }, + "delete": { + "summary": "Delete project membership", + "description": "Delete project membership", + "parameters": [ + { + "name": "workspaceId", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "ID of project" + }, + { + "name": "membershipId", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "ID of project membership to delete" + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "membership": { + "$ref": "#/components/schemas/Membership", + "description": "Deleted membership" + } + } + } + } + } + }, + "400": { + "description": "Bad Request" + } + }, + "security": [ + { + "apiKeyAuth": [] + } + ] + } + }, + "/api/v2/secret/batch-create/workspace/{workspaceId}/environment/{environment}": { + "post": { + "description": "", + "parameters": [ + { + "name": "workspaceId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "environment", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "secrets": { + "example": "any" + } + } + } + } + } + } + } + }, + "/api/v2/secret/workspace/{workspaceId}/environment/{environment}": { + "post": { + "description": "", + "parameters": [ + { + "name": "workspaceId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "environment", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "secret": { + "example": "any" + } + } + } + } + } + } + } + }, + "/api/v2/secret/workspace/{workspaceId}": { + "get": { + "description": "", + "parameters": [ + { + "name": "workspaceId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "environment", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v2/secret/{secretId}": { + "get": { + "description": "", + "parameters": [ + { + "name": "secretId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + }, + "delete": { + "description": "", + "parameters": [ + { + "name": "secretId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v2/secret/batch/workspace/{workspaceId}/environment/{environmentName}": { + "delete": { + "description": "", + "parameters": [ + { + "name": "workspaceId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "environmentName", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "secretIds": { + "example": "any" + } + } + } + } + } + } + } + }, + "/api/v2/secret/batch-modify/workspace/{workspaceId}/environment/{environmentName}": { + "patch": { + "description": "", + "parameters": [ + { + "name": "workspaceId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "environmentName", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "secrets": { + "example": "any" + } + } + } + } + } + } + } + }, + "/api/v2/secret/workspace/{workspaceId}/environment/{environmentName}": { + "patch": { + "description": "", + "parameters": [ + { + "name": "workspaceId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "environmentName", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "secret": { + "example": "any" + } + } + } + } + } + } + } + }, + "/api/v2/secrets/": { + "post": { + "summary": "Create new secret(s)", + "description": "Create one or many secrets for a given project and environment.", + "parameters": [], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "secrets": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Secret" + }, + "description": "Newly-created secrets for the given project and environment" + } + } + } + } + } + } + }, + "security": [ + { + "apiKeyAuth": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "workspaceId": { + "type": "string", + "description": "ID of project" + }, + "environment": { + "type": "string", + "description": "Environment within project" + }, + "secrets": { + "$ref": "#/components/schemas/CreateSecret", + "description": "Secret(s) to create - object or array of objects" + } + } + } + } + } + } + }, + "get": { + "summary": "Read secrets", + "description": "Read secrets from a project and environment", + "parameters": [ + { + "name": "workspaceId", + "description": "ID of project", + "required": true, + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "environment", + "description": "Environment within project", + "required": true, + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "content", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "secrets": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Secret" + }, + "description": "Secrets for the given project and environment" + } + } + } + } + } + } + }, + "security": [ + { + "apiKeyAuth": [] + } + ] + }, + "patch": { + "summary": "Update secret(s)", + "description": "Update secret(s)", + "parameters": [], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "secrets": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Secret" + }, + "description": "Updated secrets" + } + } + } + } + } + } + }, + "security": [ + { + "apiKeyAuth": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "secrets": { + "$ref": "#/components/schemas/UpdateSecret", + "description": "Secret(s) to update - object or array of objects" + } + } + } + } + } + } + }, + "delete": { + "summary": "Delete secret(s)", + "description": "Delete one or many secrets by their ID(s)", + "parameters": [], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "secrets": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Secret" + }, + "description": "Deleted secrets" + } + } + } + } + } + } + }, + "security": [ + { + "apiKeyAuth": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "secretIds": { + "type": "string", + "description": "ID(s) of secrets - string or array of strings" + } + } + } + } + } + } + } + }, + "/api/v2/service-token/": { + "get": { + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + }, + "post": { + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { + "example": "any" + }, + "workspaceId": { + "example": "any" + }, + "environment": { + "example": "any" + }, + "encryptedKey": { + "example": "any" + }, + "iv": { + "example": "any" + }, + "tag": { + "example": "any" + }, + "expiresIn": { + "example": "any" + } + } + } + } + } + } + } + }, + "/api/v2/service-token/{serviceTokenDataId}": { + "delete": { + "description": "", + "parameters": [ + { + "name": "serviceTokenDataId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + }, + "/api/v2/api-key/": { + "get": { + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + }, + "post": { + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { + "example": "any" + }, + "expiresIn": { + "example": "any" + } + } + } + } + } + } + } + }, + "/api/v2/api-key/{apiKeyDataId}": { + "delete": { + "description": "", + "parameters": [ + { + "name": "apiKeyDataId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK" + }, + "400": { + "description": "Bad Request" + } + } + } + }, + "/api/status": { + "get": { + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "OK" + } + } + } + } + }, + "components": { + "schemas": { + "CurrentUser": { + "type": "object", + "properties": { + "_id": { + "type": "string", + "example": "" + }, + "email": { + "type": "string", + "example": "johndoe@gmail.com" + }, + "firstName": { + "type": "string", + "example": "John" + }, + "lastName": { + "type": "string", + "example": "Doe" + }, + "publicKey": { + "type": "string", + "example": "johns_nacl_public_key" + }, + "encryptedPrivateKey": { + "type": "string", + "example": "johns_enc_nacl_private_key" + }, + "iv": { + "type": "string", + "example": "iv_of_enc_nacl_private_key" + }, + "tag": { + "type": "string", + "example": "tag_of_enc_nacl_private_key" + }, + "updatedAt": { + "type": "string", + "example": "2023-01-13T14:16:12.210Z" + }, + "createdAt": { + "type": "string", + "example": "2023-01-13T14:16:12.210Z" + } + } + }, + "Membership": { + "type": "object", + "properties": { + "user": { + "type": "object", + "properties": { + "_id": { + "type": "string", + "example": "" + }, + "email": { + "type": "string", + "example": "johndoe@gmail.com" + }, + "firstName": { + "type": "string", + "example": "John" + }, + "lastName": { + "type": "string", + "example": "Doe" + }, + "publicKey": { + "type": "string", + "example": "johns_nacl_public_key" + }, + "updatedAt": { + "type": "string", + "example": "2023-01-13T14:16:12.210Z" + }, + "createdAt": { + "type": "string", + "example": "2023-01-13T14:16:12.210Z" + } + } + }, + "workspace": { + "type": "string", + "example": "" + }, + "role": { + "type": "string", + "example": "admin" + } + } + }, + "MembershipOrg": { + "type": "object", + "properties": { + "user": { + "type": "object", + "properties": { + "_id": { + "type": "string", + "example": "" + }, + "email": { + "type": "string", + "example": "johndoe@gmail.com" + }, + "firstName": { + "type": "string", + "example": "John" + }, + "lastName": { + "type": "string", + "example": "Doe" + }, + "publicKey": { + "type": "string", + "example": "johns_nacl_public_key" + }, + "updatedAt": { + "type": "string", + "example": "2023-01-13T14:16:12.210Z" + }, + "createdAt": { + "type": "string", + "example": "2023-01-13T14:16:12.210Z" + } + } + }, + "organization": { + "type": "string", + "example": "" + }, + "role": { + "type": "string", + "example": "owner" + }, + "status": { + "type": "string", + "example": "accepted" + } + } + }, + "Organization": { + "type": "object", + "properties": { + "_id": { + "type": "string", + "example": "" + }, + "name": { + "type": "string", + "example": "Acme Corp." + }, + "customerId": { + "type": "string", + "example": "" + } + } + }, + "Project": { + "type": "object", + "properties": { + "name": { + "type": "string", + "example": "My Project" + }, + "organization": { + "type": "string", + "example": "" + }, + "environments": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "example": "development" + }, + "slug": { + "type": "string", + "example": "dev" + } + } + } + } + } + }, + "ProjectKey": { + "type": "object", + "properties": { + "encryptedkey": { + "type": "string", + "example": "" + }, + "nonce": { + "type": "string", + "example": "" + }, + "sender": { + "type": "object", + "properties": { + "publicKey": { + "type": "string", + "example": "senders_nacl_public_key" + } + } + }, + "receiver": { + "type": "string", + "example": "" + }, + "workspace": { + "type": "string", + "example": "" + } + } + }, + "CreateSecret": { + "type": "object", + "properties": { + "type": { + "type": "string", + "example": "shared" + }, + "secretKeyCiphertext": { + "type": "string", + "example": "" + }, + "secretKeyIV": { + "type": "string", + "example": "" + }, + "secretKeyTag": { + "type": "string", + "example": "" + }, + "secretValueCiphertext": { + "type": "string", + "example": "" + }, + "secretValueIV": { + "type": "string", + "example": "" + }, + "secretValueTag": { + "type": "string", + "example": "" + }, + "secretCommentCiphertext": { + "type": "string", + "example": "" + }, + "secretCommentIV": { + "type": "string", + "example": "" + }, + "secretCommentTag": { + "type": "string", + "example": "" + } + } + }, + "UpdateSecret": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "" + }, + "secretKeyCiphertext": { + "type": "string", + "example": "" + }, + "secretKeyIV": { + "type": "string", + "example": "" + }, + "secretKeyTag": { + "type": "string", + "example": "" + }, + "secretValueCiphertext": { + "type": "string", + "example": "" + }, + "secretValueIV": { + "type": "string", + "example": "" + }, + "secretValueTag": { + "type": "string", + "example": "" + }, + "secretCommentCiphertext": { + "type": "string", + "example": "" + }, + "secretCommentIV": { + "type": "string", + "example": "" + }, + "secretCommentTag": { + "type": "string", + "example": "" + } + } + }, + "Secret": { + "type": "object", + "properties": { + "_id": { + "type": "string", + "example": "" + }, + "version": { + "type": "number", + "example": 1 + }, + "workspace": { + "type": "string", + "example": "" + }, + "type": { + "type": "string", + "example": "shared" + }, + "user": {}, + "secretKeyCiphertext": { + "type": "string", + "example": "" + }, + "secretKeyIV": { + "type": "string", + "example": "" + }, + "secretKeyTag": { + "type": "string", + "example": "" + }, + "secretValueCiphertext": { + "type": "string", + "example": "" + }, + "secretValueIV": { + "type": "string", + "example": "" + }, + "secretValueTag": { + "type": "string", + "example": "" + }, + "secretCommentCiphertext": { + "type": "string", + "example": "" + }, + "secretCommentIV": { + "type": "string", + "example": "" + }, + "secretCommentTag": { + "type": "string", + "example": "" + }, + "updatedAt": { + "type": "string", + "example": "2023-01-13T14:16:12.210Z" + }, + "createdAt": { + "type": "string", + "example": "2023-01-13T14:16:12.210Z" + } + } + }, + "Log": { + "type": "object", + "properties": { + "_id": { + "type": "string", + "example": "" + }, + "user": { + "type": "object", + "properties": { + "_id": { + "type": "string", + "example": "" + }, + "email": { + "type": "string", + "example": "johndoe@gmail.com" + }, + "firstName": { + "type": "string", + "example": "John" + }, + "lastName": { + "type": "string", + "example": "Doe" + } + } + }, + "workspace": { + "type": "string", + "example": "" + }, + "actionNames": { + "type": "array", + "example": [ + "addSecrets" + ], + "items": { + "type": "string" + } + }, + "actions": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "example": "addSecrets" + }, + "user": { + "type": "string", + "example": "" + }, + "workspace": { + "type": "string", + "example": "" + }, + "payload": { + "type": "array", + "items": { + "type": "object", + "properties": { + "oldSecretVersion": { + "type": "string", + "example": "" + }, + "newSecretVersion": { + "type": "string", + "example": "" + } + } + } + } + } + } + }, + "channel": { + "type": "string", + "example": "cli" + }, + "ipAddress": { + "type": "string", + "example": "192.168.0.1" + }, + "updatedAt": { + "type": "string", + "example": "2023-01-13T14:16:12.210Z" + }, + "createdAt": { + "type": "string", + "example": "2023-01-13T14:16:12.210Z" + } + } + }, + "SecretSnapshot": { + "type": "object", + "properties": { + "workspace": { + "type": "string", + "example": "" + }, + "version": { + "type": "number", + "example": 1 + }, + "secretVersions": { + "type": "array", + "items": { + "type": "object", + "properties": { + "_id": { + "type": "string", + "example": "" + } + } + } + } + } + }, + "SecretVersion": { + "type": "object", + "properties": { + "_id": { + "type": "string", + "example": "" + }, + "secret": { + "type": "string", + "example": "" + }, + "version": { + "type": "number", + "example": 1 + }, + "workspace": { + "type": "string", + "example": "" + }, + "type": { + "type": "string", + "example": "shared" + }, + "user": { + "type": "string", + "example": "" + }, + "environment": { + "type": "string", + "example": "dev" + }, + "isDeleted": { + "type": "string", + "example": "" + }, + "secretKeyCiphertext": { + "type": "string", + "example": "" + }, + "secretKeyIV": { + "type": "string", + "example": "" + }, + "secretKeyTag": { + "type": "string", + "example": "" + }, + "secretValueCiphertext": { + "type": "string", + "example": "" + }, + "secretValueIV": { + "type": "string", + "example": "" + }, + "secretValueTag": { + "type": "string", + "example": "" + } + } + } + }, + "securitySchemes": { + "bearerAuth": { + "type": "http", + "scheme": "bearer", + "bearerFormat": "JWT", + "description": "This security definition uses the HTTP 'bearer' scheme, which allows the client to authenticate using a JSON Web Token (JWT) that is passed in the Authorization header of the request." + }, + "apiKeyAuth": { + "type": "apiKey", + "in": "header", + "name": "X-API-Key", + "description": "This security definition uses an API key, which is passed in the header of the request as the value of the \"X-API-Key\" header. The client must provide a valid key in order to access the API." + } + } + } +} \ No newline at end of file diff --git a/backend/src/app.ts b/backend/src/app.ts new file mode 100644 index 000000000..79561d00c --- /dev/null +++ b/backend/src/app.ts @@ -0,0 +1,138 @@ +// eslint-disable-next-line @typescript-eslint/no-var-requires +const { patchRouterParam } = require('./utils/patchAsyncRoutes'); + +import express, { Request, Response } from 'express'; +import helmet from 'helmet'; +import cors from 'cors'; +import cookieParser from 'cookie-parser'; +import dotenv from 'dotenv'; +import swaggerUi = require('swagger-ui-express'); +// eslint-disable-next-line @typescript-eslint/no-var-requires +const swaggerFile = require('../spec.json'); +// eslint-disable-next-line @typescript-eslint/no-var-requires +const requestIp = require('request-ip'); + +dotenv.config(); +import { PORT, NODE_ENV, SITE_URL } from './config'; +import { apiLimiter } from './helpers/rateLimiter'; + +import { + workspace as eeWorkspaceRouter, + secret as eeSecretRouter, + secretSnapshot as eeSecretSnapshotRouter, + action as eeActionRouter +} from './ee/routes/v1'; +import { + signup as v1SignupRouter, + auth as v1AuthRouter, + bot as v1BotRouter, + organization as v1OrganizationRouter, + workspace as v1WorkspaceRouter, + membershipOrg as v1MembershipOrgRouter, + membership as v1MembershipRouter, + key as v1KeyRouter, + inviteOrg as v1InviteOrgRouter, + user as v1UserRouter, + userAction as v1UserActionRouter, + secret as v1SecretRouter, + serviceToken as v1ServiceTokenRouter, + password as v1PasswordRouter, + stripe as v1StripeRouter, + integration as v1IntegrationRouter, + integrationAuth as v1IntegrationAuthRouter +} from './routes/v1'; +import { + users as v2UsersRouter, + organizations as v2OrganizationsRouter, + workspace as v2WorkspaceRouter, + secret as v2SecretRouter, // begin to phase out + secrets as v2SecretsRouter, + serviceTokenData as v2ServiceTokenDataRouter, + apiKeyData as v2APIKeyDataRouter, + environment as v2EnvironmentRouter, +} from './routes/v2'; + +import { healthCheck } from './routes/status'; + +import { getLogger } from './utils/logger'; +import { RouteNotFoundError } from './utils/errors'; +import { requestErrorHandler } from './middleware/requestErrorHandler'; + +// patch async route params to handle Promise Rejections +patchRouterParam(); + +export const app = express(); + +app.enable('trust proxy'); +app.use(express.json()); +app.use(cookieParser()); +app.use( + cors({ + credentials: true, + origin: SITE_URL + }) +); + +app.use(requestIp.mw()) + +if (NODE_ENV === 'production') { + // enable app-wide rate-limiting + helmet security + // in production + app.disable('x-powered-by'); + app.use(apiLimiter); + app.use(helmet()); +} + +// (EE) routes +app.use('/api/v1/secret', eeSecretRouter); +app.use('/api/v1/secret-snapshot', eeSecretSnapshotRouter); +app.use('/api/v1/workspace', eeWorkspaceRouter); +app.use('/api/v1/action', eeActionRouter); + +// v1 routes +app.use('/api/v1/signup', v1SignupRouter); +app.use('/api/v1/auth', v1AuthRouter); +app.use('/api/v1/bot', v1BotRouter); +app.use('/api/v1/user', v1UserRouter); +app.use('/api/v1/user-action', v1UserActionRouter); +app.use('/api/v1/organization', v1OrganizationRouter); +app.use('/api/v1/workspace', v1WorkspaceRouter); +app.use('/api/v1/membership-org', v1MembershipOrgRouter); +app.use('/api/v1/membership', v1MembershipRouter); +app.use('/api/v1/key', v1KeyRouter); +app.use('/api/v1/invite-org', v1InviteOrgRouter); +app.use('/api/v1/secret', v1SecretRouter); +app.use('/api/v1/service-token', v1ServiceTokenRouter); // deprecated +app.use('/api/v1/password', v1PasswordRouter); +app.use('/api/v1/stripe', v1StripeRouter); +app.use('/api/v1/integration', v1IntegrationRouter); +app.use('/api/v1/integration-auth', v1IntegrationAuthRouter); + +// v2 routes +app.use('/api/v2/users', v2UsersRouter); +app.use('/api/v2/organizations', v2OrganizationsRouter); +app.use('/api/v2/workspace', v2EnvironmentRouter); +app.use('/api/v2/workspace', v2WorkspaceRouter); +app.use('/api/v2/secret', v2SecretRouter); // deprecated +app.use('/api/v2/secrets', v2SecretsRouter); +app.use('/api/v2/service-token', v2ServiceTokenDataRouter); // TODO: turn into plural route +app.use('/api/v2/api-key', v2APIKeyDataRouter); + +// api docs +app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerFile)) + +// Server status +app.use('/api', healthCheck) + +//* Handle unrouted requests and respond with proper error message as well as status code +app.use((req, res, next) => { + if (res.headersSent) return next(); + next(RouteNotFoundError({ message: `The requested source '(${req.method})${req.url}' was not found` })) +}) + +//* Error Handling Middleware (must be after all routing logic) +app.use(requestErrorHandler) + +export const server = app.listen(PORT, () => { + getLogger("backend-main").info(`Server started listening at port ${PORT}`) +}); diff --git a/backend/src/config/index.ts b/backend/src/config/index.ts index 5575ceb44..2ecd1af8c 100644 --- a/backend/src/config/index.ts +++ b/backend/src/config/index.ts @@ -1,6 +1,7 @@ const PORT = process.env.PORT || 4000; const EMAIL_TOKEN_LIFETIME = process.env.EMAIL_TOKEN_LIFETIME! || '86400'; const ENCRYPTION_KEY = process.env.ENCRYPTION_KEY!; +const SALT_ROUNDS = parseInt(process.env.SALT_ROUNDS!) || 10; const JWT_AUTH_LIFETIME = process.env.JWT_AUTH_LIFETIME! || '10d'; const JWT_AUTH_SECRET = process.env.JWT_AUTH_SECRET!; const JWT_REFRESH_LIFETIME = process.env.JWT_REFRESH_LIFETIME! || '90d'; @@ -10,33 +11,44 @@ const JWT_SIGNUP_LIFETIME = process.env.JWT_SIGNUP_LIFETIME! || '15m'; const JWT_SIGNUP_SECRET = process.env.JWT_SIGNUP_SECRET!; const MONGO_URL = process.env.MONGO_URL!; const NODE_ENV = process.env.NODE_ENV! || 'production'; -const OAUTH_CLIENT_SECRET_HEROKU = process.env.OAUTH_CLIENT_SECRET_HEROKU!; -const OAUTH_TOKEN_URL_HEROKU = process.env.OAUTH_TOKEN_URL_HEROKU!; +const VERBOSE_ERROR_OUTPUT = process.env.VERBOSE_ERROR_OUTPUT! === 'true' && true; +const LOKI_HOST = process.env.LOKI_HOST || undefined; +const CLIENT_ID_HEROKU = process.env.CLIENT_ID_HEROKU!; +const CLIENT_ID_VERCEL = process.env.CLIENT_ID_VERCEL!; +const CLIENT_ID_NETLIFY = process.env.CLIENT_ID_NETLIFY!; +const CLIENT_ID_GITHUB = process.env.CLIENT_ID_GITHUB!; +const CLIENT_SECRET_HEROKU = process.env.CLIENT_SECRET_HEROKU!; +const CLIENT_SECRET_VERCEL = process.env.CLIENT_SECRET_VERCEL!; +const CLIENT_SECRET_NETLIFY = process.env.CLIENT_SECRET_NETLIFY!; +const CLIENT_SECRET_GITHUB = process.env.CLIENT_SECRET_GITHUB!; +const CLIENT_SLUG_VERCEL= process.env.CLIENT_SLUG_VERCEL!; const POSTHOG_HOST = process.env.POSTHOG_HOST! || 'https://app.posthog.com'; const POSTHOG_PROJECT_API_KEY = process.env.POSTHOG_PROJECT_API_KEY! || 'phc_nSin8j5q2zdhpFDI1ETmFNUIuTG4DwKVyIigrY10XiE'; -const PRIVATE_KEY = process.env.PRIVATE_KEY!; -const PUBLIC_KEY = process.env.PUBLIC_KEY!; const SENTRY_DSN = process.env.SENTRY_DSN!; const SITE_URL = process.env.SITE_URL!; -const SMTP_HOST = process.env.SMTP_HOST! || 'smtp.gmail.com'; -const SMTP_PORT = process.env.SMTP_PORT! || 587; -const SMTP_NAME = process.env.SMTP_NAME!; +const SMTP_HOST = process.env.SMTP_HOST!; +const SMTP_SECURE = process.env.SMTP_SECURE! === 'true' || false; +const SMTP_PORT = parseInt(process.env.SMTP_PORT!) || 587; const SMTP_USERNAME = process.env.SMTP_USERNAME!; const SMTP_PASSWORD = process.env.SMTP_PASSWORD!; -const STRIPE_PRODUCT_CARD_AUTH = process.env.STRIPE_PRODUCT_CARD_AUTH!; -const STRIPE_PRODUCT_PRO = process.env.STRIPE_PRODUCT_PRO!; +const SMTP_FROM_ADDRESS = process.env.SMTP_FROM_ADDRESS!; +const SMTP_FROM_NAME = process.env.SMTP_FROM_NAME! || 'Infisical'; const STRIPE_PRODUCT_STARTER = process.env.STRIPE_PRODUCT_STARTER!; +const STRIPE_PRODUCT_PRO = process.env.STRIPE_PRODUCT_PRO!; +const STRIPE_PRODUCT_TEAM = process.env.STRIPE_PRODUCT_TEAM!; const STRIPE_PUBLISHABLE_KEY = process.env.STRIPE_PUBLISHABLE_KEY!; const STRIPE_SECRET_KEY = process.env.STRIPE_SECRET_KEY!; const STRIPE_WEBHOOK_SECRET = process.env.STRIPE_WEBHOOK_SECRET!; const TELEMETRY_ENABLED = process.env.TELEMETRY_ENABLED! !== 'false' && true; +const LICENSE_KEY = process.env.LICENSE_KEY!; export { PORT, EMAIL_TOKEN_LIFETIME, ENCRYPTION_KEY, + SALT_ROUNDS, JWT_AUTH_LIFETIME, JWT_AUTH_SECRET, JWT_REFRESH_LIFETIME, @@ -46,24 +58,34 @@ export { JWT_SIGNUP_SECRET, MONGO_URL, NODE_ENV, - OAUTH_CLIENT_SECRET_HEROKU, - OAUTH_TOKEN_URL_HEROKU, + VERBOSE_ERROR_OUTPUT, + LOKI_HOST, + CLIENT_ID_HEROKU, + CLIENT_ID_VERCEL, + CLIENT_ID_NETLIFY, + CLIENT_ID_GITHUB, + CLIENT_SECRET_HEROKU, + CLIENT_SECRET_VERCEL, + CLIENT_SECRET_NETLIFY, + CLIENT_SECRET_GITHUB, + CLIENT_SLUG_VERCEL, POSTHOG_HOST, POSTHOG_PROJECT_API_KEY, - PRIVATE_KEY, - PUBLIC_KEY, SENTRY_DSN, SITE_URL, SMTP_HOST, SMTP_PORT, - SMTP_NAME, + SMTP_SECURE, SMTP_USERNAME, SMTP_PASSWORD, - STRIPE_PRODUCT_CARD_AUTH, - STRIPE_PRODUCT_PRO, + SMTP_FROM_ADDRESS, + SMTP_FROM_NAME, STRIPE_PRODUCT_STARTER, + STRIPE_PRODUCT_TEAM, + STRIPE_PRODUCT_PRO, STRIPE_PUBLISHABLE_KEY, STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET, - TELEMETRY_ENABLED + TELEMETRY_ENABLED, + LICENSE_KEY }; diff --git a/backend/src/controllers/integrationAuthController.ts b/backend/src/controllers/integrationAuthController.ts deleted file mode 100644 index 009bcd391..000000000 --- a/backend/src/controllers/integrationAuthController.ts +++ /dev/null @@ -1,153 +0,0 @@ -import { Request, Response } from 'express'; -import * as Sentry from '@sentry/node'; -import axios from 'axios'; -import { readFileSync } from 'fs'; -import { IntegrationAuth, Integration } from '../models'; -import { processOAuthTokenRes } from '../helpers/integrationAuth'; -import { INTEGRATION_SET, ENV_DEV } from '../variables'; -import { OAUTH_CLIENT_SECRET_HEROKU, OAUTH_TOKEN_URL_HEROKU } from '../config'; - -/** - * Perform OAuth2 code-token exchange as part of integration [integration] for workspace with id [workspaceId] - * Note: integration [integration] must be set up compatible/designed for OAuth2 - * @param req - * @param res - * @returns - */ -export const integrationAuthOauthExchange = async ( - req: Request, - res: Response -) => { - try { - let clientSecret; - - const { workspaceId, code, integration } = req.body; - - if (!INTEGRATION_SET.has(integration)) - throw new Error('Failed to validate integration'); - - // use correct client secret - switch (integration) { - case 'heroku': - clientSecret = OAUTH_CLIENT_SECRET_HEROKU; - } - - // TODO: unfinished - make compatible with other integration types - const res = await axios.post( - OAUTH_TOKEN_URL_HEROKU!, - new URLSearchParams({ - grant_type: 'authorization_code', - code: code, - client_secret: clientSecret - } as any) - ); - - const integrationAuth = await processOAuthTokenRes({ - workspaceId, - integration, - res - }); - - // create or replace integration - const integrationObj = await Integration.findOneAndUpdate( - { workspace: workspaceId, integration }, - { - workspace: workspaceId, - environment: ENV_DEV, - isActive: false, - app: null, - integration, - integrationAuth: integrationAuth._id - }, - { upsert: true, new: true } - ); - } catch (err) { - Sentry.setUser(null); - Sentry.captureException(err); - return res.status(400).send({ - message: 'Failed to get OAuth2 token' - }); - } - - return res.status(200).send({ - message: 'Successfully enabled integration authorization' - }); -}; - -/** - * Return list of applications allowed for integration with id [integrationAuthId] - * @param req - * @param res - * @returns - */ -export const getIntegrationAuthApps = async (req: Request, res: Response) => { - // TODO: unfinished - make compatible with other integration types - let apps; - try { - const res = await axios.get('https://api.heroku.com/apps', { - headers: { - Accept: 'application/vnd.heroku+json; version=3', - Authorization: 'Bearer ' + req.accessToken - } - }); - - apps = res.data.map((a: any) => ({ - name: a.name - })); - } catch (err) {} - - return res.status(200).send({ - apps - }); -}; - -/** - * Delete integration authorization with id [integrationAuthId] - * @param req - * @param res - * @returns - */ -export const deleteIntegrationAuth = async (req: Request, res: Response) => { - // TODO: unfinished - disable application via Heroku API and make compatible with other integration types - try { - const { integrationAuthId } = req.params; - - // TODO: disable application via Heroku API; figure out what authorization id is - - const integrations = JSON.parse( - readFileSync('./src/json/integrations.json').toString() - ); - - let authorizationId; - switch (req.integrationAuth.integration) { - case 'heroku': - authorizationId = integrations.heroku.clientId; - } - - // not sure what authorizationId is? - // // revoke authorization - // const res2 = await axios.delete( - // `https://api.heroku.com/oauth/authorizations/${authorizationId}`, - // { - // headers: { - // 'Accept': 'application/vnd.heroku+json; version=3', - // 'Authorization': 'Bearer ' + req.accessToken - // } - // } - // ); - - const deletedIntegrationAuth = await IntegrationAuth.findOneAndDelete({ - _id: integrationAuthId - }); - - if (deletedIntegrationAuth) { - await Integration.deleteMany({ - integrationAuth: deletedIntegrationAuth._id - }); - } - } catch (err) { - return res.status(400).send({ - message: 'Failed to delete integration authorization' - }); - } -}; diff --git a/backend/src/controllers/integrationController.ts b/backend/src/controllers/integrationController.ts deleted file mode 100644 index b75d9b74a..000000000 --- a/backend/src/controllers/integrationController.ts +++ /dev/null @@ -1,158 +0,0 @@ -import { Request, Response } from 'express'; -import { readFileSync } from 'fs'; -import * as Sentry from '@sentry/node'; -import axios from 'axios'; -import { Integration } from '../models'; -import { decryptAsymmetric } from '../utils/crypto'; -import { decryptSecrets } from '../helpers/secret'; -import { PRIVATE_KEY } from '../config'; - -interface Key { - encryptedKey: string; - nonce: string; -} - -interface PushSecret { - ciphertextKey: string; - ivKey: string; - tagKey: string; - hashKey: string; - ciphertextValue: string; - ivValue: string; - tagValue: string; - hashValue: string; - type: 'shared' | 'personal'; -} - -/** - * Return list of all available integrations on Infisical - * @param req - * @param res - * @returns - */ -export const getIntegrations = async (req: Request, res: Response) => { - let integrations; - try { - integrations = JSON.parse( - readFileSync('./src/json/integrations.json').toString() - ); - } catch (err) { - Sentry.setUser(null); - Sentry.captureException(err); - return res.status(400).send({ - message: 'Failed to get integrations' - }); - } - - return res.status(200).send({ - integrations - }); -}; - -/** - * Sync secrets [secrets] to integration with id [integrationId] - * @param req - * @param res - * @returns - */ -export const syncIntegration = async (req: Request, res: Response) => { - // TODO: unfinished - make more versatile to accomodate for other integrations - try { - const { key, secrets }: { key: Key; secrets: PushSecret[] } = req.body; - const symmetricKey = decryptAsymmetric({ - ciphertext: key.encryptedKey, - nonce: key.nonce, - publicKey: req.user.publicKey, - privateKey: PRIVATE_KEY - }); - - // decrypt secrets with symmetric key - const content = decryptSecrets({ - secrets, - key: symmetricKey, - format: 'object' - }); - - // TODO: make integration work for other integrations as well - const res = await axios.patch( - `https://api.heroku.com/apps/${req.integration.app}/config-vars`, - content, - { - headers: { - Accept: 'application/vnd.heroku+json; version=3', - Authorization: 'Bearer ' + req.accessToken - } - } - ); - } catch (err) { - Sentry.setUser(null); - Sentry.captureException(err); - return res.status(400).send({ - message: 'Failed to sync secrets with integration' - }); - } - - return res.status(200).send({ - message: 'Successfully synced secrets with integration' - }); -}; - -/** - * Change environment or name of integration with id [integrationId] - * @param req - * @param res - * @returns - */ -export const modifyIntegration = async (req: Request, res: Response) => { - let integration; - try { - const { update } = req.body; - - integration = await Integration.findOneAndUpdate( - { - _id: req.integration._id - }, - update, - { - new: true - } - ); - } catch (err) { - Sentry.setUser({ email: req.user.email }); - Sentry.captureException(err); - return res.status(400).send({ - message: 'Failed to modify integration' - }); - } - - return res.status(200).send({ - integration - }); -}; - -/** - * Delete integration with id [integrationId] - * @param req - * @param res - * @returns - */ -export const deleteIntegration = async (req: Request, res: Response) => { - let deletedIntegration; - try { - const { integrationId } = req.params; - - deletedIntegration = await Integration.findOneAndDelete({ - _id: integrationId - }); - } catch (err) { - Sentry.setUser({ email: req.user.email }); - Sentry.captureException(err); - return res.status(400).send({ - message: 'Failed to delete integration' - }); - } - - return res.status(200).send({ - deletedIntegration - }); -}; diff --git a/backend/src/controllers/authController.ts b/backend/src/controllers/v1/authController.ts similarity index 83% rename from backend/src/controllers/authController.ts rename to backend/src/controllers/v1/authController.ts index 20ac813d4..19850680e 100644 --- a/backend/src/controllers/authController.ts +++ b/backend/src/controllers/v1/authController.ts @@ -4,14 +4,16 @@ import jwt from 'jsonwebtoken'; import * as Sentry from '@sentry/node'; import * as bigintConversion from 'bigint-conversion'; const jsrp = require('jsrp'); -import { User } from '../models'; -import { createToken, issueTokens, clearTokens } from '../helpers/auth'; +import { User } from '../../models'; +import { createToken, issueTokens, clearTokens } from '../../helpers/auth'; import { NODE_ENV, JWT_AUTH_LIFETIME, JWT_AUTH_SECRET, JWT_REFRESH_SECRET -} from '../config'; +} from '../../config'; +import LoginSRPDetail from '../../models/LoginSRPDetail'; +import { BadRequestError } from '../../utils/errors'; declare module 'jsonwebtoken' { export interface UserIDJwtPayload extends jwt.JwtPayload { @@ -19,8 +21,6 @@ declare module 'jsonwebtoken' { } } -const clientPublicKeys: any = {}; - /** * Log in user step 1: Return [salt] and [serverPublicKey] as part of step 1 of SRP protocol * @param req @@ -46,13 +46,15 @@ export const login1 = async (req: Request, res: Response) => { salt: user.salt, verifier: user.verifier }, - () => { + async () => { // generate server-side public key const serverPublicKey = server.getPublicKey(); - clientPublicKeys[email] = { - clientPublicKey, - serverBInt: bigintConversion.bigintToBuf(server.bInt) - }; + + await LoginSRPDetail.findOneAndReplace({ email: email }, { + email: email, + clientPublicKey: clientPublicKey, + serverBInt: bigintConversion.bigintToBuf(server.bInt), + }, { upsert: true, returnNewDocument: false }) return res.status(200).send({ serverPublicKey, @@ -85,15 +87,21 @@ export const login2 = async (req: Request, res: Response) => { if (!user) throw new Error('Failed to find user'); + const loginSRPDetailFromDB = await LoginSRPDetail.findOneAndDelete({ email: email }) + + if (!loginSRPDetailFromDB) { + return BadRequestError(Error("It looks like some details from the first login are not found. Please try login one again")) + } + const server = new jsrp.server(); server.init( { salt: user.salt, verifier: user.verifier, - b: clientPublicKeys[email].serverBInt + b: loginSRPDetailFromDB.serverBInt }, async () => { - server.setClientPublicKey(clientPublicKeys[email].clientPublicKey); + server.setClientPublicKey(loginSRPDetailFromDB.clientPublicKey); // compare server and client shared keys if (server.checkClientProof(clientProof)) { @@ -170,10 +178,11 @@ export const logout = async (req: Request, res: Response) => { * @param res * @returns */ -export const checkAuth = async (req: Request, res: Response) => - res.status(200).send({ +export const checkAuth = async (req: Request, res: Response) => { + return res.status(200).send({ message: 'Authenticated' }); +} /** * Return new token by redeeming refresh token diff --git a/backend/src/controllers/v1/botController.ts b/backend/src/controllers/v1/botController.ts new file mode 100644 index 000000000..ab86897cb --- /dev/null +++ b/backend/src/controllers/v1/botController.ts @@ -0,0 +1,107 @@ +import { Request, Response } from 'express'; +import * as Sentry from '@sentry/node'; +import { Bot, BotKey } from '../../models'; +import { createBot } from '../../helpers/bot'; + +interface BotKey { + encryptedKey: string; + nonce: string; +} + +/** + * Return bot for workspace with id [workspaceId]. If a workspace bot doesn't exist, + * then create and return a new bot. + * @param req + * @param res + * @returns + */ +export const getBotByWorkspaceId = async (req: Request, res: Response) => { + let bot; + try { + const { workspaceId } = req.params; + + bot = await Bot.findOne({ + workspace: workspaceId + }); + + if (!bot) { + // case: bot doesn't exist for workspace with id [workspaceId] + // -> create a new bot and return it + bot = await createBot({ + name: 'Infisical Bot', + workspaceId + }); + } + } catch (err) { + Sentry.setUser({ email: req.user.email }); + Sentry.captureException(err); + return res.status(400).send({ + message: 'Failed to get bot for workspace' + }); + } + + return res.status(200).send({ + bot + }); +}; + +/** + * Return bot with id [req.bot._id] with active state set to [isActive]. + * @param req + * @param res + * @returns + */ +export const setBotActiveState = async (req: Request, res: Response) => { + let bot; + try { + const { isActive, botKey }: { isActive: boolean, botKey: BotKey } = req.body; + + if (isActive) { + // bot state set to active -> share workspace key with bot + if (!botKey?.encryptedKey || !botKey?.nonce) { + return res.status(400).send({ + message: 'Failed to set bot state to active - missing bot key' + }); + } + + await BotKey.findOneAndUpdate({ + workspace: req.bot.workspace + }, { + encryptedKey: botKey.encryptedKey, + nonce: botKey.nonce, + sender: req.user._id, + bot: req.bot._id, + workspace: req.bot.workspace + }, { + upsert: true, + new: true + }); + } else { + // case: bot state set to inactive -> delete bot's workspace key + await BotKey.deleteOne({ + bot: req.bot._id + }); + } + + bot = await Bot.findOneAndUpdate({ + _id: req.bot._id + }, { + isActive + }, { + new: true + }); + + if (!bot) throw new Error('Failed to update bot active state'); + + } catch (err) { + Sentry.setUser({ email: req.user.email }); + Sentry.captureException(err); + return res.status(400).send({ + message: 'Failed to update bot active state' + }); + } + + return res.status(200).send({ + bot + }); +}; diff --git a/backend/src/controllers/index.ts b/backend/src/controllers/v1/index.ts similarity index 95% rename from backend/src/controllers/index.ts rename to backend/src/controllers/v1/index.ts index 2d3debfb5..1da61835f 100644 --- a/backend/src/controllers/index.ts +++ b/backend/src/controllers/v1/index.ts @@ -1,4 +1,5 @@ import * as authController from './authController'; +import * as botController from './botController'; import * as integrationAuthController from './integrationAuthController'; import * as integrationController from './integrationController'; import * as keyController from './keyController'; @@ -16,6 +17,7 @@ import * as workspaceController from './workspaceController'; export { authController, + botController, integrationAuthController, integrationController, keyController, diff --git a/backend/src/controllers/v1/integrationAuthController.ts b/backend/src/controllers/v1/integrationAuthController.ts new file mode 100644 index 000000000..b030b79d6 --- /dev/null +++ b/backend/src/controllers/v1/integrationAuthController.ts @@ -0,0 +1,173 @@ +import { Request, Response } from 'express'; +import { Types } from 'mongoose'; +import * as Sentry from '@sentry/node'; +import { + Integration, + IntegrationAuth, + Bot +} from '../../models'; +import { INTEGRATION_SET, INTEGRATION_OPTIONS } from '../../variables'; +import { IntegrationService } from '../../services'; +import { getApps, revokeAccess } from '../../integrations'; + +export const getIntegrationOptions = async ( + req: Request, + res: Response +) => { + return res.status(200).send({ + integrationOptions: INTEGRATION_OPTIONS + }); +} + +/** + * Perform OAuth2 code-token exchange as part of integration [integration] for workspace with id [workspaceId] + * @param req + * @param res + * @returns + */ +export const oAuthExchange = async ( + req: Request, + res: Response +) => { + try { + const { workspaceId, code, integration } = req.body; + + if (!INTEGRATION_SET.has(integration)) + throw new Error('Failed to validate integration'); + + const environments = req.membership.workspace?.environments || []; + if(environments.length === 0){ + throw new Error("Failed to get environments") + } + + await IntegrationService.handleOAuthExchange({ + workspaceId, + integration, + code, + environment: environments[0].slug, + }); + } catch (err) { + Sentry.setUser({ email: req.user.email }); + Sentry.captureException(err); + return res.status(400).send({ + message: 'Failed to get OAuth2 code-token exchange' + }); + } + + return res.status(200).send({ + message: 'Successfully enabled integration authorization' + }); +}; + +/** + * Save integration access token as part of integration [integration] for workspace with id [workspaceId] + * @param req + * @param res + */ +export const saveIntegrationAccessToken = async ( + req: Request, + res: Response +) => { + // TODO: refactor + let integrationAuth; + try { + const { + workspaceId, + accessToken, + integration + }: { + workspaceId: string; + accessToken: string; + integration: string; + } = req.body; + + integrationAuth = await IntegrationAuth.findOneAndUpdate({ + workspace: new Types.ObjectId(workspaceId), + integration + }, { + workspace: new Types.ObjectId(workspaceId), + integration + }, { + new: true, + upsert: true + }); + + const bot = await Bot.findOne({ + workspace: new Types.ObjectId(workspaceId), + isActive: true + }); + + if (!bot) throw new Error('Bot must be enabled to save integration access token'); + + // encrypt and save integration access token + integrationAuth = await IntegrationService.setIntegrationAuthAccess({ + integrationAuthId: integrationAuth._id.toString(), + accessToken, + accessExpiresAt: undefined + }); + + if (!integrationAuth) throw new Error('Failed to save integration access token'); + } catch (err) { + Sentry.setUser({ email: req.user.email }); + Sentry.captureException(err); + return res.status(400).send({ + message: 'Failed to save access token for integration' + }); + } + + return res.status(200).send({ + integrationAuth + }); +} + +/** + * Return list of applications allowed for integration with integration authorization id [integrationAuthId] + * @param req + * @param res + * @returns + */ +export const getIntegrationAuthApps = async (req: Request, res: Response) => { + let apps; + try { + apps = await getApps({ + integrationAuth: req.integrationAuth, + accessToken: req.accessToken + }); + } catch (err) { + Sentry.setUser({ email: req.user.email }); + Sentry.captureException(err); + return res.status(400).send({ + message: 'Failed to get integration authorization applications' + }); + } + + return res.status(200).send({ + apps + }); +}; + +/** + * Delete integration authorization with id [integrationAuthId] + * @param req + * @param res + * @returns + */ +export const deleteIntegrationAuth = async (req: Request, res: Response) => { + let integrationAuth; + try { + integrationAuth = await revokeAccess({ + integrationAuth: req.integrationAuth, + accessToken: req.accessToken + }); + } catch (err) { + Sentry.setUser({ email: req.user.email }); + Sentry.captureException(err); + return res.status(400).send({ + message: 'Failed to delete integration authorization' + }); + } + + return res.status(200).send({ + integrationAuth + }); +} \ No newline at end of file diff --git a/backend/src/controllers/v1/integrationController.ts b/backend/src/controllers/v1/integrationController.ts new file mode 100644 index 000000000..4e66ce0aa --- /dev/null +++ b/backend/src/controllers/v1/integrationController.ts @@ -0,0 +1,131 @@ +import { Request, Response } from 'express'; +import * as Sentry from '@sentry/node'; +import { + Integration, + Workspace, + Bot, + BotKey +} from '../../models'; +import { EventService } from '../../services'; +import { eventPushSecrets } from '../../events'; + +/** + * Create/initialize an (empty) integration for integration authorization + * @param req + * @param res + * @returns + */ +export const createIntegration = async (req: Request, res: Response) => { + let integration; + try { + // initialize new integration after saving integration access token + integration = await new Integration({ + workspace: req.integrationAuth.workspace._id, + isActive: false, + app: null, + environment: req.integrationAuth.workspace?.environments[0].slug, + integration: req.integrationAuth.integration, + integrationAuth: req.integrationAuth._id + }).save(); + } catch (err) { + Sentry.setUser({ email: req.user.email }); + Sentry.captureException(err); + return res.status(400).send({ + message: 'Failed to create integration' + }); + } + + return res.status(200).send({ + integration + }); +} + +/** + * Change environment or name of integration with id [integrationId] + * @param req + * @param res + * @returns + */ +export const updateIntegration = async (req: Request, res: Response) => { + let integration; + + // TODO: add integration-specific validation to ensure that each + // integration has the correct fields populated in [Integration] + + try { + const { + environment, + isActive, + app, + appId, + targetEnvironment, + owner, // github-specific integration param + } = req.body; + + integration = await Integration.findOneAndUpdate( + { + _id: req.integration._id + }, + { + environment, + isActive, + app, + appId, + targetEnvironment, + owner + }, + { + new: true + } + ); + + if (integration) { + // trigger event - push secrets + EventService.handleEvent({ + event: eventPushSecrets({ + workspaceId: integration.workspace.toString() + }) + }); + } + } catch (err) { + Sentry.setUser({ email: req.user.email }); + Sentry.captureException(err); + return res.status(400).send({ + message: 'Failed to update integration' + }); + } + + return res.status(200).send({ + integration + }); +}; + +/** + * Delete integration with id [integrationId] and deactivate bot if there are + * no integrations left + * @param req + * @param res + * @returns + */ +export const deleteIntegration = async (req: Request, res: Response) => { + let integration; + try { + const { integrationId } = req.params; + + integration = await Integration.findOneAndDelete({ + _id: integrationId + }); + + if (!integration) throw new Error('Failed to find integration'); + } catch (err) { + Sentry.setUser({ email: req.user.email }); + Sentry.captureException(err); + return res.status(400).send({ + message: 'Failed to delete integration' + }); + } + + return res.status(200).send({ + integration + }); +}; diff --git a/backend/src/controllers/keyController.ts b/backend/src/controllers/v1/keyController.ts similarity index 71% rename from backend/src/controllers/keyController.ts rename to backend/src/controllers/v1/keyController.ts index 1c9b5e15c..ffcb16d9c 100644 --- a/backend/src/controllers/keyController.ts +++ b/backend/src/controllers/v1/keyController.ts @@ -1,9 +1,7 @@ import { Request, Response } from 'express'; import * as Sentry from '@sentry/node'; -import { Key } from '../models'; -import { findMembership } from '../helpers/membership'; -import { PUBLIC_KEY } from '../config'; -import { GRANTED } from '../variables'; +import { Key } from '../../models'; +import { findMembership } from '../../helpers/membership'; /** * Add (encrypted) copy of workspace key for workspace with id [workspaceId] for user with @@ -17,16 +15,6 @@ export const uploadKey = async (req: Request, res: Response) => { const { workspaceId } = req.params; const { key } = req.body; - // validate membership of sender - const senderMembership = await findMembership({ - user: req.user._id, - workspace: workspaceId - }); - - if (!senderMembership) { - throw new Error('Failed sender membership validation for workspace'); - } - // validate membership of receiver const receiverMembership = await findMembership({ user: key.userId, @@ -37,9 +25,6 @@ export const uploadKey = async (req: Request, res: Response) => { throw new Error('Failed receiver membership validation for workspace'); } - receiverMembership.status = GRANTED; - await receiverMembership.save(); - await new Key({ encryptedKey: key.encryptedKey, nonce: key.nonce, @@ -94,16 +79,4 @@ export const getLatestKey = async (req: Request, res: Response) => { } return res.status(200).send(resObj); -}; - -/** - * Return public key of Infisical - * @param req - * @param res - * @returns - */ -export const getPublicKeyInfisical = async (req: Request, res: Response) => { - return res.status(200).send({ - publicKey: PUBLIC_KEY - }); -}; +}; \ No newline at end of file diff --git a/backend/src/controllers/membershipController.ts b/backend/src/controllers/v1/membershipController.ts similarity index 94% rename from backend/src/controllers/membershipController.ts rename to backend/src/controllers/v1/membershipController.ts index f2ed3db6e..3627ce3fb 100644 --- a/backend/src/controllers/membershipController.ts +++ b/backend/src/controllers/v1/membershipController.ts @@ -1,13 +1,13 @@ import { Request, Response } from 'express'; import * as Sentry from '@sentry/node'; -import { Membership, MembershipOrg, User, Key } from '../models'; +import { Membership, MembershipOrg, User, Key, IMembership, Workspace } from '../../models'; import { findMembership, deleteMembership as deleteMember -} from '../helpers/membership'; -import { sendMail } from '../helpers/nodemailer'; -import { SITE_URL } from '../config'; -import { ADMIN, MEMBER, GRANTED, ACCEPTED } from '../variables'; +} from '../../helpers/membership'; +import { sendMail } from '../../helpers/nodemailer'; +import { SITE_URL } from '../../config'; +import { ADMIN, MEMBER, ACCEPTED } from '../../variables'; /** * Check that user is a member of workspace with id [workspaceId] @@ -175,8 +175,7 @@ export const inviteUserToWorkspace = async (req: Request, res: Response) => { // already a member of the workspace const inviteeMembership = await Membership.findOne({ user: invitee._id, - workspace: workspaceId, - status: GRANTED + workspace: workspaceId }); if (inviteeMembership) @@ -205,8 +204,7 @@ export const inviteUserToWorkspace = async (req: Request, res: Response) => { const m = await new Membership({ user: invitee._id, workspace: workspaceId, - role: MEMBER, - status: GRANTED + role: MEMBER }).save(); await sendMail({ @@ -232,4 +230,4 @@ export const inviteUserToWorkspace = async (req: Request, res: Response) => { invitee, latestKey }); -}; +}; \ No newline at end of file diff --git a/backend/src/controllers/membershipOrgController.ts b/backend/src/controllers/v1/membershipOrgController.ts similarity index 86% rename from backend/src/controllers/membershipOrgController.ts rename to backend/src/controllers/v1/membershipOrgController.ts index a2159bcd0..f3703b889 100644 --- a/backend/src/controllers/membershipOrgController.ts +++ b/backend/src/controllers/v1/membershipOrgController.ts @@ -1,14 +1,14 @@ import { Request, Response } from 'express'; import * as Sentry from '@sentry/node'; import crypto from 'crypto'; -import { SITE_URL, JWT_SIGNUP_LIFETIME, JWT_SIGNUP_SECRET } from '../config'; -import { MembershipOrg, Organization, User, Token } from '../models'; -import { deleteMembershipOrg as deleteMemberFromOrg } from '../helpers/membershipOrg'; -import { checkEmailVerification } from '../helpers/signup'; -import { createToken } from '../helpers/auth'; -import { updateSubscriptionOrgQuantity } from '../helpers/organization'; -import { sendMail } from '../helpers/nodemailer'; -import { OWNER, ADMIN, MEMBER, ACCEPTED, INVITED } from '../variables'; +import { SITE_URL, JWT_SIGNUP_LIFETIME, JWT_SIGNUP_SECRET } from '../../config'; +import { MembershipOrg, Organization, User, Token } from '../../models'; +import { deleteMembershipOrg as deleteMemberFromOrg } from '../../helpers/membershipOrg'; +import { checkEmailVerification } from '../../helpers/signup'; +import { createToken } from '../../helpers/auth'; +import { updateSubscriptionOrgQuantity } from '../../helpers/organization'; +import { sendMail } from '../../helpers/nodemailer'; +import { OWNER, ADMIN, MEMBER, ACCEPTED, INVITED } from '../../variables'; /** * Delete organization membership with id [membershipOrgId] from organization @@ -80,14 +80,14 @@ export const changeMembershipOrgRole = async (req: Request, res: Response) => { // TODO let membershipToChangeRole; - try { - } catch (err) { - Sentry.setUser({ email: req.user.email }); - Sentry.captureException(err); - return res.status(400).send({ - message: 'Failed to change organization membership role' - }); - } + // try { + // } catch (err) { + // Sentry.setUser({ email: req.user.email }); + // Sentry.captureException(err); + // return res.status(400).send({ + // message: 'Failed to change organization membership role' + // }); + // } return res.status(200).send({ membershipOrg: membershipToChangeRole @@ -115,13 +115,14 @@ export const inviteUserToOrganization = async (req: Request, res: Response) => { if (!membershipOrg) { throw new Error('Failed to validate organization membership'); } - + invitee = await User.findOne({ email: inviteeEmail - }); + }).select('+publicKey'); if (invitee) { // case: invitee is an existing user + inviteeMembershipOrg = await MembershipOrg.findOne({ user: invitee._id, organization: organizationId @@ -218,12 +219,6 @@ export const verifyUserToOrganization = async (req: Request, res: Response) => { const { email, code } = req.body; user = await User.findOne({ email }).select('+publicKey'); - if (user && user?.publicKey) { - // case: user has already completed account - return res.status(403).send({ - error: 'Failed email magic link verification for complete account' - }); - } const membershipOrg = await MembershipOrg.findOne({ inviteEmail: email, @@ -238,6 +233,18 @@ export const verifyUserToOrganization = async (req: Request, res: Response) => { code }); + if (user && user?.publicKey) { + // case: user has already completed account + // membership can be approved and redirected to login/dashboard + membershipOrg.status = ACCEPTED; + await membershipOrg.save(); + + return res.status(200).send({ + message: 'Successfully verified email', + user, + }); + } + if (!user) { // initialize user account user = await new User({ diff --git a/backend/src/controllers/organizationController.ts b/backend/src/controllers/v1/organizationController.ts similarity index 93% rename from backend/src/controllers/organizationController.ts rename to backend/src/controllers/v1/organizationController.ts index 056990acc..6fbccffeb 100644 --- a/backend/src/controllers/organizationController.ts +++ b/backend/src/controllers/v1/organizationController.ts @@ -2,11 +2,8 @@ import { Request, Response } from 'express'; import * as Sentry from '@sentry/node'; import { SITE_URL, - STRIPE_SECRET_KEY, - STRIPE_PRODUCT_STARTER, - STRIPE_PRODUCT_PRO, - STRIPE_PRODUCT_CARD_AUTH -} from '../config'; + STRIPE_SECRET_KEY +} from '../../config'; import Stripe from 'stripe'; const stripe = new Stripe(STRIPE_SECRET_KEY, { @@ -18,23 +15,11 @@ import { Organization, Workspace, IncidentContactOrg -} from '../models'; -import { createOrganization as create } from '../helpers/organization'; -import { addMembershipsOrg } from '../helpers/membershipOrg'; -import { OWNER, ACCEPTED } from '../variables'; +} from '../../models'; +import { createOrganization as create } from '../../helpers/organization'; +import { addMembershipsOrg } from '../../helpers/membershipOrg'; +import { OWNER, ACCEPTED } from '../../variables'; -const productToPriceMap = { - starter: STRIPE_PRODUCT_STARTER, - pro: STRIPE_PRODUCT_PRO, - cardAuth: STRIPE_PRODUCT_CARD_AUTH -}; - -/** - * Return organizations that user is part of - * @param req - * @param res - * @returns - */ export const getOrganizations = async (req: Request, res: Response) => { let organizations; try { @@ -346,7 +331,6 @@ export const createOrganizationPortalSession = async ( if (paymentMethods.data.length < 1) { // case: no payment method on file - productToPriceMap['cardAuth']; session = await stripe.checkout.sessions.create({ customer: req.membershipOrg.organization.customerId, mode: 'setup', diff --git a/backend/src/controllers/passwordController.ts b/backend/src/controllers/v1/passwordController.ts similarity index 83% rename from backend/src/controllers/passwordController.ts rename to backend/src/controllers/v1/passwordController.ts index b029bc0be..d429cbf41 100644 --- a/backend/src/controllers/passwordController.ts +++ b/backend/src/controllers/v1/passwordController.ts @@ -1,15 +1,16 @@ import { Request, Response } from 'express'; import * as Sentry from '@sentry/node'; import crypto from 'crypto'; +// eslint-disable-next-line @typescript-eslint/no-var-requires const jsrp = require('jsrp'); import * as bigintConversion from 'bigint-conversion'; -import { User, Token, BackupPrivateKey } from '../models'; -import { checkEmailVerification } from '../helpers/signup'; -import { createToken } from '../helpers/auth'; -import { sendMail } from '../helpers/nodemailer'; -import { JWT_SIGNUP_LIFETIME, JWT_SIGNUP_SECRET, SITE_URL } from '../config'; - -const clientPublicKeys: any = {}; +import { User, Token, BackupPrivateKey } from '../../models'; +import { checkEmailVerification } from '../../helpers/signup'; +import { createToken } from '../../helpers/auth'; +import { sendMail } from '../../helpers/nodemailer'; +import { JWT_SIGNUP_LIFETIME, JWT_SIGNUP_SECRET, SITE_URL } from '../../config'; +import LoginSRPDetail from '../../models/LoginSRPDetail'; +import { BadRequestError } from '../../utils/errors'; /** * Password reset step 1: Send email verification link to email [email] @@ -31,7 +32,7 @@ export const emailPasswordReset = async (req: Request, res: Response) => { error: 'Failed to send email verification for password reset' }); } - + const token = crypto.randomBytes(16).toString('hex'); await Token.findOneAndUpdate( @@ -43,7 +44,7 @@ export const emailPasswordReset = async (req: Request, res: Response) => { }, { upsert: true, new: true } ); - + await sendMail({ template: 'passwordReset.handlebars', subjectLine: 'Infisical password reset', @@ -54,15 +55,15 @@ export const emailPasswordReset = async (req: Request, res: Response) => { callback_url: SITE_URL + '/password-reset' } }); - + } catch (err) { Sentry.setUser(null); Sentry.captureException(err); return res.status(400).send({ message: 'Failed to send email for account recovery' - }); + }); } - + return res.status(200).send({ message: `Sent an email for account recovery to ${email}` }); @@ -78,7 +79,7 @@ export const emailPasswordResetVerify = async (req: Request, res: Response) => { let user, token; try { const { email, code } = req.body; - + user = await User.findOne({ email }).select('+publicKey'); if (!user || !user?.publicKey) { // case: user doesn't exist with email [email] or @@ -92,7 +93,7 @@ export const emailPasswordResetVerify = async (req: Request, res: Response) => { email, code }); - + // generate temporary password-reset token token = createToken({ payload: { @@ -106,7 +107,7 @@ export const emailPasswordResetVerify = async (req: Request, res: Response) => { Sentry.captureException(err); return res.status(400).send({ message: 'Failed email verification for password reset' - }); + }); } return res.status(200).send({ @@ -129,7 +130,7 @@ export const srp1 = async (req: Request, res: Response) => { const user = await User.findOne({ email: req.user.email }).select('+salt +verifier'); - + if (!user) throw new Error('Failed to find user'); const server = new jsrp.server(); @@ -138,13 +139,15 @@ export const srp1 = async (req: Request, res: Response) => { salt: user.salt, verifier: user.verifier }, - () => { + async () => { // generate server-side public key const serverPublicKey = server.getPublicKey(); - clientPublicKeys[req.user.email] = { - clientPublicKey, - serverBInt: bigintConversion.bigintToBuf(server.bInt) - }; + + await LoginSRPDetail.findOneAndReplace({ email: req.user.email }, { + email: req.user.email, + clientPublicKey: clientPublicKey, + serverBInt: bigintConversion.bigintToBuf(server.bInt), + }, { upsert: true, returnNewDocument: false }) return res.status(200).send({ serverPublicKey, @@ -179,17 +182,21 @@ export const changePassword = async (req: Request, res: Response) => { if (!user) throw new Error('Failed to find user'); + const loginSRPDetailFromDB = await LoginSRPDetail.findOneAndDelete({ email: req.user.email }) + + if (!loginSRPDetailFromDB) { + return BadRequestError(Error("It looks like some details from the first login are not found. Please try login one again")) + } + const server = new jsrp.server(); server.init( { salt: user.salt, verifier: user.verifier, - b: clientPublicKeys[req.user.email].serverBInt + b: loginSRPDetailFromDB.serverBInt }, async () => { - server.setClientPublicKey( - clientPublicKeys[req.user.email].clientPublicKey - ); + server.setClientPublicKey(loginSRPDetailFromDB.clientPublicKey); // compare server and client shared keys if (server.checkClientProof(clientProof)) { @@ -248,16 +255,22 @@ export const createBackupPrivateKey = async (req: Request, res: Response) => { if (!user) throw new Error('Failed to find user'); + const loginSRPDetailFromDB = await LoginSRPDetail.findOneAndDelete({ email: req.user.email }) + + if (!loginSRPDetailFromDB) { + return BadRequestError(Error("It looks like some details from the first login are not found. Please try login one again")) + } + const server = new jsrp.server(); server.init( { salt: user.salt, verifier: user.verifier, - b: clientPublicKeys[req.user.email].serverBInt + b: loginSRPDetailFromDB.serverBInt }, async () => { server.setClientPublicKey( - clientPublicKeys[req.user.email].clientPublicKey + loginSRPDetailFromDB.clientPublicKey ); // compare server and client shared keys @@ -310,16 +323,16 @@ export const getBackupPrivateKey = async (req: Request, res: Response) => { backupPrivateKey = await BackupPrivateKey.findOne({ user: req.user._id }).select('+encryptedPrivateKey +iv +tag'); - + if (!backupPrivateKey) throw new Error('Failed to find backup private key'); } catch (err) { - Sentry.setUser({ email: req.user.email}); + Sentry.setUser({ email: req.user.email }); Sentry.captureException(err); return res.status(400).send({ message: 'Failed to get backup private key' }); } - + return res.status(200).send({ backupPrivateKey }); @@ -347,15 +360,15 @@ export const resetPassword = async (req: Request, res: Response) => { { new: true } - ); + ); } catch (err) { - Sentry.setUser({ email: req.user.email}); + Sentry.setUser({ email: req.user.email }); Sentry.captureException(err); return res.status(400).send({ message: 'Failed to get backup private key' - }); + }); } - + return res.status(200).send({ message: 'Successfully reset password' }); diff --git a/backend/src/controllers/secretController.ts b/backend/src/controllers/v1/secretController.ts similarity index 80% rename from backend/src/controllers/secretController.ts rename to backend/src/controllers/v1/secretController.ts index d1cf5f65d..c76e5e883 100644 --- a/backend/src/controllers/secretController.ts +++ b/backend/src/controllers/v1/secretController.ts @@ -1,15 +1,15 @@ import { Request, Response } from 'express'; import * as Sentry from '@sentry/node'; -import { Key } from '../models'; +import { Key, Secret } from '../../models'; import { - pushSecrets as push, + v1PushSecrets as push, pullSecrets as pull, reformatPullSecrets -} from '../helpers/secret'; -import { pushKeys } from '../helpers/key'; -import { ENV_SET } from '../variables'; - -import { postHogClient } from '../services'; +} from '../../helpers/secret'; +import { pushKeys } from '../../helpers/key'; +import { eventPushSecrets } from '../../events'; +import { EventService } from '../../services'; +import { postHogClient } from '../../services'; interface PushSecret { ciphertextKey: string; @@ -20,6 +20,10 @@ interface PushSecret { ivValue: string; tagValue: string; hashValue: string; + ciphertextComment: string; + ivComment: string; + tagComment: string; + hashComment: string; type: 'shared' | 'personal'; } @@ -39,7 +43,8 @@ export const pushSecrets = async (req: Request, res: Response) => { const { workspaceId } = req.params; // validate environment - if (!ENV_SET.has(environment)) { + const workspaceEnvs = req.membership.workspace.environments; + if (!workspaceEnvs.find(({ slug }: { slug: string }) => slug === environment)) { throw new Error('Failed to validate environment'); } @@ -60,7 +65,8 @@ export const pushSecrets = async (req: Request, res: Response) => { workspaceId, keys }); - + + if (postHogClient) { postHogClient.capture({ event: 'secrets pushed', @@ -74,6 +80,13 @@ export const pushSecrets = async (req: Request, res: Response) => { }); } + // trigger event - push secrets + EventService.handleEvent({ + event: eventPushSecrets({ + workspaceId + }) + }); + } catch (err) { Sentry.setUser({ email: req.user.email }); Sentry.captureException(err); @@ -103,14 +116,17 @@ export const pullSecrets = async (req: Request, res: Response) => { const { workspaceId } = req.params; // validate environment - if (!ENV_SET.has(environment)) { + const workspaceEnvs = req.membership.workspace.environments; + if (!workspaceEnvs.find(({ slug }: { slug: string }) => slug === environment)) { throw new Error('Failed to validate environment'); } secrets = await pull({ userId: req.user._id.toString(), workspaceId, - environment + environment, + channel: channel ? channel : 'cli', + ipAddress: req.ip }); key = await Key.findOne({ @@ -160,9 +176,6 @@ export const pullSecrets = async (req: Request, res: Response) => { * @returns */ export const pullSecretsServiceToken = async (req: Request, res: Response) => { - // get (encrypted) secrets from workspace with id [workspaceId] - // service token route - let secrets; let key; try { @@ -171,14 +184,17 @@ export const pullSecretsServiceToken = async (req: Request, res: Response) => { const { workspaceId } = req.params; // validate environment - if (!ENV_SET.has(environment)) { + const workspaceEnvs = req.membership.workspace.environments; + if (!workspaceEnvs.find(({ slug }: { slug: string }) => slug === environment)) { throw new Error('Failed to validate environment'); } secrets = await pull({ userId: req.serviceToken.user._id.toString(), workspaceId, - environment + environment, + channel: 'cli', + ipAddress: req.ip }); key = { @@ -192,7 +208,7 @@ export const pullSecretsServiceToken = async (req: Request, res: Response) => { }; if (postHogClient) { - // capture secrets pushed event in production + // capture secrets pulled event in production postHogClient.capture({ distinctId: req.serviceToken.user.email, event: 'secrets pulled', @@ -216,4 +232,4 @@ export const pullSecretsServiceToken = async (req: Request, res: Response) => { secrets: reformatPullSecrets({ secrets }), key }); -}; +}; \ No newline at end of file diff --git a/backend/src/controllers/serviceTokenController.ts b/backend/src/controllers/v1/serviceTokenController.ts similarity index 77% rename from backend/src/controllers/serviceTokenController.ts rename to backend/src/controllers/v1/serviceTokenController.ts index ecc3ca0ca..3fafb9043 100644 --- a/backend/src/controllers/serviceTokenController.ts +++ b/backend/src/controllers/v1/serviceTokenController.ts @@ -1,8 +1,7 @@ import { Request, Response } from 'express'; -import { ServiceToken } from '../models'; -import { createToken } from '../helpers/auth'; -import { ENV_SET } from '../variables'; -import { JWT_SERVICE_SECRET } from '../config'; +import { ServiceToken } from '../../models'; +import { createToken } from '../../helpers/auth'; +import { JWT_SERVICE_SECRET } from '../../config'; /** * Return service token on request @@ -11,7 +10,6 @@ import { JWT_SERVICE_SECRET } from '../config'; * @returns */ export const getServiceToken = async (req: Request, res: Response) => { - // get service token return res.status(200).send({ serviceToken: req.serviceToken }); @@ -37,7 +35,8 @@ export const createServiceToken = async (req: Request, res: Response) => { } = req.body; // validate environment - if (!ENV_SET.has(environment)) { + const workspaceEnvs = req.membership.workspace.environments; + if (!workspaceEnvs.find(({ slug }: { slug: string }) => slug === environment)) { throw new Error('Failed to validate environment'); } @@ -58,7 +57,8 @@ export const createServiceToken = async (req: Request, res: Response) => { token = createToken({ payload: { - serviceTokenId: serviceToken._id.toString() + serviceTokenId: serviceToken._id.toString(), + workspaceId }, expiresIn: expiresIn, secret: JWT_SERVICE_SECRET @@ -72,4 +72,4 @@ export const createServiceToken = async (req: Request, res: Response) => { return res.status(200).send({ token }); -}; +}; \ No newline at end of file diff --git a/backend/src/controllers/signupController.ts b/backend/src/controllers/v1/signupController.ts similarity index 89% rename from backend/src/controllers/signupController.ts rename to backend/src/controllers/v1/signupController.ts index 90fad4744..62e5a62a3 100644 --- a/backend/src/controllers/signupController.ts +++ b/backend/src/controllers/v1/signupController.ts @@ -1,15 +1,16 @@ import { Request, Response } from 'express'; import * as Sentry from '@sentry/node'; -import { NODE_ENV, JWT_SIGNUP_LIFETIME, JWT_SIGNUP_SECRET } from '../config'; -import { User, MembershipOrg } from '../models'; -import { completeAccount } from '../helpers/user'; +import { NODE_ENV, JWT_SIGNUP_LIFETIME, JWT_SIGNUP_SECRET } from '../../config'; +import { User, MembershipOrg } from '../../models'; +import { completeAccount } from '../../helpers/user'; import { sendEmailVerification, checkEmailVerification, initializeDefaultOrg -} from '../helpers/signup'; -import { issueTokens, createToken } from '../helpers/auth'; -import { INVITED, ACCEPTED } from '../variables'; +} from '../../helpers/signup'; +import { issueTokens, createToken } from '../../helpers/auth'; +import { INVITED, ACCEPTED } from '../../variables'; +import axios from 'axios'; /** * Signup step 1: Initialize account for user under email [email] and send a verification code @@ -179,6 +180,21 @@ export const completeAccountSignup = async (req: Request, res: Response) => { token = tokens.token; refreshToken = tokens.refreshToken; + + // sending a welcome email to new users + if (process.env.LOOPS_API_KEY) { + await axios.post("https://app.loops.so/api/v1/events/send", { + "email": email, + "eventName": "Sign Up", + "firstName": firstName, + "lastName": lastName + }, { + headers: { + "Accept": "application/json", + "Authorization": "Bearer " + process.env.LOOPS_API_KEY + }, + }); + } } catch (err) { Sentry.setUser(null); Sentry.captureException(err); diff --git a/backend/src/ee/controllers/stripeController.ts b/backend/src/controllers/v1/stripeController.ts similarity index 100% rename from backend/src/ee/controllers/stripeController.ts rename to backend/src/controllers/v1/stripeController.ts diff --git a/backend/src/controllers/userActionController.ts b/backend/src/controllers/v1/userActionController.ts similarity index 97% rename from backend/src/controllers/userActionController.ts rename to backend/src/controllers/v1/userActionController.ts index 8203aa427..c7a3c2337 100644 --- a/backend/src/controllers/userActionController.ts +++ b/backend/src/controllers/v1/userActionController.ts @@ -1,6 +1,6 @@ import { Request, Response } from 'express'; import * as Sentry from '@sentry/node'; -import { UserAction } from '../models'; +import { UserAction } from '../../models'; /** * Add user action [action] diff --git a/backend/src/controllers/userController.ts b/backend/src/controllers/v1/userController.ts similarity index 100% rename from backend/src/controllers/userController.ts rename to backend/src/controllers/v1/userController.ts diff --git a/backend/src/controllers/workspaceController.ts b/backend/src/controllers/v1/workspaceController.ts similarity index 94% rename from backend/src/controllers/workspaceController.ts rename to backend/src/controllers/v1/workspaceController.ts index a402834d7..8675fc2b6 100644 --- a/backend/src/controllers/workspaceController.ts +++ b/backend/src/controllers/v1/workspaceController.ts @@ -7,14 +7,15 @@ import { Integration, IntegrationAuth, IUser, - ServiceToken -} from '../models'; + ServiceToken, + ServiceTokenData +} from '../../models'; import { createWorkspace as create, deleteWorkspace as deleteWork -} from '../helpers/workspace'; -import { addMemberships } from '../helpers/membership'; -import { ADMIN, COMPLETED, GRANTED } from '../variables'; +} from '../../helpers/workspace'; +import { addMemberships } from '../../helpers/membership'; +import { ADMIN } from '../../variables'; /** * Return public keys of members of workspace with id [workspaceId] @@ -32,13 +33,12 @@ export const getWorkspacePublicKeys = async (req: Request, res: Response) => { workspace: workspaceId }).populate<{ user: IUser }>('user', 'publicKey') ) - .filter((m) => m.status === COMPLETED || m.status === GRANTED) - .map((member) => { - return { - publicKey: member.user.publicKey, - userId: member.user._id - }; - }); + .map((member) => { + return { + publicKey: member.user.publicKey, + userId: member.user._id + }; + }); } catch (err) { Sentry.setUser({ email: req.user.email }); Sentry.captureException(err); @@ -168,8 +168,7 @@ export const createWorkspace = async (req: Request, res: Response) => { await addMemberships({ userIds: [req.user._id], workspaceId: workspace._id.toString(), - roles: [ADMIN], - statuses: [GRANTED] + roles: [ADMIN] }); } catch (err) { Sentry.setUser({ email: req.user.email }); @@ -318,7 +317,7 @@ export const getWorkspaceServiceTokens = async ( let serviceTokens; try { const { workspaceId } = req.params; - + // ?? FIX. serviceTokens = await ServiceToken.find({ user: req.user._id, workspace: workspaceId diff --git a/backend/src/controllers/v2/apiKeyDataController.ts b/backend/src/controllers/v2/apiKeyDataController.ts new file mode 100644 index 000000000..cafbacb5b --- /dev/null +++ b/backend/src/controllers/v2/apiKeyDataController.ts @@ -0,0 +1,105 @@ +import { Request, Response } from 'express'; +import * as Sentry from '@sentry/node'; +import crypto from 'crypto'; +import bcrypt from 'bcrypt'; +import { + APIKeyData +} from '../../models'; +import { + SALT_ROUNDS +} from '../../config'; + +/** + * Return API key data for user with id [req.user_id] + * @param req + * @param res + * @returns + */ +export const getAPIKeyData = async (req: Request, res: Response) => { + let apiKeyData; + try { + apiKeyData = await APIKeyData.find({ + user: req.user._id + }); + } catch (err) { + Sentry.setUser({ email: req.user.email }); + Sentry.captureException(err); + return res.status(400).send({ + message: 'Failed to get API key data' + }); + } + + return res.status(200).send({ + apiKeyData + }); +} + +/** + * Create new API key data for user with id [req.user._id] + * @param req + * @param res + */ +export const createAPIKeyData = async (req: Request, res: Response) => { + let apiKey, apiKeyData; + try { + const { name, expiresIn } = req.body; + + const secret = crypto.randomBytes(16).toString('hex'); + const secretHash = await bcrypt.hash(secret, SALT_ROUNDS); + + const expiresAt = new Date(); + expiresAt.setSeconds(expiresAt.getSeconds() + expiresIn); + + apiKeyData = await new APIKeyData({ + name, + expiresAt, + user: req.user._id, + secretHash + }).save(); + + // return api key data without sensitive data + apiKeyData = await APIKeyData.findById(apiKeyData._id); + + if (!apiKeyData) throw new Error('Failed to find API key data'); + + apiKey = `ak.${apiKeyData._id.toString()}.${secret}`; + + } catch (err) { + Sentry.setUser({ email: req.user.email }); + Sentry.captureException(err); + return res.status(400).send({ + message: 'Failed to API key data' + }); + } + + return res.status(200).send({ + apiKey, + apiKeyData + }); +} + +/** + * Delete API key data with id [apiKeyDataId]. + * @param req + * @param res + * @returns + */ +export const deleteAPIKeyData = async (req: Request, res: Response) => { + let apiKeyData; + try { + const { apiKeyDataId } = req.params; + + apiKeyData = await APIKeyData.findByIdAndDelete(apiKeyDataId); + + } catch (err) { + Sentry.setUser({ email: req.user.email }); + Sentry.captureException(err); + return res.status(400).send({ + message: 'Failed to delete API key data' + }); + } + + return res.status(200).send({ + apiKeyData + }); +} \ No newline at end of file diff --git a/backend/src/controllers/v2/environmentController.ts b/backend/src/controllers/v2/environmentController.ts new file mode 100644 index 000000000..7a0d5e1c5 --- /dev/null +++ b/backend/src/controllers/v2/environmentController.ts @@ -0,0 +1,261 @@ +import { Request, Response } from 'express'; +import * as Sentry from '@sentry/node'; +import { + Secret, + ServiceToken, + Workspace, + Integration, + ServiceTokenData, + Membership, +} from '../../models'; +import { SecretVersion } from '../../ee/models'; +import { BadRequestError } from '../../utils/errors'; +import _ from 'lodash'; +import { ABILITY_READ, ABILITY_WRITE } from '../../variables/organization'; + +/** + * Create new workspace environment named [environmentName] under workspace with id + * @param req + * @param res + * @returns + */ +export const createWorkspaceEnvironment = async ( + req: Request, + res: Response +) => { + const { workspaceId } = req.params; + const { environmentName, environmentSlug } = req.body; + try { + const workspace = await Workspace.findById(workspaceId).exec(); + if ( + !workspace || + workspace?.environments.find( + ({ name, slug }) => slug === environmentSlug || environmentName === name + ) + ) { + throw new Error('Failed to create workspace environment'); + } + + workspace?.environments.push({ + name: environmentName, + slug: environmentSlug.toLowerCase(), + }); + await workspace.save(); + } catch (err) { + Sentry.setUser({ email: req.user.email }); + Sentry.captureException(err); + return res.status(400).send({ + message: 'Failed to create new workspace environment', + }); + } + + return res.status(200).send({ + message: 'Successfully created new environment', + workspace: workspaceId, + environment: { + name: environmentName, + slug: environmentSlug, + }, + }); +}; + +/** + * Rename workspace environment with new name and slug of a workspace with [workspaceId] + * Old slug [oldEnvironmentSlug] must be provided + * @param req + * @param res + * @returns + */ +export const renameWorkspaceEnvironment = async ( + req: Request, + res: Response +) => { + const { workspaceId } = req.params; + const { environmentName, environmentSlug, oldEnvironmentSlug } = req.body; + try { + // user should pass both new slug and env name + if (!environmentSlug || !environmentName) { + throw new Error('Invalid environment given.'); + } + + // atomic update the env to avoid conflict + const workspace = await Workspace.findById(workspaceId).exec(); + if (!workspace) { + throw new Error('Failed to create workspace environment'); + } + + const isEnvExist = workspace.environments.some( + ({ name, slug }) => + slug !== oldEnvironmentSlug && + (name === environmentName || slug === environmentSlug) + ); + if (isEnvExist) { + throw new Error('Invalid environment given'); + } + + const envIndex = workspace?.environments.findIndex( + ({ slug }) => slug === oldEnvironmentSlug + ); + if (envIndex === -1) { + throw new Error('Invalid environment given'); + } + + workspace.environments[envIndex].name = environmentName; + workspace.environments[envIndex].slug = environmentSlug.toLowerCase(); + + await workspace.save(); + await Secret.updateMany( + { workspace: workspaceId, environment: oldEnvironmentSlug }, + { environment: environmentSlug } + ); + await SecretVersion.updateMany( + { workspace: workspaceId, environment: oldEnvironmentSlug }, + { environment: environmentSlug } + ); + await ServiceToken.updateMany( + { workspace: workspaceId, environment: oldEnvironmentSlug }, + { environment: environmentSlug } + ); + await ServiceTokenData.updateMany( + { workspace: workspaceId, environment: oldEnvironmentSlug }, + { environment: environmentSlug } + ); + await Integration.updateMany( + { workspace: workspaceId, environment: oldEnvironmentSlug }, + { environment: environmentSlug } + ); + await Membership.updateMany( + { + workspace: workspaceId, + "deniedPermissions.environmentSlug": oldEnvironmentSlug + }, + { $set: { "deniedPermissions.$[element].environmentSlug": environmentSlug } }, + { arrayFilters: [{ "element.environmentSlug": oldEnvironmentSlug }] } + ) + + } catch (err) { + Sentry.setUser({ email: req.user.email }); + Sentry.captureException(err); + return res.status(400).send({ + message: 'Failed to update workspace environment', + }); + } + + return res.status(200).send({ + message: 'Successfully update environment', + workspace: workspaceId, + environment: { + name: environmentName, + slug: environmentSlug, + }, + }); +}; + +/** + * Delete workspace environment by [environmentSlug] of workspace [workspaceId] and do the clean up + * @param req + * @param res + * @returns + */ +export const deleteWorkspaceEnvironment = async ( + req: Request, + res: Response +) => { + const { workspaceId } = req.params; + const { environmentSlug } = req.body; + try { + // atomic update the env to avoid conflict + const workspace = await Workspace.findById(workspaceId).exec(); + if (!workspace) { + throw new Error('Failed to create workspace environment'); + } + + const envIndex = workspace?.environments.findIndex( + ({ slug }) => slug === environmentSlug + ); + if (envIndex === -1) { + throw new Error('Invalid environment given'); + } + + workspace.environments.splice(envIndex, 1); + await workspace.save(); + + // clean up + await Secret.deleteMany({ + workspace: workspaceId, + environment: environmentSlug, + }); + await SecretVersion.deleteMany({ + workspace: workspaceId, + environment: environmentSlug, + }); + await ServiceToken.deleteMany({ + workspace: workspaceId, + environment: environmentSlug, + }); + await ServiceTokenData.deleteMany({ + workspace: workspaceId, + environment: environmentSlug, + }); + await Integration.deleteMany({ + workspace: workspaceId, + environment: environmentSlug, + }); + await Membership.updateMany( + { workspace: workspaceId }, + { $pull: { deniedPermissions: { environmentSlug: environmentSlug } } } + ) + + } catch (err) { + Sentry.setUser({ email: req.user.email }); + Sentry.captureException(err); + return res.status(400).send({ + message: 'Failed to delete workspace environment', + }); + } + + return res.status(200).send({ + message: 'Successfully deleted environment', + workspace: workspaceId, + environment: environmentSlug, + }); +}; + + +export const getAllAccessibleEnvironmentsOfWorkspace = async ( + req: Request, + res: Response +) => { + const { workspaceId } = req.params; + const workspacesUserIsMemberOf = await Membership.findOne({ + workspace: workspaceId, + user: req.user + }) + + if (!workspacesUserIsMemberOf) { + throw BadRequestError() + } + + const accessibleEnvironments: any = [] + const deniedPermission = workspacesUserIsMemberOf.deniedPermissions + + const relatedWorkspace = await Workspace.findById(workspaceId) + if (!relatedWorkspace) { + throw BadRequestError() + } + relatedWorkspace.environments.forEach(environment => { + const isReadBlocked = _.some(deniedPermission, { environmentSlug: environment.slug, ability: ABILITY_READ }) + const isWriteBlocked = _.some(deniedPermission, { environmentSlug: environment.slug, ability: ABILITY_WRITE }) + if (isReadBlocked) { + return + } else { + accessibleEnvironments.push({ + name: environment.name, + slug: environment.slug, + isWriteDenied: isWriteBlocked + }) + } + }) + + res.json({ accessibleEnvironments }) +}; diff --git a/backend/src/controllers/v2/index.ts b/backend/src/controllers/v2/index.ts new file mode 100644 index 000000000..936f5e281 --- /dev/null +++ b/backend/src/controllers/v2/index.ts @@ -0,0 +1,19 @@ +import * as usersController from './usersController'; +import * as organizationsController from './organizationsController'; +import * as workspaceController from './workspaceController'; +import * as serviceTokenDataController from './serviceTokenDataController'; +import * as apiKeyDataController from './apiKeyDataController'; +import * as secretController from './secretController'; +import * as secretsController from './secretsController'; +import * as environmentController from './environmentController'; + +export { + usersController, + organizationsController, + workspaceController, + serviceTokenDataController, + apiKeyDataController, + secretController, + secretsController, + environmentController +} diff --git a/backend/src/controllers/v2/organizationsController.ts b/backend/src/controllers/v2/organizationsController.ts new file mode 100644 index 000000000..d167e5129 --- /dev/null +++ b/backend/src/controllers/v2/organizationsController.ts @@ -0,0 +1,296 @@ +import { Request, Response } from 'express'; +import * as Sentry from '@sentry/node'; +import { + MembershipOrg, + Membership, + Workspace +} from '../../models'; +import { deleteMembershipOrg } from '../../helpers/membershipOrg'; +import { updateSubscriptionOrgQuantity } from '../../helpers/organization'; + +/** + * Return memberships for organization with id [organizationId] + * @param req + * @param res + */ +export const getOrganizationMemberships = async (req: Request, res: Response) => { + /* + #swagger.summary = 'Return organization memberships' + #swagger.description = 'Return organization memberships' + + #swagger.security = [{ + "apiKeyAuth": [] + }] + + #swagger.parameters['organizationId'] = { + "description": "ID of organization", + "required": true, + "type": "string" + } + + #swagger.responses[200] = { + content: { + "application/json": { + "schema": { + "type": "object", + "properties": { + "memberships": { + "type": "array", + "items": { + $ref: "#/components/schemas/MembershipOrg" + }, + "description": "Memberships of organization" + } + } + } + } + } + } + */ + let memberships; + try { + const { organizationId } = req.params; + + memberships = await MembershipOrg.find({ + organization: organizationId + }).populate('user', '+publicKey'); + } catch (err) { + Sentry.setUser({ email: req.user.email }); + Sentry.captureException(err); + return res.status(400).send({ + message: 'Failed to get organization memberships' + }); + } + + return res.status(200).send({ + memberships + }); +} + +/** + * Update role of membership with id [membershipId] to role [role] + * @param req + * @param res + */ +export const updateOrganizationMembership = async (req: Request, res: Response) => { + /* + #swagger.summary = 'Update organization membership' + #swagger.description = 'Update organization membership' + + #swagger.security = [{ + "apiKeyAuth": [] + }] + + #swagger.parameters['organizationId'] = { + "description": "ID of organization", + "required": true, + "type": "string" + } + + #swagger.parameters['membershipId'] = { + "description": "ID of organization membership to update", + "required": true, + "type": "string" + } + + #swagger.requestBody = { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "role": { + "type": "string", + "description": "Role of organization membership - either owner, admin, or member", + } + } + } + } + } + } + + #swagger.responses[200] = { + content: { + "application/json": { + "schema": { + "type": "object", + "properties": { + "membership": { + $ref: "#/components/schemas/MembershipOrg", + "description": "Updated organization membership" + } + } + } + } + } + } + */ + let membership; + try { + const { membershipId } = req.params; + const { role } = req.body; + + membership = await MembershipOrg.findByIdAndUpdate( + membershipId, + { + role + }, { + new: true + } + ); + } catch (err) { + Sentry.setUser({ email: req.user.email }); + Sentry.captureException(err); + return res.status(400).send({ + message: 'Failed to update organization membership' + }); + } + + return res.status(200).send({ + membership + }); +} + +/** + * Delete organization membership with id [membershipId] + * @param req + * @param res + * @returns + */ +export const deleteOrganizationMembership = async (req: Request, res: Response) => { + /* + #swagger.summary = 'Delete organization membership' + #swagger.description = 'Delete organization membership' + + #swagger.security = [{ + "apiKeyAuth": [] + }] + + #swagger.parameters['organizationId'] = { + "description": "ID of organization", + "required": true, + "type": "string" + } + + #swagger.parameters['membershipId'] = { + "description": "ID of organization membership to delete", + "required": true, + "type": "string" + } + + #swagger.responses[200] = { + content: { + "application/json": { + "schema": { + "type": "object", + "properties": { + "membership": { + $ref: "#/components/schemas/MembershipOrg", + "description": "Deleted organization membership" + } + } + } + } + } + } + */ + let membership; + try { + const { membershipId } = req.params; + + // delete organization membership + membership = await deleteMembershipOrg({ + membershipOrgId: membershipId + }); + + await updateSubscriptionOrgQuantity({ + organizationId: membership.organization.toString() + }); + } catch (err) { + Sentry.setUser({ email: req.user.email }); + Sentry.captureException(err); + return res.status(400).send({ + message: 'Failed to delete organization membership' + }); + } + + return res.status(200).send({ + membership + }); +} + +/** + * Return workspaces for organization with id [organizationId] that user has + * access to + * @param req + * @param res + */ +export const getOrganizationWorkspaces = async (req: Request, res: Response) => { + /* + #swagger.summary = 'Return projects in organization that user is part of' + #swagger.description = 'Return projects in organization that user is part of' + + #swagger.security = [{ + "apiKeyAuth": [] + }] + + #swagger.parameters['organizationId'] = { + "description": "ID of organization", + "required": true, + "type": "string" + } + + #swagger.responses[200] = { + content: { + "application/json": { + "schema": { + "type": "object", + "properties": { + "workspaces": { + "type": "array", + "items": { + $ref: "#/components/schemas/Project" + }, + "description": "Projects of organization" + } + } + } + } + } + } + */ + let workspaces; + try { + const { organizationId } = req.params; + + const workspacesSet = new Set( + ( + await Workspace.find( + { + organization: organizationId + }, + '_id' + ) + ).map((w) => w._id.toString()) + ); + + workspaces = ( + await Membership.find({ + user: req.user._id + }).populate('workspace') + ) + .filter((m) => workspacesSet.has(m.workspace._id.toString())) + .map((m) => m.workspace); + } catch (err) { + Sentry.setUser({ email: req.user.email }); + Sentry.captureException(err); + return res.status(400).send({ + message: 'Failed to get organization workspaces' + }); + } + + return res.status(200).send({ + workspaces + }); +} \ No newline at end of file diff --git a/backend/src/controllers/v2/secretController.ts b/backend/src/controllers/v2/secretController.ts new file mode 100644 index 000000000..89567e616 --- /dev/null +++ b/backend/src/controllers/v2/secretController.ts @@ -0,0 +1,401 @@ +import to from "await-to-js"; +import { Request, Response } from "express"; +import mongoose, { Types } from "mongoose"; +import Secret, { ISecret } from "../../models/secret"; +import { CreateSecretRequestBody, ModifySecretRequestBody, SanitizedSecretForCreate, SanitizedSecretModify } from "../../types/secret"; +const { ValidationError } = mongoose.Error; +import { BadRequestError, InternalServerError, UnauthorizedRequestError, ValidationError as RouteValidationError } from '../../utils/errors'; +import { AnyBulkWriteOperation } from 'mongodb'; +import { SECRET_PERSONAL, SECRET_SHARED } from "../../variables"; +import { postHogClient } from '../../services'; + +/** + * Create secret for workspace with id [workspaceId] and environment [environment] + * @param req + * @param res + */ +export const createSecret = async (req: Request, res: Response) => { + const secretToCreate: CreateSecretRequestBody = req.body.secret; + const { workspaceId, environment } = req.params + const sanitizedSecret: SanitizedSecretForCreate = { + secretKeyCiphertext: secretToCreate.secretKeyCiphertext, + secretKeyIV: secretToCreate.secretKeyIV, + secretKeyTag: secretToCreate.secretKeyTag, + secretKeyHash: secretToCreate.secretKeyHash, + secretValueCiphertext: secretToCreate.secretValueCiphertext, + secretValueIV: secretToCreate.secretValueIV, + secretValueTag: secretToCreate.secretValueTag, + secretValueHash: secretToCreate.secretValueHash, + secretCommentCiphertext: secretToCreate.secretCommentCiphertext, + secretCommentIV: secretToCreate.secretCommentIV, + secretCommentTag: secretToCreate.secretCommentTag, + secretCommentHash: secretToCreate.secretCommentHash, + workspace: new Types.ObjectId(workspaceId), + environment, + type: secretToCreate.type, + user: new Types.ObjectId(req.user._id) + } + + + const [error, secret] = await to(Secret.create(sanitizedSecret).then()) + if (error instanceof ValidationError) { + throw RouteValidationError({ message: error.message, stack: error.stack }) + } + + if (postHogClient) { + postHogClient.capture({ + event: 'secrets added', + distinctId: req.user.email, + properties: { + numberOfSecrets: 1, + workspaceId, + environment, + channel: req.headers?.['user-agent']?.toLowerCase().includes('mozilla') ? 'web' : 'cli', + userAgent: req.headers?.['user-agent'] + } + }); + } + + res.status(200).send({ + secret + }) +} + +/** + * Create many secrets for workspace wiht id [workspaceId] and environment [environment] + * @param req + * @param res + */ +export const createSecrets = async (req: Request, res: Response) => { + const secretsToCreate: CreateSecretRequestBody[] = req.body.secrets; + const { workspaceId, environment } = req.params + const sanitizedSecretesToCreate: SanitizedSecretForCreate[] = [] + + secretsToCreate.forEach(rawSecret => { + const safeUpdateFields: SanitizedSecretForCreate = { + secretKeyCiphertext: rawSecret.secretKeyCiphertext, + secretKeyIV: rawSecret.secretKeyIV, + secretKeyTag: rawSecret.secretKeyTag, + secretKeyHash: rawSecret.secretKeyHash, + secretValueCiphertext: rawSecret.secretValueCiphertext, + secretValueIV: rawSecret.secretValueIV, + secretValueTag: rawSecret.secretValueTag, + secretValueHash: rawSecret.secretValueHash, + secretCommentCiphertext: rawSecret.secretCommentCiphertext, + secretCommentIV: rawSecret.secretCommentIV, + secretCommentTag: rawSecret.secretCommentTag, + secretCommentHash: rawSecret.secretCommentHash, + workspace: new Types.ObjectId(workspaceId), + environment, + type: rawSecret.type, + user: new Types.ObjectId(req.user._id) + } + + sanitizedSecretesToCreate.push(safeUpdateFields) + }) + + const [bulkCreateError, secrets] = await to(Secret.insertMany(sanitizedSecretesToCreate).then()) + if (bulkCreateError) { + if (bulkCreateError instanceof ValidationError) { + throw RouteValidationError({ message: bulkCreateError.message, stack: bulkCreateError.stack }) + } + + throw InternalServerError({ message: "Unable to process your batch create request. Please try again", stack: bulkCreateError.stack }) + } + + if (postHogClient) { + postHogClient.capture({ + event: 'secrets added', + distinctId: req.user.email, + properties: { + numberOfSecrets: (secretsToCreate ?? []).length, + workspaceId, + environment, + channel: req.headers?.['user-agent']?.toLowerCase().includes('mozilla') ? 'web' : 'cli', + userAgent: req.headers?.['user-agent'] + } + }); + } + + res.status(200).send({ + secrets + }) +} + +/** + * Delete secrets in workspace with id [workspaceId] and environment [environment] + * @param req + * @param res + */ +export const deleteSecrets = async (req: Request, res: Response) => { + const { workspaceId, environmentName } = req.params + const secretIdsToDelete: string[] = req.body.secretIds + + const [secretIdsUserCanDeleteError, secretIdsUserCanDelete] = await to(Secret.find({ workspace: workspaceId, environment: environmentName }, { _id: 1 }).then()) + if (secretIdsUserCanDeleteError) { + throw InternalServerError({ message: `Unable to fetch secrets you own: [error=${secretIdsUserCanDeleteError.message}]` }) + } + + const secretsUserCanDeleteSet: Set = new Set(secretIdsUserCanDelete.map(objectId => objectId._id.toString())); + const deleteOperationsToPerform: AnyBulkWriteOperation[] = [] + + let numSecretsDeleted = 0; + secretIdsToDelete.forEach(secretIdToDelete => { + if (secretsUserCanDeleteSet.has(secretIdToDelete)) { + const deleteOperation = { deleteOne: { filter: { _id: new Types.ObjectId(secretIdToDelete) } } } + deleteOperationsToPerform.push(deleteOperation) + numSecretsDeleted++; + } else { + throw RouteValidationError({ message: "You cannot delete secrets that you do not have access to" }) + } + }) + + const [bulkDeleteError, bulkDelete] = await to(Secret.bulkWrite(deleteOperationsToPerform).then()) + if (bulkDeleteError) { + if (bulkDeleteError instanceof ValidationError) { + throw RouteValidationError({ message: "Unable to apply modifications, please try again", stack: bulkDeleteError.stack }) + } + throw InternalServerError() + } + + if (postHogClient) { + postHogClient.capture({ + event: 'secrets deleted', + distinctId: req.user.email, + properties: { + numberOfSecrets: numSecretsDeleted, + environment: environmentName, + workspaceId, + channel: req.headers?.['user-agent']?.toLowerCase().includes('mozilla') ? 'web' : 'cli', + userAgent: req.headers?.['user-agent'] + } + }); + } + + res.status(200).send() +} + +/** + * Delete secret with id [secretId] + * @param req + * @param res + */ +export const deleteSecret = async (req: Request, res: Response) => { + await Secret.findByIdAndDelete(req._secret._id) + + if (postHogClient) { + postHogClient.capture({ + event: 'secrets deleted', + distinctId: req.user.email, + properties: { + numberOfSecrets: 1, + workspaceId: req._secret.workspace.toString(), + environment: req._secret.environment, + channel: req.headers?.['user-agent']?.toLowerCase().includes('mozilla') ? 'web' : 'cli', + userAgent: req.headers?.['user-agent'] + } + }); + } + + res.status(200).send({ + secret: req._secret + }) +} + +/** + * Update secrets for workspace with id [workspaceId] and environment [environment] + * @param req + * @param res + * @returns + */ +export const updateSecrets = async (req: Request, res: Response) => { + const { workspaceId, environmentName } = req.params + const secretsModificationsRequested: ModifySecretRequestBody[] = req.body.secrets; + const [secretIdsUserCanModifyError, secretIdsUserCanModify] = await to(Secret.find({ workspace: workspaceId, environment: environmentName }, { _id: 1 }).then()) + if (secretIdsUserCanModifyError) { + throw InternalServerError({ message: "Unable to fetch secrets you own" }) + } + + const secretsUserCanModifySet: Set = new Set(secretIdsUserCanModify.map(objectId => objectId._id.toString())); + const updateOperationsToPerform: any = [] + + secretsModificationsRequested.forEach(userModifiedSecret => { + if (secretsUserCanModifySet.has(userModifiedSecret._id.toString())) { + const sanitizedSecret: SanitizedSecretModify = { + secretKeyCiphertext: userModifiedSecret.secretKeyCiphertext, + secretKeyIV: userModifiedSecret.secretKeyIV, + secretKeyTag: userModifiedSecret.secretKeyTag, + secretKeyHash: userModifiedSecret.secretKeyHash, + secretValueCiphertext: userModifiedSecret.secretValueCiphertext, + secretValueIV: userModifiedSecret.secretValueIV, + secretValueTag: userModifiedSecret.secretValueTag, + secretValueHash: userModifiedSecret.secretValueHash, + secretCommentCiphertext: userModifiedSecret.secretCommentCiphertext, + secretCommentIV: userModifiedSecret.secretCommentIV, + secretCommentTag: userModifiedSecret.secretCommentTag, + secretCommentHash: userModifiedSecret.secretCommentHash, + } + + const updateOperation = { updateOne: { filter: { _id: userModifiedSecret._id, workspace: workspaceId }, update: { $inc: { version: 1 }, $set: sanitizedSecret } } } + updateOperationsToPerform.push(updateOperation) + } else { + throw UnauthorizedRequestError({ message: "You do not have permission to modify one or more of the requested secrets" }) + } + }) + + const [bulkModificationInfoError, bulkModificationInfo] = await to(Secret.bulkWrite(updateOperationsToPerform).then()) + if (bulkModificationInfoError) { + if (bulkModificationInfoError instanceof ValidationError) { + throw RouteValidationError({ message: "Unable to apply modifications, please try again", stack: bulkModificationInfoError.stack }) + } + + throw InternalServerError() + } + + if (postHogClient) { + postHogClient.capture({ + event: 'secrets modified', + distinctId: req.user.email, + properties: { + numberOfSecrets: (secretsModificationsRequested ?? []).length, + environment: environmentName, + workspaceId, + channel: req.headers?.['user-agent']?.toLowerCase().includes('mozilla') ? 'web' : 'cli', + userAgent: req.headers?.['user-agent'] + } + }); + } + + return res.status(200).send() +} + +/** + * Update a secret within workspace with id [workspaceId] and environment [environment] + * @param req + * @param res + * @returns + */ +export const updateSecret = async (req: Request, res: Response) => { + const { workspaceId, environmentName } = req.params + const secretModificationsRequested: ModifySecretRequestBody = req.body.secret; + + const [secretIdUserCanModifyError, secretIdUserCanModify] = await to(Secret.findOne({ workspace: workspaceId, environment: environmentName }, { _id: 1 }).then()) + if (secretIdUserCanModifyError && !secretIdUserCanModify) { + throw BadRequestError() + } + + const sanitizedSecret: SanitizedSecretModify = { + secretKeyCiphertext: secretModificationsRequested.secretKeyCiphertext, + secretKeyIV: secretModificationsRequested.secretKeyIV, + secretKeyTag: secretModificationsRequested.secretKeyTag, + secretKeyHash: secretModificationsRequested.secretKeyHash, + secretValueCiphertext: secretModificationsRequested.secretValueCiphertext, + secretValueIV: secretModificationsRequested.secretValueIV, + secretValueTag: secretModificationsRequested.secretValueTag, + secretValueHash: secretModificationsRequested.secretValueHash, + secretCommentCiphertext: secretModificationsRequested.secretCommentCiphertext, + secretCommentIV: secretModificationsRequested.secretCommentIV, + secretCommentTag: secretModificationsRequested.secretCommentTag, + secretCommentHash: secretModificationsRequested.secretCommentHash, + } + + const [error, singleModificationUpdate] = await to(Secret.updateOne({ _id: secretModificationsRequested._id, workspace: workspaceId }, { $inc: { version: 1 }, $set: sanitizedSecret }).then()) + if (error instanceof ValidationError) { + throw RouteValidationError({ message: "Unable to apply modifications, please try again", stack: error.stack }) + } + + if (postHogClient) { + postHogClient.capture({ + event: 'secrets modified', + distinctId: req.user.email, + properties: { + numberOfSecrets: 1, + environment: environmentName, + workspaceId, + channel: req.headers?.['user-agent']?.toLowerCase().includes('mozilla') ? 'web' : 'cli', + userAgent: req.headers?.['user-agent'] + } + }); + } + + return res.status(200).send(singleModificationUpdate) +} + +/** + * Return secrets for workspace with id [workspaceId], environment [environment] and user + * with id [req.user._id] + * @param req + * @param res + * @returns + */ +export const getSecrets = async (req: Request, res: Response) => { + const { environment } = req.query; + const { workspaceId } = req.params; + + let userId: Types.ObjectId | undefined = undefined // used for getting personal secrets for user + let userEmail: Types.ObjectId | undefined = undefined // used for posthog + if (req.user) { + userId = req.user._id; + userEmail = req.user.email; + } + + if (req.serviceTokenData) { + userId = req.serviceTokenData.user._id + userEmail = req.serviceTokenData.user.email; + } + + const [err, secrets] = await to(Secret.find( + { + workspace: workspaceId, + environment, + $or: [{ user: userId }, { user: { $exists: false } }], + type: { $in: [SECRET_SHARED, SECRET_PERSONAL] } + } + ).then()) + + if (err) { + throw RouteValidationError({ message: "Failed to get secrets, please try again", stack: err.stack }) + } + + if (postHogClient) { + postHogClient.capture({ + event: 'secrets pulled', + distinctId: userEmail, + properties: { + numberOfSecrets: (secrets ?? []).length, + environment, + workspaceId, + channel: req.headers?.['user-agent']?.toLowerCase().includes('mozilla') ? 'web' : 'cli', + userAgent: req.headers?.['user-agent'] + } + }); + } + + return res.json(secrets) +} + +/** + * Return secret with id [secretId] + * @param req + * @param res + * @returns + */ +export const getSecret = async (req: Request, res: Response) => { + // if (postHogClient) { + // postHogClient.capture({ + // event: 'secrets pulled', + // distinctId: req.user.email, + // properties: { + // numberOfSecrets: 1, + // workspaceId: req._secret.workspace.toString(), + // environment: req._secret.environment, + // channel: req.headers?.['user-agent']?.toLowerCase().includes('mozilla') ? 'web' : 'cli', + // userAgent: req.headers?.['user-agent'] + // } + // }); + // } + + return res.status(200).send({ + secret: req._secret + }); +} \ No newline at end of file diff --git a/backend/src/controllers/v2/secretsController.ts b/backend/src/controllers/v2/secretsController.ts new file mode 100644 index 000000000..90eb8e48d --- /dev/null +++ b/backend/src/controllers/v2/secretsController.ts @@ -0,0 +1,673 @@ +import to from 'await-to-js'; +import { Types } from 'mongoose'; +import { Request, Response } from 'express'; +import { ISecret, Membership, Secret, Workspace } from '../../models'; +import { + SECRET_PERSONAL, + SECRET_SHARED, + ACTION_ADD_SECRETS, + ACTION_READ_SECRETS, + ACTION_UPDATE_SECRETS, + ACTION_DELETE_SECRETS +} from '../../variables'; +import { UnauthorizedRequestError, ValidationError } from '../../utils/errors'; +import { EventService } from '../../services'; +import { eventPushSecrets } from '../../events'; +import { EESecretService, EELogService } from '../../ee/services'; +import { postHogClient } from '../../services'; +import { getChannelFromUserAgent } from '../../utils/posthog'; +import { ABILITY_READ, ABILITY_WRITE } from '../../variables/organization'; +import { userHasWorkspaceAccess } from '../../ee/helpers/checkMembershipPermissions'; + +/** + * Create secret(s) for workspace with id [workspaceId] and environment [environment] + * @param req + * @param res + */ +export const createSecrets = async (req: Request, res: Response) => { + /* + #swagger.summary = 'Create new secret(s)' + #swagger.description = 'Create one or many secrets for a given project and environment.' + + #swagger.security = [{ + "apiKeyAuth": [] + }] + + #swagger.requestBody = { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "workspaceId": { + "type": "string", + "description": "ID of project", + }, + "environment": { + "type": "string", + "description": "Environment within project" + }, + "secrets": { + $ref: "#/components/schemas/CreateSecret", + "description": "Secret(s) to create - object or array of objects" + } + } + } + } + } + } + + #swagger.responses[200] = { + content: { + "application/json": { + "schema": { + "type": "object", + "properties": { + "secrets": { + "type": "array", + "items": { + $ref: "#/components/schemas/Secret" + }, + "description": "Newly-created secrets for the given project and environment" + } + } + } + } + } + } + */ + + const channel = getChannelFromUserAgent(req.headers['user-agent']) + const { workspaceId, environment } = req.body; + + const hasAccess = await userHasWorkspaceAccess(req.user, workspaceId, environment, ABILITY_WRITE) + if (!hasAccess) { + throw UnauthorizedRequestError({ message: "You do not have the necessary permission(s) perform this action" }) + } + + let toAdd; + if (Array.isArray(req.body.secrets)) { + // case: create multiple secrets + toAdd = req.body.secrets; + } else if (typeof req.body.secrets === 'object') { + // case: create 1 secret + toAdd = [req.body.secrets]; + } + + const newSecrets = await Secret.insertMany( + toAdd.map(({ + type, + secretKeyCiphertext, + secretKeyIV, + secretKeyTag, + secretValueCiphertext, + secretValueIV, + secretValueTag, + }: { + type: string; + secretKeyCiphertext: string; + secretKeyIV: string; + secretKeyTag: string; + secretValueCiphertext: string; + secretValueIV: string; + secretValueTag: string; + }) => { + return ({ + version: 1, + workspace: new Types.ObjectId(workspaceId), + type, + user: type === SECRET_PERSONAL ? req.user : undefined, + environment, + secretKeyCiphertext, + secretKeyIV, + secretKeyTag, + secretValueCiphertext, + secretValueIV, + secretValueTag + }); + }) + ); + + setTimeout(async () => { + // trigger event - push secrets + await EventService.handleEvent({ + event: eventPushSecrets({ + workspaceId + }) + }); + }, 5000); + + // (EE) add secret versions for new secrets + await EESecretService.addSecretVersions({ + secretVersions: newSecrets.map(({ + _id, + version, + workspace, + type, + user, + environment, + secretKeyCiphertext, + secretKeyIV, + secretKeyTag, + secretKeyHash, + secretValueCiphertext, + secretValueIV, + secretValueTag, + secretValueHash + }) => ({ + _id: new Types.ObjectId(), + secret: _id, + version, + workspace, + type, + user, + environment, + isDeleted: false, + secretKeyCiphertext, + secretKeyIV, + secretKeyTag, + secretKeyHash, + secretValueCiphertext, + secretValueIV, + secretValueTag, + secretValueHash + })) + }); + + const addAction = await EELogService.createActionSecret({ + name: ACTION_ADD_SECRETS, + userId: req.user._id.toString(), + workspaceId, + secretIds: newSecrets.map((n) => n._id) + }); + + // (EE) create (audit) log + addAction && await EELogService.createLog({ + userId: req.user._id.toString(), + workspaceId, + actions: [addAction], + channel, + ipAddress: req.ip + }); + + // (EE) take a secret snapshot + await EESecretService.takeSecretSnapshot({ + workspaceId + }); + + if (postHogClient) { + postHogClient.capture({ + event: 'secrets added', + distinctId: req.user.email, + properties: { + numberOfSecrets: toAdd.length, + environment, + workspaceId, + channel: channel, + userAgent: req.headers?.['user-agent'] + } + }); + } + + return res.status(200).send({ + secrets: newSecrets + }); +} + +/** + * Return secret(s) for workspace with id [workspaceId], environment [environment] and user + * with id [req.user._id] + * @param req + * @param res + * @returns + */ +export const getSecrets = async (req: Request, res: Response) => { + /* + #swagger.summary = 'Read secrets' + #swagger.description = 'Read secrets from a project and environment' + + #swagger.security = [{ + "apiKeyAuth": [] + }] + + #swagger.parameters['workspaceId'] = { + "description": "ID of project", + "required": true, + "type": "string" + } + + #swagger.parameters['environment'] = { + "description": "Environment within project", + "required": true, + "type": "string" + } + + #swagger.responses[200] = { + content: { + "application/json": { + "schema": { + "type": "object", + "properties": { + "secrets": { + "type": "array", + "items": { + $ref: "#/components/schemas/Secret" + }, + "description": "Secrets for the given project and environment" + } + } + } + } + } + } + */ + const { workspaceId, environment } = req.query; + + let userId = "" // used for getting personal secrets for user + let userEmail = "" // used for posthog + if (req.user) { + userId = req.user._id; + userEmail = req.user.email; + } + + if (req.serviceTokenData) { + userId = req.serviceTokenData.user._id + userEmail = req.serviceTokenData.user.email; + } + + // none service token case as service tokens are already scoped + if (!req.serviceTokenData) { + const hasAccess = await userHasWorkspaceAccess(userId, workspaceId, environment, ABILITY_READ) + if (!hasAccess) { + throw UnauthorizedRequestError({ message: "You do not have the necessary permission(s) perform this action" }) + } + } + + const [err, secrets] = await to(Secret.find( + { + workspace: workspaceId, + environment, + $or: [ + { user: userId }, + { user: { $exists: false } } + ], + type: { $in: [SECRET_SHARED, SECRET_PERSONAL] } + } + ).then()) + + if (err) throw ValidationError({ message: 'Failed to get secrets', stack: err.stack }); + + const channel = getChannelFromUserAgent(req.headers['user-agent']) + + const readAction = await EELogService.createActionSecret({ + name: ACTION_READ_SECRETS, + userId: userId, + workspaceId: workspaceId as string, + secretIds: secrets.map((n: any) => n._id) + }); + + readAction && await EELogService.createLog({ + userId: userId, + workspaceId: workspaceId as string, + actions: [readAction], + channel, + ipAddress: req.ip + }); + + if (postHogClient) { + postHogClient.capture({ + event: 'secrets pulled', + distinctId: userEmail, + properties: { + numberOfSecrets: secrets.length, + environment, + workspaceId, + channel, + userAgent: req.headers?.['user-agent'] + } + }); + } + + return res.status(200).send({ + secrets + }); +} + +/** + * Update secret(s) + * @param req + * @param res + */ +export const updateSecrets = async (req: Request, res: Response) => { + /* + #swagger.summary = 'Update secret(s)' + #swagger.description = 'Update secret(s)' + + #swagger.security = [{ + "apiKeyAuth": [] + }] + + #swagger.requestBody = { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "secrets": { + $ref: "#/components/schemas/UpdateSecret", + "description": "Secret(s) to update - object or array of objects" + } + } + } + } + } + } + + #swagger.responses[200] = { + content: { + "application/json": { + "schema": { + "type": "object", + "properties": { + "secrets": { + "type": "array", + "items": { + $ref: "#/components/schemas/Secret" + }, + "description": "Updated secrets" + } + } + } + } + } + } + */ + const channel = req.headers?.['user-agent']?.toLowerCase().includes('mozilla') ? 'web' : 'cli'; + + // TODO: move type + interface PatchSecret { + id: string; + secretKeyCiphertext: string; + secretKeyIV: string; + secretKeyTag: string; + secretValueCiphertext: string; + secretValueIV: string; + secretValueTag: string; + secretCommentCiphertext: string; + secretCommentIV: string; + secretCommentTag: string; + } + + const updateOperationsToPerform = req.body.secrets.map((secret: PatchSecret) => { + const { + secretKeyCiphertext, + secretKeyIV, + secretKeyTag, + secretValueCiphertext, + secretValueIV, + secretValueTag, + secretCommentCiphertext, + secretCommentIV, + secretCommentTag + } = secret; + + return ({ + updateOne: { + filter: { _id: new Types.ObjectId(secret.id) }, + update: { + $inc: { + version: 1 + }, + secretKeyCiphertext, + secretKeyIV, + secretKeyTag, + secretValueCiphertext, + secretValueIV, + secretValueTag, + ...(( + secretCommentCiphertext && + secretCommentIV && + secretCommentTag + ) ? { + secretCommentCiphertext, + secretCommentIV, + secretCommentTag + } : {}), + } + } + }); + }); + + await Secret.bulkWrite(updateOperationsToPerform); + + const secretModificationsBySecretId: { [key: string]: PatchSecret } = {}; + req.body.secrets.forEach((secret: PatchSecret) => { + secretModificationsBySecretId[secret.id] = secret; + }); + + const ListOfSecretsBeforeModifications = req.secrets + const secretVersions = { + secretVersions: ListOfSecretsBeforeModifications.map((secret: ISecret) => { + const { + secretKeyCiphertext, + secretKeyIV, + secretKeyTag, + secretValueCiphertext, + secretValueIV, + secretValueTag, + secretCommentCiphertext, + secretCommentIV, + secretCommentTag, + } = secretModificationsBySecretId[secret._id.toString()] + + return ({ + secret: secret._id, + version: secret.version + 1, + workspace: secret.workspace, + type: secret.type, + environment: secret.environment, + secretKeyCiphertext: secretKeyCiphertext ? secretKeyCiphertext : secret.secretKeyCiphertext, + secretKeyIV: secretKeyIV ? secretKeyIV : secret.secretKeyIV, + secretKeyTag: secretKeyTag ? secretKeyTag : secret.secretKeyTag, + secretValueCiphertext: secretValueCiphertext ? secretValueCiphertext : secret.secretValueCiphertext, + secretValueIV: secretValueIV ? secretValueIV : secret.secretValueIV, + secretValueTag: secretValueTag ? secretValueTag : secret.secretValueTag, + secretCommentCiphertext: secretCommentCiphertext ? secretCommentCiphertext : secret.secretCommentCiphertext, + secretCommentIV: secretCommentIV ? secretCommentIV : secret.secretCommentIV, + secretCommentTag: secretCommentTag ? secretCommentTag : secret.secretCommentTag, + }); + }) + } + + await EESecretService.addSecretVersions(secretVersions); + + + // group secrets into workspaces so updated secrets can + // be logged and snapshotted separately for each workspace + const workspaceSecretObj: any = {}; + req.secrets.forEach((s: any) => { + if (s.workspace.toString() in workspaceSecretObj) { + workspaceSecretObj[s.workspace.toString()].push(s); + } else { + workspaceSecretObj[s.workspace.toString()] = [s] + } + }); + + Object.keys(workspaceSecretObj).forEach(async (key) => { + // trigger event - push secrets + setTimeout(async () => { + await EventService.handleEvent({ + event: eventPushSecrets({ + workspaceId: key + }) + }); + }, 10000); + + const updateAction = await EELogService.createActionSecret({ + name: ACTION_UPDATE_SECRETS, + userId: req.user._id.toString(), + workspaceId: key, + secretIds: workspaceSecretObj[key].map((secret: ISecret) => secret._id) + }); + + // (EE) create (audit) log + updateAction && await EELogService.createLog({ + userId: req.user._id.toString(), + workspaceId: key, + actions: [updateAction], + channel, + ipAddress: req.ip + }); + + // (EE) take a secret snapshot + await EESecretService.takeSecretSnapshot({ + workspaceId: key + }) + + if (postHogClient) { + postHogClient.capture({ + event: 'secrets modified', + distinctId: req.user.email, + properties: { + numberOfSecrets: workspaceSecretObj[key].length, + environment: workspaceSecretObj[key][0].environment, + workspaceId: key, + channel: channel, + userAgent: req.headers?.['user-agent'] + } + }); + } + }); + + return res.status(200).send({ + secrets: await Secret.find({ + _id: { + $in: req.secrets.map((secret: ISecret) => secret._id) + } + }) + }); +} + +/** + * Delete secret(s) with id [workspaceId] and environment [environment] + * @param req + * @param res + */ +export const deleteSecrets = async (req: Request, res: Response) => { + /* + #swagger.summary = 'Delete secret(s)' + #swagger.description = 'Delete one or many secrets by their ID(s)' + + #swagger.security = [{ + "apiKeyAuth": [] + }] + + #swagger.requestBody = { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "secretIds": { + "type": "string", + "description": "ID(s) of secrets - string or array of strings" + }, + } + } + } + } + } + + #swagger.responses[200] = { + content: { + "application/json": { + "schema": { + "type": "object", + "properties": { + "secrets": { + "type": "array", + "items": { + $ref: "#/components/schemas/Secret" + }, + "description": "Deleted secrets" + } + } + } + } + } + } + */ + const channel = getChannelFromUserAgent(req.headers['user-agent']) + const toDelete = req.secrets.map((s: any) => s._id); + + await Secret.deleteMany({ + _id: { + $in: toDelete + } + }); + + await EESecretService.markDeletedSecretVersions({ + secretIds: toDelete + }); + + // group secrets into workspaces so deleted secrets can + // be logged and snapshotted separately for each workspace + const workspaceSecretObj: any = {}; + req.secrets.forEach((s: any) => { + if (s.workspace.toString() in workspaceSecretObj) { + workspaceSecretObj[s.workspace.toString()].push(s); + } else { + workspaceSecretObj[s.workspace.toString()] = [s] + } + }); + + Object.keys(workspaceSecretObj).forEach(async (key) => { + // trigger event - push secrets + await EventService.handleEvent({ + event: eventPushSecrets({ + workspaceId: key + }) + }); + const deleteAction = await EELogService.createActionSecret({ + name: ACTION_DELETE_SECRETS, + userId: req.user._id.toString(), + workspaceId: key, + secretIds: workspaceSecretObj[key].map((secret: ISecret) => secret._id) + }); + + // (EE) create (audit) log + deleteAction && await EELogService.createLog({ + userId: req.user._id.toString(), + workspaceId: key, + actions: [deleteAction], + channel, + ipAddress: req.ip + }); + + // (EE) take a secret snapshot + await EESecretService.takeSecretSnapshot({ + workspaceId: key + }) + + if (postHogClient) { + postHogClient.capture({ + event: 'secrets deleted', + distinctId: req.user.email, + properties: { + numberOfSecrets: workspaceSecretObj[key].length, + environment: workspaceSecretObj[key][0].environment, + workspaceId: key, + channel: channel, + userAgent: req.headers?.['user-agent'] + } + }); + } + }); + + return res.status(200).send({ + secrets: req.secrets + }); +} \ No newline at end of file diff --git a/backend/src/controllers/v2/serviceTokenDataController.ts b/backend/src/controllers/v2/serviceTokenDataController.ts new file mode 100644 index 000000000..780bae9a4 --- /dev/null +++ b/backend/src/controllers/v2/serviceTokenDataController.ts @@ -0,0 +1,114 @@ +import { Request, Response } from 'express'; +import * as Sentry from '@sentry/node'; +import crypto from 'crypto'; +import bcrypt from 'bcrypt'; +import { + ServiceTokenData +} from '../../models'; +import { + SALT_ROUNDS +} from '../../config'; +import { userHasWorkspaceAccess } from '../../ee/helpers/checkMembershipPermissions'; +import { ABILITY_READ } from '../../variables/organization'; + +/** + * Return service token data associated with service token on request + * @param req + * @param res + * @returns + */ +export const getServiceTokenData = async (req: Request, res: Response) => res.status(200).json(req.serviceTokenData); + +/** + * Create new service token data for workspace with id [workspaceId] and + * environment [environment]. + * @param req + * @param res + * @returns + */ +export const createServiceTokenData = async (req: Request, res: Response) => { + let serviceToken, serviceTokenData; + try { + const { + name, + workspaceId, + environment, + encryptedKey, + iv, + tag, + expiresIn + } = req.body; + + const hasAccess = await userHasWorkspaceAccess(req.user, workspaceId, environment, ABILITY_READ) + if (!hasAccess) { + throw UnauthorizedRequestError({ message: "You do not have the necessary permission(s) perform this action" }) + } + + const secret = crypto.randomBytes(16).toString('hex'); + const secretHash = await bcrypt.hash(secret, SALT_ROUNDS); + + const expiresAt = new Date(); + expiresAt.setSeconds(expiresAt.getSeconds() + expiresIn); + + serviceTokenData = await new ServiceTokenData({ + name, + workspace: workspaceId, + environment, + user: req.user._id, + expiresAt, + secretHash, + encryptedKey, + iv, + tag + }).save(); + + // return service token data without sensitive data + serviceTokenData = await ServiceTokenData.findById(serviceTokenData._id); + + if (!serviceTokenData) throw new Error('Failed to find service token data'); + + serviceToken = `st.${serviceTokenData._id.toString()}.${secret}`; + + } catch (err) { + Sentry.setUser({ email: req.user.email }); + Sentry.captureException(err); + return res.status(400).send({ + message: 'Failed to create service token data' + }); + } + + return res.status(200).send({ + serviceToken, + serviceTokenData + }); +} + +/** + * Delete service token data with id [serviceTokenDataId]. + * @param req + * @param res + * @returns + */ +export const deleteServiceTokenData = async (req: Request, res: Response) => { + let serviceTokenData; + try { + const { serviceTokenDataId } = req.params; + + serviceTokenData = await ServiceTokenData.findByIdAndDelete(serviceTokenDataId); + + } catch (err) { + Sentry.setUser({ email: req.user.email }); + Sentry.captureException(err); + return res.status(400).send({ + message: 'Failed to delete service token data' + }); + } + + return res.status(200).send({ + serviceTokenData + }); +} + +function UnauthorizedRequestError(arg0: { message: string; }) { + throw new Error('Function not implemented.'); +} diff --git a/backend/src/controllers/v2/usersController.ts b/backend/src/controllers/v2/usersController.ts new file mode 100644 index 000000000..4ec1099d9 --- /dev/null +++ b/backend/src/controllers/v2/usersController.ts @@ -0,0 +1,109 @@ +import { Request, Response } from 'express'; +import * as Sentry from '@sentry/node'; +import { + User, + MembershipOrg +} from '../../models'; + +/** + * Return the current user. + * @param req + * @param res + * @returns + */ +export const getMe = async (req: Request, res: Response) => { + /* + #swagger.summary = "Retrieve the current user on the request" + #swagger.description = "Retrieve the current user on the request" + + #swagger.security = [{ + "apiKeyAuth": [] + }] + + #swagger.responses[200] = { + content: { + "application/json": { + "schema": { + "type": "object", + "properties": { + "user": { + "type": "object", + $ref: "#/components/schemas/CurrentUser", + "description": "Current user on request" + } + } + } + } + } + } + */ + let user; + try { + user = await User + .findById(req.user._id) + .select('+publicKey +encryptedPrivateKey +iv +tag'); + } catch (err) { + Sentry.setUser({ email: req.user.email }); + Sentry.captureException(err); + return res.status(400).send({ + message: 'Failed to get current user' + }); + } + + return res.status(200).send({ + user + }); +} + +/** + * Return organizations that the current user is part of. + * @param req + * @param res + */ +export const getMyOrganizations = async (req: Request, res: Response) => { + /* + #swagger.summary = 'Return organizations that current user is part of' + #swagger.description = 'Return organizations that current user is part of' + + #swagger.security = [{ + "apiKeyAuth": [] + }] + + #swagger.responses[200] = { + content: { + "application/json": { + "schema": { + "type": "object", + "properties": { + "organizations": { + "type": "array", + "items": { + $ref: "#/components/schemas/Organization" + }, + "description": "Organizations that user is part of" + } + } + } + } + } + } + */ + let organizations; + try { + organizations = ( + await MembershipOrg.find({ + user: req.user._id + }).populate('organization') + ).map((m) => m.organization); + } catch (err) { + Sentry.setUser({ email: req.user.email }); + Sentry.captureException(err); + return res.status(400).send({ + message: "Failed to get current user's organizations" + }); + } + + return res.status(200).send({ + organizations + }); +} \ No newline at end of file diff --git a/backend/src/controllers/v2/workspaceController.ts b/backend/src/controllers/v2/workspaceController.ts new file mode 100644 index 000000000..90781b58c --- /dev/null +++ b/backend/src/controllers/v2/workspaceController.ts @@ -0,0 +1,470 @@ +import { Request, Response } from 'express'; +import * as Sentry from '@sentry/node'; +import { Types } from 'mongoose'; +import { + Workspace, + Secret, + Membership, + MembershipOrg, + Integration, + IntegrationAuth, + Key, + IUser, + ServiceToken, + ServiceTokenData +} from '../../models'; +import { + v2PushSecrets as push, + pullSecrets as pull, + reformatPullSecrets +} from '../../helpers/secret'; +import { pushKeys } from '../../helpers/key'; +import { postHogClient, EventService } from '../../services'; +import { eventPushSecrets } from '../../events'; + +interface V2PushSecret { + type: string; // personal or shared + secretKeyCiphertext: string; + secretKeyIV: string; + secretKeyTag: string; + secretKeyHash: string; + secretValueCiphertext: string; + secretValueIV: string; + secretValueTag: string; + secretValueHash: string; + secretCommentCiphertext?: string; + secretCommentIV?: string; + secretCommentTag?: string; + secretCommentHash?: string; +} + +/** + * Upload (encrypted) secrets to workspace with id [workspaceId] + * for environment [environment] + * @param req + * @param res + * @returns + */ +export const pushWorkspaceSecrets = async (req: Request, res: Response) => { + // upload (encrypted) secrets to workspace with id [workspaceId] + try { + let { secrets }: { secrets: V2PushSecret[] } = req.body; + const { keys, environment, channel } = req.body; + const { workspaceId } = req.params; + + // validate environment + const workspaceEnvs = req.membership.workspace.environments; + if (!workspaceEnvs.find(({ slug }: { slug: string }) => slug === environment)) { + throw new Error('Failed to validate environment'); + } + + // sanitize secrets + secrets = secrets.filter( + (s: V2PushSecret) => s.secretKeyCiphertext !== '' && s.secretValueCiphertext !== '' + ); + + await push({ + userId: req.user._id, + workspaceId, + environment, + secrets, + channel: channel ? channel : 'cli', + ipAddress: req.ip + }); + + await pushKeys({ + userId: req.user._id, + workspaceId, + keys + }); + + if (postHogClient) { + postHogClient.capture({ + event: 'secrets pushed', + distinctId: req.user.email, + properties: { + numberOfSecrets: secrets.length, + environment, + workspaceId, + channel: channel ? channel : 'cli' + } + }); + } + + // trigger event - push secrets + EventService.handleEvent({ + event: eventPushSecrets({ + workspaceId + }) + }); + + } catch (err) { + Sentry.setUser({ email: req.user.email }); + Sentry.captureException(err); + return res.status(400).send({ + message: 'Failed to upload workspace secrets' + }); + } + + return res.status(200).send({ + message: 'Successfully uploaded workspace secrets' + }); +}; + +/** + * Return (encrypted) secrets for workspace with id [workspaceId] + * for environment [environment] + * @param req + * @param res + * @returns + */ +export const pullSecrets = async (req: Request, res: Response) => { + let secrets; + try { + const environment: string = req.query.environment as string; + const channel: string = req.query.channel as string; + const { workspaceId } = req.params; + + let userId; + if (req.user) { + userId = req.user._id.toString(); + } else if (req.serviceTokenData) { + userId = req.serviceTokenData.user._id + } + // validate environment + const workspaceEnvs = req.membership.workspace.environments; + if (!workspaceEnvs.find(({ slug }: { slug: string }) => slug === environment)) { + throw new Error('Failed to validate environment'); + } + + secrets = await pull({ + userId, + workspaceId, + environment, + channel: channel ? channel : 'cli', + ipAddress: req.ip + }); + + if (channel !== 'cli') { + secrets = reformatPullSecrets({ secrets }); + } + + if (postHogClient) { + // capture secrets pushed event in production + postHogClient.capture({ + distinctId: req.user.email, + event: 'secrets pulled', + properties: { + numberOfSecrets: secrets.length, + environment, + workspaceId, + channel: channel ? channel : 'cli' + } + }); + } + } catch (err) { + Sentry.setUser({ email: req.user.email }); + Sentry.captureException(err); + return res.status(400).send({ + message: 'Failed to pull workspace secrets' + }); + } + + return res.status(200).send({ + secrets + }); +}; + +export const getWorkspaceKey = async (req: Request, res: Response) => { + /* + #swagger.summary = 'Return encrypted project key' + #swagger.description = 'Return encrypted project key' + + #swagger.security = [{ + "apiKeyAuth": [] + }] + + #swagger.parameters['workspaceId'] = { + "description": "ID of project", + "required": true, + "type": "string" + } + + #swagger.responses[200] = { + content: { + "application/json": { + "schema": { + "type": "array", + "items": { + $ref: "#/components/schemas/ProjectKey" + }, + "description": "Encrypted project key for the given project" + } + } + } + } + */ + let key; + try { + const { workspaceId } = req.params; + + key = await Key.findOne({ + workspace: workspaceId, + receiver: req.user._id + }).populate('sender', '+publicKey'); + + if (!key) throw new Error('Failed to find workspace key'); + } catch (err) { + Sentry.setUser({ email: req.user.email }); + Sentry.captureException(err); + return res.status(400).send({ + message: 'Failed to get workspace key' + }); + } + + return res.status(200).json(key); +} +export const getWorkspaceServiceTokenData = async ( + req: Request, + res: Response +) => { + let serviceTokenData; + try { + const { workspaceId } = req.params; + + serviceTokenData = await ServiceTokenData + .find({ + workspace: workspaceId + }) + .select('+encryptedKey +iv +tag'); + + } catch (err) { + Sentry.setUser({ email: req.user.email }); + Sentry.captureException(err); + return res.status(400).send({ + message: 'Failed to get workspace service token data' + }); + } + + return res.status(200).send({ + serviceTokenData + }); +} + +/** + * Return memberships for workspace with id [workspaceId] + * @param req + * @param res + * @returns + */ +export const getWorkspaceMemberships = async (req: Request, res: Response) => { + /* + #swagger.summary = 'Return project memberships' + #swagger.description = 'Return project memberships' + + #swagger.security = [{ + "apiKeyAuth": [] + }] + + #swagger.parameters['workspaceId'] = { + "description": "ID of project", + "required": true, + "type": "string" + } + + #swagger.responses[200] = { + content: { + "application/json": { + "schema": { + "type": "object", + "properties": { + "memberships": { + "type": "array", + "items": { + $ref: "#/components/schemas/Membership" + }, + "description": "Memberships of project" + } + } + } + } + } + } + */ + let memberships; + try { + const { workspaceId } = req.params; + + memberships = await Membership.find({ + workspace: workspaceId + }).populate('user', '+publicKey'); + } catch (err) { + Sentry.setUser({ email: req.user.email }); + Sentry.captureException(err); + return res.status(400).send({ + message: 'Failed to get workspace memberships' + }); + } + + return res.status(200).send({ + memberships + }); +} + +/** + * Update role of membership with id [membershipId] to role [role] + * @param req + * @param res + * @returns + */ +export const updateWorkspaceMembership = async (req: Request, res: Response) => { + /* + #swagger.summary = 'Update project membership' + #swagger.description = 'Update project membership' + + #swagger.security = [{ + "apiKeyAuth": [] + }] + + #swagger.parameters['workspaceId'] = { + "description": "ID of project", + "required": true, + "type": "string" + } + + #swagger.parameters['membershipId'] = { + "description": "ID of project membership to update", + "required": true, + "type": "string" + } + + #swagger.requestBody = { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "role": { + "type": "string", + "description": "Role of membership - either admin or member", + } + } + } + } + } + } + + #swagger.responses[200] = { + content: { + "application/json": { + "schema": { + "type": "object", + "properties": { + "membership": { + $ref: "#/components/schemas/Membership", + "description": "Updated membership" + } + } + } + } + } + } + */ + let membership; + try { + const { + membershipId + } = req.params; + const { role } = req.body; + + membership = await Membership.findByIdAndUpdate( + membershipId, + { + role + }, { + new: true + } + ); + } catch (err) { + Sentry.setUser({ email: req.user.email }); + Sentry.captureException(err); + return res.status(400).send({ + message: 'Failed to update workspace membership' + }); + } + + return res.status(200).send({ + membership + }); +} + +/** + * Delete workspace membership with id [membershipId] + * @param req + * @param res + * @returns + */ +export const deleteWorkspaceMembership = async (req: Request, res: Response) => { + /* + #swagger.summary = 'Delete project membership' + #swagger.description = 'Delete project membership' + + #swagger.security = [{ + "apiKeyAuth": [] + }] + + #swagger.parameters['workspaceId'] = { + "description": "ID of project", + "required": true, + "type": "string" + } + + #swagger.parameters['membershipId'] = { + "description": "ID of project membership to delete", + "required": true, + "type": "string" + } + + #swagger.responses[200] = { + content: { + "application/json": { + "schema": { + "type": "object", + "properties": { + "membership": { + $ref: "#/components/schemas/Membership", + "description": "Deleted membership" + } + } + } + } + } + } + */ + let membership; + try { + const { + membershipId + } = req.params; + + membership = await Membership.findByIdAndDelete(membershipId); + + if (!membership) throw new Error('Failed to delete workspace membership'); + + await Key.deleteMany({ + receiver: membership.user, + workspace: membership.workspace + }); + } catch (err) { + Sentry.setUser({ email: req.user.email }); + Sentry.captureException(err); + return res.status(400).send({ + message: 'Failed to delete workspace membership' + }); + } + + return res.status(200).send({ + membership + }); +} \ No newline at end of file diff --git a/backend/src/ee/controllers/index.ts b/backend/src/ee/controllers/index.ts deleted file mode 100644 index e4fb89a8e..000000000 --- a/backend/src/ee/controllers/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -import * as stripeController from './stripeController'; - -export { - stripeController -} \ No newline at end of file diff --git a/backend/src/ee/controllers/v1/actionController.ts b/backend/src/ee/controllers/v1/actionController.ts new file mode 100644 index 000000000..b136b0fa4 --- /dev/null +++ b/backend/src/ee/controllers/v1/actionController.ts @@ -0,0 +1,31 @@ +import { Request, Response } from 'express'; +import * as Sentry from '@sentry/node'; +import { Action, SecretVersion } from '../../models'; +import { ActionNotFoundError } from '../../../utils/errors'; + +export const getAction = async (req: Request, res: Response) => { + let action; + try { + const { actionId } = req.params; + + action = await Action + .findById(actionId) + .populate([ + 'payload.secretVersions.oldSecretVersion', + 'payload.secretVersions.newSecretVersion' + ]); + + if (!action) throw ActionNotFoundError({ + message: 'Failed to find action' + }); + + } catch (err) { + throw ActionNotFoundError({ + message: 'Failed to find action' + }); + } + + return res.status(200).send({ + action + }); +} \ No newline at end of file diff --git a/backend/src/ee/controllers/v1/index.ts b/backend/src/ee/controllers/v1/index.ts new file mode 100644 index 000000000..aaa697286 --- /dev/null +++ b/backend/src/ee/controllers/v1/index.ts @@ -0,0 +1,15 @@ +import * as stripeController from './stripeController'; +import * as secretController from './secretController'; +import * as secretSnapshotController from './secretSnapshotController'; +import * as workspaceController from './workspaceController'; +import * as actionController from './actionController'; +import * as membershipController from './membershipController'; + +export { + stripeController, + secretController, + secretSnapshotController, + workspaceController, + actionController, + membershipController +} \ No newline at end of file diff --git a/backend/src/ee/controllers/v1/membershipController.ts b/backend/src/ee/controllers/v1/membershipController.ts new file mode 100644 index 000000000..fcf158ba8 --- /dev/null +++ b/backend/src/ee/controllers/v1/membershipController.ts @@ -0,0 +1,63 @@ +import { Request, Response } from "express"; +import { Membership, Workspace } from "../../../models"; +import { IMembershipPermission } from "../../../models/membership"; +import { BadRequestError, UnauthorizedRequestError } from "../../../utils/errors"; +import { ABILITY_READ, ABILITY_WRITE, ADMIN, MEMBER } from "../../../variables/organization"; +import { Builder } from "builder-pattern" +import _ from "lodash"; + +export const denyMembershipPermissions = async (req: Request, res: Response) => { + const { membershipId } = req.params; + const { permissions } = req.body; + const sanitizedMembershipPermissions: IMembershipPermission[] = permissions.map((permission: IMembershipPermission) => { + if (!permission.ability || !permission.environmentSlug || ![ABILITY_READ, ABILITY_WRITE].includes(permission.ability)) { + throw BadRequestError({ message: "One or more required fields are missing from the request or have incorrect type" }) + } + + return Builder() + .environmentSlug(permission.environmentSlug) + .ability(permission.ability) + .build(); + }) + + const sanitizedMembershipPermissionsUnique = _.uniqWith(sanitizedMembershipPermissions, _.isEqual) + + const membershipToModify = await Membership.findById(membershipId) + if (!membershipToModify) { + throw BadRequestError({ message: "Unable to locate resource" }) + } + + // check if the user making the request is a admin of this project + if (![ADMIN, MEMBER].includes(membershipToModify.role)) { + throw UnauthorizedRequestError() + } + + // check if the requested slugs are indeed a part of this related workspace + const relatedWorkspace = await Workspace.findById(membershipToModify.workspace) + if (!relatedWorkspace) { + throw BadRequestError({ message: "Something went wrong when locating the related workspace" }) + } + + const uniqueEnvironmentSlugs = new Set(_.uniq(_.map(relatedWorkspace.environments, 'slug'))); + + sanitizedMembershipPermissionsUnique.forEach(permission => { + if (!uniqueEnvironmentSlugs.has(permission.environmentSlug)) { + throw BadRequestError({ message: "Unknown environment slug reference" }) + } + }) + + // update the permissions + const updatedMembershipWithPermissions = await Membership.findByIdAndUpdate( + { _id: membershipToModify._id }, + { $set: { deniedPermissions: sanitizedMembershipPermissionsUnique } }, + { new: true } + ) + + if (!updatedMembershipWithPermissions) { + throw BadRequestError({ message: "The resource has been removed before it can be modified" }) + } + + res.send({ + permissionsDenied: updatedMembershipWithPermissions.deniedPermissions + }) +} diff --git a/backend/src/ee/controllers/v1/secretController.ts b/backend/src/ee/controllers/v1/secretController.ts new file mode 100644 index 000000000..562c8aa88 --- /dev/null +++ b/backend/src/ee/controllers/v1/secretController.ts @@ -0,0 +1,230 @@ +import { Request, Response } from 'express'; +import * as Sentry from '@sentry/node'; +import { Secret } from '../../../models'; +import { SecretVersion } from '../../models'; +import { EESecretService } from '../../services'; + +/** + * Return secret versions for secret with id [secretId] + * @param req + * @param res + */ + export const getSecretVersions = async (req: Request, res: Response) => { + /* + #swagger.summary = 'Return secret versions' + #swagger.description = 'Return secret versions' + + #swagger.security = [{ + "apiKeyAuth": [] + }] + + #swagger.parameters['secretId'] = { + "description": "ID of secret", + "required": true, + "type": "string" + } + + #swagger.parameters['offset'] = { + "description": "Number of versions to skip", + "required": false, + "type": "string" + } + + #swagger.parameters['limit'] = { + "description": "Maximum number of versions to return", + "required": false, + "type": "string" + } + + #swagger.responses[200] = { + content: { + "application/json": { + schema: { + "type": "object", + "properties": { + "secretVersions": { + "type": "array", + "items": { + $ref: "#/components/schemas/SecretVersion" + }, + "description": "Secret versions" + } + } + } + } + } + } + */ + let secretVersions; + try { + const { secretId } = req.params; + + const offset: number = parseInt(req.query.offset as string); + const limit: number = parseInt(req.query.limit as string); + + secretVersions = await SecretVersion.find({ + secret: secretId + }) + .sort({ createdAt: -1 }) + .skip(offset) + .limit(limit); + + } catch (err) { + Sentry.setUser({ email: req.user.email }); + Sentry.captureException(err); + return res.status(400).send({ + message: 'Failed to get secret versions' + }); + } + + return res.status(200).send({ + secretVersions + }); +} + +/** + * Roll back secret with id [secretId] to version [version] + * @param req + * @param res + * @returns + */ +export const rollbackSecretVersion = async (req: Request, res: Response) => { + /* + #swagger.summary = 'Roll back secret to a version.' + #swagger.description = 'Roll back secret to a version.' + + #swagger.security = [{ + "apiKeyAuth": [] + }] + + #swagger.parameters['secretId'] = { + "description": "ID of secret", + "required": true, + "type": "string" + } + + #swagger.requestBody = { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "version": { + "type": "integer", + "description": "Version of secret to roll back to" + } + } + } + } + } + } + + #swagger.responses[200] = { + content: { + "application/json": { + schema: { + "type": "object", + "properties": { + "secret": { + "type": "object", + $ref: "#/components/schemas/Secret", + "description": "Secret rolled back to" + } + } + } + } + } + } + */ + let secret; + try { + const { secretId } = req.params; + const { version } = req.body; + + // validate secret version + const oldSecretVersion = await SecretVersion.findOne({ + secret: secretId, + version + }); + + if (!oldSecretVersion) throw new Error('Failed to find secret version'); + + const { + workspace, + type, + user, + environment, + secretKeyCiphertext, + secretKeyIV, + secretKeyTag, + secretKeyHash, + secretValueCiphertext, + secretValueIV, + secretValueTag, + secretValueHash + } = oldSecretVersion; + + // update secret + secret = await Secret.findByIdAndUpdate( + secretId, + { + $inc: { + version: 1 + }, + workspace, + type, + user, + environment, + secretKeyCiphertext, + secretKeyIV, + secretKeyTag, + secretKeyHash, + secretValueCiphertext, + secretValueIV, + secretValueTag, + secretValueHash + }, + { + new: true + } + ); + + if (!secret) throw new Error('Failed to find and update secret'); + + // add new secret version + await new SecretVersion({ + secret: secretId, + version: secret.version, + workspace, + type, + user, + environment, + isDeleted: false, + secretKeyCiphertext, + secretKeyIV, + secretKeyTag, + secretKeyHash, + secretValueCiphertext, + secretValueIV, + secretValueTag, + secretValueHash + }).save(); + + // take secret snapshot + await EESecretService.takeSecretSnapshot({ + workspaceId: secret.workspace.toString() + }); + + } catch (err) { + Sentry.setUser({ email: req.user.email }); + Sentry.captureException(err); + return res.status(400).send({ + message: 'Failed to roll back secret version' + }); + } + + return res.status(200).send({ + secret + }); +} \ No newline at end of file diff --git a/backend/src/ee/controllers/v1/secretSnapshotController.ts b/backend/src/ee/controllers/v1/secretSnapshotController.ts new file mode 100644 index 000000000..6e8605c2f --- /dev/null +++ b/backend/src/ee/controllers/v1/secretSnapshotController.ts @@ -0,0 +1,33 @@ +import { Request, Response } from 'express'; +import * as Sentry from '@sentry/node'; +import { SecretSnapshot } from '../../models'; + +/** + * Return secret snapshot with id [secretSnapshotId] + * @param req + * @param res + * @returns + */ +export const getSecretSnapshot = async (req: Request, res: Response) => { + let secretSnapshot; + try { + const { secretSnapshotId } = req.params; + + secretSnapshot = await SecretSnapshot + .findById(secretSnapshotId) + .populate('secretVersions'); + + if (!secretSnapshot) throw new Error('Failed to find secret snapshot'); + + } catch (err) { + Sentry.setUser({ email: req.user.email }); + Sentry.captureException(err); + return res.status(400).send({ + message: 'Failed to get secret snapshot' + }); + } + + return res.status(200).send({ + secretSnapshot + }); +} \ No newline at end of file diff --git a/backend/src/controllers/stripeController.ts b/backend/src/ee/controllers/v1/stripeController.ts similarity index 91% rename from backend/src/controllers/stripeController.ts rename to backend/src/ee/controllers/v1/stripeController.ts index 99a85ee2b..faef14cea 100644 --- a/backend/src/controllers/stripeController.ts +++ b/backend/src/ee/controllers/v1/stripeController.ts @@ -1,7 +1,7 @@ import { Request, Response } from 'express'; import * as Sentry from '@sentry/node'; import Stripe from 'stripe'; -import { STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET } from '../config'; +import { STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET } from '../../../config'; const stripe = new Stripe(STRIPE_SECRET_KEY, { apiVersion: '2022-08-01' }); diff --git a/backend/src/ee/controllers/v1/workspaceController.ts b/backend/src/ee/controllers/v1/workspaceController.ts new file mode 100644 index 000000000..ea9bb7dab --- /dev/null +++ b/backend/src/ee/controllers/v1/workspaceController.ts @@ -0,0 +1,434 @@ +import { Request, Response } from 'express'; +import * as Sentry from '@sentry/node'; +import { Types } from 'mongoose'; +import { + Secret +} from '../../../models'; +import { + SecretSnapshot, + Log, + SecretVersion, + ISecretVersion +} from '../../models'; +import { EESecretService } from '../../services'; +import { getLatestSecretVersionIds } from '../../helpers/secretVersion'; + +/** + * Return secret snapshots for workspace with id [workspaceId] + * @param req + * @param res + */ + export const getWorkspaceSecretSnapshots = async (req: Request, res: Response) => { + /* + #swagger.summary = 'Return project secret snapshot ids' + #swagger.description = 'Return project secret snapshots ids' + + #swagger.security = [{ + "apiKeyAuth": [] + }] + + #swagger.parameters['workspaceId'] = { + "description": "ID of project", + "required": true, + "type": "string" + } + + #swagger.parameters['offset'] = { + "description": "Number of secret snapshots to skip", + "required": false, + "type": "string" + } + + #swagger.parameters['limit'] = { + "description": "Maximum number of secret snapshots to return", + "required": false, + "type": "string" + } + + #swagger.responses[200] = { + content: { + "application/json": { + schema: { + "type": "object", + "properties": { + "secretSnapshots": { + "type": "array", + "items": { + $ref: "#/components/schemas/SecretSnapshot" + }, + "description": "Project secret snapshots" + } + } + } + } + } + } + */ + let secretSnapshots; + try { + const { workspaceId } = req.params; + + const offset: number = parseInt(req.query.offset as string); + const limit: number = parseInt(req.query.limit as string); + + secretSnapshots = await SecretSnapshot.find({ + workspace: workspaceId + }) + .sort({ createdAt: -1 }) + .skip(offset) + .limit(limit); + + } catch (err) { + Sentry.setUser({ email: req.user.email }); + Sentry.captureException(err); + return res.status(400).send({ + message: 'Failed to get secret snapshots' + }); + } + + return res.status(200).send({ + secretSnapshots + }); +} + +/** + * Return count of secret snapshots for workspace with id [workspaceId] + * @param req + * @param res + */ +export const getWorkspaceSecretSnapshotsCount = async (req: Request, res: Response) => { + let count; + try { + const { workspaceId } = req.params; + count = await SecretSnapshot.countDocuments({ + workspace: workspaceId + }); + } catch (err) { + Sentry.setUser({ email: req.user.email }); + Sentry.captureException(err); + return res.status(400).send({ + message: 'Failed to count number of secret snapshots' + }); + } + + return res.status(200).send({ + count + }); +} + +/** + * Rollback secret snapshot with id [secretSnapshotId] to version [version] + * @param req + * @param res + * @returns + */ +export const rollbackWorkspaceSecretSnapshot = async (req: Request, res: Response) => { + /* + #swagger.summary = 'Roll back project secrets to those captured in a secret snapshot version.' + #swagger.description = 'Roll back project secrets to those captured in a secret snapshot version.' + + #swagger.security = [{ + "apiKeyAuth": [] + }] + + #swagger.parameters['workspaceId'] = { + "description": "ID of project", + "required": true, + "type": "string" + } + + #swagger.requestBody = { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "version": { + "type": "integer", + "description": "Version of secret snapshot to roll back to", + } + } + } + } + } + } + + #swagger.responses[200] = { + content: { + "application/json": { + schema: { + "type": "object", + "properties": { + "secrets": { + "type": "array", + "items": { + $ref: "#/components/schemas/Secret" + }, + "description": "Secrets rolled back to" + } + } + } + } + } + } + */ + let secrets; + try { + const { workspaceId } = req.params; + const { version } = req.body; + + // validate secret snapshot + const secretSnapshot = await SecretSnapshot.findOne({ + workspace: workspaceId, + version + }).populate<{ secretVersions: ISecretVersion[]}>('secretVersions'); + + if (!secretSnapshot) throw new Error('Failed to find secret snapshot'); + + // TODO: fix any + const oldSecretVersionsObj: any = secretSnapshot.secretVersions + .reduce((accumulator, s) => ({ + ...accumulator, + [`${s.secret.toString()}`]: s + }), {}); + + const latestSecretVersionIds = await getLatestSecretVersionIds({ + secretIds: secretSnapshot.secretVersions.map((sv) => sv.secret) + }); + + // TODO: fix any + const latestSecretVersions: any = (await SecretVersion.find({ + _id: { + $in: latestSecretVersionIds.map((s) => s.versionId) + } + }, 'secret version')) + .reduce((accumulator, s) => ({ + ...accumulator, + [`${s.secret.toString()}`]: s + }), {}); + + // delete existing secrets + await Secret.deleteMany({ + workspace: workspaceId + }); + + // add secrets + secrets = await Secret.insertMany( + secretSnapshot.secretVersions.map((sv) => { + const secretId = sv.secret; + const { + workspace, + type, + user, + environment, + secretKeyCiphertext, + secretKeyIV, + secretKeyTag, + secretKeyHash, + secretValueCiphertext, + secretValueIV, + secretValueTag, + secretValueHash, + createdAt + } = oldSecretVersionsObj[secretId.toString()]; + + return ({ + _id: secretId, + version: latestSecretVersions[secretId.toString()].version + 1, + workspace, + type, + user, + environment, + secretKeyCiphertext, + secretKeyIV, + secretKeyTag, + secretKeyHash, + secretValueCiphertext, + secretValueIV, + secretValueTag, + secretValueHash, + secretCommentCiphertext: '', + secretCommentIV: '', + secretCommentTag: '', + createdAt + }); + }) + ); + + // add secret versions + await SecretVersion.insertMany( + secrets.map(({ + _id, + version, + workspace, + type, + user, + environment, + secretKeyCiphertext, + secretKeyIV, + secretKeyTag, + secretKeyHash, + secretValueCiphertext, + secretValueIV, + secretValueTag, + secretValueHash + }) => ({ + _id: new Types.ObjectId(), + secret: _id, + version, + workspace, + type, + user, + environment, + isDeleted: false, + secretKeyCiphertext, + secretKeyIV, + secretKeyTag, + secretKeyHash, + secretValueCiphertext, + secretValueIV, + secretValueTag, + secretValueHash + })) + ); + + // update secret versions of restored secrets as not deleted + await SecretVersion.updateMany({ + secret: { + $in: secretSnapshot.secretVersions.map((sv) => sv.secret) + } + }, { + isDeleted: false + }); + + // take secret snapshot + await EESecretService.takeSecretSnapshot({ + workspaceId + }); + } catch (err) { + Sentry.setUser({ email: req.user.email }); + Sentry.captureException(err); + return res.status(400).send({ + message: 'Failed to roll back secret snapshot' + }); + } + + return res.status(200).send({ + secrets + }); +} + +/** + * Return (audit) logs for workspace with id [workspaceId] + * @param req + * @param res + * @returns + */ +export const getWorkspaceLogs = async (req: Request, res: Response) => { + /* + #swagger.summary = 'Return project (audit) logs' + #swagger.description = 'Return project (audit) logs' + + #swagger.security = [{ + "apiKeyAuth": [] + }] + + #swagger.parameters['workspaceId'] = { + "description": "ID of project", + "required": true, + "type": "string" + } + + #swagger.parameters['userId'] = { + "description": "ID of project member", + "required": false, + "type": "string" + } + + #swagger.parameters['offset'] = { + "description": "Number of logs to skip", + "required": false, + "type": "string" + } + + #swagger.parameters['limit'] = { + "description": "Maximum number of logs to return", + "required": false, + "type": "string" + } + + #swagger.parameters['sortBy'] = { + "description": "Order to sort the logs by", + "schema": { + "type": "string", + "@enum": ["oldest", "recent"] + }, + "required": false + } + + #swagger.parameters['actionNames'] = { + "description": "Names of log actions (comma-separated)", + "required": false, + "type": "string" + } + + #swagger.responses[200] = { + content: { + "application/json": { + schema: { + "type": "object", + "properties": { + "logs": { + "type": "array", + "items": { + $ref: "#/components/schemas/Log" + }, + "description": "Project logs" + } + } + } + } + } + } + */ + let logs + try { + const { workspaceId } = req.params; + + const offset: number = parseInt(req.query.offset as string); + const limit: number = parseInt(req.query.limit as string); + const sortBy: string = req.query.sortBy as string; + const userId: string = req.query.userId as string; + const actionNames: string = req.query.actionNames as string; + + logs = await Log.find({ + workspace: workspaceId, + ...( userId ? { user: userId } : {}), + ...( + actionNames + ? { + actionNames: { + $in: actionNames.split(',') + } + } : {} + ) + }) + .sort({ createdAt: sortBy === 'recent' ? -1 : 1 }) + .skip(offset) + .limit(limit) + .populate('actions') + .populate('user'); + + } catch (err) { + Sentry.setUser({ email: req.user.email }); + Sentry.captureException(err); + return res.status(400).send({ + message: 'Failed to get workspace logs' + }); + } + + return res.status(200).send({ + logs + }); +} \ No newline at end of file diff --git a/backend/src/ee/helpers/action.ts b/backend/src/ee/helpers/action.ts new file mode 100644 index 000000000..389cfedbf --- /dev/null +++ b/backend/src/ee/helpers/action.ts @@ -0,0 +1,73 @@ +import * as Sentry from '@sentry/node'; +import { Types } from 'mongoose'; +import { SecretVersion, Action } from '../models'; +import { + getLatestSecretVersionIds, + getLatestNSecretSecretVersionIds +} from '../helpers/secretVersion'; +import { ACTION_UPDATE_SECRETS } from '../../variables'; + +/** + * Create an (audit) action for secrets including + * add, delete, update, and read actions. + * @param {Object} obj + * @param {String} obj.name - name of action + * @param {ObjectId[]} obj.secretIds - ids of relevant secrets + * @returns {Action} action - new action + */ +const createActionSecretHelper = async ({ + name, + userId, + workspaceId, + secretIds +}: { + name: string; + userId: string; + workspaceId: string; + secretIds: Types.ObjectId[]; +}) => { + + let action; + let latestSecretVersions; + try { + if (name === ACTION_UPDATE_SECRETS) { + // case: action is updating secrets + // -> add old and new secret versions + latestSecretVersions = (await getLatestNSecretSecretVersionIds({ + secretIds, + n: 2 + })) + .map((s) => ({ + oldSecretVersion: s.versions[0]._id, + newSecretVersion: s.versions[1]._id + })); + } else { + // case: action is adding, deleting, or reading secrets + // -> add new secret versions + latestSecretVersions = (await getLatestSecretVersionIds({ + secretIds + })) + .map((s) => ({ + newSecretVersion: s.versionId + })); + } + + action = await new Action({ + name, + user: userId, + workspace: workspaceId, + payload: { + secretVersions: latestSecretVersions + } + }).save(); + + } catch (err) { + Sentry.setUser(null); + Sentry.captureException(err); + throw new Error('Failed to create action'); + } + + return action; +} + +export { createActionSecretHelper }; \ No newline at end of file diff --git a/backend/src/ee/helpers/checkMembershipPermissions.ts b/backend/src/ee/helpers/checkMembershipPermissions.ts new file mode 100644 index 000000000..55155e885 --- /dev/null +++ b/backend/src/ee/helpers/checkMembershipPermissions.ts @@ -0,0 +1,18 @@ +import _ from "lodash"; +import { Membership } from "../../models"; + +export const userHasWorkspaceAccess = async (userId: any, workspaceId: any, environment: any, action: any) => { + const membershipForWorkspace = await Membership.findOne({ workspace: workspaceId, user: userId }) + if (!membershipForWorkspace) { + return false + } + + const deniedMembershipPermissions = membershipForWorkspace.deniedPermissions; + const isDisallowed = _.some(deniedMembershipPermissions, { environmentSlug: environment, ability: action }); + + if (isDisallowed) { + return false + } + + return true +} \ No newline at end of file diff --git a/backend/src/ee/helpers/license.ts b/backend/src/ee/helpers/license.ts deleted file mode 100644 index 256bdc23a..000000000 --- a/backend/src/ee/helpers/license.ts +++ /dev/null @@ -1,21 +0,0 @@ - -/** - * @param {Object} obj - * @param {Object} obj.licenseKey - Infisical license key - */ -const checkLicenseKey = ({ - licenseKey -}: { - licenseKey: string -}) => { - try { - // TODO - - } catch (err) { - - } -} - -export { - checkLicenseKey -} \ No newline at end of file diff --git a/backend/src/ee/helpers/log.ts b/backend/src/ee/helpers/log.ts new file mode 100644 index 000000000..c357c9818 --- /dev/null +++ b/backend/src/ee/helpers/log.ts @@ -0,0 +1,41 @@ +import * as Sentry from '@sentry/node'; +import { + Log, + IAction +} from '../models'; + +const createLogHelper = async ({ + userId, + workspaceId, + actions, + channel, + ipAddress +}: { + userId: string; + workspaceId: string; + actions: IAction[]; + channel: string; + ipAddress: string; +}) => { + let log; + try { + log = await new Log({ + user: userId, + workspace: workspaceId, + actionNames: actions.map((a) => a.name), + actions, + channel, + ipAddress + }).save(); + } catch (err) { + Sentry.setUser(null); + Sentry.captureException(err); + throw new Error('Failed to create log'); + } + + return log; +} + +export { + createLogHelper +} \ No newline at end of file diff --git a/backend/src/ee/helpers/secret.ts b/backend/src/ee/helpers/secret.ts new file mode 100644 index 000000000..7edee915f --- /dev/null +++ b/backend/src/ee/helpers/secret.ts @@ -0,0 +1,169 @@ +import { Types } from 'mongoose'; +import * as Sentry from '@sentry/node'; +import { + Secret, + ISecret +} from '../../models'; +import { + SecretSnapshot, + SecretVersion, + ISecretVersion +} from '../models'; + +/** + * Save a secret snapshot that is a copy of the current state of secrets in workspace with id + * [workspaceId] under a new snapshot with incremented version under the + * secretsnapshots collection. + * @param {Object} obj + * @param {String} obj.workspaceId + * @returns {SecretSnapshot} secretSnapshot - new secret snapshot + */ +const takeSecretSnapshotHelper = async ({ + workspaceId +}: { + workspaceId: string; +}) => { + + let secretSnapshot; + try { + const secretIds = (await Secret.find({ + workspace: workspaceId + }, '_id')).map((s) => s._id); + + const latestSecretVersions = (await SecretVersion.aggregate([ + { + $match: { + secret: { + $in: secretIds + } + } + }, + { + $group: { + _id: '$secret', + version: { $max: '$version' }, + versionId: { $max: '$_id' } // secret version id + } + }, + { + $sort: { version: -1 } + } + ]) + .exec()) + .map((s) => s.versionId); + + const latestSecretSnapshot = await SecretSnapshot.findOne({ + workspace: workspaceId + }).sort({ version: -1 }); + + secretSnapshot = await new SecretSnapshot({ + workspace: workspaceId, + version: latestSecretSnapshot ? latestSecretSnapshot.version + 1 : 1, + secretVersions: latestSecretVersions + }).save(); + } catch (err) { + Sentry.setUser(null); + Sentry.captureException(err); + throw new Error('Failed to take a secret snapshot'); + } + + return secretSnapshot; +} + +/** + * Add secret versions [secretVersions] to the SecretVersion collection. + * @param {Object} obj + * @param {Object[]} obj.secretVersions + * @returns {SecretVersion[]} newSecretVersions - new secret versions + */ +const addSecretVersionsHelper = async ({ + secretVersions +}: { + secretVersions: ISecretVersion[] +}) => { + let newSecretVersions; + try { + newSecretVersions = await SecretVersion.insertMany(secretVersions); + } catch (err) { + Sentry.setUser(null); + Sentry.captureException(err); + throw new Error(`Failed to add secret versions [err=${err}]`); + } + + return newSecretVersions; +} + +const markDeletedSecretVersionsHelper = async ({ + secretIds +}: { + secretIds: Types.ObjectId[]; +}) => { + try { + await SecretVersion.updateMany({ + secret: { $in: secretIds } + }, { + isDeleted: true + }, { + new: true + }); + } catch (err) { + Sentry.setUser(null); + Sentry.captureException(err); + throw new Error('Failed to mark secret versions as deleted'); + } +} + +/** + * Initialize secret versioning by setting previously unversioned + * secrets to version 1 and begin populating secret versions. + */ +const initSecretVersioningHelper = async () => { + try { + + await Secret.updateMany( + { version: { $exists: false } }, + { $set: { version: 1 } } + ); + + const unversionedSecrets: ISecret[] = await Secret.aggregate([ + { + $lookup: { + from: 'secretversions', + localField: '_id', + foreignField: 'secret', + as: 'versions', + }, + }, + { + $match: { + versions: { $size: 0 }, + }, + }, + ]); + + if (unversionedSecrets.length > 0) { + await addSecretVersionsHelper({ + secretVersions: unversionedSecrets.map((s, idx) => ({ + ...s, + secret: s._id, + version: s.version ? s.version : 1, + isDeleted: false, + workspace: s.workspace, + environment: s.environment + })) + }); + } + + } catch (err) { + Sentry.setUser(null); + Sentry.captureException(err); + throw new Error('Failed to ensure that secrets are versioned'); + } +} + +export { + takeSecretSnapshotHelper, + addSecretVersionsHelper, + markDeletedSecretVersionsHelper, + initSecretVersioningHelper +} \ No newline at end of file diff --git a/backend/src/ee/helpers/secretVersion.ts b/backend/src/ee/helpers/secretVersion.ts new file mode 100644 index 000000000..d5859e183 --- /dev/null +++ b/backend/src/ee/helpers/secretVersion.ts @@ -0,0 +1,110 @@ +import * as Sentry from '@sentry/node'; +import { Types } from 'mongoose'; +import { SecretVersion } from '../models'; + +/** + * Return latest secret versions for secrets with ids [secretIds] + * @param {Object} obj + * @param {Object} obj.secretIds = ids of secrets to get latest versions for + * @returns + */ +const getLatestSecretVersionIds = async ({ + secretIds +}: { + secretIds: Types.ObjectId[]; +}) => { + + interface LatestSecretVersionId { + _id: Types.ObjectId; + version: number; + versionId: Types.ObjectId; + } + + let latestSecretVersionIds: LatestSecretVersionId[]; + try { + latestSecretVersionIds = (await SecretVersion.aggregate([ + { + $match: { + secret: { + $in: secretIds + } + } + }, + { + $group: { + _id: '$secret', + version: { $max: '$version' }, + versionId: { $max: '$_id' } // id of latest secret version + } + }, + { + $sort: { version: -1 } + } + ]) + .exec()); + + } catch (err) { + Sentry.setUser(null); + Sentry.captureException(err); + throw new Error('Failed to get latest secret versions'); + } + + return latestSecretVersionIds; +} + +/** + * Return latest [n] secret versions for secrets with ids [secretIds] + * @param {Object} obj + * @param {Object} obj.secretIds = ids of secrets to get latest versions for + * @param {Number} obj.n - number of latest secret versions to return for each secret + * @returns + */ +const getLatestNSecretSecretVersionIds = async ({ + secretIds, + n +}: { + secretIds: Types.ObjectId[]; + n: number; +}) => { + + // TODO: optimize query + let latestNSecretVersions; + try { + latestNSecretVersions = (await SecretVersion.aggregate([ + { + $match: { + secret: { + $in: secretIds, + }, + }, + }, + { + $sort: { version: -1 }, + }, + { + $group: { + _id: "$secret", + versions: { $push: "$$ROOT" }, + }, + }, + { + $project: { + _id: 0, + secret: "$_id", + versions: { $slice: ["$versions", n] }, + }, + } + ])); + } catch (err) { + Sentry.setUser(null); + Sentry.captureException(err); + throw new Error('Failed to get latest n secret versions'); + } + + return latestNSecretVersions; +} + +export { + getLatestSecretVersionIds, + getLatestNSecretSecretVersionIds +} diff --git a/backend/src/ee/middleware/index.ts b/backend/src/ee/middleware/index.ts new file mode 100644 index 000000000..ff9267965 --- /dev/null +++ b/backend/src/ee/middleware/index.ts @@ -0,0 +1,7 @@ +import requireLicenseAuth from './requireLicenseAuth'; +import requireSecretSnapshotAuth from './requireSecretSnapshotAuth'; + +export { + requireLicenseAuth, + requireSecretSnapshotAuth +} \ No newline at end of file diff --git a/backend/src/ee/middleware/requireSecretSnapshotAuth.ts b/backend/src/ee/middleware/requireSecretSnapshotAuth.ts new file mode 100644 index 000000000..5eae3721c --- /dev/null +++ b/backend/src/ee/middleware/requireSecretSnapshotAuth.ts @@ -0,0 +1,47 @@ +import { Request, Response, NextFunction } from 'express'; +import { UnauthorizedRequestError, SecretSnapshotNotFoundError } from '../../utils/errors'; +import { SecretSnapshot } from '../models'; +import { + validateMembership +} from '../../helpers/membership'; + +/** + * Validate if user on request has proper membership for secret snapshot + * @param {Object} obj + * @param {String[]} obj.acceptedRoles - accepted workspace roles + * @param {String[]} obj.acceptedStatuses - accepted workspace statuses + * @param {String[]} obj.location - location of [workspaceId] on request (e.g. params, body) for parsing + */ +const requireSecretSnapshotAuth = ({ + acceptedRoles, +}: { + acceptedRoles: string[]; +}) => { + return async (req: Request, res: Response, next: NextFunction) => { + try { + const { secretSnapshotId } = req.params; + + const secretSnapshot = await SecretSnapshot.findById(secretSnapshotId); + + if (!secretSnapshot) { + return next(SecretSnapshotNotFoundError({ + message: 'Failed to find secret snapshot' + })); + } + + await validateMembership({ + userId: req.user._id.toString(), + workspaceId: secretSnapshot.workspace.toString(), + acceptedRoles + }); + + req.secretSnapshot = secretSnapshot as any; + + next(); + } catch (err) { + return next(UnauthorizedRequestError({ message: 'Unable to authenticate secret snapshot' })); + } + } +} + +export default requireSecretSnapshotAuth; \ No newline at end of file diff --git a/backend/src/ee/models/action.ts b/backend/src/ee/models/action.ts new file mode 100644 index 000000000..3d48aa04d --- /dev/null +++ b/backend/src/ee/models/action.ts @@ -0,0 +1,46 @@ +import { Schema, model, Types } from 'mongoose'; + +export interface IAction { + name: string; + user?: Types.ObjectId, + workspace?: Types.ObjectId, + payload: { + secretVersions?: Types.ObjectId[] + } +} + +const actionSchema = new Schema( + { + name: { + type: String, + required: true + }, + user: { + type: Schema.Types.ObjectId, + ref: 'User', + required: true + }, + workspace: { + type: Schema.Types.ObjectId, + ref: 'Workspace' + }, + payload: { + secretVersions: [{ + oldSecretVersion: { + type: Schema.Types.ObjectId, + ref: 'SecretVersion' + }, + newSecretVersion: { + type: Schema.Types.ObjectId, + ref: 'SecretVersion' + } + }] + } + }, { + timestamps: true + } +); + +const Action = model('Action', actionSchema); + +export default Action; \ No newline at end of file diff --git a/backend/src/ee/models/index.ts b/backend/src/ee/models/index.ts new file mode 100644 index 000000000..a6cee725e --- /dev/null +++ b/backend/src/ee/models/index.ts @@ -0,0 +1,15 @@ +import SecretSnapshot, { ISecretSnapshot } from './secretSnapshot'; +import SecretVersion, { ISecretVersion } from './secretVersion'; +import Log, { ILog } from './log'; +import Action, { IAction } from './action'; + +export { + SecretSnapshot, + ISecretSnapshot, + SecretVersion, + ISecretVersion, + Log, + ILog, + Action, + IAction +} \ No newline at end of file diff --git a/backend/src/ee/models/log.ts b/backend/src/ee/models/log.ts new file mode 100644 index 000000000..b9eadc016 --- /dev/null +++ b/backend/src/ee/models/log.ts @@ -0,0 +1,59 @@ +import { Schema, model, Types } from 'mongoose'; +import { + ACTION_ADD_SECRETS, + ACTION_UPDATE_SECRETS, + ACTION_READ_SECRETS, + ACTION_DELETE_SECRETS +} from '../../variables'; + +export interface ILog { + _id: Types.ObjectId; + user?: Types.ObjectId; + workspace?: Types.ObjectId; + actionNames: string[]; + actions: Types.ObjectId[]; + channel: string; + ipAddress?: string; +} + +const logSchema = new Schema( + { + user: { + type: Schema.Types.ObjectId, + ref: 'User' + }, + workspace: { + type: Schema.Types.ObjectId, + ref: 'Workspace' + }, + actionNames: { + type: [String], + enum: [ + ACTION_ADD_SECRETS, + ACTION_UPDATE_SECRETS, + ACTION_READ_SECRETS, + ACTION_DELETE_SECRETS + ], + required: true + }, + actions: [{ + type: Schema.Types.ObjectId, + ref: 'Action', + required: true + }], + channel: { + type: String, + enum: ['web', 'cli', 'auto', 'k8-operator', 'other'], + required: true + }, + ipAddress: { + type: String + } + }, { + timestamps: true +} +); + +const Log = model('Log', logSchema); + +export default Log; \ No newline at end of file diff --git a/backend/src/ee/models/secretSnapshot.ts b/backend/src/ee/models/secretSnapshot.ts new file mode 100644 index 000000000..c646f353a --- /dev/null +++ b/backend/src/ee/models/secretSnapshot.ts @@ -0,0 +1,33 @@ +import { Schema, model, Types } from 'mongoose'; + +export interface ISecretSnapshot { + workspace: Types.ObjectId; + version: number; + secretVersions: Types.ObjectId[]; +} + +const secretSnapshotSchema = new Schema( + { + workspace: { + type: Schema.Types.ObjectId, + ref: 'Workspace', + required: true + }, + version: { + type: Number, + required: true + }, + secretVersions: [{ + type: Schema.Types.ObjectId, + ref: 'SecretVersion', + required: true + }] + }, + { + timestamps: true + } +); + +const SecretSnapshot = model('SecretSnapshot', secretSnapshotSchema); + +export default SecretSnapshot; \ No newline at end of file diff --git a/backend/src/ee/models/secretVersion.ts b/backend/src/ee/models/secretVersion.ts new file mode 100644 index 000000000..1af4aff2c --- /dev/null +++ b/backend/src/ee/models/secretVersion.ts @@ -0,0 +1,100 @@ +import { Schema, model, Types } from 'mongoose'; +import { + SECRET_SHARED, + SECRET_PERSONAL, +} from '../../variables'; + +export interface ISecretVersion { + _id: Types.ObjectId; + secret: Types.ObjectId; + version: number; + workspace: Types.ObjectId; // new + type: string; // new + user: Types.ObjectId; // new + environment: string; // new + isDeleted: boolean; + secretKeyCiphertext: string; + secretKeyIV: string; + secretKeyTag: string; + secretKeyHash: string; + secretValueCiphertext: string; + secretValueIV: string; + secretValueTag: string; + secretValueHash: string; +} + +const secretVersionSchema = new Schema( + { + secret: { // could be deleted + type: Schema.Types.ObjectId, + ref: 'Secret', + required: true + }, + version: { + type: Number, + default: 1, + required: true + }, + workspace: { + type: Schema.Types.ObjectId, + ref: 'Workspace', + required: true + }, + type: { + type: String, + enum: [SECRET_SHARED, SECRET_PERSONAL], + required: true + }, + user: { + // user associated with the personal secret + type: Schema.Types.ObjectId, + ref: 'User' + }, + environment: { + type: String, + required: true + }, + isDeleted: { // consider removing field + type: Boolean, + default: false, + required: true + }, + secretKeyCiphertext: { + type: String, + required: true + }, + secretKeyIV: { + type: String, // symmetric + required: true + }, + secretKeyTag: { + type: String, // symmetric + required: true + }, + secretKeyHash: { + type: String + }, + secretValueCiphertext: { + type: String, + required: true + }, + secretValueIV: { + type: String, // symmetric + required: true + }, + secretValueTag: { + type: String, // symmetric + required: true + }, + secretValueHash: { + type: String + } + }, + { + timestamps: true + } +); + +const SecretVersion = model('SecretVersion', secretVersionSchema); + +export default SecretVersion; \ No newline at end of file diff --git a/backend/src/ee/routes/v1/action.ts b/backend/src/ee/routes/v1/action.ts new file mode 100644 index 000000000..5dca83cf9 --- /dev/null +++ b/backend/src/ee/routes/v1/action.ts @@ -0,0 +1,17 @@ +import express from 'express'; +const router = express.Router(); +import { + validateRequest +} from '../../../middleware'; +import { param } from 'express-validator'; +import { actionController } from '../../controllers/v1'; + +// TODO: put into action controller +router.get( + '/:actionId', + param('actionId').exists().trim(), + validateRequest, + actionController.getAction +); + +export default router; \ No newline at end of file diff --git a/backend/src/ee/routes/v1/index.ts b/backend/src/ee/routes/v1/index.ts new file mode 100644 index 000000000..612715111 --- /dev/null +++ b/backend/src/ee/routes/v1/index.ts @@ -0,0 +1,11 @@ +import secret from './secret'; +import secretSnapshot from './secretSnapshot'; +import workspace from './workspace'; +import action from './action'; + +export { + secret, + secretSnapshot, + workspace, + action +} \ No newline at end of file diff --git a/backend/src/ee/routes/v1/secret.ts b/backend/src/ee/routes/v1/secret.ts new file mode 100644 index 000000000..8e93919a0 --- /dev/null +++ b/backend/src/ee/routes/v1/secret.ts @@ -0,0 +1,40 @@ +import express from 'express'; +const router = express.Router(); +import { + requireAuth, + requireSecretAuth, + validateRequest +} from '../../../middleware'; +import { query, param, body } from 'express-validator'; +import { secretController } from '../../controllers/v1'; +import { ADMIN, MEMBER } from '../../../variables'; + +router.get( + '/:secretId/secret-versions', + requireAuth({ + acceptedAuthModes: ['jwt', 'apiKey'] + }), + requireSecretAuth({ + acceptedRoles: [ADMIN, MEMBER] + }), + param('secretId').exists().trim(), + query('offset').exists().isInt(), + query('limit').exists().isInt(), + validateRequest, + secretController.getSecretVersions +); + +router.post( + '/:secretId/secret-versions/rollback', + requireAuth({ + acceptedAuthModes: ['jwt', 'apiKey'] + }), + requireSecretAuth({ + acceptedRoles: [ADMIN, MEMBER] + }), + param('secretId').exists().trim(), + body('version').exists().isInt(), + secretController.rollbackSecretVersion +); + +export default router; \ No newline at end of file diff --git a/backend/src/ee/routes/v1/secretSnapshot.ts b/backend/src/ee/routes/v1/secretSnapshot.ts new file mode 100644 index 000000000..d10da4456 --- /dev/null +++ b/backend/src/ee/routes/v1/secretSnapshot.ts @@ -0,0 +1,27 @@ +import express from 'express'; +const router = express.Router(); +import { + requireSecretSnapshotAuth +} from '../../middleware'; +import { + requireAuth, + validateRequest +} from '../../../middleware'; +import { param, body } from 'express-validator'; +import { ADMIN, MEMBER } from '../../../variables'; +import { secretSnapshotController } from '../../controllers/v1'; + +router.get( + '/:secretSnapshotId', + requireAuth({ + acceptedAuthModes: ['jwt'] + }), + requireSecretSnapshotAuth({ + acceptedRoles: [ADMIN, MEMBER] + }), + param('secretSnapshotId').exists().trim(), + validateRequest, + secretSnapshotController.getSecretSnapshot +); + +export default router; \ No newline at end of file diff --git a/backend/src/ee/routes/stripe.ts b/backend/src/ee/routes/v1/stripe.ts similarity index 71% rename from backend/src/ee/routes/stripe.ts rename to backend/src/ee/routes/v1/stripe.ts index 6f89f5655..02d68c4ea 100644 --- a/backend/src/ee/routes/stripe.ts +++ b/backend/src/ee/routes/v1/stripe.ts @@ -1,6 +1,6 @@ import express from 'express'; const router = express.Router(); -import { stripeController } from '../controllers'; +import { stripeController } from '../../controllers/v1'; router.post('/webhook', stripeController.handleWebhook); diff --git a/backend/src/ee/routes/v1/workspace.ts b/backend/src/ee/routes/v1/workspace.ts new file mode 100644 index 000000000..a799d073b --- /dev/null +++ b/backend/src/ee/routes/v1/workspace.ts @@ -0,0 +1,72 @@ +import express from 'express'; +const router = express.Router(); +import { + requireAuth, + requireWorkspaceAuth, + validateRequest +} from '../../../middleware'; +import { param, query, body } from 'express-validator'; +import { ADMIN, MEMBER } from '../../../variables'; +import { workspaceController } from '../../controllers/v1'; + +router.get( + '/:workspaceId/secret-snapshots', + requireAuth({ + acceptedAuthModes: ['jwt', 'apiKey'] + }), + requireWorkspaceAuth({ + acceptedRoles: [ADMIN, MEMBER] + }), + param('workspaceId').exists().trim(), + query('offset').exists().isInt(), + query('limit').exists().isInt(), + validateRequest, + workspaceController.getWorkspaceSecretSnapshots +); + +router.get( + '/:workspaceId/secret-snapshots/count', + requireAuth({ + acceptedAuthModes: ['jwt'] + }), + requireWorkspaceAuth({ + acceptedRoles: [ADMIN, MEMBER] + }), + param('workspaceId').exists().trim(), + validateRequest, + workspaceController.getWorkspaceSecretSnapshotsCount +); + +router.post( + '/:workspaceId/secret-snapshots/rollback', + requireAuth({ + acceptedAuthModes: ['jwt', 'apiKey'] + }), + requireWorkspaceAuth({ + acceptedRoles: [ADMIN, MEMBER] + }), + param('workspaceId').exists().trim(), + body('version').exists().isInt(), + validateRequest, + workspaceController.rollbackWorkspaceSecretSnapshot +); + +router.get( + '/:workspaceId/logs', + requireAuth({ + acceptedAuthModes: ['jwt', 'apiKey'] + }), + requireWorkspaceAuth({ + acceptedRoles: [ADMIN, MEMBER] + }), + param('workspaceId').exists().trim(), + query('offset').exists().isInt(), + query('limit').exists().isInt(), + query('sortBy'), + query('userId'), + query('actionNames'), + validateRequest, + workspaceController.getWorkspaceLogs +); + +export default router; \ No newline at end of file diff --git a/backend/src/ee/services/EELicenseService.ts b/backend/src/ee/services/EELicenseService.ts new file mode 100644 index 000000000..f31482dde --- /dev/null +++ b/backend/src/ee/services/EELicenseService.ts @@ -0,0 +1,19 @@ +import { LICENSE_KEY } from '../../config'; + +/** + * Class to handle Enterprise Edition license actions + */ +class EELicenseService { + + private readonly _isLicenseValid: boolean; + + constructor(licenseKey: string) { + this._isLicenseValid = true; + } + + public get isLicenseValid(): boolean { + return this._isLicenseValid; + } +} + +export default new EELicenseService(LICENSE_KEY); \ No newline at end of file diff --git a/backend/src/ee/services/EELogService.ts b/backend/src/ee/services/EELogService.ts new file mode 100644 index 000000000..c1b2da6fb --- /dev/null +++ b/backend/src/ee/services/EELogService.ts @@ -0,0 +1,81 @@ +import { Types } from 'mongoose'; +import { + Log, + Action, + IAction +} from '../models'; +import { + createLogHelper +} from '../helpers/log'; +import { + createActionSecretHelper +} from '../helpers/action'; +import EELicenseService from './EELicenseService'; + +/** + * Class to handle Enterprise Edition log actions + */ +class EELogService { + /** + * Create an (audit) log + * @param {Object} obj + * @param {String} obj.userId - id of user associated with the log + * @param {String} obj.workspaceId - id of workspace associated with the log + * @param {Action} obj.actions - actions to include in log + * @param {String} obj.channel - channel (web/cli/auto) associated with the log + * @param {String} obj.ipAddress - ip address associated with the log + * @returns {Log} log - new audit log + */ + static async createLog({ + userId, + workspaceId, + actions, + channel, + ipAddress + }: { + userId: string; + workspaceId: string; + actions: IAction[]; + channel: string; + ipAddress: string; + }) { + if (!EELicenseService.isLicenseValid) return null; + return await createLogHelper({ + userId, + workspaceId, + actions, + channel, + ipAddress + }) + } + + /** + * Create an (audit) action for secrets including + * add, delete, update, and read actions. + * @param {Object} obj + * @param {String} obj.name - name of action + * @param {ObjectId[]} obj.secretIds - secret ids + * @returns {Action} action - new action + */ + static async createActionSecret({ + name, + userId, + workspaceId, + secretIds + }: { + name: string; + userId: string; + workspaceId: string; + secretIds: Types.ObjectId[]; + }) { + if (!EELicenseService.isLicenseValid) return null; + return await createActionSecretHelper({ + name, + userId, + workspaceId, + secretIds + }); + } +} + +export default EELogService; \ No newline at end of file diff --git a/backend/src/ee/services/EESecretService.ts b/backend/src/ee/services/EESecretService.ts new file mode 100644 index 000000000..cea614c96 --- /dev/null +++ b/backend/src/ee/services/EESecretService.ts @@ -0,0 +1,78 @@ +import { Types } from 'mongoose'; +import { ISecretVersion } from '../models'; +import { + takeSecretSnapshotHelper, + addSecretVersionsHelper, + markDeletedSecretVersionsHelper, + initSecretVersioningHelper +} from '../helpers/secret'; +import EELicenseService from './EELicenseService'; + +/** + * Class to handle Enterprise Edition secret actions + */ +class EESecretService { + + /** + * Save a secret snapshot that is a copy of the current state of secrets in workspace with id + * [workspaceId] under a new snapshot with incremented version under the + * SecretSnapshot collection. + * Requires a valid license key [licenseKey] + * @param {Object} obj + * @param {String} obj.workspaceId + * @returns {SecretSnapshot} secretSnapshot - new secret snpashot + */ + static async takeSecretSnapshot({ + workspaceId + }: { + workspaceId: string; + }) { + if (!EELicenseService.isLicenseValid) return; + return await takeSecretSnapshotHelper({ workspaceId }); + } + + /** + * Add secret versions [secretVersions] to the SecretVersion collection. + * @param {Object} obj + * @param {Object[]} obj.secretVersions + * @returns {SecretVersion[]} newSecretVersions - new secret versions + */ + static async addSecretVersions({ + secretVersions + }: { + secretVersions: ISecretVersion[]; + }) { + if (!EELicenseService.isLicenseValid) return; + return await addSecretVersionsHelper({ + secretVersions + }); + } + + /** + * Mark secret versions associated with secrets with ids [secretIds] + * as deleted. + * @param {Object} obj + * @param {ObjectId[]} obj.secretIds - secret ids + */ + static async markDeletedSecretVersions({ + secretIds + }: { + secretIds: Types.ObjectId[]; + }) { + if (!EELicenseService.isLicenseValid) return; + await markDeletedSecretVersionsHelper({ + secretIds + }); + } + + /** + * Initialize secret versioning by setting previously unversioned + * secrets to version 1 and begin populating secret versions. + */ + static async initSecretVersioning() { + if (!EELicenseService.isLicenseValid) return; + await initSecretVersioningHelper(); + } +} + +export default EESecretService; \ No newline at end of file diff --git a/backend/src/ee/services/index.ts b/backend/src/ee/services/index.ts new file mode 100644 index 000000000..b3544bcff --- /dev/null +++ b/backend/src/ee/services/index.ts @@ -0,0 +1,9 @@ +import EELicenseService from "./EELicenseService"; +import EESecretService from "./EESecretService"; +import EELogService from "./EELogService"; + +export { + EELicenseService, + EESecretService, + EELogService +} \ No newline at end of file diff --git a/backend/src/ee/variables.ts b/backend/src/ee/variables.ts deleted file mode 100644 index e69de29bb..000000000 diff --git a/backend/src/events/index.ts b/backend/src/events/index.ts new file mode 100644 index 000000000..461a3ece6 --- /dev/null +++ b/backend/src/events/index.ts @@ -0,0 +1,5 @@ +import { eventPushSecrets } from "./secret" + +export { + eventPushSecrets +} \ No newline at end of file diff --git a/backend/src/events/secret.ts b/backend/src/events/secret.ts new file mode 100644 index 000000000..479255a31 --- /dev/null +++ b/backend/src/events/secret.ts @@ -0,0 +1,60 @@ +import { + EVENT_PUSH_SECRETS, + EVENT_PULL_SECRETS +} from '../variables'; + +interface PushSecret { + ciphertextKey: string; + ivKey: string; + tagKey: string; + hashKey: string; + ciphertextValue: string; + ivValue: string; + tagValue: string; + hashValue: string; + type: 'shared' | 'personal'; +} + +/** + * Return event for pushing secrets + * @param {Object} obj + * @param {String} obj.workspaceId - id of workspace to push secrets to + * @returns + */ +const eventPushSecrets = ({ + workspaceId +}: { + workspaceId: string; +}) => { + return ({ + name: EVENT_PUSH_SECRETS, + workspaceId, + payload: { + + } + }); +} + +/** + * Return event for pulling secrets + * @param {Object} obj + * @param {String} obj.workspaceId - id of workspace to pull secrets from + * @returns + */ +const eventPullSecrets = ({ + workspaceId, +}: { + workspaceId: string; +}) => { + return ({ + name: EVENT_PULL_SECRETS, + workspaceId, + payload: { + + } + }); +} + +export { + eventPushSecrets +} diff --git a/backend/src/helpers/auth.ts b/backend/src/helpers/auth.ts index 7d5f2461f..a8ca48377 100644 --- a/backend/src/helpers/auth.ts +++ b/backend/src/helpers/auth.ts @@ -1,7 +1,10 @@ import jwt from 'jsonwebtoken'; import * as Sentry from '@sentry/node'; +import bcrypt from 'bcrypt'; import { - User + User, + ServiceTokenData, + APIKeyData } from '../models'; import { JWT_AUTH_LIFETIME, @@ -9,6 +12,196 @@ import { JWT_REFRESH_LIFETIME, JWT_REFRESH_SECRET } from '../config'; +import { + AccountNotFoundError, + ServiceTokenDataNotFoundError, + APIKeyDataNotFoundError, + UnauthorizedRequestError, + BadRequestError +} from '../utils/errors'; + +/** + * + * @param {Object} obj + * @param {Object} obj.headers - HTTP request headers object + */ +const validateAuthMode = ({ + headers, + acceptedAuthModes +}: { + headers: { [key: string]: string | string[] | undefined }, + acceptedAuthModes: string[] +}) => { + // TODO: refactor middleware + const apiKey = headers['x-api-key']; + const authHeader = headers['authorization']; + + let authTokenType, authTokenValue; + if (apiKey === undefined && authHeader === undefined) { + // case: no auth or X-API-KEY header present + throw BadRequestError({ message: 'Missing Authorization or X-API-KEY in request header.' }); + } + + if (typeof apiKey === 'string') { + // case: treat request authentication type as via X-API-KEY (i.e. API Key) + authTokenType = 'apiKey'; + authTokenValue = apiKey; + } + + if (typeof authHeader === 'string') { + // case: treat request authentication type as via Authorization header (i.e. either JWT or service token) + const [tokenType, tokenValue] = <[string, string]>authHeader.split(' ', 2) ?? [null, null] + if (tokenType === null) + throw BadRequestError({ message: `Missing Authorization Header in the request header.` }); + if (tokenType.toLowerCase() !== 'bearer') + throw BadRequestError({ message: `The provided authentication type '${tokenType}' is not supported.` }); + if (tokenValue === null) + throw BadRequestError({ message: 'Missing Authorization Body in the request header.' }); + + switch (tokenValue.split('.', 1)[0]) { + case 'st': + authTokenType = 'serviceToken'; + break; + default: + authTokenType = 'jwt'; + } + authTokenValue = tokenValue; + } + + if (!authTokenType || !authTokenValue) throw BadRequestError({ message: 'Missing valid Authorization or X-API-KEY in request header.' }); + + if (!acceptedAuthModes.includes(authTokenType)) throw BadRequestError({ message: 'The provided authentication type is not supported.' }); + + return ({ + authTokenType, + authTokenValue + }); +} + +/** + * Return user payload corresponding to JWT token [authTokenValue] + * @param {Object} obj + * @param {String} obj.authTokenValue - JWT token value + * @returns {User} user - user corresponding to JWT token + */ +const getAuthUserPayload = async ({ + authTokenValue +}: { + authTokenValue: string; +}) => { + let user; + try { + const decodedToken = ( + jwt.verify(authTokenValue, JWT_AUTH_SECRET) + ); + + user = await User.findOne({ + _id: decodedToken.userId + }).select('+publicKey'); + + if (!user) throw AccountNotFoundError({ message: 'Failed to find User' }); + + if (!user?.publicKey) throw UnauthorizedRequestError({ message: 'Failed to authenticate User with partially set up account' }); + + } catch (err) { + throw UnauthorizedRequestError({ + message: 'Failed to authenticate JWT token' + }); + } + + return user; +} + +/** + * Return service token data payload corresponding to service token [authTokenValue] + * @param {Object} obj + * @param {String} obj.authTokenValue - service token value + * @returns {ServiceTokenData} serviceTokenData - service token data + */ +const getAuthSTDPayload = async ({ + authTokenValue +}: { + authTokenValue: string; +}) => { + let serviceTokenData; + try { + const [_, TOKEN_IDENTIFIER, TOKEN_SECRET] = <[string, string, string]>authTokenValue.split('.', 3); + + // TODO: optimize double query + serviceTokenData = await ServiceTokenData + .findById(TOKEN_IDENTIFIER, '+secretHash +expiresAt'); + + if (!serviceTokenData) { + throw ServiceTokenDataNotFoundError({ message: 'Failed to find service token data' }); + } else if (serviceTokenData?.expiresAt && new Date(serviceTokenData.expiresAt) < new Date()) { + // case: service token expired + await ServiceTokenData.findByIdAndDelete(serviceTokenData._id); + throw UnauthorizedRequestError({ + message: 'Failed to authenticate expired service token' + }); + } + + const isMatch = await bcrypt.compare(TOKEN_SECRET, serviceTokenData.secretHash); + if (!isMatch) throw UnauthorizedRequestError({ + message: 'Failed to authenticate service token' + }); + + serviceTokenData = await ServiceTokenData + .findById(TOKEN_IDENTIFIER) + .select('+encryptedKey +iv +tag').populate('user'); + + } catch (err) { + throw UnauthorizedRequestError({ + message: 'Failed to authenticate service token' + }); + } + + return serviceTokenData; +} + +/** + * Return API key data payload corresponding to API key [authTokenValue] + * @param {Object} obj + * @param {String} obj.authTokenValue - API key value + * @returns {APIKeyData} apiKeyData - API key data + */ +const getAuthAPIKeyPayload = async ({ + authTokenValue +}: { + authTokenValue: string; +}) => { + let user; + try { + const [_, TOKEN_IDENTIFIER, TOKEN_SECRET] = <[string, string, string]>authTokenValue.split('.', 3); + + const apiKeyData = await APIKeyData + .findById(TOKEN_IDENTIFIER, '+secretHash +expiresAt') + .populate('user', '+publicKey'); + + if (!apiKeyData) { + throw APIKeyDataNotFoundError({ message: 'Failed to find API key data' }); + } else if (apiKeyData?.expiresAt && new Date(apiKeyData.expiresAt) < new Date()) { + // case: API key expired + await APIKeyData.findByIdAndDelete(apiKeyData._id); + throw UnauthorizedRequestError({ + message: 'Failed to authenticate expired API key' + }); + } + + const isMatch = await bcrypt.compare(TOKEN_SECRET, apiKeyData.secretHash); + if (!isMatch) throw UnauthorizedRequestError({ + message: 'Failed to authenticate API key' + }); + + user = apiKeyData.user; + } catch (err) { + throw UnauthorizedRequestError({ + message: 'Failed to authenticate API key' + }); + } + + return user; +} /** * Return newly issued (JWT) auth and refresh tokens to user with id [userId] @@ -99,4 +292,12 @@ const createToken = ({ } }; -export { createToken, issueTokens, clearTokens }; +export { + validateAuthMode, + getAuthUserPayload, + getAuthSTDPayload, + getAuthAPIKeyPayload, + createToken, + issueTokens, + clearTokens +}; diff --git a/backend/src/helpers/bot.ts b/backend/src/helpers/bot.ts new file mode 100644 index 000000000..7519ef18b --- /dev/null +++ b/backend/src/helpers/bot.ts @@ -0,0 +1,229 @@ +import * as Sentry from '@sentry/node'; +import { + Bot, + BotKey, + Secret, + ISecret, + IUser +} from '../models'; +import { + generateKeyPair, + encryptSymmetric, + decryptSymmetric, + decryptAsymmetric +} from '../utils/crypto'; +import { ENCRYPTION_KEY } from '../config'; +import { SECRET_SHARED } from '../variables'; + +/** + * Create an inactive bot with name [name] for workspace with id [workspaceId] + * @param {Object} obj + * @param {String} obj.name - name of bot + * @param {String} obj.workspaceId - id of workspace that bot belongs to + */ +const createBot = async ({ + name, + workspaceId, +}: { + name: string; + workspaceId: string; +}) => { + let bot; + try { + const { publicKey, privateKey } = generateKeyPair(); + const { ciphertext, iv, tag } = encryptSymmetric({ + plaintext: privateKey, + key: ENCRYPTION_KEY + }); + + bot = await new Bot({ + name, + workspace: workspaceId, + isActive: false, + publicKey, + encryptedPrivateKey: ciphertext, + iv, + tag + }).save(); + } catch (err) { + Sentry.setUser(null); + Sentry.captureException(err); + throw new Error('Failed to create bot'); + } + + return bot; +} + +/** + * Return decrypted secrets for workspace with id [workspaceId] + * and [environment] using bot + * @param {Object} obj + * @param {String} obj.workspaceId - id of workspace + * @param {String} obj.environment - environment + */ +const getSecretsHelper = async ({ + workspaceId, + environment +}: { + workspaceId: string; + environment: string; +}) => { + const content = {} as any; + try { + const key = await getKey({ workspaceId }); + const secrets = await Secret.find({ + workspace: workspaceId, + environment, + type: SECRET_SHARED + }); + + secrets.forEach((secret: ISecret) => { + const secretKey = decryptSymmetric({ + ciphertext: secret.secretKeyCiphertext, + iv: secret.secretKeyIV, + tag: secret.secretKeyTag, + key + }); + + const secretValue = decryptSymmetric({ + ciphertext: secret.secretValueCiphertext, + iv: secret.secretValueIV, + tag: secret.secretValueTag, + key + }); + + content[secretKey] = secretValue; + }); + } catch (err) { + Sentry.setUser(null); + Sentry.captureException(err); + throw new Error('Failed to get secrets'); + } + + return content; +} + +/** + * Return bot's copy of the workspace key for workspace + * with id [workspaceId] + * @param {Object} obj + * @param {String} obj.workspaceId - id of workspace + * @returns {String} key - decrypted workspace key + */ +const getKey = async ({ workspaceId }: { workspaceId: string }) => { + let key; + try { + const botKey = await BotKey.findOne({ + workspace: workspaceId + }).populate<{ sender: IUser }>('sender', 'publicKey'); + + if (!botKey) throw new Error('Failed to find bot key'); + + const bot = await Bot.findOne({ + workspace: workspaceId + }).select('+encryptedPrivateKey +iv +tag'); + + if (!bot) throw new Error('Failed to find bot'); + if (!bot.isActive) throw new Error('Bot is not active'); + + const privateKeyBot = decryptSymmetric({ + ciphertext: bot.encryptedPrivateKey, + iv: bot.iv, + tag: bot.tag, + key: ENCRYPTION_KEY + }); + + key = decryptAsymmetric({ + ciphertext: botKey.encryptedKey, + nonce: botKey.nonce, + publicKey: botKey.sender.publicKey as string, + privateKey: privateKeyBot + }); + } catch (err) { + Sentry.setUser(null); + Sentry.captureException(err); + throw new Error('Failed to get workspace key'); + } + + return key; +} + +/** + * Return symmetrically encrypted [plaintext] using the + * key for workspace with id [workspaceId] + * @param {Object} obj1 + * @param {String} obj1.workspaceId - id of workspace + * @param {String} obj1.plaintext - plaintext to encrypt + */ +const encryptSymmetricHelper = async ({ + workspaceId, + plaintext +}: { + workspaceId: string; + plaintext: string; +}) => { + + try { + const key = await getKey({ workspaceId }); + const { ciphertext, iv, tag } = encryptSymmetric({ + plaintext, + key + }); + + return ({ + ciphertext, + iv, + tag + }); + } catch (err) { + Sentry.setUser(null); + Sentry.captureException(err); + throw new Error('Failed to perform symmetric encryption with bot'); + } +} +/** + * Return symmetrically decrypted [ciphertext] using the + * key for workspace with id [workspaceId] + * @param {Object} obj + * @param {String} obj.workspaceId - id of workspace + * @param {String} obj.ciphertext - ciphertext to decrypt + * @param {String} obj.iv - iv + * @param {String} obj.tag - tag + */ +const decryptSymmetricHelper = async ({ + workspaceId, + ciphertext, + iv, + tag +}: { + workspaceId: string; + ciphertext: string; + iv: string; + tag: string; +}) => { + let plaintext; + try { + const key = await getKey({ workspaceId }); + const plaintext = decryptSymmetric({ + ciphertext, + iv, + tag, + key + }); + + return plaintext; + } catch (err) { + Sentry.setUser(null); + Sentry.captureException(err); + throw new Error('Failed to perform symmetric decryption with bot'); + } + + return plaintext; +} + +export { + createBot, + getSecretsHelper, + encryptSymmetricHelper, + decryptSymmetricHelper +} \ No newline at end of file diff --git a/backend/src/helpers/database.ts b/backend/src/helpers/database.ts new file mode 100644 index 000000000..9ba592ea3 --- /dev/null +++ b/backend/src/helpers/database.ts @@ -0,0 +1,34 @@ +import mongoose from 'mongoose'; +import { EESecretService } from '../ee/services'; +import { getLogger } from '../utils/logger'; + +/** + * Initialize database connection + * @param {Object} obj + * @param {String} obj.mongoURL - mongo connection string + * @returns + */ +const initDatabaseHelper = async ({ + mongoURL +}: { + mongoURL: string; +}) => { + try { + await mongoose.connect(mongoURL); + + // allow empty strings to pass the required validator + mongoose.Schema.Types.String.checkRequired(v => typeof v === 'string'); + + getLogger("database").info("Database connection established"); + + await EESecretService.initSecretVersioning(); + } catch (err) { + getLogger("database").error(`Unable to establish Database connection due to the error.\n${err}`); + } + + return mongoose.connection; +} + +export { + initDatabaseHelper +} \ No newline at end of file diff --git a/backend/src/helpers/event.ts b/backend/src/helpers/event.ts new file mode 100644 index 000000000..4128752e5 --- /dev/null +++ b/backend/src/helpers/event.ts @@ -0,0 +1,51 @@ +import { Bot, IBot } from '../models'; +import * as Sentry from '@sentry/node'; +import { EVENT_PUSH_SECRETS } from '../variables'; +import { IntegrationService } from '../services'; + +interface Event { + name: string; + workspaceId: string; + payload: any; +} + +/** + * Handle event [event] + * @param {Object} obj + * @param {Event} obj.event - an event + * @param {String} obj.event.name - name of event + * @param {String} obj.event.workspaceId - id of workspace that event is part of + * @param {Object} obj.event.payload - payload of event (depends on event) + */ +const handleEventHelper = async ({ + event +}: { + event: Event; +}) => { + const { workspaceId } = event; + + // TODO: moduralize bot check into separate function + const bot = await Bot.findOne({ + workspace: workspaceId, + isActive: true + }); + + if (!bot) return; + + try { + switch (event.name) { + case EVENT_PUSH_SECRETS: + IntegrationService.syncIntegrations({ + workspaceId + }); + break; + } + } catch (err) { + Sentry.setUser(null); + Sentry.captureException(err); + } +} + +export { + handleEventHelper +} \ No newline at end of file diff --git a/backend/src/helpers/integration.ts b/backend/src/helpers/integration.ts index e69de29bb..1618e5e67 100644 --- a/backend/src/helpers/integration.ts +++ b/backend/src/helpers/integration.ts @@ -0,0 +1,357 @@ +import * as Sentry from '@sentry/node'; +import { + Bot, + Integration, + IntegrationAuth, +} from '../models'; +import { exchangeCode, exchangeRefresh, syncSecrets } from '../integrations'; +import { BotService } from '../services'; +import { + INTEGRATION_VERCEL, + INTEGRATION_NETLIFY +} from '../variables'; +import { UnauthorizedRequestError } from '../utils/errors'; +import RequestError from '../utils/requestError'; + +interface Update { + workspace: string; + integration: string; + teamId?: string; + accountId?: string; +} + +/** + * Perform OAuth2 code-token exchange for workspace with id [workspaceId] and integration + * named [integration] + * - Store integration access and refresh tokens returned from the OAuth2 code-token exchange + * - Add placeholder inactive integration + * - Create bot sequence for integration + * @param {Object} obj + * @param {String} obj.workspaceId - id of workspace + * @param {String} obj.integration - name of integration + * @param {String} obj.code - code +*/ +const handleOAuthExchangeHelper = async ({ + workspaceId, + integration, + code, + environment +}: { + workspaceId: string; + integration: string; + code: string; + environment: string; +}) => { + let action; + let integrationAuth; + try { + const bot = await Bot.findOne({ + workspace: workspaceId, + isActive: true + }); + + if (!bot) throw new Error('Bot must be enabled for OAuth2 code-token exchange'); + + // exchange code for access and refresh tokens + const res = await exchangeCode({ + integration, + code + }); + + const update: Update = { + workspace: workspaceId, + integration + } + + switch (integration) { + case INTEGRATION_VERCEL: + update.teamId = res.teamId; + break; + case INTEGRATION_NETLIFY: + update.accountId = res.accountId; + break; + } + + integrationAuth = await IntegrationAuth.findOneAndUpdate({ + workspace: workspaceId, + integration + }, update, { + new: true, + upsert: true + }); + + if (res.refreshToken) { + // case: refresh token returned from exchange + // set integration auth refresh token + await setIntegrationAuthRefreshHelper({ + integrationAuthId: integrationAuth._id.toString(), + refreshToken: res.refreshToken + }); + } + + if (res.accessToken) { + // case: access token returned from exchange + // set integration auth access token + await setIntegrationAuthAccessHelper({ + integrationAuthId: integrationAuth._id.toString(), + accessToken: res.accessToken, + accessExpiresAt: res.accessExpiresAt + }); + } + + // initialize new integration after exchange + await new Integration({ + workspace: workspaceId, + isActive: false, + app: null, + environment, + integration, + integrationAuth: integrationAuth._id + }).save(); + } catch (err) { + Sentry.setUser(null); + Sentry.captureException(err); + throw new Error('Failed to handle OAuth2 code-token exchange') + } +} +/** + * Sync/push environment variables in workspace with id [workspaceId] to + * all active integrations for that workspace + * @param {Object} obj + * @param {Object} obj.workspaceId - id of workspace + */ +const syncIntegrationsHelper = async ({ + workspaceId +}: { + workspaceId: string; +}) => { + let integrations; + try { + integrations = await Integration.find({ + workspace: workspaceId, + isActive: true, + app: { $ne: null } + }); + + // for each workspace integration, sync/push secrets + // to that integration + for await (const integration of integrations) { + // get workspace, environment (shared) secrets + const secrets = await BotService.getSecrets({ // issue here? + workspaceId: integration.workspace.toString(), + environment: integration.environment + }); + + const integrationAuth = await IntegrationAuth.findById(integration.integrationAuth); + if (!integrationAuth) throw new Error('Failed to find integration auth'); + + // get integration auth access token + const accessToken = await getIntegrationAuthAccessHelper({ + integrationAuthId: integration.integrationAuth.toString() + }); + + // sync secrets to integration + await syncSecrets({ + integration, + integrationAuth, + secrets, + accessToken + }); + } + } catch (err) { + Sentry.setUser(null); + Sentry.captureException(err); + throw new Error('Failed to sync secrets to integrations'); + } +} + +/** + * Return decrypted refresh token using the bot's copy + * of the workspace key for workspace belonging to integration auth + * with id [integrationAuthId] + * @param {Object} obj + * @param {String} obj.integrationAuthId - id of integration auth + * @param {String} refreshToken - decrypted refresh token + */ + const getIntegrationAuthRefreshHelper = async ({ integrationAuthId }: { integrationAuthId: string }) => { + let refreshToken; + + try { + const integrationAuth = await IntegrationAuth + .findById(integrationAuthId) + .select('+refreshCiphertext +refreshIV +refreshTag'); + + if (!integrationAuth) throw UnauthorizedRequestError({message: 'Failed to locate Integration Authentication credentials'}); + + refreshToken = await BotService.decryptSymmetric({ + workspaceId: integrationAuth.workspace.toString(), + ciphertext: integrationAuth.refreshCiphertext as string, + iv: integrationAuth.refreshIV as string, + tag: integrationAuth.refreshTag as string + }); + + } catch (err) { + Sentry.setUser(null); + Sentry.captureException(err); + if(err instanceof RequestError) + throw err + else + throw new Error('Failed to get integration refresh token'); + } + + return refreshToken; +} + +/** + * Return decrypted access token using the bot's copy + * of the workspace key for workspace belonging to integration auth + * with id [integrationAuthId] + * @param {Object} obj + * @param {String} obj.integrationAuthId - id of integration auth + * @returns {String} accessToken - decrypted access token + */ +const getIntegrationAuthAccessHelper = async ({ integrationAuthId }: { integrationAuthId: string }) => { + let accessToken; + + try { + const integrationAuth = await IntegrationAuth + .findById(integrationAuthId) + .select('workspace integration +accessCiphertext +accessIV +accessTag +accessExpiresAt + refreshCiphertext'); + + if (!integrationAuth) throw UnauthorizedRequestError({message: 'Failed to locate Integration Authentication credentials'}); + + accessToken = await BotService.decryptSymmetric({ + workspaceId: integrationAuth.workspace.toString(), + ciphertext: integrationAuth.accessCiphertext as string, + iv: integrationAuth.accessIV as string, + tag: integrationAuth.accessTag as string + }); + + if (integrationAuth?.accessExpiresAt && integrationAuth?.refreshCiphertext) { + // there is a access token expiration date + // and refresh token to exchange with the OAuth2 server + + if (integrationAuth.accessExpiresAt < new Date()) { + // access token is expired + const refreshToken = await getIntegrationAuthRefreshHelper({ integrationAuthId }); + accessToken = await exchangeRefresh({ + integration: integrationAuth.integration, + refreshToken + }); + } + } + + } catch (err) { + Sentry.setUser(null); + Sentry.captureException(err); + if(err instanceof RequestError) + throw err + else + throw new Error('Failed to get integration access token'); + } + + return accessToken; +} + +/** + * Encrypt refresh token [refreshToken] using the bot's copy + * of the workspace key for workspace belonging to integration auth + * with id [integrationAuthId] and store it + * @param {Object} obj + * @param {String} obj.integrationAuthId - id of integration auth + * @param {String} obj.refreshToken - refresh token + */ +const setIntegrationAuthRefreshHelper = async ({ + integrationAuthId, + refreshToken +}: { + integrationAuthId: string; + refreshToken: string; +}) => { + + let integrationAuth; + try { + integrationAuth = await IntegrationAuth + .findById(integrationAuthId); + + if (!integrationAuth) throw new Error('Failed to find integration auth'); + + const obj = await BotService.encryptSymmetric({ + workspaceId: integrationAuth.workspace.toString(), + plaintext: refreshToken + }); + + integrationAuth = await IntegrationAuth.findOneAndUpdate({ + _id: integrationAuthId + }, { + refreshCiphertext: obj.ciphertext, + refreshIV: obj.iv, + refreshTag: obj.tag + }, { + new: true + }); + } catch (err) { + Sentry.setUser(null); + Sentry.captureException(err); + throw new Error('Failed to set integration auth refresh token'); + } + + return integrationAuth; +} + +/** + * Encrypt access token [accessToken] using the bot's copy + * of the workspace key for workspace belonging to integration auth + * with id [integrationAuthId] and store it along with [accessExpiresAt] + * @param {Object} obj + * @param {String} obj.integrationAuthId - id of integration auth + * @param {String} obj.accessToken - access token + * @param {Date} obj.accessExpiresAt - expiration date of access token + */ +const setIntegrationAuthAccessHelper = async ({ + integrationAuthId, + accessToken, + accessExpiresAt +}: { + integrationAuthId: string; + accessToken: string; + accessExpiresAt: Date | undefined; +}) => { + let integrationAuth; + try { + integrationAuth = await IntegrationAuth.findById(integrationAuthId); + + if (!integrationAuth) throw new Error('Failed to find integration auth'); + + const obj = await BotService.encryptSymmetric({ + workspaceId: integrationAuth.workspace.toString(), + plaintext: accessToken + }); + + integrationAuth = await IntegrationAuth.findOneAndUpdate({ + _id: integrationAuthId + }, { + accessCiphertext: obj.ciphertext, + accessIV: obj.iv, + accessTag: obj.tag, + accessExpiresAt + }, { + new: true + }); + } catch (err) { + Sentry.setUser(null); + Sentry.captureException(err); + throw new Error('Failed to save integration auth access token'); + } + + return integrationAuth; +} + +export { + handleOAuthExchangeHelper, + syncIntegrationsHelper, + getIntegrationAuthRefreshHelper, + getIntegrationAuthAccessHelper, + setIntegrationAuthRefreshHelper, + setIntegrationAuthAccessHelper +} \ No newline at end of file diff --git a/backend/src/helpers/integrationAuth.ts b/backend/src/helpers/integrationAuth.ts index 17f101676..e69de29bb 100644 --- a/backend/src/helpers/integrationAuth.ts +++ b/backend/src/helpers/integrationAuth.ts @@ -1,174 +0,0 @@ -import * as Sentry from '@sentry/node'; -import axios from 'axios'; -import { IntegrationAuth } from '../models'; -import { encryptSymmetric, decryptSymmetric } from '../utils/crypto'; -import { IIntegrationAuth } from '../models'; -import { - ENCRYPTION_KEY, - OAUTH_CLIENT_SECRET_HEROKU, - OAUTH_TOKEN_URL_HEROKU -} from '../config'; - -/** - * Process token exchange and refresh responses from respective OAuth2 authorization servers by - * encrypting access and refresh tokens, computing new access token expiration times [accessExpiresAt], - * and upserting them into the DB for workspace with id [workspaceId] and integration [integration]. - * @param {Object} obj - * @param {String} obj.workspaceId - id of workspace - * @param {String} obj.integration - name of integration (e.g. heroku) - * @param {Object} obj.res - response from OAuth2 authorization server - */ -const processOAuthTokenRes = async ({ - workspaceId, - integration, - res -}: { - workspaceId: string; - integration: string; - res: any; -}): Promise => { - let integrationAuth; - try { - // encrypt refresh + access tokens - const { - ciphertext: refreshCiphertext, - iv: refreshIV, - tag: refreshTag - } = encryptSymmetric({ - plaintext: res.data.refresh_token, - key: ENCRYPTION_KEY - }); - - const { - ciphertext: accessCiphertext, - iv: accessIV, - tag: accessTag - } = encryptSymmetric({ - plaintext: res.data.access_token, - key: ENCRYPTION_KEY - }); - - // compute access token expiration date - const accessExpiresAt = new Date(); - accessExpiresAt.setSeconds( - accessExpiresAt.getSeconds() + res.data.expires_in - ); - - // create or replace integration authorization with encrypted tokens - // and access token expiration date - integrationAuth = await IntegrationAuth.findOneAndUpdate( - { workspace: workspaceId, integration }, - { - workspace: workspaceId, - integration, - refreshCiphertext, - refreshIV, - refreshTag, - accessCiphertext, - accessIV, - accessTag, - accessExpiresAt - }, - { upsert: true, new: true } - ); - } catch (err) { - Sentry.setUser(null); - Sentry.captureException(err); - throw new Error( - 'Failed to process OAuth2 authorization server token response' - ); - } - - return integrationAuth; -}; - -/** - * Return access token for integration either by decrypting a non-expired access token [accessCiphertext] on - * the integration authorization document or by requesting a new one by decrypting and exchanging the - * refresh token [refreshCiphertext] with the respective OAuth2 authorization server. - * @param {Object} obj - * @param {IIntegrationAuth} obj.integrationAuth - an integration authorization document - * @returns {String} access token - new access token - */ -const getOAuthAccessToken = async ({ - integrationAuth -}: { - integrationAuth: IIntegrationAuth; -}) => { - let accessToken; - try { - const { - refreshCiphertext, - refreshIV, - refreshTag, - accessCiphertext, - accessIV, - accessTag, - accessExpiresAt - } = integrationAuth; - - if ( - refreshCiphertext && - refreshIV && - refreshTag && - accessCiphertext && - accessIV && - accessTag && - accessExpiresAt - ) { - if (accessExpiresAt < new Date()) { - // case: access token expired - // TODO: fetch another access token - - let clientSecret; - switch (integrationAuth.integration) { - case 'heroku': - clientSecret = OAUTH_CLIENT_SECRET_HEROKU; - } - - // record new access token and refresh token - // encrypt refresh + access tokens - const refreshToken = decryptSymmetric({ - ciphertext: refreshCiphertext, - iv: refreshIV, - tag: refreshTag, - key: ENCRYPTION_KEY - }); - - // TODO: make route compatible with other integration types - const res = await axios.post( - OAUTH_TOKEN_URL_HEROKU, // maybe shouldn't be a config variable? - new URLSearchParams({ - grant_type: 'refresh_token', - refresh_token: refreshToken, - client_secret: clientSecret - } as any) - ); - - accessToken = res.data.access_token; - - await processOAuthTokenRes({ - workspaceId: integrationAuth.workspace.toString(), - integration: integrationAuth.integration, - res - }); - } else { - // case: access token still works - accessToken = decryptSymmetric({ - ciphertext: accessCiphertext, - iv: accessIV, - tag: accessTag, - key: ENCRYPTION_KEY - }); - } - } - } catch (err) { - Sentry.setUser(null); - Sentry.captureException(err); - throw new Error('Failed to get OAuth2 access token'); - } - - return accessToken; -}; - -export { processOAuthTokenRes, getOAuthAccessToken }; diff --git a/backend/src/helpers/membership.ts b/backend/src/helpers/membership.ts index 14cd567bb..406162a8e 100644 --- a/backend/src/helpers/membership.ts +++ b/backend/src/helpers/membership.ts @@ -1,6 +1,46 @@ import * as Sentry from '@sentry/node'; import { Membership, Key } from '../models'; +/** + * Validate that user with id [userId] is a member of workspace with id [workspaceId] + * and has at least one of the roles in [acceptedRoles] + * @param {Object} obj + * @param {String} obj.userId - id of user to validate + * @param {String} obj.workspaceId - id of workspace + * @returns {Membership} membership - membership of user with id [userId] for workspace with id [workspaceId] + */ +const validateMembership = async ({ + userId, + workspaceId, + acceptedRoles, +}: { + userId: string; + workspaceId: string; + acceptedRoles: string[]; +}) => { + + let membership; + //TODO: Refactor code to take advantage of using RequestError. It's possible to create new types of errors for more detailed errors + try { + membership = await Membership.findOne({ + user: userId, + workspace: workspaceId + }).populate("workspace"); + + if (!membership) throw new Error('Failed to find membership'); + + if (!acceptedRoles.includes(membership.role)) { + throw new Error('Failed to validate membership role'); + } + } catch (err) { + Sentry.setUser(null); + Sentry.captureException(err); + throw new Error('Failed to validate membership'); + } + + return membership; +} + /** * Return membership matching criteria specified in query [queryObj] * @param {Object} queryObj - query object @@ -26,18 +66,15 @@ const findMembership = async (queryObj: any) => { * @param {String[]} obj.userIds - id of users. * @param {String} obj.workspaceId - id of workspace. * @param {String[]} obj.roles - roles of users. - * @param {String[]} obj.statuses - statuses of users. */ const addMemberships = async ({ userIds, workspaceId, - roles, - statuses + roles }: { userIds: string[]; workspaceId: string; roles: string[]; - statuses: string[]; }): Promise => { try { const operations = userIds.map((userId, idx) => { @@ -46,14 +83,12 @@ const addMemberships = async ({ filter: { user: userId, workspace: workspaceId, - role: roles[idx], - status: statuses[idx] + role: roles[idx] }, update: { user: userId, workspace: workspaceId, - role: roles[idx], - status: statuses[idx] + role: roles[idx] }, upsert: true } @@ -97,4 +132,9 @@ const deleteMembership = async ({ membershipId }: { membershipId: string }) => { return deletedMembership; }; -export { addMemberships, findMembership, deleteMembership }; +export { + validateMembership, + addMemberships, + findMembership, + deleteMembership +}; diff --git a/backend/src/helpers/membershipOrg.ts b/backend/src/helpers/membershipOrg.ts index 42164b8e4..4de4be82d 100644 --- a/backend/src/helpers/membershipOrg.ts +++ b/backend/src/helpers/membershipOrg.ts @@ -1,6 +1,42 @@ import * as Sentry from '@sentry/node'; +import { Types } from 'mongoose'; import { MembershipOrg, Workspace, Membership, Key } from '../models'; +/** + * Validate that user with id [userId] is a member of organization with id [organizationId] + * and has at least one of the roles in [acceptedRoles] + * + */ +const validateMembership = async ({ + userId, + organizationId, + acceptedRoles +}: { + userId: string; + organizationId: string; + acceptedRoles: string[]; +}) => { + let membership; + try { + membership = await MembershipOrg.findOne({ + user: new Types.ObjectId(userId), + organization: new Types.ObjectId(organizationId) + }); + + if (!membership) throw new Error('Failed to find organization membership'); + + if (!acceptedRoles.includes(membership.role)) { + throw new Error('Failed to validate organization membership role'); + } + } catch (err) { + Sentry.setUser(null); + Sentry.captureException(err); + throw new Error('Failed to validate organization membership'); + } + + return membership; +} + /** * Return organization membership matching criteria specified in * query [queryObj] @@ -84,6 +120,8 @@ const deleteMembershipOrg = async ({ _id: membershipOrgId }); + if (!deletedMembershipOrg) throw new Error('Failed to delete organization membership'); + // delete keys associated with organization membership if (deletedMembershipOrg?.user) { // case: organization membership had a registered user @@ -117,4 +155,9 @@ const deleteMembershipOrg = async ({ return deletedMembershipOrg; }; -export { findMembershipOrg, addMembershipsOrg, deleteMembershipOrg }; +export { + validateMembership, + findMembershipOrg, + addMembershipsOrg, + deleteMembershipOrg +}; diff --git a/backend/src/helpers/nodemailer.ts b/backend/src/helpers/nodemailer.ts index 1c92af93f..958342aae 100644 --- a/backend/src/helpers/nodemailer.ts +++ b/backend/src/helpers/nodemailer.ts @@ -2,40 +2,10 @@ import fs from 'fs'; import path from 'path'; import handlebars from 'handlebars'; import nodemailer from 'nodemailer'; -import { - SMTP_HOST, - SMTP_PORT, - SMTP_NAME, - SMTP_USERNAME, - SMTP_PASSWORD -} from '../config'; -import SMTPConnection from 'nodemailer/lib/smtp-connection'; +import { SMTP_FROM_NAME, SMTP_FROM_ADDRESS } from '../config'; import * as Sentry from '@sentry/node'; -const mailOpts: SMTPConnection.Options = { - host: SMTP_HOST, - port: SMTP_PORT as number -}; -if (SMTP_USERNAME && SMTP_PASSWORD) { - mailOpts.auth = { - user: SMTP_USERNAME, - pass: SMTP_PASSWORD - }; -} -// create nodemailer transporter -const transporter = nodemailer.createTransport(mailOpts); -transporter - .verify() - .then(() => { - Sentry.setUser(null); - Sentry.captureMessage('SMTP - Successfully connected'); - }) - .catch((err) => { - Sentry.setUser(null); - Sentry.captureException( - `SMTP - Failed to connect to ${SMTP_HOST}:${SMTP_PORT} \n\t${err}` - ); - }); +let smtpTransporter: nodemailer.Transporter; /** * @param {Object} obj @@ -63,8 +33,8 @@ const sendMail = async ({ const temp = handlebars.compile(html); const htmlToSend = temp(substitutions); - await transporter.sendMail({ - from: `"${SMTP_NAME}" <${SMTP_USERNAME}>`, + await smtpTransporter.sendMail({ + from: `"${SMTP_FROM_NAME}" <${SMTP_FROM_ADDRESS}>`, to: recipients.join(', '), subject: subjectLine, html: htmlToSend @@ -75,4 +45,8 @@ const sendMail = async ({ } }; -export { sendMail }; +const setTransporter = (transporter: nodemailer.Transporter) => { + smtpTransporter = transporter; +}; + +export { sendMail, setTransporter }; diff --git a/backend/src/helpers/organization.ts b/backend/src/helpers/organization.ts index e47f92fbe..4ba3592de 100644 --- a/backend/src/helpers/organization.ts +++ b/backend/src/helpers/organization.ts @@ -3,6 +3,7 @@ import Stripe from 'stripe'; import { STRIPE_SECRET_KEY, STRIPE_PRODUCT_STARTER, + STRIPE_PRODUCT_TEAM, STRIPE_PRODUCT_PRO } from '../config'; const stripe = new Stripe(STRIPE_SECRET_KEY, { @@ -14,6 +15,7 @@ import { Organization, MembershipOrg } from '../models'; const productToPriceMap = { starter: STRIPE_PRODUCT_STARTER, + team: STRIPE_PRODUCT_TEAM, pro: STRIPE_PRODUCT_PRO }; @@ -55,7 +57,7 @@ const createOrganization = async ({ } catch (err) { Sentry.setUser({ email }); Sentry.captureException(err); - throw new Error('Failed to create organization'); + throw new Error(`Failed to create organization [err=${err}]`); } return organization; diff --git a/backend/src/helpers/rateLimiter.ts b/backend/src/helpers/rateLimiter.ts index 6153369e3..432bd5f97 100644 --- a/backend/src/helpers/rateLimiter.ts +++ b/backend/src/helpers/rateLimiter.ts @@ -1,36 +1,43 @@ import rateLimit from 'express-rate-limit'; -// 300 requests per 15 minutes +// 120 requests per minute const apiLimiter = rateLimit({ - windowMs: 15 * 60 * 1000, - max: 400, + windowMs: 60 * 1000, + max: 240, standardHeaders: true, legacyHeaders: false, - skip: (request) => request.path === '/healthcheck' + skip: (request) => { + return request.path === '/healthcheck' || request.path === '/api/status' + }, + keyGenerator: (req, res) => { + return req.clientIp + } }); -// 5 requests per hour -const signupLimiter = rateLimit({ - windowMs: 60 * 60 * 1000, +// 10 requests per minute +const authLimiter = rateLimit({ + windowMs: 60 * 1000, max: 10, standardHeaders: true, - legacyHeaders: false + legacyHeaders: false, + keyGenerator: (req, res) => { + return req.clientIp + } }); // 10 requests per hour -const loginLimiter = rateLimit({ - windowMs: 60 * 60 * 1000, - max: 20, - standardHeaders: true, - legacyHeaders: false -}); - -// 5 requests per hour const passwordLimiter = rateLimit({ windowMs: 60 * 60 * 1000, max: 10, standardHeaders: true, - legacyHeaders: false + legacyHeaders: false, + keyGenerator: (req, res) => { + return req.clientIp + } }); -export { apiLimiter, signupLimiter, loginLimiter, passwordLimiter }; +export { + apiLimiter, + authLimiter, + passwordLimiter +}; diff --git a/backend/src/helpers/secret.ts b/backend/src/helpers/secret.ts index 042aba4fa..a16d114c6 100644 --- a/backend/src/helpers/secret.ts +++ b/backend/src/helpers/secret.ts @@ -1,12 +1,81 @@ import * as Sentry from '@sentry/node'; +import { Types } from 'mongoose'; import { Secret, - ISecret + ISecret, + Membership } from '../models'; -import { decryptSymmetric } from '../utils/crypto'; -import { SECRET_SHARED, SECRET_PERSONAL } from '../variables'; +import { + EESecretService, + EELogService +} from '../ee/services'; +import { + IAction +} from '../ee/models'; +import { + SECRET_SHARED, + SECRET_PERSONAL, + ACTION_ADD_SECRETS, + ACTION_UPDATE_SECRETS, + ACTION_DELETE_SECRETS, + ACTION_READ_SECRETS +} from '../variables'; +import _ from 'lodash'; +import { ABILITY_WRITE } from '../variables/organization'; +import { BadRequestError, UnauthorizedRequestError } from '../utils/errors'; -interface PushSecret { +/** + * Validate that user with id [userId] can modify secrets with ids [secretIds] + * @param {Object} obj + * @param {Object} obj.userId - id of user to validate + * @param {Object} obj.secretIds - secret ids + * @returns {Secret[]} secrets + */ +const validateSecrets = async ({ + userId, + secretIds +}: { + userId: string; + secretIds: string[]; +}) => { + let secrets; + try { + secrets = await Secret.find({ + _id: { + $in: secretIds.map((secretId: string) => new Types.ObjectId(secretId)) + } + }); + + if (secrets.length != secretIds.length) { + throw BadRequestError({ message: 'Unable to validate some secrets' }) + } + + const userMemberships = await Membership.find({ user: userId }) + const userMembershipById = _.keyBy(userMemberships, 'workspace'); + const workspaceIdsSet = new Set(userMemberships.map((m) => m.workspace.toString())); + + // for each secret check if the secret belongs to a workspace the user is a member of + secrets.forEach((secret: ISecret) => { + if (workspaceIdsSet.has(secret.workspace.toString())) { + const deniedMembershipPermissions = userMembershipById[secret.workspace.toString()].deniedPermissions; + const isDisallowed = _.some(deniedMembershipPermissions, { environmentSlug: secret.environment, ability: ABILITY_WRITE }); + + if (isDisallowed) { + throw UnauthorizedRequestError({ message: 'You do not have the required permissions to perform this action' }); + } + } else { + throw BadRequestError({ message: 'You cannot edit secrets of a workspace you are not a member of' }); + } + }); + + } catch (err) { + throw BadRequestError({ message: 'Unable to validate secrets' }) + } + + return secrets; +} + +interface V1PushSecret { ciphertextKey: string; ivKey: string; tagKey: string; @@ -15,14 +84,32 @@ interface PushSecret { ivValue: string; tagValue: string; hashValue: string; + ciphertextComment: string; + ivComment: string; + tagComment: string; + hashComment: string; type: 'shared' | 'personal'; } -interface Update { - [index: string]: string; +interface V2PushSecret { + type: string; // personal or shared + secretKeyCiphertext: string; + secretKeyIV: string; + secretKeyTag: string; + secretKeyHash: string; + secretValueCiphertext: string; + secretValueIV: string; + secretValueTag: string; + secretValueHash: string; + secretCommentCiphertext?: string; + secretCommentIV?: string; + secretCommentTag?: string; + secretCommentHash?: string; } -type DecryptSecretType = 'text' | 'object' | 'expanded'; +interface Update { + [index: string]: any; +} /** * Push secrets for user with id [userId] to workspace @@ -35,92 +122,155 @@ type DecryptSecretType = 'text' | 'object' | 'expanded'; * @param {String} obj.environment - environment for secrets * @param {Object[]} obj.secrets - secrets to push */ -const pushSecrets = async ({ +const v1PushSecrets = async ({ userId, workspaceId, environment, - secrets + secrets, }: { userId: string; workspaceId: string; environment: string; - secrets: PushSecret[]; + secrets: V1PushSecret[]; }): Promise => { + // TODO: clean up function and fix up types try { // construct useful data structures - const oldSecrets = await pullSecrets({ + const oldSecrets = await getSecrets({ userId, workspaceId, environment }); - const oldSecretsObj: any = oldSecrets.reduce((accumulator, s: any) => { - return { ...accumulator, [s.secretKeyHash]: s }; - }, {}); - const newSecretsObj = secrets.reduce((accumulator, s) => { - return { ...accumulator, [s.hashKey]: s }; - }, {}); + + const oldSecretsObj: any = oldSecrets.reduce((accumulator, s: any) => + ({ ...accumulator, [`${s.type}-${s.secretKeyHash}`]: s }) + , {}); + const newSecretsObj: any = secrets.reduce((accumulator, s) => + ({ ...accumulator, [`${s.type}-${s.hashKey}`]: s }) + , {}); // handle deleting secrets - const toDelete = oldSecrets.filter( - (s: ISecret) => !(s.secretKeyHash in newSecretsObj) - ); + const toDelete = oldSecrets + .filter( + (s: ISecret) => !(`${s.type}-${s.secretKeyHash}` in newSecretsObj) + ) + .map((s) => s._id); if (toDelete.length > 0) { await Secret.deleteMany({ - _id: { $in: toDelete.map((s) => s._id) } + _id: { $in: toDelete } + }); + + await EESecretService.markDeletedSecretVersions({ + secretIds: toDelete }); } - // handle modifying secrets where type or value changed - const operations = secrets + const toUpdate = oldSecrets .filter((s) => { - if (s.hashKey in oldSecretsObj) { - if (s.hashValue !== oldSecretsObj[s.hashKey].secretValueHash) { - // case: filter secrets where value changed + if (`${s.type}-${s.secretKeyHash}` in newSecretsObj) { + if (s.secretValueHash !== newSecretsObj[`${s.type}-${s.secretKeyHash}`].hashValue + || s.secretCommentHash !== newSecretsObj[`${s.type}-${s.secretKeyHash}`].hashComment) { + // case: filter secrets where value or comment changed return true; } - if (s.type !== oldSecretsObj[s.hashKey].type) { - // case: filter secrets where type changed + if (!s.version) { + // case: filter (legacy) secrets that were not versioned return true; } } return false; - }) + }); + + const operations = toUpdate .map((s) => { + const { + ciphertextValue, + ivValue, + tagValue, + hashValue, + ciphertextComment, + ivComment, + tagComment, + hashComment + } = newSecretsObj[`${s.type}-${s.secretKeyHash}`]; + const update: Update = { - type: s.type, - secretValueCiphertext: s.ciphertextValue, - secretValueIV: s.ivValue, - secretValueTag: s.tagValue, - secretValueHash: s.hashValue - }; + secretValueCiphertext: ciphertextValue, + secretValueIV: ivValue, + secretValueTag: tagValue, + secretValueHash: hashValue, + secretCommentCiphertext: ciphertextComment, + secretCommentIV: ivComment, + secretCommentTag: tagComment, + secretCommentHash: hashComment, + } + + if (!s.version) { + // case: (legacy) secret was not versioned + update.version = 1; + } else { + update['$inc'] = { + version: 1 + } + } if (s.type === SECRET_PERSONAL) { - // attach user assocaited with the personal secret + // attach user associated with the personal secret update['user'] = userId; } return { updateOne: { filter: { - workspace: workspaceId, - _id: oldSecretsObj[s.hashKey]._id + _id: oldSecretsObj[`${s.type}-${s.secretKeyHash}`]._id }, update } }; }); - const a = await Secret.bulkWrite(operations as any); + await Secret.bulkWrite(operations as any); + + // (EE) add secret versions for updated secrets + await EESecretService.addSecretVersions({ + secretVersions: toUpdate.map(({ + _id, + version, + type, + secretKeyHash, + }) => { + const newSecret = newSecretsObj[`${type}-${secretKeyHash}`]; + return ({ + _id: new Types.ObjectId(), + secret: _id, + version: version ? version + 1 : 1, + workspace: new Types.ObjectId(workspaceId), + type: newSecret.type, + user: new Types.ObjectId(userId), + environment, + isDeleted: false, + secretKeyCiphertext: newSecret.ciphertextKey, + secretKeyIV: newSecret.ivKey, + secretKeyTag: newSecret.tagKey, + secretKeyHash: newSecret.hashKey, + secretValueCiphertext: newSecret.ciphertextValue, + secretValueIV: newSecret.ivValue, + secretValueTag: newSecret.tagValue, + secretValueHash: newSecret.hashValue + }) + }) + }); // handle adding new secrets - const toAdd = secrets.filter((s) => !(s.hashKey in oldSecretsObj)); + const toAdd = secrets.filter((s) => !(`${s.type}-${s.hashKey}` in oldSecretsObj)); if (toAdd.length > 0) { // add secrets - await Secret.insertMany( + const newSecrets = await Secret.insertMany( toAdd.map((s, idx) => { - let obj: any = { + const obj: any = { + version: 1, workspace: workspaceId, type: toAdd[idx].type, environment, @@ -131,7 +281,11 @@ const pushSecrets = async ({ secretValueCiphertext: s.ciphertextValue, secretValueIV: s.ivValue, secretValueTag: s.tagValue, - secretValueHash: s.hashValue + secretValueHash: s.hashValue, + secretCommentCiphertext: s.ciphertextComment, + secretCommentIV: s.ivComment, + secretCommentTag: s.tagComment, + secretCommentHash: s.hashComment }; if (toAdd[idx].type === 'personal') { @@ -141,6 +295,270 @@ const pushSecrets = async ({ return obj; }) ); + + // (EE) add secret versions for new secrets + EESecretService.addSecretVersions({ + secretVersions: newSecrets.map(({ + _id, + version, + workspace, + type, + user, + environment, + secretKeyCiphertext, + secretKeyIV, + secretKeyTag, + secretKeyHash, + secretValueCiphertext, + secretValueIV, + secretValueTag, + secretValueHash + }) => ({ + _id: new Types.ObjectId(), + secret: _id, + version, + workspace, + type, + user, + environment, + isDeleted: false, + secretKeyCiphertext, + secretKeyIV, + secretKeyTag, + secretKeyHash, + secretValueCiphertext, + secretValueIV, + secretValueTag, + secretValueHash + })) + }); + } + + // (EE) take a secret snapshot + await EESecretService.takeSecretSnapshot({ + workspaceId + }); + } catch (err) { + Sentry.setUser(null); + Sentry.captureException(err); + throw new Error('Failed to push shared and personal secrets'); + } +}; + +/** + * Push secrets for user with id [userId] to workspace + * with id [workspaceId] with environment [environment]. Follow steps: + * 1. Handle shared secrets (insert, delete) + * 2. handle personal secrets (insert, delete) + * @param {Object} obj + * @param {String} obj.userId - id of user to push secrets for + * @param {String} obj.workspaceId - id of workspace to push to + * @param {String} obj.environment - environment for secrets + * @param {Object[]} obj.secrets - secrets to push + * @param {String} obj.channel - channel (web/cli/auto) + * @param {String} obj.ipAddress - ip address of request to push secrets + */ +const v2PushSecrets = async ({ + userId, + workspaceId, + environment, + secrets, + channel, + ipAddress +}: { + userId: string; + workspaceId: string; + environment: string; + secrets: V2PushSecret[]; + channel: string; + ipAddress: string; +}): Promise => { + // TODO: clean up function and fix up types + try { + const actions: IAction[] = []; + + // construct useful data structures + const oldSecrets = await getSecrets({ + userId, + workspaceId, + environment + }); + + const oldSecretsObj: any = oldSecrets.reduce((accumulator, s: any) => + ({ ...accumulator, [`${s.type}-${s.secretKeyHash}`]: s }) + , {}); + const newSecretsObj: any = secrets.reduce((accumulator, s) => + ({ ...accumulator, [`${s.type}-${s.secretKeyHash}`]: s }) + , {}); + + // handle deleting secrets + const toDelete = oldSecrets + .filter( + (s: ISecret) => !(`${s.type}-${s.secretKeyHash}` in newSecretsObj) + ) + .map((s) => s._id); + if (toDelete.length > 0) { + await Secret.deleteMany({ + _id: { $in: toDelete } + }); + + await EESecretService.markDeletedSecretVersions({ + secretIds: toDelete + }); + + const deleteAction = await EELogService.createActionSecret({ + name: ACTION_DELETE_SECRETS, + userId, + workspaceId, + secretIds: toDelete + }); + + deleteAction && actions.push(deleteAction); + } + + const toUpdate = oldSecrets + .filter((s) => { + if (`${s.type}-${s.secretKeyHash}` in newSecretsObj) { + if (s.secretValueHash !== newSecretsObj[`${s.type}-${s.secretKeyHash}`].secretValueHash + || s.secretCommentHash !== newSecretsObj[`${s.type}-${s.secretKeyHash}`].secretCommentHash) { + // case: filter secrets where value or comment changed + return true; + } + + if (!s.version) { + // case: filter (legacy) secrets that were not versioned + return true; + } + } + + return false; + }); + + if (toUpdate.length > 0) { + const operations = toUpdate + .map((s) => { + const { + secretValueCiphertext, + secretValueIV, + secretValueTag, + secretValueHash, + secretCommentCiphertext, + secretCommentIV, + secretCommentTag, + secretCommentHash, + } = newSecretsObj[`${s.type}-${s.secretKeyHash}`]; + + const update: Update = { + secretValueCiphertext, + secretValueIV, + secretValueTag, + secretValueHash, + secretCommentCiphertext, + secretCommentIV, + secretCommentTag, + secretCommentHash, + } + + if (!s.version) { + // case: (legacy) secret was not versioned + update.version = 1; + } else { + update['$inc'] = { + version: 1 + } + } + + if (s.type === SECRET_PERSONAL) { + // attach user associated with the personal secret + update['user'] = userId; + } + + return { + updateOne: { + filter: { + _id: oldSecretsObj[`${s.type}-${s.secretKeyHash}`]._id + }, + update + } + }; + }); + await Secret.bulkWrite(operations as any); + + // (EE) add secret versions for updated secrets + await EESecretService.addSecretVersions({ + secretVersions: toUpdate.map((s) => { + return ({ + ...newSecretsObj[`${s.type}-${s.secretKeyHash}`], + secret: s._id, + version: s.version ? s.version + 1 : 1, + workspace: new Types.ObjectId(workspaceId), + user: s.user, + environment: s.environment, + isDeleted: false + }) + }) + }); + + const updateAction = await EELogService.createActionSecret({ + name: ACTION_UPDATE_SECRETS, + userId, + workspaceId, + secretIds: toUpdate.map((u) => u._id) + }); + + updateAction && actions.push(updateAction); + } + + // handle adding new secrets + const toAdd = secrets.filter((s) => !(`${s.type}-${s.secretKeyHash}` in oldSecretsObj)); + + if (toAdd.length > 0) { + // add secrets + const newSecrets = await Secret.insertMany( + toAdd.map((s, idx) => ({ + ...s, + version: 1, + workspace: workspaceId, + type: toAdd[idx].type, + environment, + ...(toAdd[idx].type === 'personal' ? { user: userId } : {}) + })) + ); + + // (EE) add secret versions for new secrets + EESecretService.addSecretVersions({ + secretVersions: newSecrets.map((secretDocument) => { + return { + ...secretDocument.toObject(), + secret: secretDocument._id, + isDeleted: false + } + }) + }); + + const addAction = await EELogService.createActionSecret({ + name: ACTION_ADD_SECRETS, + userId, + workspaceId, + secretIds: newSecrets.map((n) => n._id) + }); + addAction && actions.push(addAction); + } + + // (EE) take a secret snapshot + await EESecretService.takeSecretSnapshot({ + workspaceId + }) + + // (EE) create (audit) log + if (actions.length > 0) { + await EELogService.createLog({ + userId, + workspaceId, + actions, + channel, + ipAddress + }); } } catch (err) { Sentry.setUser(null); @@ -150,15 +568,14 @@ const pushSecrets = async ({ }; /** - * Pull secrets for user with id [userId] for workspace + * Get secrets for user with id [userId] for workspace * with id [workspaceId] with environment [environment] * @param {Object} obj * @param {String} obj.userId -id of user to pull secrets for * @param {String} obj.workspaceId - id of workspace to pull from * @param {String} obj.environment - environment for secrets - * */ -const pullSecrets = async ({ +const getSecrets = async ({ userId, workspaceId, environment @@ -168,6 +585,7 @@ const pullSecrets = async ({ environment: string; }): Promise => { let secrets: any; // TODO: FIX any + try { // get shared workspace secrets const sharedSecrets = await Secret.find({ @@ -195,9 +613,64 @@ const pullSecrets = async ({ return secrets; }; +/** + * Pull secrets for user with id [userId] for workspace + * with id [workspaceId] with environment [environment] + * @param {Object} obj + * @param {String} obj.userId -id of user to pull secrets for + * @param {String} obj.workspaceId - id of workspace to pull from + * @param {String} obj.environment - environment for secrets + * @param {String} obj.channel - channel (web/cli/auto) + * @param {String} obj.ipAddress - ip address of request to push secrets + */ +const pullSecrets = async ({ + userId, + workspaceId, + environment, + channel, + ipAddress +}: { + userId: string; + workspaceId: string; + environment: string; + channel: string; + ipAddress: string; +}): Promise => { + let secrets: any; + + try { + secrets = await getSecrets({ + userId, + workspaceId, + environment + }) + + const readAction = await EELogService.createActionSecret({ + name: ACTION_READ_SECRETS, + userId, + workspaceId, + secretIds: secrets.map((n: any) => n._id) + }); + + readAction && await EELogService.createLog({ + userId, + workspaceId, + actions: [readAction], + channel, + ipAddress + }); + } catch (err) { + Sentry.setUser(null); + Sentry.captureException(err); + throw new Error('Failed to pull shared and personal secrets'); + } + + return secrets; +}; + /** * Reformat output of pullSecrets() to be compatible with how existing - * clients handle secrets + * web client handle secrets * @param {Object} obj * @param {Object} obj.secrets */ @@ -222,6 +695,13 @@ const reformatPullSecrets = ({ secrets }: { secrets: ISecret[] }) => { iv: s.secretValueIV, tag: s.secretValueTag, hash: s.secretValueHash + }, + secretComment: { + workspace: s.workspace, + ciphertext: s.secretCommentCiphertext, + iv: s.secretCommentIV, + tag: s.secretCommentTag, + hash: s.secretCommentHash } })); } catch (err) { @@ -233,71 +713,10 @@ const reformatPullSecrets = ({ secrets }: { secrets: ISecret[] }) => { return reformatedSecrets; }; -/** - * Return decrypted secrets in format [format] - * @param {Object} obj - * @param {Object[]} obj.secrets - array of (encrypted) secret key-value pair objects - * @param {String} obj.key - symmetric key to decrypt secret key-value pairs - * @param {String} obj.format - desired return format that is either "text," "object," or "expanded" - * @return {String|Object} (decrypted) secrets also called the content - */ -const decryptSecrets = ({ - secrets, - key, - format -}: { - secrets: PushSecret[]; - key: string; - format: DecryptSecretType; -}) => { - // init content - let content: any = format === 'text' ? '' : {}; - - // decrypt secrets - secrets.forEach((s, idx) => { - const secretKey = decryptSymmetric({ - ciphertext: s.ciphertextKey, - iv: s.ivKey, - tag: s.tagKey, - key - }); - - const secretValue = decryptSymmetric({ - ciphertext: s.ciphertextValue, - iv: s.ivValue, - tag: s.tagValue, - key - }); - - switch (format) { - case 'text': - content += secretKey; - content += '='; - content += secretValue; - - if (idx < secrets.length) { - content += '\n'; - } - break; - case 'object': - content[secretKey] = secretValue; - break; - case 'expanded': - content[secretKey] = { - ...s, - plaintextKey: secretKey, - plaintextValue: secretValue - }; - break; - } - }); - - return content; -}; - export { - pushSecrets, + validateSecrets, + v1PushSecrets, + v2PushSecrets, pullSecrets, - reformatPullSecrets, - decryptSecrets + reformatPullSecrets }; diff --git a/backend/src/helpers/signup.ts b/backend/src/helpers/signup.ts index 8a201cb11..1ef1219f8 100644 --- a/backend/src/helpers/signup.ts +++ b/backend/src/helpers/signup.ts @@ -5,7 +5,7 @@ import { createOrganization } from './organization'; import { addMembershipsOrg } from './membershipOrg'; import { createWorkspace } from './workspace'; import { addMemberships } from './membership'; -import { OWNER, ADMIN, ACCEPTED, GRANTED } from '../variables'; +import { OWNER, ADMIN, ACCEPTED } from '../variables'; import { sendMail } from '../helpers/nodemailer'; /** @@ -66,7 +66,7 @@ const checkEmailVerification = async ({ email, token: code }); - + if (!token) throw new Error('Failed to find email verification token'); } catch (err) { Sentry.setUser(null); @@ -113,11 +113,10 @@ const initializeDefaultOrg = async ({ await addMemberships({ userIds: [user._id.toString()], workspaceId: workspace._id.toString(), - roles: [ADMIN], - statuses: [GRANTED] + roles: [ADMIN] }); } catch (err) { - throw new Error('Failed to initialize default organization and workspace'); + throw new Error(`Failed to initialize default organization and workspace [err=${err}]`); } }; diff --git a/backend/src/helpers/workspace.ts b/backend/src/helpers/workspace.ts index 52d7d227b..b43252bf3 100644 --- a/backend/src/helpers/workspace.ts +++ b/backend/src/helpers/workspace.ts @@ -1,13 +1,16 @@ import * as Sentry from '@sentry/node'; import { Workspace, + Bot, Membership, Key, Secret } from '../models'; +import { createBot } from '../helpers/bot'; /** * Create a workspace with name [name] in organization with id [organizationId] + * and a bot for it. * @param {String} name - name of workspace to create. * @param {String} organizationId - id of organization to create workspace in * @param {Object} workspace - new workspace @@ -21,10 +24,16 @@ const createWorkspace = async ({ }) => { let workspace; try { + // create workspace workspace = await new Workspace({ name, organization: organizationId }).save(); + + const bot = await createBot({ + name: 'Infisical Bot', + workspaceId: workspace._id.toString() + }); } catch (err) { Sentry.setUser(null); Sentry.captureException(err); @@ -43,6 +52,9 @@ const createWorkspace = async ({ const deleteWorkspace = async ({ id }: { id: string }) => { try { await Workspace.deleteOne({ _id: id }); + await Bot.deleteOne({ + workspace: id + }); await Membership.deleteMany({ workspace: id }); diff --git a/backend/src/index.ts b/backend/src/index.ts index 28e27cc9a..a97b5b33b 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -1,127 +1,28 @@ -/* eslint-disable no-console */ -import http from 'http'; -import express from 'express'; -import helmet from 'helmet'; -import cors from 'cors'; -import cookieParser from 'cookie-parser'; -import mongoose from 'mongoose'; import dotenv from 'dotenv'; - dotenv.config(); + import * as Sentry from '@sentry/node'; -import { PORT, SENTRY_DSN, NODE_ENV, MONGO_URL, SITE_URL } from './config'; -import { apiLimiter } from './helpers/rateLimiter'; -import { createTerminus } from '@godaddy/terminus'; +import { SENTRY_DSN, NODE_ENV, MONGO_URL } from './config'; +import { server } from './app'; +import { DatabaseService } from './services'; +import { setUpHealthEndpoint } from './services/health'; +import { initSmtp } from './services/smtp'; +import { setTransporter } from './helpers/nodemailer'; +import { createTestUserForDevelopment } from './utils/addDevelopmentUser'; -const app = express(); +DatabaseService.initDatabase(MONGO_URL); -Sentry.init({ - dsn: SENTRY_DSN, - tracesSampleRate: 1.0, - debug: NODE_ENV === 'production' ? false : true, - environment: NODE_ENV -}); +setUpHealthEndpoint(server); -import { - signup as signupRouter, - auth as authRouter, - organization as organizationRouter, - workspace as workspaceRouter, - membershipOrg as membershipOrgRouter, - membership as membershipRouter, - key as keyRouter, - inviteOrg as inviteOrgRouter, - user as userRouter, - userAction as userActionRouter, - secret as secretRouter, - serviceToken as serviceTokenRouter, - password as passwordRouter, - stripe as stripeRouter, - integration as integrationRouter, - integrationAuth as integrationAuthRouter -} from './routes'; +setTransporter(initSmtp()); -const connectWithRetry = () => { - mongoose - .connect(MONGO_URL) - .then(() => console.log('Successfully connected to DB')) - .catch((e) => { - console.log('Failed to connect to DB ', e); - setTimeout(() => { - console.log(e); - }, 5000); - }); - return mongoose.connection; -}; - -const dbConnection = connectWithRetry(); - -app.enable('trust proxy'); -app.use(cookieParser()); -app.use( - cors({ - credentials: true, - origin: SITE_URL - }) -); - -if (NODE_ENV === 'production') { - // enable app-wide rate-limiting + helmet security - // in production - app.disable('x-powered-by'); - app.use(apiLimiter); - app.use(helmet()); +if (NODE_ENV !== 'test') { + Sentry.init({ + dsn: SENTRY_DSN, + tracesSampleRate: 1.0, + debug: NODE_ENV === 'production' ? false : true, + environment: NODE_ENV + }); } -app.use(express.json()); - -// routers -app.use('/api/v1/signup', signupRouter); -app.use('/api/v1/auth', authRouter); -app.use('/api/v1/user', userRouter); -app.use('/api/v1/user-action', userActionRouter); -app.use('/api/v1/organization', organizationRouter); -app.use('/api/v1/workspace', workspaceRouter); -app.use('/api/v1/membership-org', membershipOrgRouter); -app.use('/api/v1/membership', membershipRouter); -app.use('/api/v1/key', keyRouter); -app.use('/api/v1/invite-org', inviteOrgRouter); -app.use('/api/v1/secret', secretRouter); -app.use('/api/v1/service-token', serviceTokenRouter); -app.use('/api/v1/password', passwordRouter); -app.use('/api/v1/stripe', stripeRouter); -app.use('/api/v1/integration', integrationRouter); -app.use('/api/v1/integration-auth', integrationAuthRouter); - -const server = http.createServer(app); - -const onSignal = () => { - console.log('Server is starting clean-up'); - return Promise.all([ - () => { - dbConnection.close(() => { - console.info('Database connection closed'); - }); - } - ]); -}; - -const healthCheck = () => { - // `state.isShuttingDown` (boolean) shows whether the server is shutting down or not - return Promise - .resolve - // optionally include a resolve value to be included as - // info in the health check response - (); -}; - -createTerminus(server, { - healthChecks: { - '/healthcheck': healthCheck, - onSignal - } -}); - -server.listen(PORT, () => { - console.log('Listening on PORT ' + PORT); -}); +createTestUserForDevelopment() diff --git a/backend/src/integrations/apps.ts b/backend/src/integrations/apps.ts new file mode 100644 index 000000000..d1252954e --- /dev/null +++ b/backend/src/integrations/apps.ts @@ -0,0 +1,322 @@ +import axios from 'axios'; +import * as Sentry from '@sentry/node'; +import { Octokit } from '@octokit/rest'; +import { IIntegrationAuth } from '../models'; +import { + INTEGRATION_HEROKU, + INTEGRATION_VERCEL, + INTEGRATION_NETLIFY, + INTEGRATION_GITHUB, + INTEGRATION_RENDER, + INTEGRATION_FLYIO, + INTEGRATION_HEROKU_API_URL, + INTEGRATION_VERCEL_API_URL, + INTEGRATION_NETLIFY_API_URL, + INTEGRATION_RENDER_API_URL, + INTEGRATION_FLYIO_API_URL +} from '../variables'; + +/** + * Return list of names of apps for integration named [integration] + * @param {Object} obj + * @param {String} obj.integration - name of integration + * @param {String} obj.accessToken - access token for integration + * @returns {Object[]} apps - names of integration apps + * @returns {String} apps.name - name of integration app + */ +const getApps = async ({ + integrationAuth, + accessToken +}: { + integrationAuth: IIntegrationAuth; + accessToken: string; +}) => { + interface App { + name: string; + appId?: string; + owner?: string; + } + + let apps: App[]; + try { + switch (integrationAuth.integration) { + case INTEGRATION_HEROKU: + apps = await getAppsHeroku({ + accessToken + }); + break; + case INTEGRATION_VERCEL: + apps = await getAppsVercel({ + integrationAuth, + accessToken + }); + break; + case INTEGRATION_NETLIFY: + apps = await getAppsNetlify({ + accessToken + }); + break; + case INTEGRATION_GITHUB: + apps = await getAppsGithub({ + accessToken + }); + break; + case INTEGRATION_RENDER: + apps = await getAppsRender({ + accessToken + }); + break; + case INTEGRATION_FLYIO: + apps = await getAppsFlyio({ + accessToken + }); + break; + } + } catch (err) { + Sentry.setUser(null); + Sentry.captureException(err); + throw new Error('Failed to get integration apps'); + } + + return apps; +}; + +/** + * Return list of apps for Heroku integration + * @param {Object} obj + * @param {String} obj.accessToken - access token for Heroku API + * @returns {Object[]} apps - names of Heroku apps + * @returns {String} apps.name - name of Heroku app + */ +const getAppsHeroku = async ({ accessToken }: { accessToken: string }) => { + let apps; + try { + const res = ( + await axios.get(`${INTEGRATION_HEROKU_API_URL}/apps`, { + headers: { + Accept: 'application/vnd.heroku+json; version=3', + Authorization: `Bearer ${accessToken}` + } + }) + ).data; + + apps = res.map((a: any) => ({ + name: a.name + })); + } catch (err) { + Sentry.setUser(null); + Sentry.captureException(err); + throw new Error('Failed to get Heroku integration apps'); + } + + return apps; +}; + +/** + * Return list of names of apps for Vercel integration + * @param {Object} obj + * @param {String} obj.accessToken - access token for Vercel API + * @returns {Object[]} apps - names of Vercel apps + * @returns {String} apps.name - name of Vercel app + */ +const getAppsVercel = async ({ + integrationAuth, + accessToken +}: { + integrationAuth: IIntegrationAuth; + accessToken: string; +}) => { + let apps; + try { + const res = ( + await axios.get(`${INTEGRATION_VERCEL_API_URL}/v9/projects`, { + headers: { + Authorization: `Bearer ${accessToken}` + }, + ...( integrationAuth?.teamId ? { + params: { + teamId: integrationAuth.teamId + } + } : {}) + }) + ).data; + + apps = res.projects.map((a: any) => ({ + name: a.name + })); + } catch (err) { + Sentry.setUser(null); + Sentry.captureException(err); + throw new Error('Failed to get Vercel integration apps'); + } + + return apps; +}; + +/** + * Return list of sites for Netlify integration + * @param {Object} obj + * @param {String} obj.accessToken - access token for Netlify API + * @returns {Object[]} apps - names of Netlify sites + * @returns {String} apps.name - name of Netlify site + */ +const getAppsNetlify = async ({ + accessToken +}: { + accessToken: string; +}) => { + let apps; + try { + const res = ( + await axios.get(`${INTEGRATION_NETLIFY_API_URL}/api/v1/sites`, { + headers: { + Authorization: `Bearer ${accessToken}` + } + }) + ).data; + + apps = res.map((a: any) => ({ + name: a.name, + appId: a.site_id + })); + } catch (err) { + Sentry.setUser(null); + Sentry.captureException(err); + throw new Error('Failed to get Netlify integration apps'); + } + + return apps; +}; + +/** + * Return list of repositories for Github integration + * @param {Object} obj + * @param {String} obj.accessToken - access token for Netlify API + * @returns {Object[]} apps - names of Netlify sites + * @returns {String} apps.name - name of Netlify site + */ +const getAppsGithub = async ({ + accessToken +}: { + accessToken: string; +}) => { + let apps; + try { + const octokit = new Octokit({ + auth: accessToken + }); + + const repos = (await octokit.request( + 'GET /user/repos{?visibility,affiliation,type,sort,direction,per_page,page,since,before}', + { + per_page: 100 + } + )).data; + + apps = repos + .filter((a:any) => a.permissions.admin === true) + .map((a: any) => ({ + name: a.name, + owner: a.owner.login + }) + ); + } catch (err) { + Sentry.setUser(null); + Sentry.captureException(err); + throw new Error('Failed to get Github repos'); + } + + return apps; +}; + +/** + * Return list of services for Render integration + * @param {Object} obj + * @param {String} obj.accessToken - access token for Render API + * @returns {Object[]} apps - names and ids of Render services + * @returns {String} apps.name - name of Render service + * @returns {String} apps.appId - id of Render service + */ +const getAppsRender = async ({ + accessToken +}: { + accessToken: string; +}) => { + let apps: any; + try { + const res = ( + await axios.get(`${INTEGRATION_RENDER_API_URL}/v1/services`, { + headers: { + Authorization: `Bearer ${accessToken}` + } + }) + ).data; + + apps = res + .map((a: any) => ({ + name: a.service.name, + appId: a.service.id + })); + } catch (err) { + Sentry.setUser(null); + Sentry.captureException(err); + throw new Error('Failed to get Render services'); + } + + return apps; +} + +/** + * Return list of apps for Fly.io integration + * @param {Object} obj + * @param {String} obj.accessToken - access token for Fly.io API + * @returns {Object[]} apps - names and ids of Fly.io apps + * @returns {String} apps.name - name of Fly.io apps + */ +const getAppsFlyio = async ({ + accessToken +}: { + accessToken: string; +}) => { + let apps; + try { + const query = ` + query($role: String) { + apps(type: "container", first: 400, role: $role) { + nodes { + id + name + hostname + } + } + } + `; + + const res = (await axios({ + url: INTEGRATION_FLYIO_API_URL, + method: 'post', + headers: { + 'Authorization': 'Bearer ' + accessToken + }, + data: { + query, + variables: { + role: null + } + } + })).data.data.apps.nodes; + + apps = res + .map((a: any) => ({ + name: a.name + })); + } catch (err) { + Sentry.setUser(null); + Sentry.captureException(err); + throw new Error('Failed to get Fly.io apps'); + } + + return apps; +} + +export { getApps }; diff --git a/backend/src/integrations/exchange.ts b/backend/src/integrations/exchange.ts new file mode 100644 index 000000000..26aca5fdb --- /dev/null +++ b/backend/src/integrations/exchange.ts @@ -0,0 +1,284 @@ +import axios from 'axios'; +import * as Sentry from '@sentry/node'; +import { + INTEGRATION_HEROKU, + INTEGRATION_VERCEL, + INTEGRATION_NETLIFY, + INTEGRATION_GITHUB, + INTEGRATION_HEROKU_TOKEN_URL, + INTEGRATION_VERCEL_TOKEN_URL, + INTEGRATION_NETLIFY_TOKEN_URL, + INTEGRATION_GITHUB_TOKEN_URL +} from '../variables'; +import { + SITE_URL, + CLIENT_ID_VERCEL, + CLIENT_ID_NETLIFY, + CLIENT_ID_GITHUB, + CLIENT_SECRET_HEROKU, + CLIENT_SECRET_VERCEL, + CLIENT_SECRET_NETLIFY, + CLIENT_SECRET_GITHUB +} from '../config'; + +interface ExchangeCodeHerokuResponse { + token_type: string; + access_token: string; + expires_in: number; + refresh_token: string; + user_id: string; + session_nonce?: string; +} + +interface ExchangeCodeVercelResponse { + token_type: string; + access_token: string; + installation_id: string; + user_id: string; + team_id?: string; +} + +interface ExchangeCodeNetlifyResponse { + access_token: string; + token_type: string; + refresh_token: string; + scope: string; + created_at: number; +} + +interface ExchangeCodeGithubResponse { + access_token: string; + scope: string; + token_type: string; +} + +/** + * Return [accessToken], [accessExpiresAt], and [refreshToken] for OAuth2 + * code-token exchange for integration named [integration] + * @param {Object} obj1 + * @param {String} obj1.integration - name of integration + * @param {String} obj1.code - code for code-token exchange + * @returns {Object} obj + * @returns {String} obj.accessToken - access token for integration + * @returns {String} obj.refreshToken - refresh token for integration + * @returns {Date} obj.accessExpiresAt - date of expiration for access token + * @returns {String} obj.action - integration action for bot sequence + */ +const exchangeCode = async ({ + integration, + code +}: { + integration: string; + code: string; +}) => { + let obj = {} as any; + + try { + switch (integration) { + case INTEGRATION_HEROKU: + obj = await exchangeCodeHeroku({ + code + }); + break; + case INTEGRATION_VERCEL: + obj = await exchangeCodeVercel({ + code + }); + break; + case INTEGRATION_NETLIFY: + obj = await exchangeCodeNetlify({ + code + }); + break; + case INTEGRATION_GITHUB: + obj = await exchangeCodeGithub({ + code + }); + break; + } + } catch (err) { + Sentry.setUser(null); + Sentry.captureException(err); + throw new Error('Failed OAuth2 code-token exchange'); + } + + return obj; +}; + +/** + * Return [accessToken], [accessExpiresAt], and [refreshToken] for Heroku + * OAuth2 code-token exchange + * @param {Object} obj1 + * @param {Object} obj1.code - code for code-token exchange + * @returns {Object} obj2 + * @returns {String} obj2.accessToken - access token for Heroku API + * @returns {String} obj2.refreshToken - refresh token for Heroku API + * @returns {Date} obj2.accessExpiresAt - date of expiration for access token + */ +const exchangeCodeHeroku = async ({ + code +}: { + code: string; +}) => { + let res: ExchangeCodeHerokuResponse; + const accessExpiresAt = new Date(); + try { + res = (await axios.post( + INTEGRATION_HEROKU_TOKEN_URL, + new URLSearchParams({ + grant_type: 'authorization_code', + code: code, + client_secret: CLIENT_SECRET_HEROKU + } as any) + )).data; + + accessExpiresAt.setSeconds( + accessExpiresAt.getSeconds() + res.expires_in + ); + } catch (err) { + Sentry.setUser(null); + Sentry.captureException(err); + throw new Error('Failed OAuth2 code-token exchange with Heroku'); + } + + return ({ + accessToken: res.access_token, + refreshToken: res.refresh_token, + accessExpiresAt + }); +} + +/** + * Return [accessToken], [accessExpiresAt], and [refreshToken] for Vercel + * code-token exchange + * @param {Object} obj1 + * @param {Object} obj1.code - code for code-token exchange + * @returns {Object} obj2 + * @returns {String} obj2.accessToken - access token for Heroku API + * @returns {String} obj2.refreshToken - refresh token for Heroku API + * @returns {Date} obj2.accessExpiresAt - date of expiration for access token + */ +const exchangeCodeVercel = async ({ code }: { code: string }) => { + let res: ExchangeCodeVercelResponse; + try { + res = ( + await axios.post( + INTEGRATION_VERCEL_TOKEN_URL, + new URLSearchParams({ + code: code, + client_id: CLIENT_ID_VERCEL, + client_secret: CLIENT_SECRET_VERCEL, + redirect_uri: `${SITE_URL}/vercel` + } as any) + ) + ).data; + } catch (err) { + Sentry.setUser(null); + Sentry.captureException(err); + throw new Error('Failed OAuth2 code-token exchange with Vercel'); + } + + return { + accessToken: res.access_token, + refreshToken: null, + accessExpiresAt: null, + teamId: res.team_id + }; +}; + +/** + * Return [accessToken], [accessExpiresAt], and [refreshToken] for Vercel + * code-token exchange + * @param {Object} obj1 + * @param {Object} obj1.code - code for code-token exchange + * @returns {Object} obj2 + * @returns {String} obj2.accessToken - access token for Heroku API + * @returns {String} obj2.refreshToken - refresh token for Heroku API + * @returns {Date} obj2.accessExpiresAt - date of expiration for access token + */ +const exchangeCodeNetlify = async ({ code }: { code: string }) => { + let res: ExchangeCodeNetlifyResponse; + let accountId; + try { + res = ( + await axios.post( + INTEGRATION_NETLIFY_TOKEN_URL, + new URLSearchParams({ + grant_type: 'authorization_code', + code: code, + client_id: CLIENT_ID_NETLIFY, + client_secret: CLIENT_SECRET_NETLIFY, + redirect_uri: `${SITE_URL}/netlify` + } as any) + ) + ).data; + + const res2 = await axios.get('https://api.netlify.com/api/v1/sites', { + headers: { + Authorization: `Bearer ${res.access_token}` + } + }); + + const res3 = ( + await axios.get('https://api.netlify.com/api/v1/accounts', { + headers: { + Authorization: `Bearer ${res.access_token}` + } + }) + ).data; + + accountId = res3[0].id; + } catch (err) { + Sentry.setUser(null); + Sentry.captureException(err); + throw new Error('Failed OAuth2 code-token exchange with Netlify'); + } + + return { + accessToken: res.access_token, + refreshToken: res.refresh_token, + accountId + }; +}; + +/** + * Return [accessToken], [accessExpiresAt], and [refreshToken] for Github + * code-token exchange + * @param {Object} obj1 + * @param {Object} obj1.code - code for code-token exchange + * @returns {Object} obj2 + * @returns {String} obj2.accessToken - access token for Github API + * @returns {String} obj2.refreshToken - refresh token for Github API + * @returns {Date} obj2.accessExpiresAt - date of expiration for access token + */ +const exchangeCodeGithub = async ({ code }: { code: string }) => { + let res: ExchangeCodeGithubResponse; + try { + res = ( + await axios.get(INTEGRATION_GITHUB_TOKEN_URL, { + params: { + client_id: CLIENT_ID_GITHUB, + client_secret: CLIENT_SECRET_GITHUB, + code: code, + redirect_uri: `${SITE_URL}/github` + }, + headers: { + Accept: 'application/json' + } + }) + ).data; + + } catch (err) { + Sentry.setUser(null); + Sentry.captureException(err); + throw new Error('Failed OAuth2 code-token exchange with Github'); + } + + return { + accessToken: res.access_token, + refreshToken: null, + accessExpiresAt: null + }; +}; + +export { exchangeCode }; diff --git a/backend/src/integrations/index.ts b/backend/src/integrations/index.ts new file mode 100644 index 000000000..86c22de0c --- /dev/null +++ b/backend/src/integrations/index.ts @@ -0,0 +1,13 @@ +import { exchangeCode } from './exchange'; +import { exchangeRefresh } from './refresh'; +import { getApps } from './apps'; +import { syncSecrets } from './sync'; +import { revokeAccess } from './revoke'; + +export { + exchangeCode, + exchangeRefresh, + getApps, + syncSecrets, + revokeAccess +} \ No newline at end of file diff --git a/backend/src/integrations/refresh.ts b/backend/src/integrations/refresh.ts new file mode 100644 index 000000000..ea232f1e5 --- /dev/null +++ b/backend/src/integrations/refresh.ts @@ -0,0 +1,77 @@ +import axios from 'axios'; +import * as Sentry from '@sentry/node'; +import { INTEGRATION_HEROKU } from '../variables'; +import { + CLIENT_SECRET_HEROKU +} from '../config'; +import { + INTEGRATION_HEROKU_TOKEN_URL +} from '../variables'; + +/** + * Return new access token by exchanging refresh token [refreshToken] for integration + * named [integration] + * @param {Object} obj + * @param {String} obj.integration - name of integration + * @param {String} obj.refreshToken - refresh token to use to get new access token for Heroku + */ +const exchangeRefresh = async ({ + integration, + refreshToken +}: { + integration: string; + refreshToken: string; +}) => { + let accessToken; + try { + switch (integration) { + case INTEGRATION_HEROKU: + accessToken = await exchangeRefreshHeroku({ + refreshToken + }); + break; + } + } catch (err) { + Sentry.setUser(null); + Sentry.captureException(err); + throw new Error('Failed to get new OAuth2 access token'); + } + + return accessToken; +}; + +/** + * Return new access token by exchanging refresh token [refreshToken] for the + * Heroku integration + * @param {Object} obj + * @param {String} obj.refreshToken - refresh token to use to get new access token for Heroku + * @returns + */ +const exchangeRefreshHeroku = async ({ + refreshToken +}: { + refreshToken: string; +}) => { + let accessToken; + //TODO: Refactor code to take advantage of using RequestError. It's possible to create new types of errors for more detailed errors + try { + const res = await axios.post( + INTEGRATION_HEROKU_TOKEN_URL, + new URLSearchParams({ + grant_type: 'refresh_token', + refresh_token: refreshToken, + client_secret: CLIENT_SECRET_HEROKU + } as any) + ); + + accessToken = res.data.access_token; + } catch (err) { + Sentry.setUser(null); + Sentry.captureException(err); + throw new Error('Failed to get new OAuth2 access token for Heroku'); + } + + return accessToken; +}; + +export { exchangeRefresh }; diff --git a/backend/src/integrations/revoke.ts b/backend/src/integrations/revoke.ts new file mode 100644 index 000000000..25ec70313 --- /dev/null +++ b/backend/src/integrations/revoke.ts @@ -0,0 +1,55 @@ +import * as Sentry from '@sentry/node'; +import { + IIntegrationAuth, + IntegrationAuth, + Integration, + Bot, + BotKey +} from '../models'; +import { + INTEGRATION_HEROKU, + INTEGRATION_VERCEL, + INTEGRATION_NETLIFY, + INTEGRATION_GITHUB +} from '../variables'; + +const revokeAccess = async ({ + integrationAuth, + accessToken +}: { + integrationAuth: IIntegrationAuth; + accessToken: string; +}) => { + let deletedIntegrationAuth; + try { + // add any integration-specific revocation logic + switch (integrationAuth.integration) { + case INTEGRATION_HEROKU: + break; + case INTEGRATION_VERCEL: + break; + case INTEGRATION_NETLIFY: + break; + case INTEGRATION_GITHUB: + break; + } + + deletedIntegrationAuth = await IntegrationAuth.findOneAndDelete({ + _id: integrationAuth._id + }); + + if (deletedIntegrationAuth) { + await Integration.deleteMany({ + integrationAuth: deletedIntegrationAuth._id + }); + } + } catch (err) { + Sentry.setUser(null); + Sentry.captureException(err); + throw new Error('Failed to delete integration authorization'); + } + + return deletedIntegrationAuth; +}; + +export { revokeAccess }; diff --git a/backend/src/integrations/sync.ts b/backend/src/integrations/sync.ts new file mode 100644 index 000000000..9954943b8 --- /dev/null +++ b/backend/src/integrations/sync.ts @@ -0,0 +1,798 @@ +import axios from 'axios'; +import * as Sentry from '@sentry/node'; +import { Octokit } from '@octokit/rest'; +// import * as sodium from 'libsodium-wrappers'; +import sodium from 'libsodium-wrappers'; +// const sodium = require('libsodium-wrappers'); +import { IIntegration, IIntegrationAuth } from '../models'; +import { + INTEGRATION_HEROKU, + INTEGRATION_VERCEL, + INTEGRATION_NETLIFY, + INTEGRATION_GITHUB, + INTEGRATION_RENDER, + INTEGRATION_FLYIO, + INTEGRATION_HEROKU_API_URL, + INTEGRATION_VERCEL_API_URL, + INTEGRATION_NETLIFY_API_URL, + INTEGRATION_RENDER_API_URL, + INTEGRATION_FLYIO_API_URL +} from '../variables'; +import { access, appendFile } from 'fs'; + +/** + * Sync/push [secrets] to [app] in integration named [integration] + * @param {Object} obj + * @param {IIntegration} obj.integration - integration details + * @param {IIntegrationAuth} obj.integrationAuth - integration auth details + * @param {Object} obj.secrets - secrets to push to integration (object where keys are secret keys and values are secret values) + * @param {String} obj.accessToken - access token for integration + */ +const syncSecrets = async ({ + integration, + integrationAuth, + secrets, + accessToken +}: { + integration: IIntegration; + integrationAuth: IIntegrationAuth; + secrets: any; + accessToken: string; +}) => { + try { + switch (integration.integration) { + case INTEGRATION_HEROKU: + await syncSecretsHeroku({ + integration, + secrets, + accessToken + }); + break; + case INTEGRATION_VERCEL: + await syncSecretsVercel({ + integration, + integrationAuth, + secrets, + accessToken + }); + break; + case INTEGRATION_NETLIFY: + await syncSecretsNetlify({ + integration, + integrationAuth, + secrets, + accessToken + }); + break; + case INTEGRATION_GITHUB: + await syncSecretsGitHub({ + integration, + secrets, + accessToken + }); + break; + case INTEGRATION_RENDER: + await syncSecretsRender({ + integration, + secrets, + accessToken + }); + break; + case INTEGRATION_FLYIO: + await syncSecretsFlyio({ + integration, + secrets, + accessToken + }); + break; + } + } catch (err) { + Sentry.setUser(null); + Sentry.captureException(err); + throw new Error('Failed to sync secrets to integration'); + } +}; + +/** + * Sync/push [secrets] to Heroku app named [integration.app] + * @param {Object} obj + * @param {IIntegration} obj.integration - integration details + * @param {Object} obj.secrets - secrets to push to integration (object where keys are secret keys and values are secret values) + * @param {String} obj.accessToken - access token for Heroku integration + */ +const syncSecretsHeroku = async ({ + integration, + secrets, + accessToken +}: { + integration: IIntegration; + secrets: any; + accessToken: string; +}) => { + try { + const herokuSecrets = ( + await axios.get( + `${INTEGRATION_HEROKU_API_URL}/apps/${integration.app}/config-vars`, + { + headers: { + Accept: 'application/vnd.heroku+json; version=3', + Authorization: `Bearer ${accessToken}` + } + } + ) + ).data; + + Object.keys(herokuSecrets).forEach((key) => { + if (!(key in secrets)) { + secrets[key] = null; + } + }); + + await axios.patch( + `${INTEGRATION_HEROKU_API_URL}/apps/${integration.app}/config-vars`, + secrets, + { + headers: { + Accept: 'application/vnd.heroku+json; version=3', + Authorization: `Bearer ${accessToken}` + } + } + ); + } catch (err) { + Sentry.setUser(null); + Sentry.captureException(err); + throw new Error('Failed to sync secrets to Heroku'); + } +}; + +/** + * Sync/push [secrets] to Vercel project named [integration.app] + * @param {Object} obj + * @param {IIntegration} obj.integration - integration details + * @param {Object} obj.secrets - secrets to push to integration (object where keys are secret keys and values are secret values) + */ +const syncSecretsVercel = async ({ + integration, + integrationAuth, + secrets, + accessToken +}: { + integration: IIntegration, + integrationAuth: IIntegrationAuth, + secrets: any; + accessToken: string; +}) => { + interface VercelSecret { + id?: string; + type: string; + key: string; + value: string; + target: string[]; + } + + try { + // Get all (decrypted) secrets back from Vercel in + // decrypted format + const params: { [key: string]: string } = { + decrypt: 'true', + ...( integrationAuth?.teamId ? { + teamId: integrationAuth.teamId + } : {}) + } + + const res = (await Promise.all((await axios.get( + `${INTEGRATION_VERCEL_API_URL}/v9/projects/${integration.app}/env`, + { + params, + headers: { + Authorization: `Bearer ${accessToken}` + } + } + )) + .data + .envs + .filter((secret: VercelSecret) => secret.target.includes(integration.targetEnvironment)) + .map(async (secret: VercelSecret) => (await axios.get( + `${INTEGRATION_VERCEL_API_URL}/v9/projects/${integration.app}/env/${secret.id}`, + { + params, + headers: { + Authorization: `Bearer ${accessToken}` + } + } + )).data) + )).reduce((obj: any, secret: any) => ({ + ...obj, + [secret.key]: secret + }), {}); + + const updateSecrets: VercelSecret[] = []; + const deleteSecrets: VercelSecret[] = []; + const newSecrets: VercelSecret[] = []; + + // Identify secrets to create + Object.keys(secrets).map((key) => { + if (!(key in res)) { + // case: secret has been created + newSecrets.push({ + key: key, + value: secrets[key], + type: 'encrypted', + target: [integration.targetEnvironment] + }); + } + }); + + // Identify secrets to update and delete + Object.keys(res).map((key) => { + if (key in secrets) { + if (res[key].value !== secrets[key]) { + // case: secret value has changed + updateSecrets.push({ + id: res[key].id, + key: key, + value: secrets[key], + type: 'encrypted', + target: [integration.targetEnvironment] + }); + } + } else { + // case: secret has been deleted + deleteSecrets.push({ + id: res[key].id, + key: key, + value: res[key].value, + type: 'encrypted', + target: [integration.targetEnvironment], + }); + } + }); + + // Sync/push new secrets + if (newSecrets.length > 0) { + await axios.post( + `${INTEGRATION_VERCEL_API_URL}/v10/projects/${integration.app}/env`, + newSecrets, + { + params, + headers: { + Authorization: `Bearer ${accessToken}` + } + } + ); + } + + // Sync/push updated secrets + if (updateSecrets.length > 0) { + updateSecrets.forEach(async (secret: VercelSecret) => { + const { + id, + ...updatedSecret + } = secret; + await axios.patch( + `${INTEGRATION_VERCEL_API_URL}/v9/projects/${integration.app}/env/${secret.id}`, + updatedSecret, + { + params, + headers: { + Authorization: `Bearer ${accessToken}` + } + } + ); + }); + } + + // Delete secrets + if (deleteSecrets.length > 0) { + deleteSecrets.forEach(async (secret: VercelSecret) => { + await axios.delete( + `${INTEGRATION_VERCEL_API_URL}/v9/projects/${integration.app}/env/${secret.id}`, + { + params, + headers: { + Authorization: `Bearer ${accessToken}` + } + } + ); + }); + } + } catch (err) { + Sentry.setUser(null); + Sentry.captureException(err); + throw new Error('Failed to sync secrets to Vercel'); + } +} + +/** + * Sync/push [secrets] to Netlify site with id [integration.appId] + * @param {Object} obj + * @param {IIntegration} obj.integration - integration details + * @param {IIntegrationAuth} obj.integrationAuth - integration auth details + * @param {Object} obj.secrets - secrets to push to integration (object where keys are secret keys and values are secret values) + * @param {Object} obj.accessToken - access token for Netlify integration + */ +const syncSecretsNetlify = async ({ + integration, + integrationAuth, + secrets, + accessToken +}: { + integration: IIntegration; + integrationAuth: IIntegrationAuth; + secrets: any; + accessToken: string; +}) => { + try { + + interface NetlifyValue { + id?: string; + context: string; // 'dev' | 'branch-deploy' | 'deploy-preview' | 'production', + value: string; + } + + interface NetlifySecret { + key: string; + values: NetlifyValue[]; + } + + interface NetlifySecretsRes { + [index: string]: NetlifySecret; + } + + const getParams = new URLSearchParams({ + context_name: 'all', // integration.context or all + site_id: integration.appId + }); + + const res = (await axios.get( + `${INTEGRATION_NETLIFY_API_URL}/api/v1/accounts/${integrationAuth.accountId}/env`, + { + params: getParams, + headers: { + Authorization: `Bearer ${accessToken}` + } + } + )) + .data + .reduce((obj: any, secret: any) => ({ + ...obj, + [secret.key]: secret + }), {}); + + const newSecrets: NetlifySecret[] = []; // createEnvVars + const deleteSecrets: string[] = []; // deleteEnvVar + const deleteSecretValues: NetlifySecret[] = []; // deleteEnvVarValue + const updateSecrets: NetlifySecret[] = []; // setEnvVarValue + + // identify secrets to create and update + Object.keys(secrets).map((key) => { + if (!(key in res)) { + // case: Infisical secret does not exist in Netlify -> create secret + newSecrets.push({ + key, + values: [{ + value: secrets[key], + context: integration.targetEnvironment + }] + }); + } else { + // case: Infisical secret exists in Netlify + const contexts = res[key].values + .reduce((obj: any, value: NetlifyValue) => ({ + ...obj, + [value.context]: value + }), {}); + + if (integration.targetEnvironment in contexts) { + // case: Netlify secret value exists in integration context + if (secrets[key] !== contexts[integration.targetEnvironment].value) { + // case: Infisical and Netlify secret values are different + // -> update Netlify secret context and value + updateSecrets.push({ + key, + values: [{ + context: integration.targetEnvironment, + value: secrets[key] + }] + }); + } + } else { + // case: Netlify secret value does not exist in integration context + // -> add the new Netlify secret context and value + updateSecrets.push({ + key, + values: [{ + context: integration.targetEnvironment, + value: secrets[key] + }] + }); + } + } + }) + + // identify secrets to delete + // TODO: revise (patch case where 1 context was deleted but others still there + Object.keys(res).map((key) => { + // loop through each key's context + if (!(key in secrets)) { + // case: Netlify secret does not exist in Infisical + + const numberOfValues = res[key].values.length; + + res[key].values.forEach((value: NetlifyValue) => { + if (value.context === integration.targetEnvironment) { + if (numberOfValues <= 1) { + // case: Netlify secret value has less than 1 context -> delete secret + deleteSecrets.push(key); + } else { + // case: Netlify secret value has more than 1 context -> delete secret value context + deleteSecretValues.push({ + key, + values: [{ + id: value.id, + context: integration.targetEnvironment, + value: value.value + }] + }); + } + } + }); + } + }); + + const syncParams = new URLSearchParams({ + site_id: integration.appId + }); + + if (newSecrets.length > 0) { + await axios.post( + `${INTEGRATION_NETLIFY_API_URL}/api/v1/accounts/${integrationAuth.accountId}/env`, + newSecrets, + { + params: syncParams, + headers: { + Authorization: `Bearer ${accessToken}` + } + } + ); + } + + if (updateSecrets.length > 0) { + updateSecrets.forEach(async (secret: NetlifySecret) => { + await axios.patch( + `${INTEGRATION_NETLIFY_API_URL}/api/v1/accounts/${integrationAuth.accountId}/env/${secret.key}`, + { + context: secret.values[0].context, + value: secret.values[0].value + }, + { + params: syncParams, + headers: { + Authorization: `Bearer ${accessToken}` + } + } + ); + }); + } + + if (deleteSecrets.length > 0) { + deleteSecrets.forEach(async (key: string) => { + await axios.delete( + `${INTEGRATION_NETLIFY_API_URL}/api/v1/accounts/${integrationAuth.accountId}/env/${key}`, + { + params: syncParams, + headers: { + Authorization: `Bearer ${accessToken}` + } + } + ); + }); + } + + if (deleteSecretValues.length > 0) { + deleteSecretValues.forEach(async (secret: NetlifySecret) => { + await axios.delete( + `${INTEGRATION_NETLIFY_API_URL}/api/v1/accounts/${integrationAuth.accountId}/env/${secret.key}/value/${secret.values[0].id}`, + { + params: syncParams, + headers: { + Authorization: `Bearer ${accessToken}` + } + } + ); + }); + } + } catch (err) { + Sentry.setUser(null); + Sentry.captureException(err); + throw new Error('Failed to sync secrets to Heroku'); + } +} + +/** + * Sync/push [secrets] to GitHub repo with name [integration.app] + * @param {Object} obj + * @param {IIntegration} obj.integration - integration details + * @param {IIntegrationAuth} obj.integrationAuth - integration auth details + * @param {Object} obj.secrets - secrets to push to integration (object where keys are secret keys and values are secret values) + * @param {String} obj.accessToken - access token for GitHub integration + */ +const syncSecretsGitHub = async ({ + integration, + secrets, + accessToken +}: { + integration: IIntegration; + secrets: any; + accessToken: string; +}) => { + try { + + interface GitHubRepoKey { + key_id: string; + key: string; + } + + interface GitHubSecret { + name: string; + created_at: string; + updated_at: string; + } + + interface GitHubSecretRes { + [index: string]: GitHubSecret; + } + + const deleteSecrets: GitHubSecret[] = []; + + const octokit = new Octokit({ + auth: accessToken + }); + + // const user = (await octokit.request('GET /user', {})).data; + const repoPublicKey: GitHubRepoKey = (await octokit.request( + 'GET /repos/{owner}/{repo}/actions/secrets/public-key', + { + owner: integration.owner, + repo: integration.app + } + )).data; + + // Get local copy of decrypted secrets. We cannot decrypt them as we dont have access to GH private key + const encryptedSecrets: GitHubSecretRes = (await octokit.request( + 'GET /repos/{owner}/{repo}/actions/secrets', + { + owner: integration.owner, + repo: integration.app + } + )) + .data + .secrets + .reduce((obj: any, secret: any) => ({ + ...obj, + [secret.name]: secret + }), {}); + + Object.keys(encryptedSecrets).map(async (key) => { + if (!(key in secrets)) { + await octokit.request( + 'DELETE /repos/{owner}/{repo}/actions/secrets/{secret_name}', + { + owner: integration.owner, + repo: integration.app, + secret_name: key + } + ); + } + }); + + Object.keys(secrets).map((key) => { + // let encryptedSecret; + sodium.ready.then(async () => { + // convert secret & base64 key to Uint8Array. + const binkey = sodium.from_base64( + repoPublicKey.key, + sodium.base64_variants.ORIGINAL + ); + const binsec = sodium.from_string(secrets[key]); + + // encrypt secret using libsodium + const encBytes = sodium.crypto_box_seal(binsec, binkey); + + // convert encrypted Uint8Array to base64 + const encryptedSecret = sodium.to_base64( + encBytes, + sodium.base64_variants.ORIGINAL + ); + + await octokit.request( + 'PUT /repos/{owner}/{repo}/actions/secrets/{secret_name}', + { + owner: integration.owner, + repo: integration.app, + secret_name: key, + encrypted_value: encryptedSecret, + key_id: repoPublicKey.key_id + } + ); + }); + }); + } catch (err) { + Sentry.setUser(null); + Sentry.captureException(err); + throw new Error('Failed to sync secrets to GitHub'); + } +}; + +/** + * Sync/push [secrets] to Render service with id [integration.appId] + * @param {Object} obj + * @param {IIntegration} obj.integration - integration details + * @param {Object} obj.secrets - secrets to push to integration (object where keys are secret keys and values are secret values) + * @param {String} obj.accessToken - access token for Render integration + */ +const syncSecretsRender = async ({ + integration, + secrets, + accessToken +}: { + integration: IIntegration; + secrets: any; + accessToken: string; +}) => { + try { + await axios.put( + `${INTEGRATION_RENDER_API_URL}/v1/services/${integration.appId}/env-vars`, + Object.keys(secrets).map((key) => ({ + key, + value: secrets[key] + })), + { + headers: { + Authorization: `Bearer ${accessToken}` + } + } + ); + } catch (err) { + Sentry.setUser(null); + Sentry.captureException(err); + throw new Error('Failed to sync secrets to Render'); + } +} + +/** + * Sync/push [secrets] to Fly.io app + * @param {Object} obj + * @param {IIntegration} obj.integration - integration details + * @param {Object} obj.secrets - secrets to push to integration (object where keys are secret keys and values are secret values) + * @param {String} obj.accessToken - access token for Render integration + */ +const syncSecretsFlyio = async ({ + integration, + secrets, + accessToken +}: { + integration: IIntegration; + secrets: any; + accessToken: string; +}) => { + try { + // set secrets + const SetSecrets = ` + mutation($input: SetSecretsInput!) { + setSecrets(input: $input) { + release { + id + version + reason + description + user { + id + email + name + } + evaluationId + createdAt + } + } + } + `; + + await axios({ + url: INTEGRATION_FLYIO_API_URL, + method: 'post', + headers: { + 'Authorization': 'Bearer ' + accessToken + }, + data: { + query: SetSecrets, + variables: { + input: { + appId: integration.app, + secrets: Object.entries(secrets).map(([key, value]) => ({ key, value })) + } + } + } + }); + + // get secrets + interface FlyioSecret { + name: string; + digest: string; + createdAt: string; + } + + const GetSecrets = `query ($appName: String!) { + app(name: $appName) { + secrets { + name + digest + createdAt + } + } + }`; + + const getSecretsRes = (await axios({ + method: 'post', + url: INTEGRATION_FLYIO_API_URL, + headers: { + 'Authorization': 'Bearer ' + accessToken, + 'Content-Type': 'application/json' + }, + data: { + query: GetSecrets, + variables: { + appName: integration.app + } + } + })).data.data.app.secrets; + + const deleteSecretsKeys = getSecretsRes + .filter((secret: FlyioSecret) => !(secret.name in secrets)) + .map((secret: FlyioSecret) => secret.name); + + // unset (delete) secrets + const DeleteSecrets = `mutation($input: UnsetSecretsInput!) { + unsetSecrets(input: $input) { + release { + id + version + reason + description + user { + id + email + name + } + evaluationId + createdAt + } + } + }`; + + await axios({ + method: 'post', + url: INTEGRATION_FLYIO_API_URL, + headers: { + 'Authorization': 'Bearer ' + accessToken, + 'Content-Type': 'application/json' + }, + data: { + query: DeleteSecrets, + variables: { + input: { + appId: integration.app, + keys: deleteSecretsKeys + } + } + } + }); + + } catch (err) { + Sentry.setUser(null); + Sentry.captureException(err); + throw new Error('Failed to sync secrets to Fly.io'); + } +} + +export { syncSecrets }; \ No newline at end of file diff --git a/backend/src/json/integrations.json b/backend/src/json/integrations.json deleted file mode 100644 index 16b09ebf4..000000000 --- a/backend/src/json/integrations.json +++ /dev/null @@ -1,50 +0,0 @@ -{ - "heroku": { - "name": "Heroku", - "type": "oauth2", - "clientId": "bc132901-935a-4590-b010-f1857efc380d", - "docsLink": "" - }, - "netlify": { - "name": "Netlify", - "type": "oauth2", - "clientId": "", - "docsLink": "" - }, - "digitalocean": { - "name": "Digital Ocean", - "type": "oauth2", - "clientId": "", - "docsLink": "" - }, - "gcp": { - "name": "Google Cloud Platform", - "type": "oauth2", - "clientId": "", - "docsLink": "" - }, - "aws": { - "name": "Amazon Web Services", - "type": "oauth2", - "clientId": "", - "docsLink": "" - }, - "azure": { - "name": "Microsoft Azure", - "type": "oauth2", - "clientId": "", - "docsLink": "" - }, - "travisci": { - "name": "Travis CI", - "type": "oauth2", - "clientId": "", - "docsLink": "" - }, - "circleci": { - "name": "Circle CI", - "type": "oauth2", - "clientId": "", - "docsLink": "" - } -} diff --git a/backend/src/middleware/index.ts b/backend/src/middleware/index.ts index e445b64cf..86b653281 100644 --- a/backend/src/middleware/index.ts +++ b/backend/src/middleware/index.ts @@ -1,19 +1,31 @@ import requireAuth from './requireAuth'; +import requireBotAuth from './requireBotAuth'; import requireSignupAuth from './requireSignupAuth'; import requireWorkspaceAuth from './requireWorkspaceAuth'; +import requireMembershipAuth from './requireMembershipAuth'; +import requireMembershipOrgAuth from './requireMembershipOrgAuth'; import requireOrganizationAuth from './requireOrganizationAuth'; import requireIntegrationAuth from './requireIntegrationAuth'; import requireIntegrationAuthorizationAuth from './requireIntegrationAuthorizationAuth'; import requireServiceTokenAuth from './requireServiceTokenAuth'; +import requireServiceTokenDataAuth from './requireServiceTokenDataAuth'; +import requireSecretAuth from './requireSecretAuth'; +import requireSecretsAuth from './requireSecretsAuth'; import validateRequest from './validateRequest'; export { requireAuth, + requireBotAuth, requireSignupAuth, requireWorkspaceAuth, + requireMembershipAuth, + requireMembershipOrgAuth, requireOrganizationAuth, requireIntegrationAuth, requireIntegrationAuthorizationAuth, requireServiceTokenAuth, + requireServiceTokenDataAuth, + requireSecretAuth, + requireSecretsAuth, validateRequest }; diff --git a/backend/src/middleware/requestErrorHandler.ts b/backend/src/middleware/requestErrorHandler.ts new file mode 100644 index 000000000..50044387e --- /dev/null +++ b/backend/src/middleware/requestErrorHandler.ts @@ -0,0 +1,36 @@ +import { ErrorRequestHandler } from "express"; + +import * as Sentry from '@sentry/node'; +import { InternalServerError } from "../utils/errors"; +import { getLogger } from "../utils/logger"; +import RequestError, { LogLevel } from "../utils/requestError"; +import { NODE_ENV } from "../config"; + + +export const requestErrorHandler: ErrorRequestHandler = (error: RequestError | Error, req, res, next) => { + if (res.headersSent) return next(); + if (NODE_ENV !== "production") { + /* eslint-disable no-console */ + console.log(error) + /* eslint-enable no-console */ + } + + //TODO: Find better way to type check for error. In current setting you need to cast type to get the functions and variables from RequestError + if (!(error instanceof RequestError)) { + error = InternalServerError({ context: { exception: error.message }, stack: error.stack }) + getLogger('backend-main').log((error).levelName.toLowerCase(), (error).message) + } + + //* Set Sentry user identification if req.user is populated + if (req.user !== undefined && req.user !== null) { + Sentry.setUser({ email: req.user.email }) + } + //* Only sent error to Sentry if LogLevel is one of the following level 'ERROR', 'EMERGENCY' or 'CRITICAL' + //* with this we will eliminate false-positive errors like 'BadRequestError', 'UnauthorizedRequestError' and so on + if ([LogLevel.ERROR, LogLevel.EMERGENCY, LogLevel.CRITICAL].includes((error).level)) { + Sentry.captureException(error) + } + + res.status((error).statusCode).json((error).format(req)) + next() +} \ No newline at end of file diff --git a/backend/src/middleware/requireAuth.ts b/backend/src/middleware/requireAuth.ts index a6bd79073..24ef92f06 100644 --- a/backend/src/middleware/requireAuth.ts +++ b/backend/src/middleware/requireAuth.ts @@ -1,8 +1,12 @@ import jwt from 'jsonwebtoken'; import { Request, Response, NextFunction } from 'express'; -import * as Sentry from '@sentry/node'; -import { User } from '../models'; -import { JWT_AUTH_SECRET } from '../config'; +import { User, ServiceTokenData } from '../models'; +import { + validateAuthMode, + getAuthUserPayload, + getAuthSTDPayload, + getAuthAPIKeyPayload +} from '../helpers/auth'; declare module 'jsonwebtoken' { export interface UserIDJwtPayload extends jwt.JwtPayload { @@ -11,41 +15,49 @@ declare module 'jsonwebtoken' { } /** - * Validate if JWT (auth) token on request is valid (e.g. not expired), - * if there is an associated user, and if that user is fully setup. - * @param req - express request object - * @param res - express response object - * @param next - express next function + * Validate if token on request is valid (e.g. not expired) for various auth modes: + * - If token is a JWT token, then check if there is an associated user + * and if user is fully setup. + * - If token is a service token (st), then check if there is associated + * service token data. + * @param {Object} obj + * @param {String[]} obj.acceptedAuthModes - accepted modes of authentication (jwt/st) * @returns */ -const requireAuth = async (req: Request, res: Response, next: NextFunction) => { - // JWT authentication middleware - try { - if (!req.headers?.authorization) - throw new Error('Failed to locate authorization header'); - - const token = req.headers.authorization.split(' ')[1]; - const decodedToken = ( - jwt.verify(token, JWT_AUTH_SECRET) - ); - - const user = await User.findOne({ - _id: decodedToken.userId - }).select('+publicKey'); - - if (!user) throw new Error('Failed to authenticate unfound user'); - if (!user?.publicKey) - throw new Error('Failed to authenticate not fully set up account'); - - req.user = user; - return next(); - } catch (err) { - Sentry.setUser(null); - Sentry.captureException(err); - return res.status(401).send({ - error: 'Failed to authenticate user. Try logging in' +const requireAuth = ({ + acceptedAuthModes = ['jwt'] +}: { + acceptedAuthModes: string[]; +}) => { + return async (req: Request, res: Response, next: NextFunction) => { + // validate auth token against accepted auth modes [acceptedAuthModes] + // and return token type [authTokenType] and value [authTokenValue] + const { authTokenType, authTokenValue } = validateAuthMode({ + headers: req.headers, + acceptedAuthModes }); + + // attach auth payloads + switch (authTokenType) { + case 'serviceToken': + req.serviceTokenData = await getAuthSTDPayload({ + authTokenValue + }); + break; + case 'apiKey': + req.user = await getAuthAPIKeyPayload({ + authTokenValue + }); + break; + default: + req.user = await getAuthUserPayload({ + authTokenValue + }); + break; + } + + return next(); } -}; +} export default requireAuth; diff --git a/backend/src/middleware/requireBotAuth.ts b/backend/src/middleware/requireBotAuth.ts new file mode 100644 index 000000000..435b06a59 --- /dev/null +++ b/backend/src/middleware/requireBotAuth.ts @@ -0,0 +1,34 @@ +import { Request, Response, NextFunction } from 'express'; +import { Bot } from '../models'; +import { validateMembership } from '../helpers/membership'; +import { AccountNotFoundError } from '../utils/errors'; + +type req = 'params' | 'body' | 'query'; + +const requireBotAuth = ({ + acceptedRoles, + location = 'params' +}: { + acceptedRoles: string[]; + location?: req; +}) => { + return async (req: Request, res: Response, next: NextFunction) => { + const bot = await Bot.findById(req[location].botId); + + if (!bot) { + return next(AccountNotFoundError({message: 'Failed to locate Bot account'})) + } + + await validateMembership({ + userId: req.user._id.toString(), + workspaceId: bot.workspace.toString(), + acceptedRoles + }); + + req.bot = bot; + + next(); + } +} + +export default requireBotAuth; \ No newline at end of file diff --git a/backend/src/middleware/requireIntegrationAuth.ts b/backend/src/middleware/requireIntegrationAuth.ts index 70ca320c3..b185b922b 100644 --- a/backend/src/middleware/requireIntegrationAuth.ts +++ b/backend/src/middleware/requireIntegrationAuth.ts @@ -1,75 +1,56 @@ -import * as Sentry from '@sentry/node'; import { Request, Response, NextFunction } from 'express'; -import { Integration, IntegrationAuth, Membership } from '../models'; -import { getOAuthAccessToken } from '../helpers/integrationAuth'; +import { Integration, IntegrationAuth } from '../models'; +import { IntegrationService } from '../services'; +import { validateMembership } from '../helpers/membership'; +import { IntegrationNotFoundError, UnauthorizedRequestError } from '../utils/errors'; /** * Validate if user on request is a member of workspace with proper roles associated * with the integration on request params. * @param {Object} obj * @param {String[]} obj.acceptedRoles - accepted workspace roles - * @param {String[]} obj.acceptedStatuses - accepted workspace statuses */ const requireIntegrationAuth = ({ - acceptedRoles, - acceptedStatuses + acceptedRoles }: { acceptedRoles: string[]; - acceptedStatuses: string[]; }) => { return async (req: Request, res: Response, next: NextFunction) => { // integration authorization middleware - try { - const { integrationId } = req.params; + const { integrationId } = req.params; - // validate integration accessibility - const integration = await Integration.findOne({ - _id: integrationId - }); + // validate integration accessibility + const integration = await Integration.findOne({ + _id: integrationId + }); - if (!integration) { - throw new Error('Failed to find integration'); - } - - const membership = await Membership.findOne({ - user: req.user._id, - workspace: integration.workspace - }); - - if (!membership) { - throw new Error('Failed to find integration workspace membership'); - } - - if (!acceptedRoles.includes(membership.role)) { - throw new Error('Failed to validate workspace membership role'); - } - - if (!acceptedStatuses.includes(membership.status)) { - throw new Error('Failed to validate workspace membership status'); - } - - const integrationAuth = await IntegrationAuth.findOne({ - _id: integration.integrationAuth - }).select( - '+refreshCiphertext +refreshIV +refreshTag +accessCiphertext +accessIV +accessTag +accessExpiresAt' - ); - - if (!integrationAuth) { - throw new Error('Failed to find integration authorization'); - } - - req.integration = integration; - req.accessToken = await getOAuthAccessToken({ integrationAuth }); - - return next(); - } catch (err) { - Sentry.setUser(null); - Sentry.captureException(err); - return res.status(401).send({ - error: 'Failed integration authorization' - }); + if (!integration) { + return next(IntegrationNotFoundError({message: 'Failed to locate Integration'})) } + + await validateMembership({ + userId: req.user._id.toString(), + workspaceId: integration.workspace.toString(), + acceptedRoles + }); + + const integrationAuth = await IntegrationAuth.findOne({ + _id: integration.integrationAuth + }).select( + '+refreshCiphertext +refreshIV +refreshTag +accessCiphertext +accessIV +accessTag +accessExpiresAt' + ); + + if (!integrationAuth) { + return next(UnauthorizedRequestError({message: 'Failed to locate Integration Authentication credentials'})) + } + + req.integration = integration; + req.accessToken = await IntegrationService.getIntegrationAuthAccess({ + integrationAuthId: integrationAuth._id.toString() + }); + + return next(); }; }; diff --git a/backend/src/middleware/requireIntegrationAuthorizationAuth.ts b/backend/src/middleware/requireIntegrationAuthorizationAuth.ts index 1f5c6dfc8..c43af2452 100644 --- a/backend/src/middleware/requireIntegrationAuthorizationAuth.ts +++ b/backend/src/middleware/requireIntegrationAuthorizationAuth.ts @@ -1,71 +1,56 @@ import * as Sentry from '@sentry/node'; import { Request, Response, NextFunction } from 'express'; -import { IntegrationAuth, Membership } from '../models'; -import { decryptSymmetric } from '../utils/crypto'; -import { getOAuthAccessToken } from '../helpers/integrationAuth'; +import { IntegrationAuth, IWorkspace } from '../models'; +import { IntegrationService } from '../services'; +import { validateMembership } from '../helpers/membership'; +import { UnauthorizedRequestError } from '../utils/errors'; + +type req = 'params' | 'body' | 'query'; /** * Validate if user on request is a member of workspace with proper roles associated * with the integration authorization on request params. * @param {Object} obj * @param {String[]} obj.acceptedRoles - accepted workspace roles - * @param {String[]} obj.acceptedStatuses - accepted workspace statuses - * @param {Boolean} obj.attachRefresh - whether or not to decrypt and attach integration authorization refresh token onto request + * @param {Boolean} obj.attachAccessToken - whether or not to decrypt and attach integration authorization access token onto request */ const requireIntegrationAuthorizationAuth = ({ acceptedRoles, - acceptedStatuses + attachAccessToken = true, + location = 'params' }: { acceptedRoles: string[]; - acceptedStatuses: string[]; + attachAccessToken?: boolean; + location?: req; }) => { return async (req: Request, res: Response, next: NextFunction) => { - // (authorization) integration authorization middleware + const { integrationAuthId } = req[location]; + const integrationAuth = await IntegrationAuth.findOne({ + _id: integrationAuthId + }) + .populate<{ workspace: IWorkspace }>('workspace') + .select( + '+refreshCiphertext +refreshIV +refreshTag +accessCiphertext +accessIV +accessTag +accessExpiresAt' + ); - try { - const { integrationAuthId } = req.params; + if (!integrationAuth) { + return next(UnauthorizedRequestError({message: 'Failed to locate Integration Authorization credentials'})) + } + + await validateMembership({ + userId: req.user._id.toString(), + workspaceId: integrationAuth.workspace._id.toString(), + acceptedRoles + }); - const integrationAuth = await IntegrationAuth.findOne({ - _id: integrationAuthId - }).select( - '+refreshCiphertext +refreshIV +refreshTag +accessCiphertext +accessIV +accessTag +accessExpiresAt' - ); - - if (!integrationAuth) { - throw new Error('Failed to find integration authorization'); - } - - const membership = await Membership.findOne({ - user: req.user._id, - workspace: integrationAuth.workspace - }); - - if (!membership) { - throw new Error( - 'Failed to find integration authorization workspace membership' - ); - } - - if (!acceptedRoles.includes(membership.role)) { - throw new Error('Failed to validate workspace membership role'); - } - - if (!acceptedStatuses.includes(membership.status)) { - throw new Error('Failed to validate workspace membership status'); - } - - req.integrationAuth = integrationAuth; - - // TODO: make compatible with other integration types since they won't necessarily have access tokens - req.accessToken = await getOAuthAccessToken({ integrationAuth }); - return next(); - } catch (err) { - Sentry.setUser(null); - Sentry.captureException(err); - return res.status(401).send({ - error: 'Failed (authorization) integration authorizationt' + req.integrationAuth = integrationAuth; + if (attachAccessToken) { + req.accessToken = await IntegrationService.getIntegrationAuthAccess({ + integrationAuthId: integrationAuth._id.toString() }); } + + return next(); }; }; diff --git a/backend/src/middleware/requireMembershipAuth.ts b/backend/src/middleware/requireMembershipAuth.ts new file mode 100644 index 000000000..f5e4fe8b1 --- /dev/null +++ b/backend/src/middleware/requireMembershipAuth.ts @@ -0,0 +1,59 @@ +import { Request, Response, NextFunction } from 'express'; +import { UnauthorizedRequestError } from '../utils/errors'; +import { + Membership, +} from '../models'; +import { validateMembership } from '../helpers/membership'; + +type req = 'params' | 'body' | 'query'; + +/** + * Validate membership with id [membershipId] and that user with id + * [req.user._id] can modify that membership. + * @param {Object} obj + * @param {String[]} obj.acceptedRoles - accepted workspace roles + * @param {String[]} obj.location - location of [workspaceId] on request (e.g. params, body) for parsing + */ +const requireMembershipAuth = ({ + acceptedRoles, + location = 'params' +}: { + acceptedRoles: string[]; + location?: req; +}) => { + return async ( + req: Request, + res: Response, + next: NextFunction + ) => { + try { + const { membershipId } = req[location]; + + const membership = await Membership.findById(membershipId); + + if (!membership) throw new Error('Failed to find target membership'); + + const userMembership = await Membership.findOne({ + workspace: membership.workspace + }); + + if (!userMembership) throw new Error('Failed to validate own membership') + + const targetMembership = await validateMembership({ + userId: req.user._id.toString(), + workspaceId: membership.workspace.toString(), + acceptedRoles + }); + + req.targetMembership = targetMembership; + + return next(); + } catch (err) { + return next(UnauthorizedRequestError({ + message: 'Unable to validate workspace membership' + })); + } + } +} + +export default requireMembershipAuth; \ No newline at end of file diff --git a/backend/src/middleware/requireMembershipOrgAuth.ts b/backend/src/middleware/requireMembershipOrgAuth.ts new file mode 100644 index 000000000..ec1a4d4f1 --- /dev/null +++ b/backend/src/middleware/requireMembershipOrgAuth.ts @@ -0,0 +1,49 @@ +import { Request, Response, NextFunction } from 'express'; +import { UnauthorizedRequestError } from '../utils/errors'; +import { + MembershipOrg +} from '../models'; +import { validateMembership } from '../helpers/membershipOrg'; + + +type req = 'params' | 'body' | 'query'; + +/** + * Validate (organization) membership id [membershipId] and that user with id + * [req.user._id] can modify that membership. + * @param {Object} obj + * @param {String[]} obj.acceptedRoles - accepted organization roles + * @param {String[]} obj.location - location of [membershipId] on request (e.g. params, body) for parsing + */ +const requireMembershipOrgAuth = ({ + acceptedRoles, + location = 'params' +}: { + acceptedRoles: string[]; + location?: req; +}) => { + return async (req: Request, res: Response, next: NextFunction) => { + try { + const { membershipId } = req[location]; + const membershipOrg = await MembershipOrg.findById(membershipId); + + if (!membershipOrg) throw new Error('Failed to find target organization membership'); + + const targetMembership = await validateMembership({ + userId: req.user._id.toString(), + organizationId: membershipOrg.organization.toString(), + acceptedRoles + }); + + req.targetMembership = targetMembership; + + return next(); + } catch (err) { + return next(UnauthorizedRequestError({ + message: 'Unable to validate organization membership' + })); + } + } +} + +export default requireMembershipOrgAuth; \ No newline at end of file diff --git a/backend/src/middleware/requireOrganizationAuth.ts b/backend/src/middleware/requireOrganizationAuth.ts index c77bd312e..04542b429 100644 --- a/backend/src/middleware/requireOrganizationAuth.ts +++ b/backend/src/middleware/requireOrganizationAuth.ts @@ -1,6 +1,6 @@ -import * as Sentry from '@sentry/node'; import { Request, Response, NextFunction } from 'express'; import { IOrganization, MembershipOrg } from '../models'; +import { UnauthorizedRequestError, ValidationError } from '../utils/errors'; /** * Validate if user on request is a member with proper roles for organization @@ -19,35 +19,28 @@ const requireOrganizationAuth = ({ return async (req: Request, res: Response, next: NextFunction) => { // organization authorization middleware - try { - // validate organization membership - const membershipOrg = await MembershipOrg.findOne({ - user: req.user._id, - organization: req.params.organizationId - }).populate<{ organization: IOrganization }>('organization'); + // validate organization membership + const membershipOrg = await MembershipOrg.findOne({ + user: req.user._id, + organization: req.params.organizationId + }).populate<{ organization: IOrganization }>('organization'); - if (!membershipOrg) { - throw new Error('Failed to find organization membership'); - } - if (!acceptedRoles.includes(membershipOrg.role)) { - throw new Error('Failed to validate organization membership role'); - } - - if (!acceptedStatuses.includes(membershipOrg.status)) { - throw new Error('Failed to validate organization membership status'); - } - - req.membershipOrg = membershipOrg; - - return next(); - } catch (err) { - Sentry.setUser(null); - Sentry.captureException(err); - return res.status(401).send({ - error: 'Failed organization authorization' - }); + if (!membershipOrg) { + return next(UnauthorizedRequestError({message: "You're not a member of this Organization."})) } + //TODO is this important to validate? I mean is it possible to save wrong role to database or get wrong role from databse? - Zamion101 + if (!acceptedRoles.includes(membershipOrg.role)) { + return next(ValidationError({message: 'Failed to validate Organization Membership Role'})) + } + + if (!acceptedStatuses.includes(membershipOrg.status)) { + return next(ValidationError({message: 'Failed to validate Organization Membership Status'})) + } + + req.membershipOrg = membershipOrg; + + return next(); }; }; diff --git a/backend/src/middleware/requireSecretAuth.ts b/backend/src/middleware/requireSecretAuth.ts new file mode 100644 index 000000000..36e47247e --- /dev/null +++ b/backend/src/middleware/requireSecretAuth.ts @@ -0,0 +1,49 @@ +import { Request, Response, NextFunction } from 'express'; +import { UnauthorizedRequestError, SecretNotFoundError } from '../utils/errors'; +import { Secret } from '../models'; +import { + validateMembership +} from '../helpers/membership'; + +// note: used for old /v1/secret and /v2/secret routes. +// newer /v2/secrets routes use [requireSecretsAuth] middleware + +/** + * Validate if user on request has proper membership to modify secret. + * @param {Object} obj + * @param {String[]} obj.acceptedRoles - accepted workspace roles + * @param {String[]} obj.location - location of [workspaceId] on request (e.g. params, body) for parsing + */ +const requireSecretAuth = ({ + acceptedRoles +}: { + acceptedRoles: string[]; +}) => { + return async (req: Request, res: Response, next: NextFunction) => { + try { + const { secretId } = req.params; + + const secret = await Secret.findById(secretId); + + if (!secret) { + return next(SecretNotFoundError({ + message: 'Failed to find secret' + })); + } + + await validateMembership({ + userId: req.user._id.toString(), + workspaceId: secret.workspace.toString(), + acceptedRoles + }); + + req._secret = secret; + + next(); + } catch (err) { + return next(UnauthorizedRequestError({ message: 'Unable to authenticate secret' })); + } + } +} + +export default requireSecretAuth; \ No newline at end of file diff --git a/backend/src/middleware/requireSecretsAuth.ts b/backend/src/middleware/requireSecretsAuth.ts new file mode 100644 index 000000000..c8b89a74c --- /dev/null +++ b/backend/src/middleware/requireSecretsAuth.ts @@ -0,0 +1,49 @@ +import { Request, Response, NextFunction } from 'express'; +import { UnauthorizedRequestError } from '../utils/errors'; +import { Secret, Membership } from '../models'; +import { validateSecrets } from '../helpers/secret'; + +// TODO: make this work for delete route + +const requireSecretsAuth = ({ + acceptedRoles +}: { + acceptedRoles: string[]; +}) => { + return async (req: Request, res: Response, next: NextFunction) => { + let secrets; + try { + if (Array.isArray(req.body.secrets)) { + // case: validate multiple secrets + secrets = await validateSecrets({ + userId: req.user._id.toString(), + secretIds: req.body.secrets.map((s: any) => s.id) + }); + } else if (typeof req.body.secrets === 'object') { // change this to check for object + // case: validate 1 secret + secrets = await validateSecrets({ + userId: req.user._id.toString(), + secretIds: req.body.secrets.id + }); + } else if (Array.isArray(req.body.secretIds)) { + secrets = await validateSecrets({ + userId: req.user._id.toString(), + secretIds: req.body.secretIds + }); + } else if (typeof req.body.secretIds === 'string') { + // case: validate secretIds + secrets = await validateSecrets({ + userId: req.user._id.toString(), + secretIds: [req.body.secretIds] + }); + } + + req.secrets = secrets; + return next(); + } catch (err) { + return next(UnauthorizedRequestError({ message: 'Unable to authenticate secret(s)' })); + } + } +} + +export default requireSecretsAuth; \ No newline at end of file diff --git a/backend/src/middleware/requireServiceTokenAuth.ts b/backend/src/middleware/requireServiceTokenAuth.ts index d403e8fe5..904f4d38e 100644 --- a/backend/src/middleware/requireServiceTokenAuth.ts +++ b/backend/src/middleware/requireServiceTokenAuth.ts @@ -1,9 +1,10 @@ import jwt from 'jsonwebtoken'; import { Request, Response, NextFunction } from 'express'; -import * as Sentry from '@sentry/node'; import { ServiceToken } from '../models'; import { JWT_SERVICE_SECRET } from '../config'; +import { BadRequestError, UnauthorizedRequestError } from '../utils/errors'; +// TODO: deprecate declare module 'jsonwebtoken' { export interface UserIDJwtPayload extends jwt.JwtPayload { userId: string; @@ -24,33 +25,27 @@ const requireServiceTokenAuth = async ( next: NextFunction ) => { // JWT service token middleware - try { - if (!req.headers?.authorization) - throw new Error('Failed to locate authorization header'); + + const [ AUTH_TOKEN_TYPE, AUTH_TOKEN_VALUE ] = <[string, string]>req.headers['authorization']?.split(' ', 2) ?? [null, null] + if(AUTH_TOKEN_TYPE === null) return next(BadRequestError({message: `Missing Authorization Header in the request header.`})) + //TODO: Determine what is the actual Token Type for Service Token Authentication (ex. Bearer) + //if(AUTH_TOKEN_TYPE.toLowerCase() !== 'bearer') return next(UnauthorizedRequestError({message: `The provided authentication type '${AUTH_TOKEN_TYPE}' is not supported.`})) + if(AUTH_TOKEN_VALUE === null) return next(BadRequestError({message: 'Missing Authorization Body in the request header'})) - const token = req.headers.authorization.split(' ')[1]; + const decodedToken = ( + jwt.verify(AUTH_TOKEN_VALUE, JWT_SERVICE_SECRET) + ); - const decodedToken = ( - jwt.verify(token, JWT_SERVICE_SECRET) - ); + const serviceToken = await ServiceToken.findOne({ + _id: decodedToken.serviceTokenId + }) + .populate('user', '+publicKey') + .select('+encryptedKey +publicKey +nonce'); - const serviceToken = await ServiceToken.findOne({ - _id: decodedToken.serviceTokenId - }) - .populate('user', '+publicKey') - .select('+encryptedKey +publicKey +nonce'); + if (!serviceToken) return next(UnauthorizedRequestError({message: 'The service token does not match the record in the database'})) - if (!serviceToken) throw new Error('Failed to find service token'); - - req.serviceToken = serviceToken; - return next(); - } catch (err) { - Sentry.setUser(null); - Sentry.captureException(err); - return res.status(401).send({ - error: 'Failed to authenticate service token' - }); - } + req.serviceToken = serviceToken; + return next(); }; export default requireServiceTokenAuth; diff --git a/backend/src/middleware/requireServiceTokenDataAuth.ts b/backend/src/middleware/requireServiceTokenDataAuth.ts new file mode 100644 index 000000000..7c5ab4669 --- /dev/null +++ b/backend/src/middleware/requireServiceTokenDataAuth.ts @@ -0,0 +1,41 @@ +import { Request, Response, NextFunction } from 'express'; +import { ServiceToken, ServiceTokenData } from '../models'; +import { validateMembership } from '../helpers/membership'; +import { AccountNotFoundError, UnauthorizedRequestError } from '../utils/errors'; + +type req = 'params' | 'body' | 'query'; + +const requireServiceTokenDataAuth = ({ + acceptedRoles, + location = 'params' +}: { + acceptedRoles: string[]; + location?: req; +}) => { + return async (req: Request, res: Response, next: NextFunction) => { + const { serviceTokenDataId } = req[location]; + + const serviceTokenData = await ServiceTokenData + .findById(req[location].serviceTokenDataId) + .select('+encryptedKey +iv +tag').populate('user'); + + if (!serviceTokenData) { + return next(AccountNotFoundError({ message: 'Failed to locate service token data' })); + } + + if (req.user) { + // case: jwt auth + await validateMembership({ + userId: req.user._id.toString(), + workspaceId: serviceTokenData.workspace.toString(), + acceptedRoles + }); + } + + req.serviceTokenData = serviceTokenData; + + next(); + } +} + +export default requireServiceTokenDataAuth; \ No newline at end of file diff --git a/backend/src/middleware/requireSignupAuth.ts b/backend/src/middleware/requireSignupAuth.ts index 9384387ee..3318bd8d3 100644 --- a/backend/src/middleware/requireSignupAuth.ts +++ b/backend/src/middleware/requireSignupAuth.ts @@ -1,8 +1,8 @@ import jwt from 'jsonwebtoken'; import { Request, Response, NextFunction } from 'express'; -import * as Sentry from '@sentry/node'; import { User } from '../models'; import { JWT_SIGNUP_SECRET } from '../config'; +import { BadRequestError, UnauthorizedRequestError } from '../utils/errors'; declare module 'jsonwebtoken' { export interface UserIDJwtPayload extends jwt.JwtPayload { @@ -21,32 +21,24 @@ const requireSignupAuth = async ( ) => { // JWT (temporary) authentication middleware for complete signup - try { - if (!req.headers?.authorization) - throw new Error('Failed to locate authorization header'); + const [ AUTH_TOKEN_TYPE, AUTH_TOKEN_VALUE ] = <[string, string]>req.headers['authorization']?.split(' ', 2) ?? [null, null] + if(AUTH_TOKEN_TYPE === null) return next(BadRequestError({message: `Missing Authorization Header in the request header.`})) + if(AUTH_TOKEN_TYPE.toLowerCase() !== 'bearer') return next(BadRequestError({message: `The provided authentication type '${AUTH_TOKEN_TYPE}' is not supported.`})) + if(AUTH_TOKEN_VALUE === null) return next(BadRequestError({message: 'Missing Authorization Body in the request header'})) + + const decodedToken = ( + jwt.verify(AUTH_TOKEN_VALUE, JWT_SIGNUP_SECRET) + ); - const token = req.headers.authorization.split(' ')[1]; - const decodedToken = ( - jwt.verify(token, JWT_SIGNUP_SECRET) - ); + const user = await User.findOne({ + _id: decodedToken.userId + }).select('+publicKey'); - const user = await User.findOne({ - _id: decodedToken.userId - }).select('+publicKey'); + if (!user) + return next(UnauthorizedRequestError({message: 'Unable to authenticate for User account completion. Try logging in again'})) - if (!user) - throw new Error('Failed to temporarily authenticate unfound user'); - - req.user = user; - return next(); - } catch (err) { - Sentry.setUser(null); - Sentry.captureException(err); - return res.status(401).send({ - error: - 'Failed to temporarily authenticate user for complete account. Try logging in' - }); - } + req.user = user; + return next(); }; export default requireSignupAuth; diff --git a/backend/src/middleware/requireWorkspaceAuth.ts b/backend/src/middleware/requireWorkspaceAuth.ts index 03fb7357f..9b710cc83 100644 --- a/backend/src/middleware/requireWorkspaceAuth.ts +++ b/backend/src/middleware/requireWorkspaceAuth.ts @@ -1,6 +1,6 @@ -import * as Sentry from '@sentry/node'; import { Request, Response, NextFunction } from 'express'; -import { Membership, IWorkspace } from '../models'; +import { validateMembership } from '../helpers/membership'; +import { UnauthorizedRequestError } from '../utils/errors'; type req = 'params' | 'body' | 'query'; @@ -8,51 +8,42 @@ type req = 'params' | 'body' | 'query'; * Validate if user on request is a member with proper roles for workspace * on request params. * @param {Object} obj - * @param {String[]} obj.acceptedRoles - accepted workspace roles - * @param {String[]} obj.acceptedStatuses - accepted workspace statuses + * @param {String[]} obj.acceptedRoles - accepted workspace roles for JWT auth * @param {String[]} obj.location - location of [workspaceId] on request (e.g. params, body) for parsing */ const requireWorkspaceAuth = ({ acceptedRoles, - acceptedStatuses, location = 'params' }: { acceptedRoles: string[]; - acceptedStatuses: string[]; location?: req; }) => { return async (req: Request, res: Response, next: NextFunction) => { - // workspace authorization middleware - try { - // validate workspace membership + const { workspaceId } = req[location]; - const membership = await Membership.findOne({ - user: req.user._id, - workspace: req[location].workspaceId - }).populate<{ workspace: IWorkspace }>('workspace'); + if (req.user) { + // case: jwt auth + const membership = await validateMembership({ + userId: req.user._id.toString(), + workspaceId, + acceptedRoles + }); - if (!membership) { - throw new Error('Failed to find workspace membership'); + req.membership = membership; } - - if (!acceptedRoles.includes(membership.role)) { - throw new Error('Failed to validate workspace membership role'); + + if ( + req.serviceTokenData + && req.serviceTokenData.workspace !== workspaceId + && req.serviceTokenData.environment !== req.query.environment + ) { + next(UnauthorizedRequestError({message: 'Unable to authenticate workspace'})) } - if (!acceptedStatuses.includes(membership.status)) { - throw new Error('Failed to validate workspace membership status'); - } - - req.membership = membership; - return next(); } catch (err) { - Sentry.setUser(null); - Sentry.captureException(err); - return res.status(401).send({ - error: 'Failed workspace authorization' - }); + return next(UnauthorizedRequestError({message: 'Unable to authenticate workspace'})) } }; }; diff --git a/backend/src/middleware/validateRequest.ts b/backend/src/middleware/validateRequest.ts index 4dcafc13b..1b0364766 100644 --- a/backend/src/middleware/validateRequest.ts +++ b/backend/src/middleware/validateRequest.ts @@ -1,6 +1,6 @@ import { Request, Response, NextFunction } from 'express'; -import * as Sentry from '@sentry/node'; import { validationResult } from 'express-validator'; +import { BadRequestError, UnauthorizedRequestError, ValidationError } from '../utils/errors'; /** * Validate intended inputs on [req] via express-validator @@ -15,16 +15,12 @@ const validate = (req: Request, res: Response, next: NextFunction) => { try { const errors = validationResult(req); if (!errors.isEmpty()) { - return res.status(400).json({ errors: errors.array() }); + return next(ValidationError({ context: { errors: `One or more of your parameters are invalid [error(s)=${(JSON.stringify(errors))}]` } })) } return next(); } catch (err) { - Sentry.setUser(null); - Sentry.captureException(err); - return res.status(401).send({ - error: "Looks like you're unauthenticated . Try logging in" - }); + return next(UnauthorizedRequestError({ message: 'Unauthenticated requests are not allowed. Try logging in' })) } }; diff --git a/backend/src/models/LoginSRPDetail.ts b/backend/src/models/LoginSRPDetail.ts new file mode 100644 index 000000000..f65e779c3 --- /dev/null +++ b/backend/src/models/LoginSRPDetail.ts @@ -0,0 +1,23 @@ +import mongoose, { Schema, model } from 'mongoose'; + +const LoginSRPDetailSchema = new Schema( + { + clientPublicKey: { + type: String, + required: true + }, + email: { + type: String, + required: true, + unique: true + }, + serverBInt: { type: mongoose.Schema.Types.Buffer }, + expireAt: { type: Date } + } +); + +const LoginSRPDetail = model('LoginSRPDetail', LoginSRPDetailSchema); + +// LoginSRPDetailSchema.index({ "expireAt": 1 }, { expireAfterSeconds: 0 }); + +export default LoginSRPDetail; diff --git a/backend/src/models/apiKeyData.ts b/backend/src/models/apiKeyData.ts new file mode 100644 index 000000000..af73b5f69 --- /dev/null +++ b/backend/src/models/apiKeyData.ts @@ -0,0 +1,37 @@ +import { Schema, model, Types } from 'mongoose'; + +export interface IAPIKeyData { + name: string; + user: Types.ObjectId; + expiresAt: Date; + secretHash: string; +} + +const apiKeyDataSchema = new Schema( + { + name: { + type: String, + required: true + }, + user: { + type: Schema.Types.ObjectId, + ref: 'User', + required: true + }, + expiresAt: { + type: Date + }, + secretHash: { + type: String, + required: true, + select: false + } + }, + { + timestamps: true + } +); + +const APIKeyData = model('APIKeyData', apiKeyDataSchema); + +export default APIKeyData; diff --git a/backend/src/models/bot.ts b/backend/src/models/bot.ts new file mode 100644 index 000000000..c7e5a9abe --- /dev/null +++ b/backend/src/models/bot.ts @@ -0,0 +1,57 @@ +import { Schema, model, Types } from 'mongoose'; + +export interface IBot { + _id: Types.ObjectId; + name: string; + workspace: Types.ObjectId; + isActive: boolean; + publicKey: string; + encryptedPrivateKey: string; + iv: string; + tag: string; +} + +const botSchema = new Schema( + { + name: { + type: String, + required: true + }, + workspace: { + type: Schema.Types.ObjectId, + ref: 'Workspace', + required: true + }, + isActive: { + type: Boolean, + required: true, + default: false + }, + publicKey: { + type: String, + required: true + }, + encryptedPrivateKey: { + type: String, + required: true, + select: false + }, + iv: { + type: String, + required: true, + select: false + }, + tag: { + type: String, + required: true, + select: false + } + }, + { + timestamps: true + } +); + +const Bot = model('Bot', botSchema); + +export default Bot; diff --git a/backend/src/models/botKey.ts b/backend/src/models/botKey.ts new file mode 100644 index 000000000..79555cd53 --- /dev/null +++ b/backend/src/models/botKey.ts @@ -0,0 +1,45 @@ +import { Schema, model, Types } from 'mongoose'; + +export interface IBotKey { + _id: Types.ObjectId; + encryptedKey: string; + nonce: string; + sender: Types.ObjectId; + bot: Types.ObjectId; + workspace: Types.ObjectId; +} + +const botKeySchema = new Schema( + { + encryptedKey: { + type: String, + required: true + }, + nonce: { + type: String, + required: true + }, + sender: { + type: Schema.Types.ObjectId, + ref: 'User', + required: true + }, + bot: { + type: Schema.Types.ObjectId, + ref: 'Bot', + required: true + }, + workspace: { + type: Schema.Types.ObjectId, + ref: 'Workspace', + required: true + } + }, + { + timestamps: true + } +); + +const BotKey = model('BotKey', botKeySchema); + +export default BotKey; diff --git a/backend/src/models/index.ts b/backend/src/models/index.ts index 9b07f6766..72ffca607 100644 --- a/backend/src/models/index.ts +++ b/backend/src/models/index.ts @@ -1,4 +1,6 @@ import BackupPrivateKey, { IBackupPrivateKey } from './backupPrivateKey'; +import Bot, { IBot } from './bot'; +import BotKey, { IBotKey } from './botKey'; import IncidentContactOrg, { IIncidentContactOrg } from './incidentContactOrg'; import Integration, { IIntegration } from './integration'; import IntegrationAuth, { IIntegrationAuth } from './integrationAuth'; @@ -12,10 +14,16 @@ import Token, { IToken } from './token'; import User, { IUser } from './user'; import UserAction, { IUserAction } from './userAction'; import Workspace, { IWorkspace } from './workspace'; +import ServiceTokenData, { IServiceTokenData } from './serviceTokenData'; +import APIKeyData, { IAPIKeyData } from './apiKeyData'; export { BackupPrivateKey, IBackupPrivateKey, + Bot, + IBot, + BotKey, + IBotKey, IncidentContactOrg, IIncidentContactOrg, Integration, @@ -41,5 +49,9 @@ export { UserAction, IUserAction, Workspace, - IWorkspace + IWorkspace, + ServiceTokenData, + IServiceTokenData, + APIKeyData, + IAPIKeyData }; diff --git a/backend/src/models/integration.ts b/backend/src/models/integration.ts index 5e72e8b54..01e1d7ee3 100644 --- a/backend/src/models/integration.ts +++ b/backend/src/models/integration.ts @@ -1,59 +1,82 @@ import { Schema, model, Types } from 'mongoose'; import { - ENV_DEV, - ENV_TESTING, - ENV_STAGING, - ENV_PROD, - INTEGRATION_HEROKU, - INTEGRATION_NETLIFY + INTEGRATION_HEROKU, + INTEGRATION_VERCEL, + INTEGRATION_NETLIFY, + INTEGRATION_GITHUB, + INTEGRATION_RENDER, + INTEGRATION_FLYIO } from '../variables'; export interface IIntegration { - _id: Types.ObjectId; - workspace: Types.ObjectId; - environment: 'dev' | 'test' | 'staging' | 'prod'; - isActive: boolean; - app: string; - integration: 'heroku' | 'netlify'; - integrationAuth: Types.ObjectId; + _id: Types.ObjectId; + workspace: Types.ObjectId; + environment: string; + isActive: boolean; + app: string; + owner: string; + targetEnvironment: string; + appId: string; + integration: 'heroku' | 'vercel' | 'netlify' | 'github' | 'render' | 'flyio'; + integrationAuth: Types.ObjectId; } const integrationSchema = new Schema( - { - workspace: { - type: Schema.Types.ObjectId, - ref: 'Workspace', - required: true - }, - environment: { - type: String, - enum: [ENV_DEV, ENV_TESTING, ENV_STAGING, ENV_PROD], - required: true - }, - isActive: { - type: Boolean, - required: true - }, - app: { - // name of app in provider - type: String, - default: null, - required: true - }, - integration: { - type: String, - enum: [INTEGRATION_HEROKU, INTEGRATION_NETLIFY], - required: true - }, - integrationAuth: { - type: Schema.Types.ObjectId, - ref: 'IntegrationAuth', - required: true - } - }, - { - timestamps: true - } + { + workspace: { + type: Schema.Types.ObjectId, + ref: 'Workspace', + required: true + }, + environment: { + type: String, + required: true + }, + isActive: { + type: Boolean, + required: true + }, + app: { + // name of app in provider + type: String, + default: null + }, + appId: { // (new) + // id of app in provider + type: String, + default: null + }, + targetEnvironment: { // (new) + // target environment + type: String, + default: null + }, + owner: { + // github-specific repo owner-login + type: String, + default: null + }, + integration: { + type: String, + enum: [ + INTEGRATION_HEROKU, + INTEGRATION_VERCEL, + INTEGRATION_NETLIFY, + INTEGRATION_GITHUB, + INTEGRATION_RENDER, + INTEGRATION_FLYIO + ], + required: true + }, + integrationAuth: { + type: Schema.Types.ObjectId, + ref: 'IntegrationAuth', + required: true + } + }, + { + timestamps: true + } ); const Integration = model('Integration', integrationSchema); diff --git a/backend/src/models/integrationAuth.ts b/backend/src/models/integrationAuth.ts index 0e9542a20..bff56f09a 100644 --- a/backend/src/models/integrationAuth.ts +++ b/backend/src/models/integrationAuth.ts @@ -1,67 +1,88 @@ import { Schema, model, Types } from 'mongoose'; -import { INTEGRATION_HEROKU, INTEGRATION_NETLIFY } from '../variables'; +import { + INTEGRATION_HEROKU, + INTEGRATION_VERCEL, + INTEGRATION_NETLIFY, + INTEGRATION_GITHUB +} from '../variables'; export interface IIntegrationAuth { - _id: Types.ObjectId; - workspace: Types.ObjectId; - integration: 'heroku' | 'netlify'; - refreshCiphertext?: string; - refreshIV?: string; - refreshTag?: string; - accessCiphertext?: string; - accessIV?: string; - accessTag?: string; - accessExpiresAt?: Date; + _id: Types.ObjectId; + workspace: Types.ObjectId; + integration: 'heroku' | 'vercel' | 'netlify' | 'github' | 'render' | 'flyio'; + teamId: string; + accountId: string; + refreshCiphertext?: string; + refreshIV?: string; + refreshTag?: string; + accessCiphertext?: string; + accessIV?: string; + accessTag?: string; + accessExpiresAt?: Date; } const integrationAuthSchema = new Schema( - { - workspace: { - type: Schema.Types.ObjectId, - required: true - }, - integration: { - type: String, - enum: [INTEGRATION_HEROKU, INTEGRATION_NETLIFY], - required: true - }, - refreshCiphertext: { - type: String, - select: false - }, - refreshIV: { - type: String, - select: false - }, - refreshTag: { - type: String, - select: false - }, - accessCiphertext: { - type: String, - select: false - }, - accessIV: { - type: String, - select: false - }, - accessTag: { - type: String, - select: false - }, - accessExpiresAt: { - type: Date, - select: false - } - }, - { - timestamps: true - } + { + workspace: { + type: Schema.Types.ObjectId, + ref: 'Workspace', + required: true + }, + integration: { + type: String, + enum: [ + INTEGRATION_HEROKU, + INTEGRATION_VERCEL, + INTEGRATION_NETLIFY, + INTEGRATION_GITHUB + ], + required: true + }, + teamId: { + // vercel-specific integration param + type: String + }, + accountId: { + // netlify-specific integration param + type: String + }, + refreshCiphertext: { + type: String, + select: false + }, + refreshIV: { + type: String, + select: false + }, + refreshTag: { + type: String, + select: false + }, + accessCiphertext: { + type: String, + select: false + }, + accessIV: { + type: String, + select: false + }, + accessTag: { + type: String, + select: false + }, + accessExpiresAt: { + type: Date, + select: false + } + }, + { + timestamps: true + } ); const IntegrationAuth = model( - 'IntegrationAuth', - integrationAuthSchema + 'IntegrationAuth', + integrationAuthSchema ); export default IntegrationAuth; diff --git a/backend/src/models/membership.ts b/backend/src/models/membership.ts index a38c64651..55b8f2048 100644 --- a/backend/src/models/membership.ts +++ b/backend/src/models/membership.ts @@ -1,5 +1,10 @@ import { Schema, model, Types } from 'mongoose'; -import { ADMIN, MEMBER, INVITED, COMPLETED, GRANTED } from '../variables'; +import { ADMIN, MEMBER } from '../variables'; + +export interface IMembershipPermission { + environmentSlug: string, + ability: string +} export interface IMembership { _id: Types.ObjectId; @@ -7,10 +12,10 @@ export interface IMembership { inviteEmail?: string; workspace: Types.ObjectId; role: 'admin' | 'member'; - status: 'invited' | 'completed' | 'granted'; + deniedPermissions: IMembershipPermission[] } -const membershipSchema = new Schema( +const membershipSchema = new Schema( { user: { type: Schema.Types.ObjectId, @@ -24,16 +29,22 @@ const membershipSchema = new Schema( ref: 'Workspace', required: true }, + deniedPermissions: { + type: [ + { + environmentSlug: String, + ability: { + type: String, + enum: ['read', 'write'] + }, + }, + ], + default: [] + }, role: { type: String, enum: [ADMIN, MEMBER], required: true - }, - status: { - // INVITED, COMPLETED, GRANTED - type: String, - enum: [INVITED, COMPLETED, GRANTED], - required: true } }, { diff --git a/backend/src/models/secret.ts b/backend/src/models/secret.ts index b83ef728d..6887c8b0f 100644 --- a/backend/src/models/secret.ts +++ b/backend/src/models/secret.ts @@ -2,14 +2,11 @@ import { Schema, model, Types } from 'mongoose'; import { SECRET_SHARED, SECRET_PERSONAL, - ENV_DEV, - ENV_TESTING, - ENV_STAGING, - ENV_PROD } from '../variables'; export interface ISecret { _id: Types.ObjectId; + version: number; workspace: Types.ObjectId; type: string; user: Types.ObjectId; @@ -22,10 +19,19 @@ export interface ISecret { secretValueIV: string; secretValueTag: string; secretValueHash: string; + secretCommentCiphertext?: string; + secretCommentIV?: string; + secretCommentTag?: string; + secretCommentHash?: string; } const secretSchema = new Schema( { + version: { + type: Number, + required: true, + default: 1 + }, workspace: { type: Schema.Types.ObjectId, ref: 'Workspace', @@ -43,7 +49,6 @@ const secretSchema = new Schema( }, environment: { type: String, - enum: [ENV_DEV, ENV_TESTING, ENV_STAGING, ENV_PROD], required: true }, secretKeyCiphertext: { @@ -59,8 +64,7 @@ const secretSchema = new Schema( required: true }, secretKeyHash: { - type: String, - required: true + type: String }, secretValueCiphertext: { type: String, @@ -75,8 +79,23 @@ const secretSchema = new Schema( required: true }, secretValueHash: { + type: String + }, + secretCommentCiphertext: { type: String, - required: true + required: false + }, + secretCommentIV: { + type: String, // symmetric + required: false + }, + secretCommentTag: { + type: String, // symmetric + required: false + }, + secretCommentHash: { + type: String, + required: false } }, { diff --git a/backend/src/models/serviceToken.ts b/backend/src/models/serviceToken.ts index 73f705fc8..9d91b076e 100644 --- a/backend/src/models/serviceToken.ts +++ b/backend/src/models/serviceToken.ts @@ -1,6 +1,4 @@ import { Schema, model, Types } from 'mongoose'; -import { ENV_DEV, ENV_TESTING, ENV_STAGING, ENV_PROD } from '../variables'; - export interface IServiceToken { _id: Types.ObjectId; name: string; @@ -32,7 +30,6 @@ const serviceTokenSchema = new Schema( }, environment: { type: String, - enum: [ENV_DEV, ENV_TESTING, ENV_STAGING, ENV_PROD], required: true }, expiresAt: { diff --git a/backend/src/models/serviceTokenData.ts b/backend/src/models/serviceTokenData.ts new file mode 100644 index 000000000..612d07bf6 --- /dev/null +++ b/backend/src/models/serviceTokenData.ts @@ -0,0 +1,63 @@ +import { Schema, model, Types } from 'mongoose'; + +export interface IServiceTokenData { + name: string; + workspace: Types.ObjectId; + environment: string; // TODO: adapt to upcoming environment id + user: Types.ObjectId; + expiresAt: Date; + secretHash: string; + encryptedKey: string; + iv: string; + tag: string; +} + +const serviceTokenDataSchema = new Schema( + { + name: { + type: String, + required: true + }, + workspace: { + type: Schema.Types.ObjectId, + ref: 'Workspace', + required: true + }, + environment: { // TODO: adapt to upcoming environment id + type: String, + required: true + }, + user: { + type: Schema.Types.ObjectId, + ref: 'User', + required: true + }, + expiresAt: { + type: Date + }, + secretHash: { + type: String, + required: true, + select: false + }, + encryptedKey: { + type: String, + select: false + }, + iv: { + type: String, + select: false + }, + tag: { + type: String, + select: false + } + }, + { + timestamps: true + } +); + +const ServiceTokenData = model('ServiceTokenData', serviceTokenDataSchema); + +export default ServiceTokenData; diff --git a/backend/src/models/user.ts b/backend/src/models/user.ts index aa1c5d239..7ea988c9d 100644 --- a/backend/src/models/user.ts +++ b/backend/src/models/user.ts @@ -11,7 +11,7 @@ export interface IUser { tag?: string; salt?: string; verifier?: string; - refreshVersion?: Number; + refreshVersion?: number; } const userSchema = new Schema( @@ -52,7 +52,8 @@ const userSchema = new Schema( }, refreshVersion: { type: Number, - default: 0 + default: 0, + select: false } }, { diff --git a/backend/src/models/workspace.ts b/backend/src/models/workspace.ts index 1e886c523..a70b64340 100644 --- a/backend/src/models/workspace.ts +++ b/backend/src/models/workspace.ts @@ -4,6 +4,10 @@ export interface IWorkspace { _id: Types.ObjectId; name: string; organization: Types.ObjectId; + environments: Array<{ + name: string; + slug: string; + }>; } const workspaceSchema = new Schema({ @@ -15,7 +19,33 @@ const workspaceSchema = new Schema({ type: Schema.Types.ObjectId, ref: 'Organization', required: true - } + }, + environments: { + type: [ + { + name: String, + slug: String, + }, + ], + default: [ + { + name: "Development", + slug: "dev" + }, + { + name: "Test", + slug: "test" + }, + { + name: "Staging", + slug: "staging" + }, + { + name: "Production", + slug: "prod" + } + ], + }, }); const Workspace = model('Workspace', workspaceSchema); diff --git a/backend/src/routes/integration.ts b/backend/src/routes/integration.ts deleted file mode 100644 index d16154172..000000000 --- a/backend/src/routes/integration.ts +++ /dev/null @@ -1,53 +0,0 @@ -import express from 'express'; -const router = express.Router(); -import { - requireAuth, - requireIntegrationAuth, - validateRequest -} from '../middleware'; -import { ADMIN, MEMBER, GRANTED } from '../variables'; -import { body, param } from 'express-validator'; -import { integrationController } from '../controllers'; - -router.get('/integrations', requireAuth, integrationController.getIntegrations); - -router.post( - '/:integrationId/sync', - requireAuth, - requireIntegrationAuth({ - acceptedRoles: [ADMIN, MEMBER], - acceptedStatuses: [GRANTED] - }), - param('integrationId').exists().trim(), - body('key').exists(), - body('secrets').exists(), - validateRequest, - integrationController.syncIntegration -); - -router.patch( - '/:integrationId', - requireAuth, - requireIntegrationAuth({ - acceptedRoles: [ADMIN, MEMBER], - acceptedStatuses: [GRANTED] - }), - param('integrationId'), - body('update'), - validateRequest, - integrationController.modifyIntegration -); - -router.delete( - '/:integrationId', - requireAuth, - requireIntegrationAuth({ - acceptedRoles: [ADMIN, MEMBER], - acceptedStatuses: [GRANTED] - }), - param('integrationId'), - validateRequest, - integrationController.deleteIntegration -); - -export default router; diff --git a/backend/src/routes/membership.ts b/backend/src/routes/membership.ts deleted file mode 100644 index 04d94f576..000000000 --- a/backend/src/routes/membership.ts +++ /dev/null @@ -1,31 +0,0 @@ -import express from 'express'; -const router = express.Router(); -import { body, param } from 'express-validator'; -import { requireAuth, validateRequest } from '../middleware'; -import { membershipController } from '../controllers'; - -router.get( // used for CLI (deprecate) - '/:workspaceId/connect', - requireAuth, - param('workspaceId').exists().trim(), - validateRequest, - membershipController.validateMembership -); - -router.delete( - '/:membershipId', - requireAuth, - param('membershipId').exists().trim(), - validateRequest, - membershipController.deleteMembership -); - -router.post( - '/:membershipId/change-role', - requireAuth, - body('role').exists().trim(), - validateRequest, - membershipController.changeMembershipRole -); - -export default router; diff --git a/backend/src/routes/status/index.ts b/backend/src/routes/status/index.ts new file mode 100644 index 000000000..d3c694b92 --- /dev/null +++ b/backend/src/routes/status/index.ts @@ -0,0 +1,5 @@ +import healthCheck from './status'; + +export { + healthCheck +} \ No newline at end of file diff --git a/backend/src/routes/status/status.ts b/backend/src/routes/status/status.ts new file mode 100644 index 000000000..4ab82cca9 --- /dev/null +++ b/backend/src/routes/status/status.ts @@ -0,0 +1,15 @@ +import express, { Request, Response } from 'express'; + +const router = express.Router(); + +router.get( + '/status', + (req: Request, res: Response) => { + res.status(200).json({ + date: new Date(), + message: 'Ok', + }) + } +); + +export default router \ No newline at end of file diff --git a/backend/src/routes/user.ts b/backend/src/routes/user.ts deleted file mode 100644 index 4a25c48fb..000000000 --- a/backend/src/routes/user.ts +++ /dev/null @@ -1,8 +0,0 @@ -import express from 'express'; -const router = express.Router(); -import { requireAuth } from '../middleware'; -import { userController } from '../controllers'; - -router.get('/', requireAuth, userController.getUser); - -export default router; diff --git a/backend/src/routes/auth.ts b/backend/src/routes/v1/auth.ts similarity index 54% rename from backend/src/routes/auth.ts rename to backend/src/routes/v1/auth.ts index 6be9c09f7..99a65e4ef 100644 --- a/backend/src/routes/auth.ts +++ b/backend/src/routes/v1/auth.ts @@ -1,15 +1,15 @@ import express from 'express'; const router = express.Router(); import { body } from 'express-validator'; -import { requireAuth, validateRequest } from '../middleware'; -import { authController } from '../controllers'; -import { loginLimiter } from '../helpers/rateLimiter'; +import { requireAuth, validateRequest } from '../../middleware'; +import { authController } from '../../controllers/v1'; +import { authLimiter } from '../../helpers/rateLimiter'; router.post('/token', validateRequest, authController.getNewToken); router.post( '/login1', - loginLimiter, + authLimiter, body('email').exists().trim().notEmpty(), body('clientPublicKey').exists().trim().notEmpty(), validateRequest, @@ -18,14 +18,28 @@ router.post( router.post( '/login2', - loginLimiter, + authLimiter, body('email').exists().trim().notEmpty(), body('clientProof').exists().trim().notEmpty(), validateRequest, authController.login2 ); -router.post('/logout', requireAuth, authController.logout); -router.post('/checkAuth', requireAuth, authController.checkAuth); +router.post( + '/logout', + authLimiter, + requireAuth({ + acceptedAuthModes: ['jwt'] + }), + authController.logout +); + +router.post( + '/checkAuth', + requireAuth({ + acceptedAuthModes: ['jwt'] + }), + authController.checkAuth +); export default router; diff --git a/backend/src/routes/v1/bot.ts b/backend/src/routes/v1/bot.ts new file mode 100644 index 000000000..1b98f48c5 --- /dev/null +++ b/backend/src/routes/v1/bot.ts @@ -0,0 +1,40 @@ +import express from 'express'; +const router = express.Router(); +import { body, param } from 'express-validator'; +import { + requireAuth, + requireBotAuth, + requireWorkspaceAuth, + validateRequest +} from '../../middleware'; +import { botController } from '../../controllers/v1'; +import { ADMIN, MEMBER } from '../../variables'; + +router.get( + '/:workspaceId', + requireAuth({ + acceptedAuthModes: ['jwt'] + }), + requireWorkspaceAuth({ + acceptedRoles: [ADMIN, MEMBER] + }), + param('workspaceId').exists().trim().notEmpty(), + validateRequest, + botController.getBotByWorkspaceId +); + +router.patch( + '/:botId/active', + requireAuth({ + acceptedAuthModes: ['jwt'] + }), + requireBotAuth({ + acceptedRoles: [ADMIN, MEMBER] + }), + body('isActive').isBoolean(), + body('botKey'), + validateRequest, + botController.setBotActiveState +); + +export default router; \ No newline at end of file diff --git a/backend/src/routes/index.ts b/backend/src/routes/v1/index.ts similarity index 96% rename from backend/src/routes/index.ts rename to backend/src/routes/v1/index.ts index cf015abfb..2dfe58baa 100644 --- a/backend/src/routes/index.ts +++ b/backend/src/routes/v1/index.ts @@ -1,4 +1,5 @@ import signup from './signup'; +import bot from './bot'; import auth from './auth'; import user from './user'; import userAction from './userAction'; @@ -18,6 +19,7 @@ import integrationAuth from './integrationAuth'; export { signup, auth, + bot, user, userAction, organization, diff --git a/backend/src/routes/v1/integration.ts b/backend/src/routes/v1/integration.ts new file mode 100644 index 000000000..d587bd2e5 --- /dev/null +++ b/backend/src/routes/v1/integration.ts @@ -0,0 +1,59 @@ +import express from 'express'; +const router = express.Router(); +import { + requireAuth, + requireIntegrationAuth, + requireIntegrationAuthorizationAuth, + validateRequest +} from '../../middleware'; +import { ADMIN, MEMBER } from '../../variables'; +import { body, param } from 'express-validator'; +import { integrationController } from '../../controllers/v1'; + +router.post( // new: add new integration + '/', + requireAuth({ + acceptedAuthModes: ['jwt', 'apiKey'] + }), + requireIntegrationAuthorizationAuth({ + acceptedRoles: [ADMIN, MEMBER], + location: 'body' + }), + body('integrationAuthId').exists().trim(), + validateRequest, + integrationController.createIntegration +); + +router.patch( + '/:integrationId', + requireAuth({ + acceptedAuthModes: ['jwt'] + }), + requireIntegrationAuth({ + acceptedRoles: [ADMIN, MEMBER] + }), + param('integrationId').exists().trim(), + body('isActive').exists().isBoolean(), + body('app').exists().trim(), + body('environment').exists().trim(), + body('appId').exists(), + body('targetEnvironment').exists(), + body('owner').exists(), + validateRequest, + integrationController.updateIntegration +); + +router.delete( + '/:integrationId', + requireAuth({ + acceptedAuthModes: ['jwt'] + }), + requireIntegrationAuth({ + acceptedRoles: [ADMIN, MEMBER] + }), + param('integrationId').exists().trim(), + validateRequest, + integrationController.deleteIntegration +); + +export default router; diff --git a/backend/src/routes/integrationAuth.ts b/backend/src/routes/v1/integrationAuth.ts similarity index 50% rename from backend/src/routes/integrationAuth.ts rename to backend/src/routes/v1/integrationAuth.ts index 61e5f56bf..3f88aa7e5 100644 --- a/backend/src/routes/integrationAuth.ts +++ b/backend/src/routes/v1/integrationAuth.ts @@ -6,31 +6,57 @@ import { requireWorkspaceAuth, requireIntegrationAuthorizationAuth, validateRequest -} from '../middleware'; -import { ADMIN, MEMBER, GRANTED } from '../variables'; -import { integrationAuthController } from '../controllers'; +} from '../../middleware'; +import { ADMIN, MEMBER } from '../../variables'; +import { integrationAuthController } from '../../controllers/v1'; + +router.get( + '/integration-options', + requireAuth({ + acceptedAuthModes: ['jwt'] + }), + integrationAuthController.getIntegrationOptions +); router.post( '/oauth-token', - requireAuth, + requireAuth({ + acceptedAuthModes: ['jwt'] + }), requireWorkspaceAuth({ acceptedRoles: [ADMIN, MEMBER], - acceptedStatuses: [GRANTED], location: 'body' }), body('workspaceId').exists().trim().notEmpty(), body('code').exists().trim().notEmpty(), body('integration').exists().trim().notEmpty(), validateRequest, - integrationAuthController.integrationAuthOauthExchange + integrationAuthController.oAuthExchange +); + +router.post( + '/access-token', + requireAuth({ + acceptedAuthModes: ['jwt', 'apiKey'] + }), + requireWorkspaceAuth({ + acceptedRoles: [ADMIN, MEMBER], + location: 'body' + }), + body('workspaceId').exists().trim().notEmpty(), + body('accessToken').exists().trim().notEmpty(), + body('integration').exists().trim().notEmpty(), + validateRequest, + integrationAuthController.saveIntegrationAccessToken ); router.get( '/:integrationAuthId/apps', - requireAuth, + requireAuth({ + acceptedAuthModes: ['jwt'] + }), requireIntegrationAuthorizationAuth({ - acceptedRoles: [ADMIN, MEMBER], - acceptedStatuses: [GRANTED] + acceptedRoles: [ADMIN, MEMBER] }), param('integrationAuthId'), validateRequest, @@ -39,10 +65,12 @@ router.get( router.delete( '/:integrationAuthId', - requireAuth, + requireAuth({ + acceptedAuthModes: ['jwt'] + }), requireIntegrationAuthorizationAuth({ acceptedRoles: [ADMIN, MEMBER], - acceptedStatuses: [GRANTED] + attachAccessToken: false }), param('integrationAuthId'), validateRequest, diff --git a/backend/src/routes/inviteOrg.ts b/backend/src/routes/v1/inviteOrg.ts similarity index 73% rename from backend/src/routes/inviteOrg.ts rename to backend/src/routes/v1/inviteOrg.ts index 16ab64f85..d8e2d67cc 100644 --- a/backend/src/routes/inviteOrg.ts +++ b/backend/src/routes/v1/inviteOrg.ts @@ -1,12 +1,14 @@ import express from 'express'; const router = express.Router(); import { body } from 'express-validator'; -import { requireAuth, validateRequest } from '../middleware'; -import { membershipOrgController } from '../controllers'; +import { requireAuth, validateRequest } from '../../middleware'; +import { membershipOrgController } from '../../controllers/v1'; router.post( '/signup', - requireAuth, + requireAuth({ + acceptedAuthModes: ['jwt'] + }), body('inviteeEmail').exists().trim().notEmpty().isEmail(), body('organizationId').exists().trim().notEmpty(), validateRequest, diff --git a/backend/src/routes/key.ts b/backend/src/routes/v1/key.ts similarity index 56% rename from backend/src/routes/key.ts rename to backend/src/routes/v1/key.ts index 9541ca123..b66bd1276 100644 --- a/backend/src/routes/key.ts +++ b/backend/src/routes/v1/key.ts @@ -4,17 +4,18 @@ import { requireAuth, requireWorkspaceAuth, validateRequest -} from '../middleware'; +} from '../../middleware'; import { body, param } from 'express-validator'; -import { ADMIN, MEMBER, COMPLETED, GRANTED } from '../variables'; -import { keyController } from '../controllers'; +import { ADMIN, MEMBER } from '../../variables'; +import { keyController } from '../../controllers/v1'; router.post( '/:workspaceId', - requireAuth, + requireAuth({ + acceptedAuthModes: ['jwt'] + }), requireWorkspaceAuth({ - acceptedRoles: [ADMIN, MEMBER], - acceptedStatuses: [COMPLETED, GRANTED] + acceptedRoles: [ADMIN, MEMBER] }), param('workspaceId').exists().trim(), body('key').exists(), @@ -24,16 +25,15 @@ router.post( router.get( '/:workspaceId/latest', - requireAuth, + requireAuth({ + acceptedAuthModes: ['jwt'] + }), requireWorkspaceAuth({ - acceptedRoles: [ADMIN, MEMBER], - acceptedStatuses: [COMPLETED, GRANTED] + acceptedRoles: [ADMIN, MEMBER] }), param('workspaceId'), validateRequest, keyController.getLatestKey ); -router.get('/publicKey/infisical', keyController.getPublicKeyInfisical); - export default router; diff --git a/backend/src/routes/v1/membership.ts b/backend/src/routes/v1/membership.ts new file mode 100644 index 000000000..aaacada74 --- /dev/null +++ b/backend/src/routes/v1/membership.ts @@ -0,0 +1,51 @@ +import express from 'express'; +const router = express.Router(); +import { body, param } from 'express-validator'; +import { requireAuth, validateRequest } from '../../middleware'; +import { membershipController } from '../../controllers/v1'; +import { membershipController as EEMembershipControllers } from '../../ee/controllers/v1'; + +// note: ALL DEPRECIATED (moved to api/v2/workspace/:workspaceId/memberships/:membershipId) + +router.get( // used for old CLI (deprecate) + '/:workspaceId/connect', + requireAuth({ + acceptedAuthModes: ['jwt'] + }), + param('workspaceId').exists().trim(), + validateRequest, + membershipController.validateMembership +); + +router.delete( + '/:membershipId', + requireAuth({ + acceptedAuthModes: ['jwt'] + }), + param('membershipId').exists().trim(), + validateRequest, + membershipController.deleteMembership +); + +router.post( + '/:membershipId/change-role', + requireAuth({ + acceptedAuthModes: ['jwt'] + }), + body('role').exists().trim(), + validateRequest, + membershipController.changeMembershipRole +); + +router.post( + '/:membershipId/deny-permissions', + requireAuth({ + acceptedAuthModes: ['jwt'] + }), + param('membershipId').isMongoId().exists().trim(), + body('permissions').isArray().exists(), + validateRequest, + EEMembershipControllers.denyMembershipPermissions +); + +export default router; diff --git a/backend/src/routes/membershipOrg.ts b/backend/src/routes/v1/membershipOrg.ts similarity index 66% rename from backend/src/routes/membershipOrg.ts rename to backend/src/routes/v1/membershipOrg.ts index b6cd6313f..255b836aa 100644 --- a/backend/src/routes/membershipOrg.ts +++ b/backend/src/routes/v1/membershipOrg.ts @@ -1,13 +1,15 @@ import express from 'express'; const router = express.Router(); import { param } from 'express-validator'; -import { requireAuth, validateRequest } from '../middleware'; -import { membershipOrgController } from '../controllers'; +import { requireAuth, validateRequest } from '../../middleware'; +import { membershipOrgController } from '../../controllers/v1'; router.post( // TODO '/membershipOrg/:membershipOrgId/change-role', - requireAuth, + requireAuth({ + acceptedAuthModes: ['jwt'] + }), param('membershipOrgId'), validateRequest, membershipOrgController.changeMembershipOrgRole @@ -15,7 +17,9 @@ router.post( router.delete( '/:membershipOrgId', - requireAuth, + requireAuth({ + acceptedAuthModes: ['jwt'] + }), param('membershipOrgId').exists().trim(), validateRequest, membershipOrgController.deleteMembershipOrg diff --git a/backend/src/routes/organization.ts b/backend/src/routes/v1/organization.ts similarity index 75% rename from backend/src/routes/organization.ts rename to backend/src/routes/v1/organization.ts index 276e26095..65a4b373f 100644 --- a/backend/src/routes/organization.ts +++ b/backend/src/routes/v1/organization.ts @@ -5,19 +5,23 @@ import { requireAuth, requireOrganizationAuth, validateRequest -} from '../middleware'; -import { OWNER, ADMIN, MEMBER, ACCEPTED } from '../variables'; -import { organizationController } from '../controllers'; +} from '../../middleware'; +import { OWNER, ADMIN, MEMBER, ACCEPTED } from '../../variables'; +import { organizationController } from '../../controllers/v1'; -router.get( +router.get( // deprecated (moved to api/v2/users/me/organizations) '/', - requireAuth, + requireAuth({ + acceptedAuthModes: ['jwt'] + }), organizationController.getOrganizations ); router.post( // not used on frontend '/', - requireAuth, + requireAuth({ + acceptedAuthModes: ['jwt'] + }), body('organizationName').exists().trim().notEmpty(), validateRequest, organizationController.createOrganization @@ -25,7 +29,9 @@ router.post( // not used on frontend router.get( '/:organizationId', - requireAuth, + requireAuth({ + acceptedAuthModes: ['jwt'] + }), requireOrganizationAuth({ acceptedRoles: [OWNER, ADMIN, MEMBER], acceptedStatuses: [ACCEPTED] @@ -35,9 +41,11 @@ router.get( organizationController.getOrganization ); -router.get( +router.get( // deprecated (moved to api/v2/organizations/:organizationId/memberships) '/:organizationId/users', - requireAuth, + requireAuth({ + acceptedAuthModes: ['jwt'] + }), requireOrganizationAuth({ acceptedRoles: [OWNER, ADMIN, MEMBER], acceptedStatuses: [ACCEPTED] @@ -48,8 +56,10 @@ router.get( ); router.get( - '/:organizationId/my-workspaces', - requireAuth, + '/:organizationId/my-workspaces', // deprecated (moved to api/v2/organizations/:organizationId/workspaces) + requireAuth({ + acceptedAuthModes: ['jwt'] + }), requireOrganizationAuth({ acceptedRoles: [OWNER, ADMIN, MEMBER], acceptedStatuses: [ACCEPTED] @@ -61,7 +71,9 @@ router.get( router.patch( '/:organizationId/name', - requireAuth, + requireAuth({ + acceptedAuthModes: ['jwt'] + }), requireOrganizationAuth({ acceptedRoles: [OWNER, ADMIN, MEMBER], acceptedStatuses: [ACCEPTED] @@ -74,7 +86,9 @@ router.patch( router.get( '/:organizationId/incidentContactOrg', - requireAuth, + requireAuth({ + acceptedAuthModes: ['jwt'] + }), requireOrganizationAuth({ acceptedRoles: [OWNER, ADMIN, MEMBER], acceptedStatuses: [ACCEPTED] @@ -86,7 +100,9 @@ router.get( router.post( '/:organizationId/incidentContactOrg', - requireAuth, + requireAuth({ + acceptedAuthModes: ['jwt'] + }), requireOrganizationAuth({ acceptedRoles: [OWNER, ADMIN, MEMBER], acceptedStatuses: [ACCEPTED] @@ -99,7 +115,9 @@ router.post( router.delete( '/:organizationId/incidentContactOrg', - requireAuth, + requireAuth({ + acceptedAuthModes: ['jwt'] + }), requireOrganizationAuth({ acceptedRoles: [OWNER, ADMIN, MEMBER], acceptedStatuses: [ACCEPTED] @@ -112,7 +130,9 @@ router.delete( router.post( '/:organizationId/customer-portal-session', - requireAuth, + requireAuth({ + acceptedAuthModes: ['jwt'] + }), requireOrganizationAuth({ acceptedRoles: [OWNER, ADMIN, MEMBER], acceptedStatuses: [ACCEPTED] @@ -124,7 +144,9 @@ router.post( router.get( '/:organizationId/subscriptions', - requireAuth, + requireAuth({ + acceptedAuthModes: ['jwt'] + }), requireOrganizationAuth({ acceptedRoles: [OWNER, ADMIN, MEMBER], acceptedStatuses: [ACCEPTED] diff --git a/backend/src/routes/password.ts b/backend/src/routes/v1/password.ts similarity index 89% rename from backend/src/routes/password.ts rename to backend/src/routes/v1/password.ts index 955e532a0..784ef1813 100644 --- a/backend/src/routes/password.ts +++ b/backend/src/routes/v1/password.ts @@ -1,13 +1,15 @@ import express from 'express'; const router = express.Router(); import { body } from 'express-validator'; -import { requireAuth, requireSignupAuth, validateRequest } from '../middleware'; -import { passwordController } from '../controllers'; -import { passwordLimiter } from '../helpers/rateLimiter'; +import { requireAuth, requireSignupAuth, validateRequest } from '../../middleware'; +import { passwordController } from '../../controllers/v1'; +import { passwordLimiter } from '../../helpers/rateLimiter'; router.post( '/srp1', - requireAuth, + requireAuth({ + acceptedAuthModes: ['jwt'] + }), body('clientPublicKey').exists().trim().notEmpty(), validateRequest, passwordController.srp1 @@ -16,7 +18,9 @@ router.post( router.post( '/change-password', passwordLimiter, - requireAuth, + requireAuth({ + acceptedAuthModes: ['jwt'] + }), body('clientProof').exists().trim().notEmpty(), body('encryptedPrivateKey').exists().trim().notEmpty().notEmpty(), // private key encrypted under new pwd body('iv').exists().trim().notEmpty(), // new iv for private key @@ -27,7 +31,6 @@ router.post( passwordController.changePassword ); -// NEW router.post( '/email/password-reset', passwordLimiter, @@ -36,7 +39,6 @@ router.post( passwordController.emailPasswordReset ); -// NEW router.post( '/email/password-reset-verify', passwordLimiter, @@ -46,7 +48,6 @@ router.post( passwordController.emailPasswordResetVerify ); -// NEW router.get( '/backup-private-key', passwordLimiter, @@ -57,7 +58,9 @@ router.get( router.post( '/backup-private-key', passwordLimiter, - requireAuth, + requireAuth({ + acceptedAuthModes: ['jwt'] + }), body('clientProof').exists().trim().notEmpty(), body('encryptedPrivateKey').exists().trim().notEmpty(), // (backup) private key encrypted under a strong key body('iv').exists().trim().notEmpty(), // new iv for (backup) private key @@ -68,7 +71,6 @@ router.post( passwordController.createBackupPrivateKey ); -// NEW router.post( '/password-reset', requireSignupAuth, diff --git a/backend/src/routes/secret.ts b/backend/src/routes/v1/secret.ts similarity index 74% rename from backend/src/routes/secret.ts rename to backend/src/routes/v1/secret.ts index 98b3009de..cce105500 100644 --- a/backend/src/routes/secret.ts +++ b/backend/src/routes/v1/secret.ts @@ -5,17 +5,18 @@ import { requireWorkspaceAuth, requireServiceTokenAuth, validateRequest -} from '../middleware'; +} from '../../middleware'; import { body, query, param } from 'express-validator'; -import { ADMIN, MEMBER, COMPLETED, GRANTED } from '../variables'; -import { secretController } from '../controllers'; +import { secretController } from '../../controllers/v1'; +import { ADMIN, MEMBER } from '../../variables'; router.post( '/:workspaceId', - requireAuth, + requireAuth({ + acceptedAuthModes: ['jwt'] + }), requireWorkspaceAuth({ - acceptedRoles: [ADMIN, MEMBER], - acceptedStatuses: [COMPLETED, GRANTED] + acceptedRoles: [ADMIN, MEMBER] }), body('secrets').exists(), body('keys').exists(), @@ -28,10 +29,11 @@ router.post( router.get( '/:workspaceId', - requireAuth, + requireAuth({ + acceptedAuthModes: ['jwt'] + }), requireWorkspaceAuth({ - acceptedRoles: [ADMIN, MEMBER], - acceptedStatuses: [COMPLETED, GRANTED] + acceptedRoles: [ADMIN, MEMBER] }), query('environment').exists().trim(), query('channel'), diff --git a/backend/src/routes/serviceToken.ts b/backend/src/routes/v1/serviceToken.ts similarity index 74% rename from backend/src/routes/serviceToken.ts rename to backend/src/routes/v1/serviceToken.ts index 00195edee..18487ac3e 100644 --- a/backend/src/routes/serviceToken.ts +++ b/backend/src/routes/v1/serviceToken.ts @@ -5,12 +5,12 @@ import { requireWorkspaceAuth, requireServiceTokenAuth, validateRequest -} from '../middleware'; +} from '../../middleware'; import { body } from 'express-validator'; -import { ADMIN, MEMBER, GRANTED } from '../variables'; -import { serviceTokenController } from '../controllers'; +import { ADMIN, MEMBER } from '../../variables'; +import { serviceTokenController } from '../../controllers/v1'; -// TODO: revoke service token +// note: deprecate service-token routes in favor of service-token data routes/structure router.get( '/', @@ -20,10 +20,11 @@ router.get( router.post( '/', - requireAuth, + requireAuth({ + acceptedAuthModes: ['jwt'] + }), requireWorkspaceAuth({ acceptedRoles: [ADMIN, MEMBER], - acceptedStatuses: [GRANTED], location: 'body' }), body('name').exists().trim().notEmpty(), diff --git a/backend/src/routes/signup.ts b/backend/src/routes/v1/signup.ts similarity index 86% rename from backend/src/routes/signup.ts rename to backend/src/routes/v1/signup.ts index 40b5929b0..d1582474c 100644 --- a/backend/src/routes/signup.ts +++ b/backend/src/routes/v1/signup.ts @@ -1,13 +1,13 @@ import express from 'express'; const router = express.Router(); import { body } from 'express-validator'; -import { requireSignupAuth, validateRequest } from '../middleware'; -import { signupController } from '../controllers'; -import { signupLimiter } from '../helpers/rateLimiter'; +import { requireSignupAuth, validateRequest } from '../../middleware'; +import { signupController } from '../../controllers/v1'; +import { authLimiter } from '../../helpers/rateLimiter'; router.post( '/email/signup', - signupLimiter, + authLimiter, body('email').exists().trim().notEmpty().isEmail(), validateRequest, signupController.beginEmailSignup @@ -15,7 +15,7 @@ router.post( router.post( '/email/verify', - signupLimiter, + authLimiter, body('email').exists().trim().notEmpty().isEmail(), body('code').exists().trim().notEmpty(), validateRequest, @@ -24,7 +24,7 @@ router.post( router.post( '/complete-account/signup', - signupLimiter, + authLimiter, requireSignupAuth, body('email').exists().trim().notEmpty().isEmail(), body('firstName').exists().trim().notEmpty(), @@ -42,7 +42,7 @@ router.post( router.post( '/complete-account/invite', - signupLimiter, + authLimiter, requireSignupAuth, body('email').exists().trim().notEmpty().isEmail(), body('firstName').exists().trim().notEmpty(), diff --git a/backend/src/routes/stripe.ts b/backend/src/routes/v1/stripe.ts similarity index 71% rename from backend/src/routes/stripe.ts rename to backend/src/routes/v1/stripe.ts index ba5706562..cfcca77cb 100644 --- a/backend/src/routes/stripe.ts +++ b/backend/src/routes/v1/stripe.ts @@ -1,6 +1,6 @@ import express from 'express'; const router = express.Router(); -import { stripeController } from '../controllers'; +import { stripeController } from '../../controllers/v1'; router.post('/webhook', stripeController.handleWebhook); diff --git a/backend/src/routes/v1/user.ts b/backend/src/routes/v1/user.ts new file mode 100644 index 000000000..e73a6e0f2 --- /dev/null +++ b/backend/src/routes/v1/user.ts @@ -0,0 +1,14 @@ +import express from 'express'; +const router = express.Router(); +import { requireAuth } from '../../middleware'; +import { userController } from '../../controllers/v1'; + +router.get( + '/', + requireAuth({ + acceptedAuthModes: ['jwt'] + }), + userController.getUser +); + +export default router; diff --git a/backend/src/routes/userAction.ts b/backend/src/routes/v1/userAction.ts similarity index 52% rename from backend/src/routes/userAction.ts rename to backend/src/routes/v1/userAction.ts index 5ea454156..b14ab3471 100644 --- a/backend/src/routes/userAction.ts +++ b/backend/src/routes/v1/userAction.ts @@ -1,12 +1,15 @@ import express from 'express'; const router = express.Router(); -import { requireAuth, validateRequest } from '../middleware'; +import { requireAuth, validateRequest } from '../../middleware'; import { body, query } from 'express-validator'; -import { userActionController } from '../controllers'; +import { userActionController } from '../../controllers/v1'; +// note: [userAction] will be deprecated in /v2 in favor of [action] router.post( '/', - requireAuth, + requireAuth({ + acceptedAuthModes: ['jwt'] + }), body('action'), validateRequest, userActionController.addUserAction @@ -14,7 +17,9 @@ router.post( router.get( '/', - requireAuth, + requireAuth({ + acceptedAuthModes: ['jwt'] + }), query('action'), validateRequest, userActionController.getUserAction diff --git a/backend/src/routes/workspace.ts b/backend/src/routes/v1/workspace.ts similarity index 63% rename from backend/src/routes/workspace.ts rename to backend/src/routes/v1/workspace.ts index 1d20c102a..801462662 100644 --- a/backend/src/routes/workspace.ts +++ b/backend/src/routes/v1/workspace.ts @@ -1,20 +1,21 @@ import express from 'express'; const router = express.Router(); -import { body, param } from 'express-validator'; +import { body, param, query } from 'express-validator'; import { requireAuth, requireWorkspaceAuth, validateRequest -} from '../middleware'; -import { ADMIN, MEMBER, COMPLETED, GRANTED } from '../variables'; -import { workspaceController, membershipController } from '../controllers'; +} from '../../middleware'; +import { ADMIN, MEMBER } from '../../variables'; +import { workspaceController, membershipController } from '../../controllers/v1'; router.get( '/:workspaceId/keys', - requireAuth, + requireAuth({ + acceptedAuthModes: ['jwt'] + }), requireWorkspaceAuth({ - acceptedRoles: [ADMIN, MEMBER], - acceptedStatuses: [COMPLETED, GRANTED] + acceptedRoles: [ADMIN, MEMBER] }), param('workspaceId').exists().trim(), validateRequest, @@ -23,24 +24,32 @@ router.get( router.get( '/:workspaceId/users', - requireAuth, + requireAuth({ + acceptedAuthModes: ['jwt'] + }), requireWorkspaceAuth({ acceptedRoles: [ADMIN, MEMBER], - acceptedStatuses: [COMPLETED, GRANTED] }), param('workspaceId').exists().trim(), validateRequest, workspaceController.getWorkspaceMemberships ); -router.get('/', requireAuth, workspaceController.getWorkspaces); +router.get( + '/', + requireAuth({ + acceptedAuthModes: ['jwt'] + }), + workspaceController.getWorkspaces +); router.get( '/:workspaceId', - requireAuth, + requireAuth({ + acceptedAuthModes: ['jwt'] + }), requireWorkspaceAuth({ - acceptedRoles: [ADMIN, MEMBER], - acceptedStatuses: [COMPLETED, GRANTED] + acceptedRoles: [ADMIN, MEMBER] }), param('workspaceId').exists().trim(), validateRequest, @@ -49,7 +58,9 @@ router.get( router.post( '/', - requireAuth, + requireAuth({ + acceptedAuthModes: ['jwt'] + }), body('workspaceName').exists().trim().notEmpty(), body('organizationId').exists().trim().notEmpty(), validateRequest, @@ -58,10 +69,11 @@ router.post( router.delete( '/:workspaceId', - requireAuth, + requireAuth({ + acceptedAuthModes: ['jwt'] + }), requireWorkspaceAuth({ - acceptedRoles: [ADMIN], - acceptedStatuses: [GRANTED] + acceptedRoles: [ADMIN] }), param('workspaceId').exists().trim(), validateRequest, @@ -70,10 +82,11 @@ router.delete( router.post( '/:workspaceId/name', - requireAuth, + requireAuth({ + acceptedAuthModes: ['jwt'] + }), requireWorkspaceAuth({ - acceptedRoles: [ADMIN, MEMBER], - acceptedStatuses: [COMPLETED, GRANTED] + acceptedRoles: [ADMIN, MEMBER] }), param('workspaceId').exists().trim(), body('name').exists().trim().notEmpty(), @@ -83,10 +96,11 @@ router.post( router.post( '/:workspaceId/invite-signup', - requireAuth, + requireAuth({ + acceptedAuthModes: ['jwt'] + }), requireWorkspaceAuth({ - acceptedRoles: [ADMIN, MEMBER], - acceptedStatuses: [GRANTED] + acceptedRoles: [ADMIN, MEMBER] }), param('workspaceId').exists().trim(), body('email').exists().trim().notEmpty(), @@ -96,10 +110,11 @@ router.post( router.get( '/:workspaceId/integrations', - requireAuth, + requireAuth({ + acceptedAuthModes: ['jwt'] + }), requireWorkspaceAuth({ - acceptedRoles: [ADMIN, MEMBER], - acceptedStatuses: [GRANTED] + acceptedRoles: [ADMIN, MEMBER] }), param('workspaceId').exists().trim(), validateRequest, @@ -108,10 +123,11 @@ router.get( router.get( '/:workspaceId/authorizations', - requireAuth, + requireAuth({ + acceptedAuthModes: ['jwt'] + }), requireWorkspaceAuth({ - acceptedRoles: [ADMIN, MEMBER], - acceptedStatuses: [GRANTED] + acceptedRoles: [ADMIN, MEMBER] }), param('workspaceId').exists().trim(), validateRequest, @@ -119,11 +135,12 @@ router.get( ); router.get( - '/:workspaceId/service-tokens', - requireAuth, + '/:workspaceId/service-tokens', // deprecate + requireAuth({ + acceptedAuthModes: ['jwt'] + }), requireWorkspaceAuth({ - acceptedRoles: [ADMIN, MEMBER], - acceptedStatuses: [GRANTED] + acceptedRoles: [ADMIN, MEMBER] }), param('workspaceId').exists().trim(), validateRequest, diff --git a/backend/src/routes/v2/apiKeyData.ts b/backend/src/routes/v2/apiKeyData.ts new file mode 100644 index 000000000..07bbcbc44 --- /dev/null +++ b/backend/src/routes/v2/apiKeyData.ts @@ -0,0 +1,39 @@ +import express from 'express'; +const router = express.Router(); +import { + requireAuth, + validateRequest +} from '../../middleware'; +import { param, body } from 'express-validator'; +import { apiKeyDataController } from '../../controllers/v2'; + +router.get( + '/', + requireAuth({ + acceptedAuthModes: ['jwt'] + }), + apiKeyDataController.getAPIKeyData +); + +router.post( + '/', + requireAuth({ + acceptedAuthModes: ['jwt'] + }), + body('name').exists().trim(), + body('expiresIn'), // measured in ms + validateRequest, + apiKeyDataController.createAPIKeyData +); + +router.delete( + '/:apiKeyDataId', + requireAuth({ + acceptedAuthModes: ['jwt'] + }), + param('apiKeyDataId').exists().trim(), + validateRequest, + apiKeyDataController.deleteAPIKeyData +); + +export default router; \ No newline at end of file diff --git a/backend/src/routes/v2/environment.ts b/backend/src/routes/v2/environment.ts new file mode 100644 index 000000000..11afa4f2e --- /dev/null +++ b/backend/src/routes/v2/environment.ts @@ -0,0 +1,70 @@ +import express, { Response, Request } from 'express'; +const router = express.Router(); +import { body, param } from 'express-validator'; +import { environmentController } from '../../controllers/v2'; +import { + requireAuth, + requireWorkspaceAuth, + validateRequest, +} from '../../middleware'; +import { ADMIN, MEMBER } from '../../variables'; + +router.post( + '/:workspaceId/environments', + requireAuth({ + acceptedAuthModes: ['jwt'], + }), + requireWorkspaceAuth({ + acceptedRoles: [ADMIN, MEMBER], + }), + param('workspaceId').exists().trim(), + body('environmentSlug').exists().trim(), + body('environmentName').exists().trim(), + validateRequest, + environmentController.createWorkspaceEnvironment +); + +router.put( + '/:workspaceId/environments', + requireAuth({ + acceptedAuthModes: ['jwt'], + }), + requireWorkspaceAuth({ + acceptedRoles: [ADMIN, MEMBER], + }), + param('workspaceId').exists().trim(), + body('environmentSlug').exists().trim(), + body('environmentName').exists().trim(), + body('oldEnvironmentSlug').exists().trim(), + validateRequest, + environmentController.renameWorkspaceEnvironment +); + +router.delete( + '/:workspaceId/environments', + requireAuth({ + acceptedAuthModes: ['jwt'], + }), + requireWorkspaceAuth({ + acceptedRoles: [ADMIN], + }), + param('workspaceId').exists().trim(), + body('environmentSlug').exists().trim(), + validateRequest, + environmentController.deleteWorkspaceEnvironment +); + +router.get( + '/:workspaceId/environments', + requireAuth({ + acceptedAuthModes: ['jwt'], + }), + requireWorkspaceAuth({ + acceptedRoles: [MEMBER, ADMIN], + }), + param('workspaceId').exists().trim(), + validateRequest, + environmentController.getAllAccessibleEnvironmentsOfWorkspace +); + +export default router; diff --git a/backend/src/routes/v2/index.ts b/backend/src/routes/v2/index.ts new file mode 100644 index 000000000..6f698e316 --- /dev/null +++ b/backend/src/routes/v2/index.ts @@ -0,0 +1,19 @@ +import users from './users'; +import organizations from './organizations'; +import workspace from './workspace'; +import secret from './secret'; // deprecated +import secrets from './secrets'; +import serviceTokenData from './serviceTokenData'; +import apiKeyData from './apiKeyData'; +import environment from "./environment" + +export { + users, + organizations, + workspace, + secret, + secrets, + serviceTokenData, + apiKeyData, + environment +} \ No newline at end of file diff --git a/backend/src/routes/v2/organizations.ts b/backend/src/routes/v2/organizations.ts new file mode 100644 index 000000000..e1488e8a7 --- /dev/null +++ b/backend/src/routes/v2/organizations.ts @@ -0,0 +1,80 @@ +import express from 'express'; +const router = express.Router(); +import { + requireAuth, + requireOrganizationAuth, + requireMembershipOrgAuth, + validateRequest +} from '../../middleware'; +import { body, param, query } from 'express-validator'; +import { OWNER, ADMIN, MEMBER, ACCEPTED } from '../../variables'; +import { organizationsController } from '../../controllers/v2'; + +// TODO: /POST to create membership + +router.get( + '/:organizationId/memberships', + param('organizationId').exists().trim(), + validateRequest, + requireAuth({ + acceptedAuthModes: ['jwt', 'apiKey'] + }), + requireOrganizationAuth({ + acceptedRoles: [OWNER, ADMIN, MEMBER], + acceptedStatuses: [ACCEPTED] + }), + organizationsController.getOrganizationMemberships +); + +router.patch( + '/:organizationId/memberships/:membershipId', + param('organizationId').exists().trim(), + param('membershipId').exists().trim(), + body('role').exists().isString().trim().isIn([OWNER, ADMIN, MEMBER]), + validateRequest, + requireAuth({ + acceptedAuthModes: ['jwt', 'apiKey'] + }), + requireOrganizationAuth({ + acceptedRoles: [OWNER, ADMIN], + acceptedStatuses: [ACCEPTED] + }), + requireMembershipOrgAuth({ + acceptedRoles: [OWNER, ADMIN] + }), + organizationsController.updateOrganizationMembership +); + +router.delete( + '/:organizationId/memberships/:membershipId', + param('organizationId').exists().trim(), + param('membershipId').exists().trim(), + validateRequest, + requireAuth({ + acceptedAuthModes: ['jwt', 'apiKey'] + }), + requireOrganizationAuth({ + acceptedRoles: [OWNER, ADMIN], + acceptedStatuses: [ACCEPTED] + }), + requireMembershipOrgAuth({ + acceptedRoles: [OWNER, ADMIN] + }), + organizationsController.deleteOrganizationMembership +); + +router.get( + '/:organizationId/workspaces', + param('organizationId').exists().trim(), + validateRequest, + requireAuth({ + acceptedAuthModes: ['jwt', 'apiKey'] + }), + requireOrganizationAuth({ + acceptedRoles: [OWNER, ADMIN], + acceptedStatuses: [ACCEPTED] + }), + organizationsController.getOrganizationWorkspaces +); + +export default router; \ No newline at end of file diff --git a/backend/src/routes/v2/secret.ts b/backend/src/routes/v2/secret.ts new file mode 100644 index 000000000..f1b61b47c --- /dev/null +++ b/backend/src/routes/v2/secret.ts @@ -0,0 +1,135 @@ +import express from 'express'; +import { + requireAuth, + requireWorkspaceAuth, + requireSecretAuth, + validateRequest +} from '../../middleware'; +import { body, param, query } from 'express-validator'; +import { ADMIN, MEMBER } from '../../variables'; +import { CreateSecretRequestBody, ModifySecretRequestBody } from '../../types/secret'; +import { secretController } from '../../controllers/v2'; + +// note to devs: stop supporting these routes [deprecated] + +const router = express.Router(); + +router.post( + '/batch-create/workspace/:workspaceId/environment/:environment', + requireAuth({ + acceptedAuthModes: ['jwt'] + }), + requireWorkspaceAuth({ + acceptedRoles: [ADMIN, MEMBER] + }), + param('workspaceId').exists().isMongoId().trim(), + param('environment').exists().trim(), + body('secrets').exists().isArray().custom((value) => value.every((item: CreateSecretRequestBody) => typeof item === 'object')), + body('channel'), + validateRequest, + secretController.createSecrets +); + +router.post( + '/workspace/:workspaceId/environment/:environment', + requireAuth({ + acceptedAuthModes: ['jwt'] + }), + requireWorkspaceAuth({ + acceptedRoles: [ADMIN, MEMBER] + }), + param('workspaceId').exists().isMongoId().trim(), + param('environment').exists().trim(), + body('secret').exists().isObject(), + body('channel'), + validateRequest, + secretController.createSecret +); + +router.get( + '/workspace/:workspaceId', + param('workspaceId').exists().trim(), + query("environment").exists(), + requireAuth({ + acceptedAuthModes: ['jwt', 'serviceToken'] + }), + requireWorkspaceAuth({ + acceptedRoles: [ADMIN, MEMBER] + }), + query('channel'), + validateRequest, + secretController.getSecrets +); + +router.get( + '/:secretId', + requireAuth({ + acceptedAuthModes: ['jwt', 'serviceToken'] + }), + requireSecretAuth({ + acceptedRoles: [ADMIN, MEMBER] + }), + validateRequest, + secretController.getSecret +); + +router.delete( + '/batch/workspace/:workspaceId/environment/:environmentName', + requireAuth({ + acceptedAuthModes: ['jwt'] + }), + param('workspaceId').exists().isMongoId().trim(), + param('environmentName').exists().trim(), + body('secretIds').exists().isArray().custom(array => array.length > 0), + requireWorkspaceAuth({ + acceptedRoles: [ADMIN, MEMBER] + }), + validateRequest, + secretController.deleteSecrets +); + +router.delete( + '/:secretId', + requireAuth({ + acceptedAuthModes: ['jwt'] + }), + requireSecretAuth({ + acceptedRoles: [ADMIN, MEMBER] + }), + param('secretId').isMongoId(), + validateRequest, + secretController.deleteSecret +); + +router.patch( + '/batch-modify/workspace/:workspaceId/environment/:environmentName', + requireAuth({ + acceptedAuthModes: ['jwt'] + }), + body('secrets').exists().isArray().custom((secrets: ModifySecretRequestBody[]) => secrets.length > 0), + param('workspaceId').exists().isMongoId().trim(), + param('environmentName').exists().trim(), + requireWorkspaceAuth({ + acceptedRoles: [ADMIN, MEMBER] + }), + validateRequest, + secretController.updateSecrets +); + + +router.patch( + '/workspace/:workspaceId/environment/:environmentName', + requireAuth({ + acceptedAuthModes: ['jwt'] + }), + body('secret').isObject(), + param('workspaceId').exists().isMongoId().trim(), + param('environmentName').exists().trim(), + requireWorkspaceAuth({ + acceptedRoles: [ADMIN, MEMBER] + }), + validateRequest, + secretController.updateSecret +); + +export default router; diff --git a/backend/src/routes/v2/secrets.ts b/backend/src/routes/v2/secrets.ts new file mode 100644 index 000000000..9fca3039a --- /dev/null +++ b/backend/src/routes/v2/secrets.ts @@ -0,0 +1,157 @@ +import express from 'express'; +const router = express.Router(); +import { + requireAuth, + requireWorkspaceAuth, + requireSecretsAuth, + validateRequest +} from '../../middleware'; +import { query, check, body } from 'express-validator'; +import { secretsController } from '../../controllers/v2'; +import { + ADMIN, + MEMBER, + SECRET_PERSONAL, + SECRET_SHARED +} from '../../variables'; + +router.post( + '/', + body('workspaceId').exists().isString().trim(), + body('environment').exists().isString().trim(), + body('secrets') + .exists() + .custom((value) => { + if (Array.isArray(value)) { + // case: create multiple secrets + if (value.length === 0) throw new Error('secrets cannot be an empty array') + for (const secret of value) { + if ( + !secret.type || + !(secret.type === SECRET_PERSONAL || secret.type === SECRET_SHARED) || + !secret.secretKeyCiphertext || + !secret.secretKeyIV || + !secret.secretKeyTag || + (typeof secret.secretValueCiphertext !== 'string') || + !secret.secretValueIV || + !secret.secretValueTag + ) { + throw new Error('secrets array must contain objects that have required secret properties'); + } + } + } else if (typeof value === 'object') { + // case: update 1 secret + if ( + !value.type || + !(value.type === SECRET_PERSONAL || value.type === SECRET_SHARED) || + !value.secretKeyCiphertext || + !value.secretKeyIV || + !value.secretKeyTag || + !value.secretValueCiphertext || + !value.secretValueIV || + !value.secretValueTag + ) { + throw new Error('secrets object is missing required secret properties'); + } + } else { + throw new Error('secrets must be an object or an array of objects') + } + + return true; + }), + validateRequest, + requireAuth({ + acceptedAuthModes: ['jwt', 'apiKey'] + }), + requireWorkspaceAuth({ + acceptedRoles: [ADMIN, MEMBER], + location: 'body' + }), + secretsController.createSecrets +); + +router.get( + '/', + query('workspaceId').exists().trim(), + query('environment').exists().trim(), + validateRequest, + requireAuth({ + acceptedAuthModes: ['jwt', 'apiKey', 'serviceToken'] + }), + requireWorkspaceAuth({ + acceptedRoles: [ADMIN, MEMBER], + location: 'query' + }), + secretsController.getSecrets +); + +router.patch( + '/', + body('secrets') + .exists() + .custom((value) => { + if (Array.isArray(value)) { + // case: update multiple secrets + if (value.length === 0) throw new Error('secrets cannot be an empty array') + for (const secret of value) { + if ( + !secret.id + ) { + throw new Error('Each secret must contain a ID property'); + } + } + } else if (typeof value === 'object') { + // case: update 1 secret + if ( + !value.id + ) { + throw new Error('secret must contain a ID property'); + } + } else { + throw new Error('secrets must be an object or an array of objects') + } + + return true; + }), + validateRequest, + requireAuth({ + acceptedAuthModes: ['jwt', 'apiKey'] + }), + requireSecretsAuth({ + acceptedRoles: [ADMIN, MEMBER] + }), + secretsController.updateSecrets +); + +router.delete( + '/', + body('secretIds') + .exists() + .custom((value) => { + // case: delete 1 secret + if (typeof value === 'string') return true; + + if (Array.isArray(value)) { + // case: delete multiple secrets + if (value.length === 0) throw new Error('secrets cannot be an empty array'); + return value.every((id: string) => typeof id === 'string') + } + + throw new Error('secretIds must be a string or an array of strings'); + }) + .not() + .isEmpty(), + validateRequest, + requireAuth({ + acceptedAuthModes: ['jwt', 'apiKey'] + }), + requireSecretsAuth({ + acceptedRoles: [ADMIN, MEMBER] + }), + secretsController.deleteSecrets +); + +export default router; + + + diff --git a/backend/src/routes/v2/serviceTokenData.ts b/backend/src/routes/v2/serviceTokenData.ts new file mode 100644 index 000000000..254bf60f3 --- /dev/null +++ b/backend/src/routes/v2/serviceTokenData.ts @@ -0,0 +1,57 @@ +import express from 'express'; +const router = express.Router(); +import { + requireAuth, + requireWorkspaceAuth, + requireServiceTokenDataAuth, + validateRequest +} from '../../middleware'; +import { param, body } from 'express-validator'; +import { + ADMIN, + MEMBER, +} from '../../variables'; +import { serviceTokenDataController } from '../../controllers/v2'; + +router.get( + '/', + requireAuth({ + acceptedAuthModes: ['serviceToken'] + }), + serviceTokenDataController.getServiceTokenData +); + +router.post( + '/', + requireAuth({ + acceptedAuthModes: ['jwt'] + }), + requireWorkspaceAuth({ + acceptedRoles: [ADMIN, MEMBER], + location: 'body' + }), + body('name').exists().trim(), + body('workspaceId'), + body('environment'), + body('encryptedKey'), + body('iv'), + body('tag'), + body('expiresIn'), // measured in ms + validateRequest, + serviceTokenDataController.createServiceTokenData +); + +router.delete( + '/:serviceTokenDataId', + requireAuth({ + acceptedAuthModes: ['jwt'] + }), + requireServiceTokenDataAuth({ + acceptedRoles: [ADMIN, MEMBER] + }), + param('serviceTokenDataId').exists().trim(), + validateRequest, + serviceTokenDataController.deleteServiceTokenData +); + +export default router; \ No newline at end of file diff --git a/backend/src/routes/v2/users.ts b/backend/src/routes/v2/users.ts new file mode 100644 index 000000000..48c015cca --- /dev/null +++ b/backend/src/routes/v2/users.ts @@ -0,0 +1,24 @@ +import express from 'express'; +const router = express.Router(); +import { + requireAuth +} from '../../middleware'; +import { usersController } from '../../controllers/v2'; + +router.get( + '/me', + requireAuth({ + acceptedAuthModes: ['jwt', 'apiKey'] + }), + usersController.getMe +); + +router.get( + '/me/organizations', + requireAuth({ + acceptedAuthModes: ['jwt', 'apiKey'] + }), + usersController.getMyOrganizations +); + +export default router; \ No newline at end of file diff --git a/backend/src/routes/v2/workspace.ts b/backend/src/routes/v2/workspace.ts new file mode 100644 index 000000000..55299e575 --- /dev/null +++ b/backend/src/routes/v2/workspace.ts @@ -0,0 +1,121 @@ +import express from 'express'; +const router = express.Router(); +import { body, param, query } from 'express-validator'; +import { + requireAuth, + requireMembershipAuth, + requireWorkspaceAuth, + validateRequest +} from '../../middleware'; +import { ADMIN, MEMBER } from '../../variables'; +import { workspaceController } from '../../controllers/v2'; + +router.post( + '/:workspaceId/secrets', + requireAuth({ + acceptedAuthModes: ['jwt'] + }), + requireWorkspaceAuth({ + acceptedRoles: [ADMIN, MEMBER] + }), + body('secrets').exists(), + body('keys').exists(), + body('environment').exists().trim().notEmpty(), + body('channel'), + param('workspaceId').exists().trim(), + validateRequest, + workspaceController.pushWorkspaceSecrets +); + +router.get( + '/:workspaceId/secrets', + requireAuth({ + acceptedAuthModes: ['jwt', 'serviceToken'] + }), + requireWorkspaceAuth({ + acceptedRoles: [ADMIN, MEMBER] + }), + query('environment').exists().trim(), + query('channel'), + param('workspaceId').exists().trim(), + validateRequest, + workspaceController.pullSecrets +); + +router.get( + '/:workspaceId/encrypted-key', + requireAuth({ + acceptedAuthModes: ['jwt', 'apiKey'] + }), + requireWorkspaceAuth({ + acceptedRoles: [ADMIN, MEMBER] + }), + param('workspaceId').exists().trim(), + validateRequest, + workspaceController.getWorkspaceKey +); + +router.get( + '/:workspaceId/service-token-data', + requireAuth({ + acceptedAuthModes: ['jwt'] + }), + requireWorkspaceAuth({ + acceptedRoles: [ADMIN, MEMBER] + }), + param('workspaceId').exists().trim(), + validateRequest, + workspaceController.getWorkspaceServiceTokenData +); + +// TODO: /POST to create membership and re-route inviting user to workspace there + +router.get( // new - TODO: rewire dashboard to this route + '/:workspaceId/memberships', + param('workspaceId').exists().trim(), + validateRequest, + requireAuth({ + acceptedAuthModes: ['jwt', 'apiKey'] + }), + requireWorkspaceAuth({ + acceptedRoles: [ADMIN, MEMBER], + }), + workspaceController.getWorkspaceMemberships +); + +router.patch( // TODO - rewire dashboard to this route + '/:workspaceId/memberships/:membershipId', + param('workspaceId').exists().trim(), + param('membershipId').exists().trim(), + body('role').exists().isString().trim().isIn([ADMIN, MEMBER]), + validateRequest, + requireAuth({ + acceptedAuthModes: ['jwt', 'apiKey'] + }), + requireWorkspaceAuth({ + acceptedRoles: [ADMIN], + }), + requireMembershipAuth({ + acceptedRoles: [ADMIN] + }), + workspaceController.updateWorkspaceMembership +); + +router.delete( // TODO - rewire dashboard to this route + '/:workspaceId/memberships/:membershipId', + param('workspaceId').exists().trim(), + param('membershipId').exists().trim(), + validateRequest, + requireAuth({ + acceptedAuthModes: ['jwt', 'apiKey'] + }), + requireWorkspaceAuth({ + acceptedRoles: [ADMIN], + }), + requireMembershipAuth({ + acceptedRoles: [ADMIN] + }), + workspaceController.deleteWorkspaceMembership +); + +export default router; diff --git a/backend/src/services/BotService.ts b/backend/src/services/BotService.ts new file mode 100644 index 000000000..792bd8e35 --- /dev/null +++ b/backend/src/services/BotService.ts @@ -0,0 +1,82 @@ +import { + getSecretsHelper, + encryptSymmetricHelper, + decryptSymmetricHelper +} from '../helpers/bot'; + +/** + * Class to handle bot actions + */ +class BotService { + + /** + * Return decrypted secrets for workspace with id [workspaceId] and + * environment [environmen] shared to bot. + * @param {Object} obj + * @param {String} obj.workspaceId - id of workspace of secrets + * @param {String} obj.environment - environment for secrets + * @returns {Object} secretObj - object where keys are secret keys and values are secret values + */ + static async getSecrets({ + workspaceId, + environment + }: { + workspaceId: string; + environment: string; + }) { + return await getSecretsHelper({ + workspaceId, + environment + }); + } + + /** + * Return symmetrically encrypted [plaintext] using the + * bot's copy of the workspace key for workspace with id [workspaceId] + * @param {Object} obj + * @param {String} obj.workspaceId - id of workspace + * @param {String} obj.plaintext - plaintext to encrypt + */ + static async encryptSymmetric({ + workspaceId, + plaintext + }: { + workspaceId: string; + plaintext: string; + }) { + return await encryptSymmetricHelper({ + workspaceId, + plaintext + }); + } + + /** + * Return symmetrically decrypted [ciphertext] using the + * bot's copy of the workspace key for workspace with id [workspaceId] + * @param {Object} obj + * @param {String} obj.workspaceId - id of workspace + * @param {String} obj.ciphertext - ciphertext to decrypt + * @param {String} obj.iv - iv + * @param {String} obj.tag - tag + */ + static async decryptSymmetric({ + workspaceId, + ciphertext, + iv, + tag + }: { + workspaceId: string; + ciphertext: string; + iv: string; + tag: string; + }) { + return await decryptSymmetricHelper({ + workspaceId, + ciphertext, + iv, + tag + }); + } +} + +export default BotService; \ No newline at end of file diff --git a/backend/src/services/DatabaseService.ts b/backend/src/services/DatabaseService.ts new file mode 100644 index 000000000..2e8dc839f --- /dev/null +++ b/backend/src/services/DatabaseService.ts @@ -0,0 +1,16 @@ +import mongoose from 'mongoose'; +import { getLogger } from '../utils/logger'; +import { initDatabaseHelper } from '../helpers/database'; + +/** + * Class to handle database actions + */ +class DatabaseService { + static async initDatabase(MONGO_URL: string) { + return await initDatabaseHelper({ + mongoURL: MONGO_URL + }); + } +} + +export default DatabaseService; \ No newline at end of file diff --git a/backend/src/services/EventService.ts b/backend/src/services/EventService.ts new file mode 100644 index 000000000..fcbac9ad0 --- /dev/null +++ b/backend/src/services/EventService.ts @@ -0,0 +1,30 @@ +import { Bot, IBot } from '../models'; +import * as Sentry from '@sentry/node'; +import { handleEventHelper } from '../helpers/event'; + +interface Event { + name: string; + workspaceId: string; + payload: any; +} + +/** + * Class to handle events. + */ +class EventService { + /** + * Handle event [event] + * @param {Object} obj + * @param {Event} obj.event - an event + * @param {String} obj.event.name - name of event + * @param {String} obj.event.workspaceId - id of workspace that event is part of + * @param {Object} obj.event.payload - payload of event (depends on event) + */ + static async handleEvent({ event }: { event: Event }): Promise { + await handleEventHelper({ + event + }); + } +} + +export default EventService; \ No newline at end of file diff --git a/backend/src/services/IntegrationService.ts b/backend/src/services/IntegrationService.ts new file mode 100644 index 000000000..4ee991cdd --- /dev/null +++ b/backend/src/services/IntegrationService.ts @@ -0,0 +1,145 @@ +import * as Sentry from '@sentry/node'; +import { + Integration +} from '../models'; +import { + handleOAuthExchangeHelper, + syncIntegrationsHelper, + getIntegrationAuthRefreshHelper, + getIntegrationAuthAccessHelper, + setIntegrationAuthRefreshHelper, + setIntegrationAuthAccessHelper, +} from '../helpers/integration'; +import { exchangeCode } from '../integrations'; + +// should sync stuff be here too? Probably. +// TODO: move bot functions to IntegrationService. + +/** + * Class to handle integrations + */ +class IntegrationService { + + /** + * Perform OAuth2 code-token exchange for workspace with id [workspaceId] and integration + * named [integration] + * - Store integration access and refresh tokens returned from the OAuth2 code-token exchange + * - Add placeholder inactive integration + * - Create bot sequence for integration + * @param {Object} obj + * @param {String} obj.workspaceId - id of workspace + * @param {String} obj.environment - workspace environment + * @param {String} obj.integration - name of integration + * @param {String} obj.code - code + */ + static async handleOAuthExchange({ + workspaceId, + integration, + code, + environment + }: { + workspaceId: string; + integration: string; + code: string; + environment: string; + }) { + await handleOAuthExchangeHelper({ + workspaceId, + integration, + code, + environment + }); + } + + /** + * Sync/push environment variables in workspace with id [workspaceId] to + * all associated integrations + * @param {Object} obj + * @param {Object} obj.workspaceId - id of workspace + */ + static async syncIntegrations({ + workspaceId + }: { + workspaceId: string; + }) { + return await syncIntegrationsHelper({ + workspaceId + }); + } + + /** + * Return decrypted refresh token for integration auth + * with id [integrationAuthId] + * @param {Object} obj + * @param {String} obj.integrationAuthId - id of integration auth + * @param {String} refreshToken - decrypted refresh token + */ + static async getIntegrationAuthRefresh({ integrationAuthId }: { integrationAuthId: string}) { + return await getIntegrationAuthRefreshHelper({ + integrationAuthId + }); + } + + /** + * Return decrypted access token for integration auth + * with id [integrationAuthId] + * @param {Object} obj + * @param {String} obj.integrationAuthId - id of integration auth + * @param {String} accessToken - decrypted access token + */ + static async getIntegrationAuthAccess({ integrationAuthId }: { integrationAuthId: string}) { + return await getIntegrationAuthAccessHelper({ + integrationAuthId + }); + } + + /** + * Encrypt refresh token [refreshToken] using the bot's copy + * of the workspace key for workspace belonging to integration auth + * with id [integrationAuthId] + * @param {Object} obj + * @param {String} obj.integrationAuthId - id of integration auth + * @param {String} obj.refreshToken - refresh token + * @returns {IntegrationAuth} integrationAuth - updated integration auth + */ + static async setIntegrationAuthRefresh({ + integrationAuthId, + refreshToken + }: { + integrationAuthId: string; + refreshToken: string; + }) { + return await setIntegrationAuthRefreshHelper({ + integrationAuthId, + refreshToken + }); + } + + /** + * Encrypt access token [accessToken] using the bot's copy + * of the workspace key for workspace belonging to integration auth + * with id [integrationAuthId] + * @param {Object} obj + * @param {String} obj.integrationAuthId - id of integration auth + * @param {String} obj.accessToken - access token + * @param {Date} obj.accessExpiresAt - expiration date of access token + * @returns {IntegrationAuth} - updated integration auth + */ + static async setIntegrationAuthAccess({ + integrationAuthId, + accessToken, + accessExpiresAt + }: { + integrationAuthId: string; + accessToken: string; + accessExpiresAt: Date | undefined; + }) { + return await setIntegrationAuthAccessHelper({ + integrationAuthId, + accessToken, + accessExpiresAt + }); + } +} + +export default IntegrationService; \ No newline at end of file diff --git a/backend/src/services/PostHogClient.ts b/backend/src/services/PostHogClient.ts index 4096ac8ec..0d91a1c13 100644 --- a/backend/src/services/PostHogClient.ts +++ b/backend/src/services/PostHogClient.ts @@ -5,8 +5,16 @@ import { POSTHOG_PROJECT_API_KEY, TELEMETRY_ENABLED } from '../config'; +import { getLogger } from '../utils/logger'; -console.log('TELEMETRY_ENABLED: ', TELEMETRY_ENABLED); +if(!TELEMETRY_ENABLED){ + getLogger("backend-main").info([ + "", + "To improve, Infisical collects telemetry data about general usage.", + "This helps us understand how the product is doing and guide our product development to create the best possible platform; it also helps us demonstrate growth as we support Infisical as open-source software.", + "To opt into telemetry, you can set `TELEMETRY_ENABLED=true` within the environment variables.", + ].join('\n')) +} let postHogClient: any; if (NODE_ENV === 'production' && TELEMETRY_ENABLED) { diff --git a/backend/src/services/health.ts b/backend/src/services/health.ts new file mode 100644 index 000000000..9c441ba9d --- /dev/null +++ b/backend/src/services/health.ts @@ -0,0 +1,32 @@ +import mongoose from 'mongoose'; +import { createTerminus } from '@godaddy/terminus'; +import { getLogger } from '../utils/logger'; + +export const setUpHealthEndpoint = (server: T) => { + const onSignal = () => { + getLogger('backend-main').info('Server is starting clean-up'); + return Promise.all([ + new Promise((resolve) => { + if (mongoose.connection && mongoose.connection.readyState == 1) { + mongoose.connection.close() + .then(() => resolve('Database connection closed')); + } else { + resolve('Database connection already closed'); + } + }) + ]); + }; + + const healthCheck = () => { + // `state.isShuttingDown` (boolean) shows whether the server is shutting down or not + // optionally include a resolve value to be included as info in the health check response + return Promise.resolve(); + }; + + createTerminus(server, { + healthChecks: { + '/healthcheck': healthCheck, + onSignal + } + }); +}; diff --git a/backend/src/services/index.ts b/backend/src/services/index.ts index 54cdf94f4..c53829922 100644 --- a/backend/src/services/index.ts +++ b/backend/src/services/index.ts @@ -1,5 +1,13 @@ +import DatabaseService from './DatabaseService'; import postHogClient from './PostHogClient'; +import BotService from './BotService'; +import EventService from './EventService'; +import IntegrationService from './IntegrationService'; export { - postHogClient + DatabaseService, + postHogClient, + BotService, + EventService, + IntegrationService } \ No newline at end of file diff --git a/backend/src/services/smtp.ts b/backend/src/services/smtp.ts new file mode 100644 index 000000000..f960f6bae --- /dev/null +++ b/backend/src/services/smtp.ts @@ -0,0 +1,58 @@ +import nodemailer from 'nodemailer'; +import { SMTP_HOST, SMTP_PORT, SMTP_USERNAME, SMTP_PASSWORD, SMTP_SECURE } from '../config'; +import { SMTP_HOST_SENDGRID, SMTP_HOST_MAILGUN } from '../variables'; +import SMTPConnection from 'nodemailer/lib/smtp-connection'; +import * as Sentry from '@sentry/node'; + +const mailOpts: SMTPConnection.Options = { + host: SMTP_HOST, + port: SMTP_PORT as number +}; + +if (SMTP_USERNAME && SMTP_PASSWORD) { + mailOpts.auth = { + user: SMTP_USERNAME, + pass: SMTP_PASSWORD + }; +} + +if (SMTP_SECURE) { + switch (SMTP_HOST) { + case SMTP_HOST_SENDGRID: + mailOpts.requireTLS = true; + break; + case SMTP_HOST_MAILGUN: + mailOpts.requireTLS = true; + mailOpts.tls = { + ciphers: 'TLSv1.2' + } + break; + default: + if (SMTP_HOST.includes('amazonaws.com')) { + mailOpts.tls = { + ciphers: 'TLSv1.2' + } + } else { + mailOpts.secure = true; + } + break; + } +} + +export const initSmtp = () => { + const transporter = nodemailer.createTransport(mailOpts); + transporter + .verify() + .then(() => { + Sentry.setUser(null); + Sentry.captureMessage('SMTP - Successfully connected'); + }) + .catch((err) => { + Sentry.setUser(null); + Sentry.captureException( + `SMTP - Failed to connect to ${SMTP_HOST}:${SMTP_PORT} \n\t${err}` + ); + }); + + return transporter; +}; diff --git a/backend/src/types/express/index.d.ts b/backend/src/types/express/index.d.ts index 8fdb2b3fe..acee877bd 100644 --- a/backend/src/types/express/index.d.ts +++ b/backend/src/types/express/index.d.ts @@ -1,18 +1,27 @@ import * as express from 'express'; +import { ISecret } from '../../models'; // TODO: fix (any) types declare global { namespace Express { interface Request { + clientIp: any; user: any; workspace: any; membership: any; - organizationt: any; + targetMembership: any; + organization: any; membershipOrg: any; integration: any; integrationAuth: any; + bot: any; + _secret: any; + secrets: any; + secretSnapshot: any; serviceToken: any; accessToken: any; + serviceTokenData: any; + apiKeyData: any; query?: any; } } diff --git a/backend/src/types/secret/index.d.ts b/backend/src/types/secret/index.d.ts new file mode 100644 index 000000000..177df8c0f --- /dev/null +++ b/backend/src/types/secret/index.d.ts @@ -0,0 +1,14 @@ +import { Assign, Omit } from 'utility-types'; +import { ISecret } from '../../models'; + +// Everything is required, except the omitted types +export type CreateSecretRequestBody = Omit; + +// Omit the listed properties, then make everything optional and then make _id required +export type ModifySecretRequestBody = Assign>, { _id: string }>; + +// Used for modeling sanitized secrets before uplaod. To be used for converting user input for uploading +export type SanitizedSecretModify = Partial>; + +// Everything is required, except the omitted types +export type SanitizedSecretForCreate = Omit; diff --git a/backend/src/utils/addDevelopmentUser.ts b/backend/src/utils/addDevelopmentUser.ts new file mode 100644 index 000000000..2020cf3ad --- /dev/null +++ b/backend/src/utils/addDevelopmentUser.ts @@ -0,0 +1,140 @@ +/************************************************************************************************ +* +* Attention: The credentials below are only for development purposes, it should never be used for production +* +************************************************************************************************/ + +import { NODE_ENV } from "../config" +import { Key, Membership, MembershipOrg, Organization, User, Workspace } from "../models"; +import { Types } from 'mongoose'; + +export const createTestUserForDevelopment = async () => { + if (NODE_ENV === "development") { + const testUserEmail = "test@localhost.local" + const testUserPassword = "testInfisical1" + const testUserId = "63cefa6ec8d3175601cfa980" + const testWorkspaceId = "63cefb15c8d3175601cfa989" + const testOrgId = "63cefb15c8d3175601cfa985" + const testMembershipId = "63cefb159185d9aa3ef0cf35" + const testMembershipOrgId = "63cefb159185d9aa3ef0cf31" + const testWorkspaceKeyId = "63cf48f0225e6955acec5eff" + + const testUser = { + _id: testUserId, + email: testUserEmail, + refreshVersion: 0, + encryptedPrivateKey: 'ITMdDXtLoxib4+53U/qzvIV/T/UalRwimogFCXv/UsulzEoiKM+aK2aqOb0=', + firstName: 'Jake', + iv: '9fp0dZHI+UuHeKkWMDvD6w==', + lastName: 'Moni', + publicKey: 'cf44BhkybbBfsE0fZHe2jvqtCj6KLXvSq4hVjV0svzk=', + salt: 'd8099dc70958090346910fb9639262b83cf526fc9b4555a171b36a9e1bcd0240', + tag: 'bQ/UTghqcQHRoSMpLQD33g==', + verifier: '12271fcd50937ca4512e1e3166adaf9d9fc7a5cd0e4c4cb3eda89f35572ede4d9eef23f64aef9220367abff9437b0b6fa55792c442f177201d87051cf77dadade254ff667170440327355fb7d6ac4745d4db302f4843632c2ed5919ebdcff343287a4cd552255d9e3ce81177edefe089617b7616683901475d393405f554634b9bf9230c041ac85624f37a60401be20b78044932580ae0868323be3749fbf856df1518153ba375fec628275f0c445f237446ea4aa7f12c1aa1d6b5fd74b7f2e88d062845a19819ec63f2d2ed9e9f37c055149649461d997d2ae1482f53b04f9de7493efbb9686fb19b2d559b9aa2b502c22dec83f9fc43290dfea89a1dc6f03580b3642b3824513853e81a441be9a0b2fde2231bac60f3287872617a36884697805eeea673cf1a351697834484ada0f282e4745015c9c2928d61e6d092f1b9c3a27eda8413175d23bb2edae62f82ccaf52bf5a6a90344a766c7e4ebf65dae9ae90b2ad4ae65dbf16e3a6948e429771cc50307ae86d454f71a746939ed061f080dd3ae369c1a0739819aca17af46a085bac1f2a5d936d198e7951a8ac3bb38b893665fe7312835abd3f61811f81efa2a8761af5070085f9b6adcca80bf9b0d81899c3d41487fba90728bb24eceb98bd69770360a232624133700ceb4d153f2ad702e0a5b7dfaf97d20bc8aa71dc8c20024a58c06a8fecdad18cb5a2f89c51eaf7' + } + + const testWorkspaceKey = { + _id: new Types.ObjectId(testWorkspaceKeyId), + workspace: testWorkspaceId, + encryptedKey: '96ZIRSU21CjVzIQ4Yp994FGWQvDdyK3gq+z+NCaJLK0ByTlvUePmf+AYGFJjkAdz', + nonce: '1jhCGqg9Wx3n0OtVxbDgiYYGq4S3EdgO', + sender: '63cefa6ec8d3175601cfa980', + receiver: '63cefa6ec8d3175601cfa980', + } + + const testWorkspace = { + _id: new Types.ObjectId(testWorkspaceId), + name: 'Example Project', + organization: testOrgId, + environments: [ + { + _id: '63cefb15c8d3175601cfa98a', + name: 'Development', + slug: 'dev' + }, + { + _id: '63cefb15c8d3175601cfa98b', + name: 'Test', + slug: 'test' + }, + { + _id: '63cefb15c8d3175601cfa98c', + name: 'Staging', + slug: 'staging' + }, + { + _id: '63cefb15c8d3175601cfa98d', + name: 'Production', + slug: 'prod' + } + ], + } + + const testOrg = { + _id: testOrgId, + name: 'Jake\'s organization' + } + + const testMembershipOrg = { + _id: testMembershipOrgId, + organization: testOrgId, + role: 'owner', + status: 'accepted', + user: testUserId, + } + + const testMembership = { + _id: testMembershipId, + role: 'admin', + user: testUserId, + workspace: testWorkspaceId + } + + try { + // create user if not exist + const userInDB = await User.findById(testUserId) + if (!userInDB) { + await User.create(testUser) + } + + // create org if not exist + const orgInDB = await Organization.findById(testOrgId) + if (!orgInDB) { + await Organization.create(testOrg) + } + + // create membership org if not exist + const membershipOrgInDB = await MembershipOrg.findById(testMembershipOrgId) + if (!membershipOrgInDB) { + await MembershipOrg.create(testMembershipOrg) + } + + // create membership + const membershipInDB = await Membership.findById(testMembershipId) + if (!membershipInDB) { + await Membership.create(testMembership) + } + + // create workspace if not exist + const workspaceInDB = await Workspace.findById(testWorkspaceId) + if (!workspaceInDB) { + await Workspace.create(testWorkspace) + } + + // create workspace key if not exist + const workspaceKeyInDB = await Key.findById(testWorkspaceKeyId) + if (!workspaceKeyInDB) { + await Key.create(testWorkspaceKey) + } + + /* eslint-disable no-console */ + console.info(`DEVELOPMENT MODE DETECTED: You may login with test user with email: ${testUserEmail} and password: ${testUserPassword}`) + /* eslint-enable no-console */ + + } catch (e) { + /* eslint-disable no-console */ + console.error(`Unable to create test user while booting up [err=${e}]`) + /* eslint-enable no-console */ + } + } +} \ No newline at end of file diff --git a/backend/src/utils/crypto.ts b/backend/src/utils/crypto.ts index 742e65e80..28f96b0cf 100644 --- a/backend/src/utils/crypto.ts +++ b/backend/src/utils/crypto.ts @@ -1,6 +1,22 @@ import nacl from 'tweetnacl'; import util from 'tweetnacl-util'; import AesGCM from './aes-gcm'; +import * as Sentry from '@sentry/node'; + +/** + * Return new base64, NaCl, public-private key pair. + * @returns {Object} obj + * @returns {String} obj.publicKey - base64, NaCl, public key + * @returns {String} obj.privateKey - base64, NaCl, private key + */ +const generateKeyPair = () => { + const pair = nacl.box.keyPair(); + + return ({ + publicKey: util.encodeBase64(pair.publicKey), + privateKey: util.encodeBase64(pair.secretKey) + }); +} /** * Return assymmetrically encrypted [plaintext] using [publicKey] where @@ -32,6 +48,8 @@ const encryptAsymmetric = ({ util.decodeBase64(privateKey) ); } catch (err) { + Sentry.setUser(null); + Sentry.captureException(err); throw new Error('Failed to perform asymmetric encryption'); } @@ -71,6 +89,8 @@ const decryptAsymmetric = ({ util.decodeBase64(privateKey) ); } catch (err) { + Sentry.setUser(null); + Sentry.captureException(err); throw new Error('Failed to perform asymmetric decryption'); } @@ -81,7 +101,7 @@ const decryptAsymmetric = ({ * Return symmetrically encrypted [plaintext] using [key]. * @param {Object} obj * @param {String} obj.plaintext - plaintext to encrypt - * @param {String} obj.key - 16-byte hex key + * @param {String} obj.key - hex key */ const encryptSymmetric = ({ plaintext, @@ -97,6 +117,8 @@ const encryptSymmetric = ({ iv = obj.iv; tag = obj.tag; } catch (err) { + Sentry.setUser(null); + Sentry.captureException(err); throw new Error('Failed to perform symmetric encryption'); } @@ -114,7 +136,7 @@ const encryptSymmetric = ({ * @param {String} obj.ciphertext - ciphertext to decrypt * @param {String} obj.iv - iv * @param {String} obj.tag - tag - * @param {String} obj.key - 32-byte hex key + * @param {String} obj.key - hex key * */ const decryptSymmetric = ({ @@ -132,6 +154,8 @@ const decryptSymmetric = ({ try { plaintext = AesGCM.decrypt(ciphertext, iv, tag, key); } catch (err) { + Sentry.setUser(null); + Sentry.captureException(err); throw new Error('Failed to perform symmetric decryption'); } @@ -139,6 +163,7 @@ const decryptSymmetric = ({ }; export { + generateKeyPair, encryptAsymmetric, decryptAsymmetric, encryptSymmetric, diff --git a/backend/src/utils/errors.ts b/backend/src/utils/errors.ts new file mode 100644 index 000000000..e9972edf5 --- /dev/null +++ b/backend/src/utils/errors.ts @@ -0,0 +1,166 @@ +import RequestError, { LogLevel, RequestErrorContext } from "./requestError" + +//* ----->[GENERAL HTTP ERRORS]<----- +export const RouteNotFoundError = (error?: Partial) => new RequestError({ + logLevel: error?.logLevel ?? LogLevel.INFO, + statusCode: error?.statusCode ?? 404, + type: error?.type ?? 'route_not_found', + message: error?.message ?? 'The requested source was not found', + context: error?.context, + stack: error?.stack +}); + +export const MethodNotAllowedError = (error?: Partial) => new RequestError({ + logLevel: error?.logLevel ?? LogLevel.INFO, + statusCode: error?.statusCode ?? 405, + type: error?.type ?? 'method_not_allowed', + message: error?.message ?? 'The requested method is not allowed for the resource', + context: error?.context, + stack: error?.stack +}); + +export const UnauthorizedRequestError = (error?: Partial) => new RequestError({ + logLevel: error?.logLevel ?? LogLevel.INFO, + statusCode: error?.statusCode ?? 401, + type: error?.type ?? 'unauthorized', + message: error?.message ?? 'You are not authorized to access this resource', + context: error?.context, + stack: error?.stack +}); + +export const ForbiddenRequestError = (error?: Partial) => new RequestError({ + logLevel: error?.logLevel ?? LogLevel.INFO, + statusCode: error?.statusCode ?? 403, + type: error?.type ?? 'forbidden', + message: error?.message ?? 'You are not allowed to access this resource', + context: error?.context, + stack: error?.stack +}); + +export const BadRequestError = (error?: Partial) => new RequestError({ + logLevel: error?.logLevel ?? LogLevel.INFO, + statusCode: error?.statusCode ?? 400, + type: error?.type ?? 'bad_request', + message: error?.message ?? 'The request is invalid or cannot be served', + context: error?.context, + stack: error?.stack +}); + +export const InternalServerError = (error?: Partial) => new RequestError({ + logLevel: error?.logLevel ?? LogLevel.ERROR, + statusCode: error?.statusCode ?? 500, + type: error?.type ?? 'internal_server_error', + message: error?.message ?? 'The server encountered an error while processing the request', + context: error?.context, + stack: error?.stack +}); + +export const ServiceUnavailableError = (error?: Partial) => new RequestError({ + logLevel: error?.logLevel ?? LogLevel.ERROR, + statusCode: error?.statusCode ?? 503, + type: error?.type ?? 'service_unavailable', + message: error?.message ?? 'The service is currently unavailable. Please try again later.', + context: error?.context, + stack: error?.stack +}); + +export const ValidationError = (error?: Partial) => new RequestError({ + logLevel: error?.logLevel ?? LogLevel.ERROR, + statusCode: error?.statusCode ?? 400, + type: error?.type ?? 'validation_error', + message: error?.message ?? 'The request failed validation', + context: error?.context, + stack: error?.stack +}); + +//* ----->[INTEGRATION ERRORS]<----- +export const IntegrationNotFoundError = (error?: Partial) => new RequestError({ + logLevel: error?.logLevel ?? LogLevel.ERROR, + statusCode: error?.statusCode ?? 404, + type: error?.type ?? 'integration_not_found_error', + message: error?.message ?? 'The requested integration was not found', + context: error?.context, + stack: error?.stack +}); + +//* ----->[WORKSPACE ERRORS]<----- +export const WorkspaceNotFoundError = (error?: Partial) => new RequestError({ + logLevel: error?.logLevel ?? LogLevel.ERROR, + statusCode: error?.statusCode ?? 404, + type: error?.type ?? 'workspace_not_found_error', + message: error?.message ?? 'The requested workspace was not found', + context: error?.context, + stack: error?.stack +}); + +//* ----->[ORGANIZATION ERRORS]<----- +export const OrganizationNotFoundError = (error?: Partial) => new RequestError({ + logLevel: error?.logLevel ?? LogLevel.ERROR, + statusCode: error?.statusCode ?? 404, + type: error?.type ?? 'organization_not_found_error', + message: error?.message ?? 'The requested organization was not found', + context: error?.context, + stack: error?.stack +}); + +//* ----->[ACCOUNT ERRORS]<----- +export const AccountNotFoundError = (error?: Partial) => new RequestError({ + logLevel: error?.logLevel ?? LogLevel.ERROR, + statusCode: error?.statusCode ?? 404, + type: error?.type ?? 'account_not_found_error', + message: error?.message ?? 'The requested account was not found', + context: error?.context, + stack: error?.stack +}); + +//* ----->[SECRET ERRORS]<----- +export const SecretNotFoundError = (error?: Partial) => new RequestError({ + logLevel: error?.logLevel ?? LogLevel.ERROR, + statusCode: error?.statusCode ?? 404, + type: error?.type ?? 'secret_not_found_error', + message: error?.message ?? 'The requested secret was not found', + context: error?.context, + stack: error?.stack +}); + +//* ----->[SECRET SNAPSHOT ERRORS]<----- +export const SecretSnapshotNotFoundError = (error?: Partial) => new RequestError({ + logLevel: error?.logLevel ?? LogLevel.ERROR, + statusCode: error?.statusCode ?? 404, + type: error?.type ?? 'secret_snapshot_not_found_error', + message: error?.message ?? 'The requested secret snapshot was not found', + context: error?.context, + stack: error?.stack +}); + +//* ----->[ACTION ERRORS]<----- +export const ActionNotFoundError = (error?: Partial) => new RequestError({ + logLevel: error?.logLevel ?? LogLevel.ERROR, + statusCode: error?.statusCode ?? 404, + type: error?.type ?? 'action_not_found_error', + message: error?.message ?? 'The requested action was not found', + context: error?.context, + stack: error?.stack +}); + +//* ----->[SERVICE TOKEN DATA ERRORS]<----- +export const ServiceTokenDataNotFoundError = (error?: Partial) => new RequestError({ + logLevel: error?.logLevel ?? LogLevel.ERROR, + statusCode: error?.statusCode ?? 404, + type: error?.type ?? 'service_token_data_not_found_error', + message: error?.message ?? 'The requested service token data was not found', + context: error?.context, + stack: error?.stack +}) + +//* ----->[API KEY DATA ERRORS]<----- +export const APIKeyDataNotFoundError = (error?: Partial) => new RequestError({ + logLevel: error?.logLevel ?? LogLevel.ERROR, + statusCode: error?.statusCode ?? 404, + type: error?.type ?? 'service_token_data_not_found_error', + message: error?.message ?? 'The requested service token data was not found', + context: error?.context, + stack: error?.stack +}) + +//* ----->[MISC ERRORS]<----- diff --git a/backend/src/utils/logger.ts b/backend/src/utils/logger.ts new file mode 100644 index 000000000..64c65ea49 --- /dev/null +++ b/backend/src/utils/logger.ts @@ -0,0 +1,65 @@ +/* eslint-disable no-console */ +import { createLogger, format, transports } from 'winston'; +import LokiTransport from 'winston-loki'; +import { LOKI_HOST, NODE_ENV } from '../config'; + +const { combine, colorize, label, printf, splat, timestamp } = format; + +const logFormat = (prefix: string) => combine( + timestamp(), + splat(), + label({ label: prefix }), + printf((info) => `${info.timestamp} ${info.label} ${info.level}: ${info.message}`) +); + +const createLoggerWithLabel = (level: string, label: string) => { + const _level = level.toLowerCase() || 'info' + //* Always add Console output to transports + const _transports: any[] = [ + new transports.Console({ + format: combine( + colorize(), + logFormat(label), + // format.json() + ) + }) + ] + //* Add LokiTransport if it's enabled + if(LOKI_HOST !== undefined){ + _transports.push( + new LokiTransport({ + host: LOKI_HOST, + handleExceptions: true, + handleRejections: true, + batching: true, + level: _level, + timeout: 30000, + format: format.combine( + format.json() + ), + labels: {app: process.env.npm_package_name, version: process.env.npm_package_version, environment: NODE_ENV}, + onConnectionError: (err: Error)=> console.error('Connection error while connecting to Loki Server.\n', err) + }) + ) + } + + + return createLogger({ + level: _level, + transports: _transports, + format: format.combine( + logFormat(label), + format.metadata({ fillExcept: ['message', 'level', 'timestamp', 'label'] }) + ) + }); +} + +const DEFAULT_LOGGERS = { + "backend-main": createLoggerWithLabel('info', '[IFSC:backend-main]'), + "database": createLoggerWithLabel('info', '[IFSC:database]'), +} +type LoggerNames = keyof typeof DEFAULT_LOGGERS + +export const getLogger = (loggerName: LoggerNames) => { + return DEFAULT_LOGGERS[loggerName] +} diff --git a/backend/src/utils/patchAsyncRoutes.js b/backend/src/utils/patchAsyncRoutes.js new file mode 100644 index 000000000..24fe007f9 --- /dev/null +++ b/backend/src/utils/patchAsyncRoutes.js @@ -0,0 +1,69 @@ +/* +Original work Copyright (c) 2016, Nikolay Nemshilov +Modified work Copyright (c) 2016, David Banham + +Permission to use, copy, modify, and/or distribute this software for any purpose +with or without fee is hereby granted, provided that the above copyright notice +and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS +OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +THIS SOFTWARE. + +*/ + +/* eslint-disable @typescript-eslint/no-var-requires */ +/* eslint-env node */ +const Layer = require('express/lib/router/layer'); +const Router = require('express/lib/router'); + +const last = (arr = []) => arr[arr.length - 1]; +const noop = Function.prototype; + +function copyFnProps(oldFn, newFn) { + Object.keys(oldFn).forEach((key) => { + newFn[key] = oldFn[key]; + }); + return newFn; +} + +function wrap(fn) { + const newFn = function newFn(...args) { + const ret = fn.apply(this, args); + const next = (args.length === 5 ? args[2] : last(args)) || noop; + if (ret && ret.catch) ret.catch(err => next(err)); + return ret; + }; + Object.defineProperty(newFn, 'length', { + value: fn.length, + writable: false, + }); + return copyFnProps(fn, newFn); +} + +function patchRouterParam() { + const originalParam = Router.prototype.constructor.param; + Router.prototype.constructor.param = function param(name, fn) { + fn = wrap(fn); + return originalParam.call(this, name, fn); + }; +} + +Object.defineProperty(Layer.prototype, 'handle', { + enumerable: true, + get() { + return this.__handle; + }, + set(fn) { + fn = wrap(fn); + this.__handle = fn; + }, +}); + +module.exports = { + patchRouterParam +}; diff --git a/backend/src/utils/posthog.ts b/backend/src/utils/posthog.ts new file mode 100644 index 000000000..85a411ca7 --- /dev/null +++ b/backend/src/utils/posthog.ts @@ -0,0 +1,15 @@ +const CLI_USER_AGENT_NAME = "cli" +const K8_OPERATOR_AGENT_NAME = "k8-operator" +export const getChannelFromUserAgent = function (userAgent: string | undefined) { + if (userAgent == undefined) { + return "other" + } else if (userAgent == CLI_USER_AGENT_NAME) { + return "cli" + } else if (userAgent == K8_OPERATOR_AGENT_NAME) { + return "k8-operator" + } else if (userAgent.toLowerCase().includes('mozilla')) { + return "web" + } else { + return "other" + } +} \ No newline at end of file diff --git a/backend/src/utils/requestError.ts b/backend/src/utils/requestError.ts new file mode 100644 index 000000000..da2803da7 --- /dev/null +++ b/backend/src/utils/requestError.ts @@ -0,0 +1,113 @@ +import { Request } from 'express' +import { VERBOSE_ERROR_OUTPUT } from '../config' + +export enum LogLevel { + DEBUG = 100, + INFO = 200, + NOTICE = 250, + WARNING = 300, + ERROR = 400, + CRITICAL = 500, + ALERT = 550, + EMERGENCY = 600, +} + +export type RequestErrorContext = { + logLevel?: LogLevel, + statusCode: number, + type: string, + message: string, + context?: Record, + stack?: string|undefined +} + +export default class RequestError extends Error{ + + private _logLevel: LogLevel + private _logName: string + statusCode: number + type: string + context: Record + extra: Record[] + private stacktrace: string|undefined|string[] + + constructor( + {logLevel, statusCode, type, message, context, stack} : RequestErrorContext + ){ + super(message) + this._logLevel = logLevel || LogLevel.INFO + this._logName = LogLevel[this._logLevel] + this.statusCode = statusCode + this.type = type + this.context = context || {} + this.extra = [] + + if(stack) this.stack = stack + else Error.captureStackTrace(this, this.constructor) + this.stacktrace = this.stack?.split('\n') + } + + static convertFrom(error: Error) { + //This error was not handled by error handler. Please report this incident to the staff. + return new RequestError({ + logLevel: LogLevel.ERROR, + statusCode: 500, + type: 'internal_server_error', + message: 'This error was not handled by error handler. Please report this incident to the staff', + context: { + message: error.message, + name: error.name + }, + stack: error.stack + }) + } + + get level(){ return this._logLevel } + get levelName(){ return this._logName } + + withTags(...tags: string[]|number[]){ + this.context['tags'] = Object.assign(tags, this.context['tags']) + return this + } + + withExtras(...extras: Record[]){ + this.extra = Object.assign(extras, this.extra) + return this + } + + private _omit(obj: any, keys: string[]): typeof obj{ + const exclude = new Set(keys) + obj = Object.fromEntries(Object.entries(obj).filter(e => !exclude.has(e[0]))) + return obj + } + + public format(req: Request){ + let _context = Object.assign({ + stacktrace: this.stacktrace + }, this.context) + + //* Omit sensitive information from context that can leak internal workings of this program if user is not developer + if(!VERBOSE_ERROR_OUTPUT){ + _context = this._omit(_context, [ + 'stacktrace', + 'exception', + ]) + } + + const formatObject = { + type: this.type, + message: this.message, + context: _context, + level: this.level, + level_name: this.levelName, + status_code: this.statusCode, + datetime_iso: new Date().toISOString(), + application: process.env.npm_package_name || 'unknown', + request_id: req.headers["Request-Id"], + extra: this.extra + } + + return formatObject + + } +} \ No newline at end of file diff --git a/backend/src/variables.ts b/backend/src/variables.ts deleted file mode 100644 index cdd771b71..000000000 --- a/backend/src/variables.ts +++ /dev/null @@ -1,60 +0,0 @@ -// membership roles -const OWNER = 'owner'; -const ADMIN = 'admin'; -const MEMBER = 'member'; - -// membership statuses -const INVITED = 'invited'; - -// -- organization -const ACCEPTED = 'accepted'; - -// -- workspace -const COMPLETED = 'completed'; -const GRANTED = 'granted'; - -// subscriptions -const PLAN_STARTER = 'starter'; -const PLAN_PRO = 'pro'; - -// secrets -const SECRET_SHARED = 'shared'; -const SECRET_PERSONAL = 'personal'; - -// environments -const ENV_DEV = 'dev'; -const ENV_TESTING = 'test'; -const ENV_STAGING = 'staging'; -const ENV_PROD = 'prod'; -const ENV_SET = new Set([ENV_DEV, ENV_TESTING, ENV_STAGING, ENV_PROD]); - -// integrations -const INTEGRATION_HEROKU = 'heroku'; -const INTEGRATION_NETLIFY = 'netlify'; -const INTEGRATION_SET = new Set([INTEGRATION_HEROKU, INTEGRATION_NETLIFY]); - -// integration types -const INTEGRATION_OAUTH2 = 'oauth2'; - -export { - OWNER, - ADMIN, - MEMBER, - INVITED, - ACCEPTED, - COMPLETED, - GRANTED, - PLAN_STARTER, - PLAN_PRO, - SECRET_SHARED, - SECRET_PERSONAL, - ENV_DEV, - ENV_TESTING, - ENV_STAGING, - ENV_PROD, - ENV_SET, - INTEGRATION_HEROKU, - INTEGRATION_NETLIFY, - INTEGRATION_SET, - INTEGRATION_OAUTH2 -}; diff --git a/backend/src/variables/action.ts b/backend/src/variables/action.ts new file mode 100644 index 000000000..512eb8e8d --- /dev/null +++ b/backend/src/variables/action.ts @@ -0,0 +1,11 @@ +const ACTION_ADD_SECRETS = 'addSecrets'; +const ACTION_DELETE_SECRETS = 'deleteSecrets'; +const ACTION_UPDATE_SECRETS = 'updateSecrets'; +const ACTION_READ_SECRETS = 'readSecrets'; + +export { + ACTION_ADD_SECRETS, + ACTION_DELETE_SECRETS, + ACTION_UPDATE_SECRETS, + ACTION_READ_SECRETS +} \ No newline at end of file diff --git a/backend/src/variables/environment.ts b/backend/src/variables/environment.ts new file mode 100644 index 000000000..44d7cdbb2 --- /dev/null +++ b/backend/src/variables/environment.ts @@ -0,0 +1,14 @@ +// environments +const ENV_DEV = 'dev'; +const ENV_TESTING = 'test'; +const ENV_STAGING = 'staging'; +const ENV_PROD = 'prod'; +const ENV_SET = new Set([ENV_DEV, ENV_TESTING, ENV_STAGING, ENV_PROD]); + +export { + ENV_DEV, + ENV_TESTING, + ENV_STAGING, + ENV_PROD, + ENV_SET +} \ No newline at end of file diff --git a/backend/src/variables/event.ts b/backend/src/variables/event.ts new file mode 100644 index 000000000..4477e8e02 --- /dev/null +++ b/backend/src/variables/event.ts @@ -0,0 +1,7 @@ +const EVENT_PUSH_SECRETS = 'pushSecrets'; +const EVENT_PULL_SECRETS = 'pullSecrets'; + +export { + EVENT_PUSH_SECRETS, + EVENT_PULL_SECRETS +} \ No newline at end of file diff --git a/backend/src/variables/index.ts b/backend/src/variables/index.ts new file mode 100644 index 000000000..dc1ce6f78 --- /dev/null +++ b/backend/src/variables/index.ts @@ -0,0 +1,87 @@ +import { + ENV_DEV, + ENV_TESTING, + ENV_STAGING, + ENV_PROD, + ENV_SET +} from './environment'; +import { + INTEGRATION_HEROKU, + INTEGRATION_VERCEL, + INTEGRATION_NETLIFY, + INTEGRATION_GITHUB, + INTEGRATION_RENDER, + INTEGRATION_FLYIO, + INTEGRATION_SET, + INTEGRATION_OAUTH2, + INTEGRATION_HEROKU_TOKEN_URL, + INTEGRATION_VERCEL_TOKEN_URL, + INTEGRATION_NETLIFY_TOKEN_URL, + INTEGRATION_GITHUB_TOKEN_URL, + INTEGRATION_HEROKU_API_URL, + INTEGRATION_VERCEL_API_URL, + INTEGRATION_NETLIFY_API_URL, + INTEGRATION_RENDER_API_URL, + INTEGRATION_FLYIO_API_URL, + INTEGRATION_OPTIONS +} from './integration'; +import { + OWNER, + ADMIN, + MEMBER, + INVITED, + ACCEPTED, +} from './organization'; +import { SECRET_SHARED, SECRET_PERSONAL } from './secret'; +import { EVENT_PUSH_SECRETS, EVENT_PULL_SECRETS } from './event'; +import { + ACTION_ADD_SECRETS, + ACTION_UPDATE_SECRETS, + ACTION_DELETE_SECRETS, + ACTION_READ_SECRETS +} from './action'; +import { SMTP_HOST_SENDGRID, SMTP_HOST_MAILGUN } from './smtp'; +import { PLAN_STARTER, PLAN_PRO } from './stripe'; + +export { + OWNER, + ADMIN, + MEMBER, + INVITED, + ACCEPTED, + SECRET_SHARED, + SECRET_PERSONAL, + ENV_DEV, + ENV_TESTING, + ENV_STAGING, + ENV_PROD, + ENV_SET, + INTEGRATION_HEROKU, + INTEGRATION_VERCEL, + INTEGRATION_NETLIFY, + INTEGRATION_GITHUB, + INTEGRATION_RENDER, + INTEGRATION_FLYIO, + INTEGRATION_SET, + INTEGRATION_OAUTH2, + INTEGRATION_HEROKU_TOKEN_URL, + INTEGRATION_VERCEL_TOKEN_URL, + INTEGRATION_NETLIFY_TOKEN_URL, + INTEGRATION_GITHUB_TOKEN_URL, + INTEGRATION_HEROKU_API_URL, + INTEGRATION_VERCEL_API_URL, + INTEGRATION_NETLIFY_API_URL, + INTEGRATION_RENDER_API_URL, + INTEGRATION_FLYIO_API_URL, + EVENT_PUSH_SECRETS, + EVENT_PULL_SECRETS, + ACTION_ADD_SECRETS, + ACTION_UPDATE_SECRETS, + ACTION_DELETE_SECRETS, + ACTION_READ_SECRETS, + INTEGRATION_OPTIONS, + SMTP_HOST_SENDGRID, + SMTP_HOST_MAILGUN, + PLAN_STARTER, + PLAN_PRO, +}; diff --git a/backend/src/variables/integration.ts b/backend/src/variables/integration.ts new file mode 100644 index 000000000..7cecb54c2 --- /dev/null +++ b/backend/src/variables/integration.ts @@ -0,0 +1,164 @@ +import { + CLIENT_ID_HEROKU, + CLIENT_ID_NETLIFY, + CLIENT_ID_GITHUB, + CLIENT_SLUG_VERCEL +} from '../config'; + +// integrations +const INTEGRATION_HEROKU = 'heroku'; +const INTEGRATION_VERCEL = 'vercel'; +const INTEGRATION_NETLIFY = 'netlify'; +const INTEGRATION_GITHUB = 'github'; +const INTEGRATION_RENDER = 'render'; +const INTEGRATION_FLYIO = 'flyio'; +const INTEGRATION_SET = new Set([ + INTEGRATION_HEROKU, + INTEGRATION_VERCEL, + INTEGRATION_NETLIFY, + INTEGRATION_GITHUB, + INTEGRATION_RENDER, + INTEGRATION_FLYIO +]); + +// integration types +const INTEGRATION_OAUTH2 = 'oauth2'; + +// integration oauth endpoints +const INTEGRATION_HEROKU_TOKEN_URL = 'https://id.heroku.com/oauth/token'; +const INTEGRATION_VERCEL_TOKEN_URL = + 'https://api.vercel.com/v2/oauth/access_token'; +const INTEGRATION_NETLIFY_TOKEN_URL = 'https://api.netlify.com/oauth/token'; +const INTEGRATION_GITHUB_TOKEN_URL = + 'https://github.com/login/oauth/access_token'; + +// integration apps endpoints +const INTEGRATION_HEROKU_API_URL = 'https://api.heroku.com'; +const INTEGRATION_VERCEL_API_URL = 'https://api.vercel.com'; +const INTEGRATION_NETLIFY_API_URL = 'https://api.netlify.com'; +const INTEGRATION_RENDER_API_URL = 'https://api.render.com'; +const INTEGRATION_FLYIO_API_URL = 'https://api.fly.io/graphql'; + +const INTEGRATION_OPTIONS = [ + { + name: 'Heroku', + slug: 'heroku', + image: 'Heroku.png', + isAvailable: true, + type: 'oauth', + clientId: CLIENT_ID_HEROKU, + docsLink: '' + }, + { + name: 'Vercel', + slug: 'vercel', + image: 'Vercel.png', + isAvailable: true, + type: 'oauth', + clientId: '', + clientSlug: CLIENT_SLUG_VERCEL, + docsLink: '' + }, + { + name: 'Netlify', + slug: 'netlify', + image: 'Netlify.png', + isAvailable: true, + type: 'oauth', + clientId: CLIENT_ID_NETLIFY, + docsLink: '' + }, + { + name: 'GitHub', + slug: 'github', + image: 'GitHub.png', + isAvailable: true, + type: 'oauth', + clientId: CLIENT_ID_GITHUB, + docsLink: '' + }, + { + name: 'Render', + slug: 'render', + image: 'Render.png', + isAvailable: true, + type: 'pat', + clientId: '', + docsLink: '' + }, + { + name: 'Fly.io', + slug: 'flyio', + image: 'Flyio.svg', + isAvailable: true, + type: 'pat', + clientId: '', + docsLink: '' + }, + { + name: 'Google Cloud Platform', + slug: 'gcp', + image: 'Google Cloud Platform.png', + isAvailable: false, + type: '', + clientId: '', + docsLink: '' + }, + { + name: 'Amazon Web Services', + slug: 'aws', + image: 'Amazon Web Services.png', + isAvailable: false, + type: '', + clientId: '', + docsLink: '' + }, + { + name: 'Microsoft Azure', + slug: 'azure', + image: 'Microsoft Azure.png', + isAvailable: false, + type: '', + clientId: '', + docsLink: '' + }, + { + name: 'Travis CI', + slug: 'travisci', + image: 'Travis CI.png', + isAvailable: false, + type: '', + clientId: '', + docsLink: '' + }, + { + name: 'Circle CI', + slug: 'circleci', + image: 'Circle CI.png', + isAvailable: false, + type: '', + clientId: '', + docsLink: '' + } +] + +export { + INTEGRATION_HEROKU, + INTEGRATION_VERCEL, + INTEGRATION_NETLIFY, + INTEGRATION_GITHUB, + INTEGRATION_RENDER, + INTEGRATION_FLYIO, + INTEGRATION_SET, + INTEGRATION_OAUTH2, + INTEGRATION_HEROKU_TOKEN_URL, + INTEGRATION_VERCEL_TOKEN_URL, + INTEGRATION_NETLIFY_TOKEN_URL, + INTEGRATION_GITHUB_TOKEN_URL, + INTEGRATION_HEROKU_API_URL, + INTEGRATION_VERCEL_API_URL, + INTEGRATION_NETLIFY_API_URL, + INTEGRATION_RENDER_API_URL, + INTEGRATION_FLYIO_API_URL, + INTEGRATION_OPTIONS +}; diff --git a/backend/src/variables/organization.ts b/backend/src/variables/organization.ts new file mode 100644 index 000000000..806460997 --- /dev/null +++ b/backend/src/variables/organization.ts @@ -0,0 +1,24 @@ +// membership roles +const OWNER = 'owner'; +const ADMIN = 'admin'; +const MEMBER = 'member'; + +// membership statuses +const INVITED = 'invited'; + +// membership permissions ability +const ABILITY_READ = 'read'; +const ABILITY_WRITE = 'write'; + +// -- organization +const ACCEPTED = 'accepted'; + +export { + OWNER, + ADMIN, + MEMBER, + INVITED, + ACCEPTED, + ABILITY_READ, + ABILITY_WRITE +} \ No newline at end of file diff --git a/backend/src/variables/secret.ts b/backend/src/variables/secret.ts new file mode 100644 index 000000000..31cbcf951 --- /dev/null +++ b/backend/src/variables/secret.ts @@ -0,0 +1,8 @@ +// secrets +const SECRET_SHARED = 'shared'; +const SECRET_PERSONAL = 'personal'; + +export { + SECRET_SHARED, + SECRET_PERSONAL +} \ No newline at end of file diff --git a/backend/src/variables/smtp.ts b/backend/src/variables/smtp.ts new file mode 100644 index 000000000..4db7c9f12 --- /dev/null +++ b/backend/src/variables/smtp.ts @@ -0,0 +1,7 @@ +const SMTP_HOST_SENDGRID = 'smtp.sendgrid.net'; +const SMTP_HOST_MAILGUN = 'smtp.mailgun.org'; + +export { + SMTP_HOST_SENDGRID, + SMTP_HOST_MAILGUN +} \ No newline at end of file diff --git a/backend/src/variables/stripe.ts b/backend/src/variables/stripe.ts new file mode 100644 index 000000000..ecdbd98ae --- /dev/null +++ b/backend/src/variables/stripe.ts @@ -0,0 +1,7 @@ +const PLAN_STARTER = 'starter'; +const PLAN_PRO = 'pro'; + +export { + PLAN_STARTER, + PLAN_PRO +} \ No newline at end of file diff --git a/backend/swagger/index.ts b/backend/swagger/index.ts new file mode 100644 index 000000000..9f4d4732c --- /dev/null +++ b/backend/swagger/index.ts @@ -0,0 +1,212 @@ +/* eslint-disable @typescript-eslint/no-var-requires */ +const swaggerAutogen = require('swagger-autogen')({ openapi: '3.0.0' }); +const fs = require('fs').promises; +const yaml = require('js-yaml'); + +/** + * Generates OpenAPI specs for all Infisical API endpoints: + * - spec.json in /backend for api-serving + * - spec.yaml in /docs for API reference + */ +const generateOpenAPISpec = async () => { + const doc = { + info: { + title: 'Infisical API', + description: 'List of all available APIs that can be consumed', + }, + host: ['https://infisical.com'], + servers: [ + { + url: 'https://infisical.com', + description: 'Production server' + }, + { + url: 'http://localhost:8080', + description: 'Local server' + } + ], + securityDefinitions: { + bearerAuth: { + type: 'http', + scheme: 'bearer', + bearerFormat: 'JWT', + description: "This security definition uses the HTTP 'bearer' scheme, which allows the client to authenticate using a JSON Web Token (JWT) that is passed in the Authorization header of the request." + }, + apiKeyAuth: { + type: 'apiKey', + in: 'header', + name: 'X-API-Key', + description: 'This security definition uses an API key, which is passed in the header of the request as the value of the "X-API-Key" header. The client must provide a valid key in order to access the API.' + } + }, + definitions: { + CurrentUser: { + _id: '', + email: 'johndoe@gmail.com', + firstName: 'John', + lastName: 'Doe', + publicKey: 'johns_nacl_public_key', + encryptedPrivateKey: 'johns_enc_nacl_private_key', + iv: 'iv_of_enc_nacl_private_key', + tag: 'tag_of_enc_nacl_private_key', + updatedAt: '2023-01-13T14:16:12.210Z', + createdAt: '2023-01-13T14:16:12.210Z' + }, + Membership: { + user: { + _id: '', + email: 'johndoe@gmail.com', + firstName: 'John', + lastName: 'Doe', + publicKey: 'johns_nacl_public_key', + updatedAt: '2023-01-13T14:16:12.210Z', + createdAt: '2023-01-13T14:16:12.210Z' + }, + workspace: '', + role: 'admin' + }, + MembershipOrg: { + user: { + _id: '', + email: 'johndoe@gmail.com', + firstName: 'John', + lastName: 'Doe', + publicKey: 'johns_nacl_public_key', + updatedAt: '2023-01-13T14:16:12.210Z', + createdAt: '2023-01-13T14:16:12.210Z' + }, + organization: '', + role: 'owner', + status: 'accepted' + }, + Organization: { + _id: '', + name: 'Acme Corp.', + customerId: '' + }, + Project: { + name: 'My Project', + organization: '', + environments: [{ + name: 'development', + slug: 'dev' + }] + }, + ProjectKey: { + encryptedkey: '', + nonce: '', + sender: { + publicKey: 'senders_nacl_public_key' + }, + receiver: '', + workspace: '' + }, + CreateSecret: { + type: 'shared', + secretKeyCiphertext: '', + secretKeyIV: '', + secretKeyTag: '', + secretValueCiphertext: '', + secretValueIV: '', + secretValueTag: '', + secretCommentCiphertext: '', + secretCommentIV: '', + secretCommentTag: '' + }, + UpdateSecret: { + id: '', + secretKeyCiphertext: '', + secretKeyIV: '', + secretKeyTag: '', + secretValueCiphertext: '', + secretValueIV: '', + secretValueTag: '', + secretCommentCiphertext: '', + secretCommentIV: '', + secretCommentTag: '' + }, + Secret: { + _id: '', + version: 1, + workspace : '', + type: 'shared', + user: null, + secretKeyCiphertext: '', + secretKeyIV: '', + secretKeyTag: '', + secretValueCiphertext: '', + secretValueIV: '', + secretValueTag: '', + secretCommentCiphertext: '', + secretCommentIV: '', + secretCommentTag: '', + updatedAt: '2023-01-13T14:16:12.210Z', + createdAt: '2023-01-13T14:16:12.210Z' + }, + Log: { + _id: '', + user: { + _id: '', + email: 'johndoe@gmail.com', + firstName: 'John', + lastName: 'Doe' + }, + workspace: '', + actionNames: [ + 'addSecrets' + ], + actions: [ + { + name: 'addSecrets', + user: '', + workspace: '', + payload: [ + { + oldSecretVersion: '', + newSecretVersion: '' + } + ] + } + ], + channel: 'cli', + ipAddress: '192.168.0.1', + updatedAt: '2023-01-13T14:16:12.210Z', + createdAt: '2023-01-13T14:16:12.210Z' + }, + SecretSnapshot: { + workspace: '', + version: 1, + secretVersions: [ + { + _id: '' + } + ] + }, + SecretVersion: { + _id: '', + secret: '', + version: 1, + workspace: '', + type: 'shared', + user: '', + environment: 'dev', + isDeleted: '', + secretKeyCiphertext: '', + secretKeyIV: '', + secretKeyTag: '', + secretValueCiphertext: '', + secretValueIV: '', + secretValueTag: '', + } + } + }; + + const outputJSONFile = '../spec.json'; + const outputYAMLFile = '../docs/spec.yaml'; + const endpointsFiles = ['../src/app.ts']; + + const spec = await swaggerAutogen(outputJSONFile, endpointsFiles, doc); + await fs.writeFile(outputYAMLFile, yaml.dump(spec.data)); +} + +generateOpenAPISpec(); diff --git a/backend/test-resources/docker-compose.test.yml b/backend/test-resources/docker-compose.test.yml new file mode 100644 index 000000000..e9a8c519a --- /dev/null +++ b/backend/test-resources/docker-compose.test.yml @@ -0,0 +1,12 @@ +version: '3' + +services: + mongo-test: + image: mongo + container_name: infisical-test-mongo + restart: always + ports: + - 27018:27017 + environment: + - MONGO_INITDB_ROOT_USERNAME=test + - MONGO_INITDB_ROOT_PASSWORD=test1234 diff --git a/backend/test-resources/env-vars.js b/backend/test-resources/env-vars.js new file mode 100644 index 000000000..a7542728f --- /dev/null +++ b/backend/test-resources/env-vars.js @@ -0,0 +1,5 @@ +/* eslint-disable no-undef */ +process.env.MONGO_URL = + 'mongodb://test:test1234@localhost:27018/?authSource=admin'; +process.env.MONGO_USERNAME = 'test'; +process.env.MONGO_PASSWORD = 'test1234'; diff --git a/backend/tsconfig.json b/backend/tsconfig.json index d6d293372..98ea0808a 100644 --- a/backend/tsconfig.json +++ b/backend/tsconfig.json @@ -1,18 +1,24 @@ { "compilerOptions": { "target": "es2016", - "lib": ["es6"], + "lib": [ + "es6" + ], "module": "commonjs", "rootDir": "src", "resolveJsonModule": true, "allowJs": true, "outDir": "build", "esModuleInterop": true, + "moduleResolution": "node", "forceConsistentCasingInFileNames": true, "strict": true, "noImplicitAny": true, "skipLibCheck": true, - "typeRoots" : ["./src/types", "./node_modules/@types"] + "typeRoots": [ + "./src/types", + "./node_modules/@types" + ] }, "include": [ "src/**/*" @@ -20,4 +26,4 @@ "exclude": [ "node_modules" ] -} +} \ No newline at end of file diff --git a/cli/go.mod b/cli/go.mod index 1c175e2f0..6b7d92489 100644 --- a/cli/go.mod +++ b/cli/go.mod @@ -3,24 +3,44 @@ module github.com/Infisical/infisical-merge go 1.19 require ( + github.com/99designs/keyring v1.2.2 + github.com/muesli/mango-cobra v1.2.0 + github.com/muesli/roff v0.1.0 github.com/spf13/cobra v1.6.1 golang.org/x/crypto v0.3.0 + golang.org/x/term v0.3.0 ) require ( - github.com/alessio/shellescape v1.4.1 // indirect + github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect + github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef // indirect github.com/chzyer/readline v1.5.1 // indirect github.com/danieljoos/wincred v1.1.2 // indirect - github.com/godbus/dbus/v5 v5.1.0 // indirect + github.com/dvsekhvalnov/jose2go v1.5.0 // indirect + github.com/go-openapi/errors v0.20.2 // indirect + github.com/go-openapi/strfmt v0.21.3 // indirect + github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect + github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect + github.com/mattn/go-colorable v0.1.9 // indirect + github.com/mattn/go-isatty v0.0.14 // indirect + github.com/mattn/go-runewidth v0.0.14 // indirect + github.com/mitchellh/mapstructure v1.3.3 // indirect + github.com/mtibben/percent v0.2.1 // indirect + github.com/muesli/mango v0.1.0 // indirect + github.com/muesli/mango-pflag v0.1.0 // indirect + github.com/oklog/ulid v1.3.1 // indirect + github.com/rivo/uniseg v0.2.0 // indirect + go.mongodb.org/mongo-driver v1.10.0 // indirect golang.org/x/net v0.2.0 // indirect - golang.org/x/sys v0.2.0 // indirect + golang.org/x/sys v0.3.0 // indirect ) require ( + github.com/fatih/color v1.13.0 github.com/go-resty/resty/v2 v2.7.0 github.com/inconshreveable/mousetrap v1.0.1 // indirect + github.com/jedib0t/go-pretty v4.3.0+incompatible github.com/manifoldco/promptui v0.9.0 github.com/sirupsen/logrus v1.9.0 github.com/spf13/pflag v1.0.5 // indirect - github.com/zalando/go-keyring v0.2.1 ) diff --git a/cli/go.sum b/cli/go.sum index 975332397..f7e17c62a 100644 --- a/cli/go.sum +++ b/cli/go.sum @@ -1,5 +1,9 @@ -github.com/alessio/shellescape v1.4.1 h1:V7yhSDDn8LP4lc4jS8pFkt0zCnzVJlG5JXy9BVKJUX0= -github.com/alessio/shellescape v1.4.1/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPpyFjDCtHLS30= +github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 h1:/vQbFIOMbk2FiG/kXiLl8BRyzTWDw7gX/Hz7Dd5eDMs= +github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4/go.mod h1:hN7oaIRCjzsZ2dE+yG5k+rsdt3qcwykqK6HVGcKwsw4= +github.com/99designs/keyring v1.2.2 h1:pZd3neh/EmUzWONb35LxQfvuY7kiSXAq3HQd97+XBn0= +github.com/99designs/keyring v1.2.2/go.mod h1:wes/FrByc8j7lFOAGLGSNEg8f/PaI3cgTBqhFkHUrPk= +github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef h1:46PFijGLmAjMPwCCCo7Jf0W6f9slllCkkv7vyc1yOSg= +github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/logex v1.2.1 h1:XHDu3E6q+gdHgsdTPH6ImJMIp436vR6MPtH8gP05QzM= github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ= @@ -10,23 +14,72 @@ github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMn github.com/chzyer/test v1.0.0 h1:p3BQDXSxOhOG0P9z6/hGnII4LGiEPOYBhs8asl/fC04= github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/danieljoos/wincred v1.1.0/go.mod h1:XYlo+eRTsVA9aHGp7NGjFkPla4m+DCL7hqDjlFjiygg= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/danieljoos/wincred v1.1.2 h1:QLdCxFs1/Yl4zduvBdcHB8goaYk9RARS2SgLLRuAyr0= github.com/danieljoos/wincred v1.1.2/go.mod h1:GijpziifJoIBfYh+S7BbkdUTU4LfM+QnGqR5Vl2tAx0= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dvsekhvalnov/jose2go v1.5.0 h1:3j8ya4Z4kMCwT5nXIKFSV84YS+HdqSSO0VsTQxaLAeM= +github.com/dvsekhvalnov/jose2go v1.5.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB/mPZadG+mhXU= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/go-openapi/errors v0.20.2 h1:dxy7PGTqEh94zj2E3h1cUmQQWiM1+aeCROfAr02EmK8= +github.com/go-openapi/errors v0.20.2/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= +github.com/go-openapi/strfmt v0.21.3 h1:xwhj5X6CjXEZZHMWy1zKJxvW9AfHC9pkyUjLvHtKG7o= +github.com/go-openapi/strfmt v0.21.3/go.mod h1:k+RzNO0Da+k3FrrynSNN8F7n/peCmQQqbbXjtDfvmGg= github.com/go-resty/resty/v2 v2.7.0 h1:me+K9p3uhSmXtrBZ4k9jcEAfJmuC8IivWHwaLZwPrFY= github.com/go-resty/resty/v2 v2.7.0/go.mod h1:9PWDzw47qPphMRFfhsyk0NnSgvluHcljSMVIq3w7q0I= -github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= -github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0= +github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c h1:6rhixN/i8ZofjG1Y75iExal34USq5p+wiN1tpie8IrU= +github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c/go.mod h1:NMPJylDgVpX0MLRlPy15sqSwOFv/U1GZ2m21JhFfek0= github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc= github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/jedib0t/go-pretty v4.3.0+incompatible h1:CGs8AVhEKg/n9YbUenWmNStRW2PHJzaeDodcfvRAbIo= +github.com/jedib0t/go-pretty v4.3.0+incompatible/go.mod h1:XemHduiw8R651AF9Pt4FwCTKeG3oo7hrHJAoznj9nag= +github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA= github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg= +github.com/mattn/go-colorable v0.1.9 h1:sqDoxXbdeALODt0DAeJCVp38ps9ZogZEAXjus69YV3U= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= +github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mitchellh/mapstructure v1.3.3 h1:SzB1nHZ2Xi+17FP0zVQBHIZqvwRN9408fJO8h+eeNA8= +github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= +github.com/mtibben/percent v0.2.1 h1:5gssi8Nqo8QU/r2pynCm+hBQHpkB/uNK7BJCFogWdzs= +github.com/mtibben/percent v0.2.1/go.mod h1:KG9uO+SZkUp+VkRHsCdYQV3XSZrrSpR3O9ibNBTZrns= +github.com/muesli/mango v0.1.0 h1:DZQK45d2gGbql1arsYA4vfg4d7I9Hfx5rX/GCmzsAvI= +github.com/muesli/mango v0.1.0/go.mod h1:5XFpbC8jY5UUv89YQciiXNlbi+iJgt29VDC5xbzrLL4= +github.com/muesli/mango-cobra v1.2.0 h1:DQvjzAM0PMZr85Iv9LIMaYISpTOliMEg+uMFtNbYvWg= +github.com/muesli/mango-cobra v1.2.0/go.mod h1:vMJL54QytZAJhCT13LPVDfkvCUJ5/4jNUKF/8NC2UjA= +github.com/muesli/mango-pflag v0.1.0 h1:UADqbYgpUyRoBja3g6LUL+3LErjpsOwaC9ywvBWe7Sg= +github.com/muesli/mango-pflag v0.1.0/go.mod h1:YEQomTxaCUp8PrbhFh10UfbhbQrM/xJ4i2PB8VTLLW0= +github.com/muesli/roff v0.1.0 h1:YD0lalCotmYuF5HhZliKWlIx7IEhiXeSfq7hNjFqGF8= +github.com/muesli/roff v0.1.0/go.mod h1:pjAHQM9hdUUwm/krAfrLGgJkXJ+YuhtsfZ42kieB2Ig= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= @@ -34,32 +87,55 @@ github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA= github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/zalando/go-keyring v0.2.1 h1:MBRN/Z8H4U5wEKXiD67YbDAr5cj/DOStmSga70/2qKc= -github.com/zalando/go-keyring v0.2.1/go.mod h1:g63M2PPn0w5vjmEbwAX3ib5I+41zdm4esSETOn9Y6Dw= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= +github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= +github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= +github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= +github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= +go.mongodb.org/mongo-driver v1.10.0 h1:UtV6N5k14upNp4LTduX0QCufG124fSu25Wz9tu94GLg= +go.mongodb.org/mongo-driver v1.10.0/go.mod h1:wsihk0Kdgv8Kqu1Anit4sfK+22vSFbUrAVEYRhCXrA8= +golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.3.0 h1:a06MkbcxBrEFc0w0QIZWXrH/9cCX6KJyWbBOIwAn+7A= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210819135213-f52c844e1c1c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A= -golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ= +golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.3.0 h1:qoo4akIqOcDME5bhc/NgxUdovd6BSS2uMsVjB56q1xI= +golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U= +gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/cli/main.go b/cli/main.go index 9b1e420fa..a51661ff6 100644 --- a/cli/main.go +++ b/cli/main.go @@ -1,5 +1,5 @@ /* -Copyright ยฉ 2022 NAME HERE +Copyright (c) 2023 Infisical Inc. */ package main diff --git a/cli/packages/api/api.go b/cli/packages/api/api.go new file mode 100644 index 000000000..7417a2594 --- /dev/null +++ b/cli/packages/api/api.go @@ -0,0 +1,168 @@ +package api + +import ( + "fmt" + + "github.com/Infisical/infisical-merge/packages/config" + "github.com/go-resty/resty/v2" + log "github.com/sirupsen/logrus" +) + +const USER_AGENT = "cli" + +func CallBatchModifySecretsByWorkspaceAndEnv(httpClient *resty.Client, request BatchModifySecretsByWorkspaceAndEnvRequest) error { + endpoint := fmt.Sprintf("%v/v2/secrets", config.INFISICAL_URL) + response, err := httpClient. + R(). + SetBody(request). + SetHeader("User-Agent", USER_AGENT). + Patch(endpoint) + + if err != nil { + return fmt.Errorf("CallBatchModifySecretsByWorkspaceAndEnv: Unable to complete api request [err=%s]", err) + } + + if response.IsError() { + return fmt.Errorf("CallBatchModifySecretsByWorkspaceAndEnv: Unsuccessful response: [response=%s]", response) + } + + return nil +} + +func CallBatchCreateSecretsByWorkspaceAndEnv(httpClient *resty.Client, request BatchCreateSecretsByWorkspaceAndEnvRequest) error { + endpoint := fmt.Sprintf("%v/v2/secrets/", config.INFISICAL_URL) + response, err := httpClient. + R(). + SetBody(request). + SetHeader("User-Agent", USER_AGENT). + Post(endpoint) + + if err != nil { + return fmt.Errorf("CallBatchCreateSecretsByWorkspaceAndEnv: Unable to complete api request [err=%s]", err) + } + + if response.IsError() { + return fmt.Errorf("CallBatchCreateSecretsByWorkspaceAndEnv: Unsuccessful response: [response=%s]", response) + } + + return nil +} + +func CallBatchDeleteSecretsByWorkspaceAndEnv(httpClient *resty.Client, request BatchDeleteSecretsBySecretIdsRequest) error { + endpoint := fmt.Sprintf("%v/v2/secrets", config.INFISICAL_URL) + response, err := httpClient. + R(). + SetBody(request). + SetHeader("User-Agent", USER_AGENT). + Delete(endpoint) + + if err != nil { + return fmt.Errorf("CallBatchDeleteSecretsByWorkspaceAndEnv: Unable to complete api request [err=%s]", err) + } + + if response.IsError() { + return fmt.Errorf("CallBatchDeleteSecretsByWorkspaceAndEnv: Unsuccessful response: [response=%s]", response) + } + + return nil +} + +func CallGetEncryptedWorkspaceKey(httpClient *resty.Client, request GetEncryptedWorkspaceKeyRequest) (GetEncryptedWorkspaceKeyResponse, error) { + endpoint := fmt.Sprintf("%v/v2/workspace/%v/encrypted-key", config.INFISICAL_URL, request.WorkspaceId) + var result GetEncryptedWorkspaceKeyResponse + response, err := httpClient. + R(). + SetResult(&result). + SetHeader("User-Agent", USER_AGENT). + Get(endpoint) + + if err != nil { + return GetEncryptedWorkspaceKeyResponse{}, fmt.Errorf("CallGetEncryptedWorkspaceKey: Unable to complete api request [err=%s]", err) + } + + if response.IsError() { + return GetEncryptedWorkspaceKeyResponse{}, fmt.Errorf("CallGetEncryptedWorkspaceKey: Unsuccessful response: [response=%s]", response) + } + + return result, nil +} + +func CallGetServiceTokenDetailsV2(httpClient *resty.Client) (GetServiceTokenDetailsResponse, error) { + var tokenDetailsResponse GetServiceTokenDetailsResponse + response, err := httpClient. + R(). + SetResult(&tokenDetailsResponse). + SetHeader("User-Agent", USER_AGENT). + Get(fmt.Sprintf("%v/v2/service-token", config.INFISICAL_URL)) + + if err != nil { + return GetServiceTokenDetailsResponse{}, fmt.Errorf("CallGetServiceTokenDetails: Unable to complete api request [err=%s]", err) + } + + if response.IsError() { + return GetServiceTokenDetailsResponse{}, fmt.Errorf("CallGetServiceTokenDetails: Unsuccessful response: [response=%s]", response) + } + + return tokenDetailsResponse, nil +} + +func CallGetSecretsV2(httpClient *resty.Client, request GetEncryptedSecretsV2Request) (GetEncryptedSecretsV2Response, error) { + var secretsResponse GetEncryptedSecretsV2Response + response, err := httpClient. + R(). + SetResult(&secretsResponse). + SetHeader("User-Agent", USER_AGENT). + SetQueryParam("environment", request.Environment). + SetQueryParam("workspaceId", request.WorkspaceId). + Get(fmt.Sprintf("%v/v2/secrets", config.INFISICAL_URL)) + + if err != nil { + return GetEncryptedSecretsV2Response{}, fmt.Errorf("CallGetSecretsV2: Unable to complete api request [err=%s]", err) + } + + if response.IsError() { + return GetEncryptedSecretsV2Response{}, fmt.Errorf("CallGetSecretsV2: Unsuccessful response: [response=%s]", response) + } + + return secretsResponse, nil +} + +func CallGetAllWorkSpacesUserBelongsTo(httpClient *resty.Client) (GetWorkSpacesResponse, error) { + var workSpacesResponse GetWorkSpacesResponse + response, err := httpClient. + R(). + SetResult(&workSpacesResponse). + SetHeader("User-Agent", USER_AGENT). + Get(fmt.Sprintf("%v/v1/workspace", config.INFISICAL_URL)) + + if err != nil { + return GetWorkSpacesResponse{}, err + } + + if response.IsError() { + return GetWorkSpacesResponse{}, fmt.Errorf("CallGetAllWorkSpacesUserBelongsTo: Unsuccessful response: [response=%v]", response) + } + + return workSpacesResponse, nil +} + +func CallIsAuthenticated(httpClient *resty.Client) bool { + var workSpacesResponse GetWorkSpacesResponse + response, err := httpClient. + R(). + SetResult(&workSpacesResponse). + SetHeader("User-Agent", USER_AGENT). + Post(fmt.Sprintf("%v/v1/auth/checkAuth", config.INFISICAL_URL)) + + log.Debugln(fmt.Errorf("CallIsAuthenticated: Unsuccessful response: [response=%v]", response)) + + if err != nil { + return false + } + + if response.IsError() { + return false + } + + return true +} diff --git a/cli/packages/api/model.go b/cli/packages/api/model.go new file mode 100644 index 000000000..698d41408 --- /dev/null +++ b/cli/packages/api/model.go @@ -0,0 +1,243 @@ +package api + +import "time" + +// Stores info for login one +type LoginOneRequest struct { + Email string `json:"email"` + ClientPublicKey string `json:"clientPublicKey"` +} + +type LoginOneResponse struct { + ServerPublicKey string `json:"serverPublicKey"` + ServerSalt string `json:"salt"` +} + +// Stores info for login two + +type LoginTwoRequest struct { + Email string `json:"email"` + ClientProof string `json:"clientProof"` +} + +type LoginTwoResponse struct { + JTWToken string `json:"token"` + RefreshToken string `json:"refreshToken"` + PublicKey string `json:"publicKey"` + EncryptedPrivateKey string `json:"encryptedPrivateKey"` + IV string `json:"iv"` + Tag string `json:"tag"` +} + +type PullSecretsRequest struct { + Environment string `json:"environment"` +} + +type PullSecretsResponse struct { + Secrets []struct { + ID string `json:"_id"` + Workspace string `json:"workspace"` + Type string `json:"type"` + Environment string `json:"environment"` + SecretKeyCiphertext string `json:"secretKeyCiphertext"` + SecretKeyIV string `json:"secretKeyIV"` + SecretKeyTag string `json:"secretKeyTag"` + SecretKeyHash string `json:"secretKeyHash"` + SecretValueCiphertext string `json:"secretValueCiphertext"` + SecretValueIV string `json:"secretValueIV"` + SecretValueTag string `json:"secretValueTag"` + SecretValueHash string `json:"secretValueHash"` + V int `json:"__v"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` + User string `json:"user,omitempty"` + } `json:"secrets"` + Key struct { + ID string `json:"_id"` + EncryptedKey string `json:"encryptedKey"` + Nonce string `json:"nonce"` + Sender struct { + ID string `json:"_id"` + Email string `json:"email"` + CustomerID string `json:"customerId"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` + V int `json:"__v"` + FirstName string `json:"firstName"` + LastName string `json:"lastName"` + PublicKey string `json:"publicKey"` + } `json:"sender"` + Receiver string `json:"receiver"` + Workspace string `json:"workspace"` + V int `json:"__v"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` + } `json:"key"` +} + +type PullSecretsByInfisicalTokenResponse struct { + Secrets []struct { + ID string `json:"_id"` + Workspace string `json:"workspace"` + Type string `json:"type"` + Environment string `json:"environment"` + SecretKey struct { + Workspace string `json:"workspace"` + Ciphertext string `json:"ciphertext"` + Iv string `json:"iv"` + Tag string `json:"tag"` + Hash string `json:"hash"` + } `json:"secretKey"` + SecretValue struct { + Workspace string `json:"workspace"` + Ciphertext string `json:"ciphertext"` + Iv string `json:"iv"` + Tag string `json:"tag"` + Hash string `json:"hash"` + } `json:"secretValue"` + } `json:"secrets"` + Key struct { + EncryptedKey string `json:"encryptedKey"` + Nonce string `json:"nonce"` + Sender struct { + PublicKey string `json:"publicKey"` + } `json:"sender"` + Receiver struct { + RefreshVersion int `json:"refreshVersion"` + ID string `json:"_id"` + Email string `json:"email"` + CustomerID string `json:"customerId"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` + V int `json:"__v"` + FirstName string `json:"firstName"` + LastName string `json:"lastName"` + PublicKey string `json:"publicKey"` + } `json:"receiver"` + Workspace string `json:"workspace"` + } `json:"key"` +} + +type GetWorkSpacesResponse struct { + Workspaces []struct { + ID string `json:"_id"` + Name string `json:"name"` + Plan string `json:"plan,omitempty"` + V int `json:"__v"` + Organization string `json:"organization,omitempty"` + } `json:"workspaces"` +} + +type Secret struct { + SecretKeyCiphertext string `json:"secretKeyCiphertext,omitempty"` + SecretKeyIV string `json:"secretKeyIV,omitempty"` + SecretKeyTag string `json:"secretKeyTag,omitempty"` + SecretKeyHash string `json:"secretKeyHash,omitempty"` + SecretValueCiphertext string `json:"secretValueCiphertext,omitempty"` + SecretValueIV string `json:"secretValueIV,omitempty"` + SecretValueTag string `json:"secretValueTag,omitempty"` + SecretValueHash string `json:"secretValueHash,omitempty"` + SecretCommentCiphertext string `json:"secretCommentCiphertext,omitempty"` + SecretCommentIV string `json:"secretCommentIV,omitempty"` + SecretCommentTag string `json:"secretCommentTag,omitempty"` + SecretCommentHash string `json:"secretCommentHash,omitempty"` + Type string `json:"type,omitempty"` + ID string `json:"id,omitempty"` +} + +type BatchCreateSecretsByWorkspaceAndEnvRequest struct { + Environment string `json:"environment"` + WorkspaceId string `json:"workspaceId"` + Secrets []Secret `json:"secrets"` +} + +type BatchModifySecretsByWorkspaceAndEnvRequest struct { + Environment string `json:"environment"` + WorkspaceId string `json:"workspaceId"` + Secrets []Secret `json:"secrets"` +} + +type BatchDeleteSecretsBySecretIdsRequest struct { + EnvironmentName string `json:"environmentName"` + WorkspaceId string `json:"workspaceId"` + SecretIds []string `json:"secretIds"` +} + +type GetEncryptedWorkspaceKeyRequest struct { + WorkspaceId string `json:"workspaceId"` +} + +type GetEncryptedWorkspaceKeyResponse struct { + ID string `json:"_id"` + EncryptedKey string `json:"encryptedKey"` + Nonce string `json:"nonce"` + Sender struct { + ID string `json:"_id"` + Email string `json:"email"` + RefreshVersion int `json:"refreshVersion"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` + V int `json:"__v"` + FirstName string `json:"firstName"` + LastName string `json:"lastName"` + PublicKey string `json:"publicKey"` + } `json:"sender"` + Receiver string `json:"receiver"` + Workspace string `json:"workspace"` + V int `json:"__v"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` +} + +type GetSecretsByWorkspaceIdAndEnvironmentRequest struct { + EnvironmentName string `json:"environmentName"` + WorkspaceId string `json:"workspaceId"` +} + +type GetEncryptedSecretsV2Request struct { + Environment string `json:"environment"` + WorkspaceId string `json:"workspaceId"` +} + +type GetEncryptedSecretsV2Response struct { + Secrets []struct { + ID string `json:"_id"` + Version int `json:"version"` + Workspace string `json:"workspace"` + Type string `json:"type"` + Environment string `json:"environment"` + SecretKeyCiphertext string `json:"secretKeyCiphertext"` + SecretKeyIV string `json:"secretKeyIV"` + SecretKeyTag string `json:"secretKeyTag"` + SecretValueCiphertext string `json:"secretValueCiphertext"` + SecretValueIV string `json:"secretValueIV"` + SecretValueTag string `json:"secretValueTag"` + V int `json:"__v"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` + User string `json:"user,omitempty"` + } `json:"secrets"` +} + +type GetServiceTokenDetailsResponse struct { + ID string `json:"_id"` + Name string `json:"name"` + Workspace string `json:"workspace"` + Environment string `json:"environment"` + User struct { + ID string `json:"_id"` + Email string `json:"email"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` + V int `json:"__v"` + FirstName string `json:"firstName"` + LastName string `json:"lastName"` + } `json:"user"` + ExpiresAt time.Time `json:"expiresAt"` + EncryptedKey string `json:"encryptedKey"` + Iv string `json:"iv"` + Tag string `json:"tag"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` + V int `json:"__v"` +} diff --git a/cli/packages/cmd/export.go b/cli/packages/cmd/export.go index f25a726e7..41e170f70 100644 --- a/cli/packages/cmd/export.go +++ b/cli/packages/cmd/export.go @@ -1,5 +1,5 @@ /* -Copyright ยฉ 2022 NAME HERE +Copyright (c) 2023 Infisical Inc. */ package cmd @@ -16,10 +16,11 @@ import ( ) const ( - FormatDotenv string = "dotenv" - FormatJson string = "json" - FormatCSV string = "csv" - FormatYaml string = "yaml" + FormatDotenv string = "dotenv" + FormatJson string = "json" + FormatCSV string = "csv" + FormatYaml string = "yaml" + FormatDotEnvExport string = "dotenv-export" ) // exportCmd represents the export command @@ -29,58 +30,57 @@ var exportCmd = &cobra.Command{ DisableFlagsInUseLine: true, Example: "infisical export --env=prod --format=json > secrets.json", Args: cobra.NoArgs, - PreRun: toggleDebug, + PreRun: func(cmd *cobra.Command, args []string) { + toggleDebug(cmd, args) + // util.RequireLogin() + // util.RequireLocalWorkspaceFile() + }, Run: func(cmd *cobra.Command, args []string) { envName, err := cmd.Flags().GetString("env") if err != nil { - log.Errorln("Unable to parse the environment flag") - log.Debugln(err) - return + util.HandleError(err) } shouldExpandSecrets, err := cmd.Flags().GetBool("expand") if err != nil { - log.Errorln("Unable to parse the substitute flag") - log.Debugln(err) - return - } - - projectId, err := cmd.Flags().GetString("projectId") - if err != nil { - log.Errorln("Unable to parse the project id flag") - log.Debugln(err) - return + util.HandleError(err) } format, err := cmd.Flags().GetString("format") if err != nil { - log.Errorln("Unable to parse the format flag") - log.Debugln(err) - return + util.HandleError(err) } - envsFromApi, err := util.GetAllEnvironmentVariables(projectId, envName) + secretOverriding, err := cmd.Flags().GetBool("secret-overriding") if err != nil { - log.Errorln("Something went wrong when pulling secrets using your Infisical token. Double check the token, project id or environment name (dev, prod, ect.)") - log.Debugln(err) - return + util.HandleError(err, "Unable to parse flag") + } + + secrets, err := util.GetAllEnvironmentVariables(envName) + if err != nil { + util.HandleError(err, "Unable to fetch secrets") + } + + if secretOverriding { + secrets = util.OverrideSecrets(secrets, util.SECRET_TYPE_PERSONAL) + } else { + secrets = util.OverrideSecrets(secrets, util.SECRET_TYPE_SHARED) } var output string if shouldExpandSecrets { - substitutions := util.SubstituteSecrets(envsFromApi) + substitutions := util.SubstituteSecrets(secrets) output, err = formatEnvs(substitutions, format) if err != nil { - log.Errorln(err) - return + util.HandleError(err) } } else { - output, err = formatEnvs(envsFromApi, format) + output, err = formatEnvs(secrets, format) if err != nil { - log.Errorln(err) - return + util.HandleError(err) } } + fmt.Print(output) }, } @@ -88,9 +88,9 @@ var exportCmd = &cobra.Command{ func init() { rootCmd.AddCommand(exportCmd) exportCmd.Flags().StringP("env", "e", "dev", "Set the environment (dev, prod, etc.) from which your secrets should be pulled from") - exportCmd.Flags().String("projectId", "", "The project ID from which your secrets should be pulled from") exportCmd.Flags().Bool("expand", true, "Parse shell parameter expansions in your secrets") exportCmd.Flags().StringP("format", "f", "dotenv", "Set the format of the output file (dotenv, json, csv)") + exportCmd.Flags().Bool("secret-overriding", true, "Prioritizes personal secrets, if any, with the same name over shared secrets") } // Format according to the format flag @@ -98,6 +98,8 @@ func formatEnvs(envs []models.SingleEnvironmentVariable, format string) (string, switch strings.ToLower(format) { case FormatDotenv: return formatAsDotEnv(envs), nil + case FormatDotEnvExport: + return formatAsDotEnvExport(envs), nil case FormatJson: return formatAsJson(envs), nil case FormatCSV: @@ -105,7 +107,7 @@ func formatEnvs(envs []models.SingleEnvironmentVariable, format string) (string, case FormatYaml: return formatAsYaml(envs), nil default: - return "", fmt.Errorf("invalid format type: %s. Available format types are [%s]", format, []string{FormatDotenv, FormatJson, FormatCSV, FormatYaml}) + return "", fmt.Errorf("invalid format type: %s. Available format types are [%s]", format, []string{FormatDotenv, FormatJson, FormatCSV, FormatYaml, FormatDotEnvExport}) } } @@ -130,6 +132,15 @@ func formatAsDotEnv(envs []models.SingleEnvironmentVariable) string { return dotenv } +// Format environment variables as a dotenv file with export at the beginning +func formatAsDotEnvExport(envs []models.SingleEnvironmentVariable) string { + var dotenv string + for _, env := range envs { + dotenv += fmt.Sprintf("export %s='%s'\n", env.Key, env.Value) + } + return dotenv +} + func formatAsYaml(envs []models.SingleEnvironmentVariable) string { var dotenv string for _, env := range envs { diff --git a/cli/packages/cmd/init.go b/cli/packages/cmd/init.go index 2789f220d..413f61440 100644 --- a/cli/packages/cmd/init.go +++ b/cli/packages/cmd/init.go @@ -1,14 +1,17 @@ /* -Copyright ยฉ 2022 NAME HERE +Copyright (c) 2023 Infisical Inc. */ package cmd import ( "encoding/json" + "fmt" "os" + "github.com/Infisical/infisical-merge/packages/api" "github.com/Infisical/infisical-merge/packages/models" "github.com/Infisical/infisical-merge/packages/util" + "github.com/go-resty/resty/v2" "github.com/manifoldco/promptui" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -21,21 +24,10 @@ var initCmd = &cobra.Command{ DisableFlagsInUseLine: true, Example: "infisical init", Args: cobra.ExactArgs(0), - PreRun: toggleDebug, + PreRun: func(cmd *cobra.Command, args []string) { + util.RequireLogin() + }, Run: func(cmd *cobra.Command, args []string) { - // check if user is logged - hasUserLoggedInbefore, loggedInUserEmail, err := util.IsUserLoggedIn() - if err != nil { - log.Info("Unexpected issue occurred while checking login status. To see more details, add flag --debug") - log.Debugln(err) - return - } - - if !hasUserLoggedInbefore { - log.Infoln("No logged in user. To login, please run command [infisical login]") - return - } - if util.WorkspaceConfigFileExistsInCurrentPath() { shouldOverride, err := shouldOverrideWorkspacePrompt() if err != nil { @@ -49,23 +41,22 @@ var initCmd = &cobra.Command{ } } - userCreds, err := util.GetUserCredsFromKeyRing(loggedInUserEmail) + userCreds, err := util.GetCurrentLoggedInUserDetails() if err != nil { - log.Infoln("Unable to get user creds from key ring") - log.Debug(err) - return + util.HandleError(err, "Unable to get your login details") } - workspaces, err := util.GetWorkSpacesFromAPI(userCreds) + httpClient := resty.New() + httpClient.SetAuthToken(userCreds.UserCredentials.JTWToken) + workspaceResponse, err := api.CallGetAllWorkSpacesUserBelongsTo(httpClient) if err != nil { - log.Errorln("Unable to pull your projects. To see more logs add the --debug flag to this command") - log.Debugln("Unable to get your projects because:", err) - return + util.HandleError(err, "Unable to pull projects that belong to you") } + workspaces := workspaceResponse.Workspaces if len(workspaces) == 0 { - log.Infoln("You don't have any projects created in Infisical. You must first create a project at https://infisical.com") - return + message := fmt.Sprintf("You don't have any projects created in Infisical. You must first create a project at %s", util.INFISICAL_TOKEN_NAME) + util.PrintMessageAndExit(message) } var workspaceNames []string @@ -81,16 +72,12 @@ var initCmd = &cobra.Command{ index, _, err := prompt.Run() if err != nil { - log.Errorln("Unable to parse your response") - log.Debug(err) - return + util.HandleError(err) } err = writeWorkspaceFile(workspaces[index]) if err != nil { - log.Errorln("Something went wrong when creating your workspace file") - log.Debug("Error while writing your workspace file:", err) - return + util.HandleError(err) } }, } diff --git a/cli/packages/cmd/login.go b/cli/packages/cmd/login.go index 29e2c4935..6a1dc2313 100644 --- a/cli/packages/cmd/login.go +++ b/cli/packages/cmd/login.go @@ -1,19 +1,24 @@ /* -Copyright ยฉ 2022 NAME HERE +Copyright (c) 2023 Infisical Inc. */ package cmd import ( "encoding/base64" "encoding/hex" + "strings" "errors" "fmt" "regexp" + "github.com/Infisical/infisical-merge/packages/api" + "github.com/Infisical/infisical-merge/packages/config" + "github.com/Infisical/infisical-merge/packages/crypto" "github.com/Infisical/infisical-merge/packages/models" "github.com/Infisical/infisical-merge/packages/srp" "github.com/Infisical/infisical-merge/packages/util" + "github.com/fatih/color" "github.com/go-resty/resty/v2" "github.com/manifoldco/promptui" log "github.com/sirupsen/logrus" @@ -27,18 +32,17 @@ var loginCmd = &cobra.Command{ DisableFlagsInUseLine: true, PreRun: toggleDebug, Run: func(cmd *cobra.Command, args []string) { - hasUserLoggedInbefore, currentLoggedInUserEmail, err := util.IsUserLoggedIn() - - if err != nil { - log.Debugln("Unable to get current logged in user.", err) + currentLoggedInUserDetails, err := util.GetCurrentLoggedInUserDetails() + if err != nil && (strings.Contains(err.Error(), "The specified item could not be found in the keyring") || strings.Contains(err.Error(), "unable to get key from Keyring")) { // if the key can't be found allow them to override + log.Debug(err) + } else if err != nil { + util.HandleError(err) } - if hasUserLoggedInbefore { - shouldOverride, err := shouldOverrideLoginPrompt(currentLoggedInUserEmail) + if currentLoggedInUserDetails.IsUserLoggedIn && !currentLoggedInUserDetails.LoginExpired { // if you are logged in but not expired + shouldOverride, err := shouldOverrideLoginPrompt(currentLoggedInUserDetails.UserCredentials.Email) if err != nil { - log.Errorln("Unable to parse your answer") - log.Debug(err) - return + util.HandleError(err) } if !shouldOverride { @@ -48,14 +52,12 @@ var loginCmd = &cobra.Command{ email, password, err := askForLoginCredentials() if err != nil { - log.Errorln("Unable to parse email and password for authentication") - log.Debugln(err) - return + util.HandleError(err, "Unable to parse email and password for authentication") } userCredentials, err := getFreshUserCredentials(email, password) if err != nil { - log.Errorln("Unable to authenticate with the provided credentials, please try again") + log.Infoln("Unable to authenticate with the provided credentials, please try again") log.Debugln(err) return } @@ -63,24 +65,20 @@ var loginCmd = &cobra.Command{ encryptedPrivateKey, _ := base64.StdEncoding.DecodeString(userCredentials.EncryptedPrivateKey) tag, err := base64.StdEncoding.DecodeString(userCredentials.Tag) if err != nil { - log.Errorln("Unable to decode the auth tag") - log.Debugln(err) + util.HandleError(err) } IV, err := base64.StdEncoding.DecodeString(userCredentials.IV) if err != nil { - log.Errorln("Unable to decode the IV/Nonce") - log.Debugln(err) + util.HandleError(err) } paddedPassword := fmt.Sprintf("%032s", password) key := []byte(paddedPassword) - decryptedPrivateKey, err := util.DecryptSymmetric(key, encryptedPrivateKey, tag, IV) + decryptedPrivateKey, err := crypto.DecryptSymmetric(key, encryptedPrivateKey, tag, IV) if err != nil || len(decryptedPrivateKey) == 0 { - log.Errorln("There was an issue decrypting your keys") - log.Debugln(err) - return + util.HandleError(err) } userCredentialsToBeStored := &models.UserCredentials{ @@ -91,19 +89,19 @@ var loginCmd = &cobra.Command{ err = util.StoreUserCredsInKeyRing(userCredentialsToBeStored) if err != nil { - log.Errorln("Unable to store your credentials in system key ring") + currentVault, _ := util.GetCurrentVaultBackend() + log.Errorf("Unable to store your credentials in system vault [%s]. Rerun with flag -d to see full logs", currentVault) + log.Errorln("To trouble shoot further, read https://infisical.com/docs/cli/faq") log.Debugln(err) return } err = util.WriteInitalConfig(userCredentialsToBeStored) if err != nil { - log.Errorln("Unable to write write to Infisical Config file. Please try again") - log.Debugln(err) - return + util.HandleError(err, "Unable to write write to Infisical Config file. Please try again") } - log.Infoln("Nice! You are loggin as:", email) + color.Green("Nice! You are logged in as: %v", email) }, } @@ -154,7 +152,7 @@ func askForLoginCredentials() (email string, password string, err error) { return userEmail, userPassword, nil } -func getFreshUserCredentials(email string, password string) (*models.LoginTwoResponse, error) { +func getFreshUserCredentials(email string, password string) (*api.LoginTwoResponse, error) { log.Debugln("getFreshUserCredentials:", "email", email, "password", password) httpClient := resty.New() httpClient.SetRetryCount(5) @@ -165,18 +163,18 @@ func getFreshUserCredentials(email string, password string) (*models.LoginTwoRes srpA := hex.EncodeToString(srpClient.ComputeA()) // ** Login one - loginOneRequest := models.LoginOneRequest{ + loginOneRequest := api.LoginOneRequest{ Email: email, ClientPublicKey: srpA, } - var loginOneResponseResult models.LoginOneResponse + var loginOneResponseResult api.LoginOneResponse loginOneResponse, err := httpClient. R(). SetBody(loginOneRequest). SetResult(&loginOneResponseResult). - Post(fmt.Sprintf("%v/v1/auth/login1", util.INFISICAL_URL)) + Post(fmt.Sprintf("%v/v1/auth/login1", config.INFISICAL_URL)) if err != nil { return nil, err @@ -202,17 +200,17 @@ func getFreshUserCredentials(email string, password string) (*models.LoginTwoRes srpM1 := srpClient.ComputeM1() - LoginTwoRequest := models.LoginTwoRequest{ + LoginTwoRequest := api.LoginTwoRequest{ Email: email, ClientProof: hex.EncodeToString(srpM1), } - var loginTwoResponseResult models.LoginTwoResponse + var loginTwoResponseResult api.LoginTwoResponse loginTwoResponse, err := httpClient. R(). SetBody(LoginTwoRequest). SetResult(&loginTwoResponseResult). - Post(fmt.Sprintf("%v/v1/auth/login2", util.INFISICAL_URL)) + Post(fmt.Sprintf("%v/v1/auth/login2", config.INFISICAL_URL)) if err != nil { return nil, err diff --git a/cli/packages/cmd/man.go b/cli/packages/cmd/man.go new file mode 100644 index 000000000..86d68c8e7 --- /dev/null +++ b/cli/packages/cmd/man.go @@ -0,0 +1,35 @@ +/* +Copyright (c) 2023 Infisical Inc. +*/ +package cmd + +import ( + "fmt" + "os" + + mcobra "github.com/muesli/mango-cobra" + "github.com/muesli/roff" + "github.com/spf13/cobra" +) + +var manCmd = &cobra.Command{ + Use: "man", + Short: "generates the manpages", + SilenceUsage: true, + DisableFlagsInUseLine: true, + Hidden: true, + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + manPage, err := mcobra.NewManPage(1, rootCmd) + if err != nil { + return err + } + + _, err = fmt.Fprint(os.Stdout, manPage.Build(roff.NewDocument())) + return err + }, +} + +func init() { + rootCmd.AddCommand(manCmd) +} diff --git a/cli/packages/cmd/root.go b/cli/packages/cmd/root.go index 7317b3eea..ac827feb3 100644 --- a/cli/packages/cmd/root.go +++ b/cli/packages/cmd/root.go @@ -1,21 +1,23 @@ /* -Copyright ยฉ 2022 NAME HERE +Copyright (c) 2023 Infisical Inc. */ package cmd import ( "os" - "github.com/Infisical/infisical-merge/packages/util" "github.com/spf13/cobra" + + "github.com/Infisical/infisical-merge/packages/config" + "github.com/Infisical/infisical-merge/packages/util" ) var rootCmd = &cobra.Command{ Use: "infisical", Short: "Infisical CLI is used to inject environment variables into any process", Long: `Infisical is a simple, end-to-end encrypted service that enables teams to sync and manage their environment variables across their development life cycle.`, - CompletionOptions: cobra.CompletionOptions{DisableDefaultCmd: true}, - Version: "0.1.11", + CompletionOptions: cobra.CompletionOptions{HiddenDefaultCmd: true}, + Version: util.CLI_VERSION, } // Execute adds all child commands to the root command and sets flags appropriately. @@ -30,5 +32,17 @@ func Execute() { func init() { rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") rootCmd.PersistentFlags().BoolVarP(&debugLogging, "debug", "d", false, "Enable verbose logging") - rootCmd.PersistentFlags().StringVar(&util.INFISICAL_URL, "domain", "https://app.infisical.com/api", "Point the CLI to your own backend") + rootCmd.PersistentFlags().StringVar(&config.INFISICAL_URL, "domain", util.INFISICAL_DEFAULT_API_URL, "Point the CLI to your own backend [can also set via environment variable name: INFISICAL_API_URL]") + rootCmd.PersistentPreRun = func(cmd *cobra.Command, args []string) { + util.CheckForUpdate() + } + + // if config.INFISICAL_URL is set to the default value, check if INFISICAL_URL is set in the environment + // this is used to allow overrides of the default value + if !rootCmd.Flag("domain").Changed { + if envInfisicalBackendUrl, ok := os.LookupEnv("INFISICAL_API_URL"); ok { + config.INFISICAL_URL = envInfisicalBackendUrl + } + } + } diff --git a/cli/packages/cmd/run.go b/cli/packages/cmd/run.go index ec5210b1f..d31981b02 100644 --- a/cli/packages/cmd/run.go +++ b/cli/packages/cmd/run.go @@ -1,5 +1,5 @@ /* -Copyright ยฉ 2022 NAME HERE +Copyright (c) 2023 Infisical Inc. */ package cmd @@ -8,82 +8,184 @@ import ( "os" "os/exec" "os/signal" + "runtime" "strings" "syscall" - "github.com/Infisical/infisical-merge/packages/models" "github.com/Infisical/infisical-merge/packages/util" + "github.com/fatih/color" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) // runCmd represents the run command var runCmd = &cobra.Command{ + Example: ` + infisical run --env=dev -- npm run dev + infisical run --command "first-command && second-command; more-commands..." + `, Use: "run [any infisical run command flags] -- [your application start command]", Short: "Used to inject environments variables into your application process", DisableFlagsInUseLine: true, - Example: "infisical run --env=prod -- npm run dev", - Args: cobra.MinimumNArgs(1), PreRun: toggleDebug, + Args: func(cmd *cobra.Command, args []string) error { + // Check if the --command flag has been set + commandFlagSet := cmd.Flags().Changed("command") + + // If the --command flag has been set, check if a value was provided + if commandFlagSet { + command := cmd.Flag("command").Value.String() + if command == "" { + return fmt.Errorf("you need to provide a command after the flag --command") + } + + // If the --command flag has been set, args should not be provided + if len(args) > 0 { + return fmt.Errorf("you cannot set any arguments after --command flag. --command only takes a string command") + } + } else { + // If the --command flag has not been set, at least one arg should be provided + if len(args) == 0 { + return fmt.Errorf("at least one argument is required after the run command, received %d", len(args)) + } + } + + return nil + }, Run: func(cmd *cobra.Command, args []string) { envName, err := cmd.Flags().GetString("env") if err != nil { - log.Errorln("Unable to parse the environment flag") - log.Debugln(err) - return + util.HandleError(err, "Unable to parse flag") + } + + // if !util.IsSecretEnvironmentValid(envName) { + // util.PrintMessageAndExit("Invalid environment name passed. Environment names can only be prod, dev, test or staging") + // } + + secretOverriding, err := cmd.Flags().GetBool("secret-overriding") + if err != nil { + util.HandleError(err, "Unable to parse flag") } shouldExpandSecrets, err := cmd.Flags().GetBool("expand") if err != nil { - log.Errorln("Unable to parse the substitute flag") - log.Debugln(err) - return + util.HandleError(err, "Unable to parse flag") } - projectId, err := cmd.Flags().GetString("projectId") + secrets, err := util.GetAllEnvironmentVariables(envName) if err != nil { - log.Errorln("Unable to parse the project id flag") - log.Debugln(err) - return + util.HandleError(err, "Could not fetch secrets", "If you are using a service token to fetch secrets, please ensure it is valid") } - secrets, err := util.GetAllEnvironmentVariables(projectId, envName) - if err != nil { - log.Debugln(err) - return + if secretOverriding { + secrets = util.OverrideSecrets(secrets, util.SECRET_TYPE_PERSONAL) + } else { + secrets = util.OverrideSecrets(secrets, util.SECRET_TYPE_SHARED) } if shouldExpandSecrets { - secretsWithSubstitutions := util.SubstituteSecrets(secrets) - execCmd(args[0], args[1:], secretsWithSubstitutions) - } else { - execCmd(args[0], args[1:], secrets) + secrets = util.SubstituteSecrets(secrets) } + secretsByKey := getSecretsByKeys(secrets) + environmentVariables := make(map[string]string) + + // add all existing environment vars + for _, s := range os.Environ() { + kv := strings.SplitN(s, "=", 2) + key := kv[0] + value := kv[1] + environmentVariables[key] = value + } + + // check to see if there are any reserved key words in secrets to inject + reservedEnvironmentVariables := []string{"HOME", "PATH", "PS1", "PS2"} + for _, reservedEnvName := range reservedEnvironmentVariables { + if _, ok := secretsByKey[reservedEnvName]; ok { + delete(secretsByKey, reservedEnvName) + util.PrintWarning(fmt.Sprintf("Infisical secret named [%v] has been removed because it is a reserved secret name", reservedEnvName)) + } + } + + // now add infisical secrets + for k, v := range secretsByKey { + environmentVariables[k] = v.Value + } + + // turn it back into a list of envs + var env []string + for key, value := range environmentVariables { + s := key + "=" + value + env = append(env, s) + } + + log.Debugf("injecting the following environment variables into shell: %v", env) + + if cmd.Flags().Changed("command") { + command := cmd.Flag("command").Value.String() + + err = executeMultipleCommandWithEnvs(command, len(secretsByKey), env) + if err != nil { + util.HandleError(err, "Unable to execute your chained command") + } + + } else { + err = executeSingleCommandWithEnvs(args, len(secretsByKey), env) + if err != nil { + util.HandleError(err, "Unable to execute your single command") + } + } }, } func init() { rootCmd.AddCommand(runCmd) runCmd.Flags().StringP("env", "e", "dev", "Set the environment (dev, prod, etc.) from which your secrets should be pulled from") - runCmd.Flags().String("projectId", "", "The project ID from which your secrets should be pulled from") runCmd.Flags().Bool("expand", true, "Parse shell parameter expansions in your secrets") + runCmd.Flags().Bool("secret-overriding", true, "Prioritizes personal secrets, if any, with the same name over shared secrets") + runCmd.Flags().StringP("command", "c", "", "chained commands to execute (e.g. \"npm install && npm run dev; echo ...\")") } -// Credit: inspired by AWS Valut -func execCmd(command string, args []string, envs []models.SingleEnvironmentVariable) error { - numberOfSecretsInjected := fmt.Sprintf("\u2713 Injected %v Infisical secrets into your application process successfully", len(envs)) +// Will execute a single command and pass in the given secrets into the process +func executeSingleCommandWithEnvs(args []string, secretsCount int, env []string) error { + command := args[0] + argsForCommand := args[1:] + color.Green("Injecting %v Infisical secrets into your application process", secretsCount) - log.Infof("\x1b[%dm%s\x1b[0m", 32, numberOfSecretsInjected) - log.Debugf("executing command: %s %s \n", command, strings.Join(args, " ")) - log.Debugln("Secrets injected:", envs) - - cmd := exec.Command(command, args...) + cmd := exec.Command(command, argsForCommand...) cmd.Stdin = os.Stdin cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr - cmd.Env = getAllEnvs(envs) + cmd.Env = env + return execCmd(cmd) +} + +func executeMultipleCommandWithEnvs(fullCommand string, secretsCount int, env []string) error { + shell := [2]string{"sh", "-c"} + if runtime.GOOS == "windows" { + shell = [2]string{"cmd", "/C"} + } else { + currentShell := os.Getenv("SHELL") + if currentShell != "" { + shell[0] = currentShell + } + } + + cmd := exec.Command(shell[0], shell[1], fullCommand) + cmd.Stdin = os.Stdin + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + cmd.Env = env + + color.Green("Injecting %v Infisical secrets into your application process", secretsCount) + log.Debugf("executing command: %s %s %s \n", shell[0], shell[1], fullCommand) + + return execCmd(cmd) +} + +// Credit: inspired by AWS Valut +func execCmd(cmd *exec.Cmd) error { sigChannel := make(chan os.Signal, 1) signal.Notify(sigChannel) @@ -100,30 +202,10 @@ func execCmd(command string, args []string, envs []models.SingleEnvironmentVaria if err := cmd.Wait(); err != nil { _ = cmd.Process.Signal(os.Kill) - return fmt.Errorf("Failed to wait for command termination: %v", err) + return fmt.Errorf("failed to wait for command termination: %v", err) } waitStatus := cmd.ProcessState.Sys().(syscall.WaitStatus) os.Exit(waitStatus.ExitStatus()) return nil } - -func getAllEnvs(envsToInject []models.SingleEnvironmentVariable) []string { - env_map := make(map[string]string) - - for _, env := range os.Environ() { - splitEnv := strings.Split(env, "=") - env_map[splitEnv[0]] = splitEnv[1] - } - - for _, env := range envsToInject { - env_map[env.Key] = env.Value // overrite any envs with ones to inject if they clash - } - - var allEnvs []string - for key, value := range env_map { - allEnvs = append(allEnvs, fmt.Sprintf("%s=%s", key, value)) - } - - return allEnvs -} diff --git a/cli/packages/cmd/secrets.go b/cli/packages/cmd/secrets.go new file mode 100644 index 000000000..060a69a45 --- /dev/null +++ b/cli/packages/cmd/secrets.go @@ -0,0 +1,382 @@ +/* +Copyright (c) 2023 Infisical Inc. +*/ +package cmd + +import ( + "encoding/base64" + "fmt" + "strings" + "unicode" + + "crypto/sha256" + + "github.com/Infisical/infisical-merge/packages/api" + "github.com/Infisical/infisical-merge/packages/crypto" + "github.com/Infisical/infisical-merge/packages/models" + "github.com/Infisical/infisical-merge/packages/util" + "github.com/Infisical/infisical-merge/packages/visualize" + "github.com/go-resty/resty/v2" + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" +) + +var secretsCmd = &cobra.Command{ + Example: `infisical secrets"`, + Short: "Used to create, read update and delete secrets", + Use: "secrets", + DisableFlagsInUseLine: true, + PreRun: toggleDebug, + Args: cobra.NoArgs, + Run: func(cmd *cobra.Command, args []string) { + environmentName, err := cmd.Flags().GetString("env") + if err != nil { + util.HandleError(err) + } + + shouldExpandSecrets, err := cmd.Flags().GetBool("expand") + if err != nil { + util.HandleError(err) + } + + secrets, err := util.GetAllEnvironmentVariables(environmentName) + if err != nil { + util.HandleError(err) + } + + if shouldExpandSecrets { + secrets = util.SubstituteSecrets(secrets) + } + + visualize.PrintAllSecretDetails(secrets) + }, +} + +var secretsGetCmd = &cobra.Command{ + Example: `secrets get ..."`, + Short: "Used to retrieve secrets by name", + Use: "get [secrets]", + DisableFlagsInUseLine: true, + Args: cobra.MinimumNArgs(1), + PreRun: toggleDebug, + Run: getSecretsByNames, +} + +var secretsSetCmd = &cobra.Command{ + Example: `secrets set ..."`, + Short: "Used set secrets", + Use: "set [secrets]", + DisableFlagsInUseLine: true, + PreRun: toggleDebug, + Args: cobra.MinimumNArgs(1), + Run: func(cmd *cobra.Command, args []string) { + environmentName, err := cmd.Flags().GetString("env") + if err != nil { + util.HandleError(err, "Unable to parse flag") + } + + if !util.IsSecretEnvironmentValid(environmentName) { + util.PrintMessageAndExit("You have entered a invalid environment name", "Environment names can only be prod, dev, test or staging") + } + + workspaceFile, err := util.GetWorkSpaceFromFile() + if err != nil { + util.HandleError(err, "Unable to get your local config details") + } + + loggedInUserDetails, err := util.GetCurrentLoggedInUserDetails() + if err != nil { + util.HandleError(err, "Unable to authenticate") + } + + httpClient := resty.New(). + SetAuthToken(loggedInUserDetails.UserCredentials.JTWToken). + SetHeader("Accept", "application/json") + + request := api.GetEncryptedWorkspaceKeyRequest{ + WorkspaceId: workspaceFile.WorkspaceId, + } + + workspaceKeyResponse, err := api.CallGetEncryptedWorkspaceKey(httpClient, request) + if err != nil { + util.HandleError(err, "unable to get your encrypted workspace key") + } + + encryptedWorkspaceKey, _ := base64.StdEncoding.DecodeString(workspaceKeyResponse.EncryptedKey) + encryptedWorkspaceKeySenderPublicKey, _ := base64.StdEncoding.DecodeString(workspaceKeyResponse.Sender.PublicKey) + encryptedWorkspaceKeyNonce, _ := base64.StdEncoding.DecodeString(workspaceKeyResponse.Nonce) + currentUsersPrivateKey, _ := base64.StdEncoding.DecodeString(loggedInUserDetails.UserCredentials.PrivateKey) + + // decrypt workspace key + plainTextEncryptionKey := crypto.DecryptAsymmetric(encryptedWorkspaceKey, encryptedWorkspaceKeyNonce, encryptedWorkspaceKeySenderPublicKey, currentUsersPrivateKey) + + // pull current secrets + secrets, err := util.GetAllEnvironmentVariables(environmentName) + if err != nil { + util.HandleError(err, "unable to retrieve secrets") + } + + type SecretSetOperation struct { + SecretKey string + SecretValue string + SecretOperation string + } + + secretsToCreate := []api.Secret{} + secretsToModify := []api.Secret{} + secretOperations := []SecretSetOperation{} + + secretByKey := getSecretsByKeys(secrets) + + for _, arg := range args { + splitKeyValueFromArg := strings.SplitN(arg, "=", 2) + if splitKeyValueFromArg[0] == "" || splitKeyValueFromArg[1] == "" { + util.PrintMessageAndExit("ensure that each secret has a none empty key and value. Modify the input and try again") + } + + if unicode.IsNumber(rune(splitKeyValueFromArg[0][0])) { + util.PrintMessageAndExit("keys of secrets cannot start with a number. Modify the key name(s) and try again") + } + + // Key and value from argument + key := strings.ToUpper(splitKeyValueFromArg[0]) + value := splitKeyValueFromArg[1] + + hashedKey := fmt.Sprintf("%x", sha256.Sum256([]byte(key))) + encryptedKey, err := crypto.EncryptSymmetric([]byte(key), []byte(plainTextEncryptionKey)) + if err != nil { + util.HandleError(err, "unable to encrypt your secrets") + } + + hashedValue := fmt.Sprintf("%x", sha256.Sum256([]byte(value))) + encryptedValue, err := crypto.EncryptSymmetric([]byte(value), []byte(plainTextEncryptionKey)) + if err != nil { + util.HandleError(err, "unable to encrypt your secrets") + } + + if existingSecret, ok := secretByKey[key]; ok { + // case: secret exists in project so it needs to be modified + encryptedSecretDetails := api.Secret{ + ID: existingSecret.ID, + SecretValueCiphertext: base64.StdEncoding.EncodeToString(encryptedValue.CipherText), + SecretValueIV: base64.StdEncoding.EncodeToString(encryptedValue.Nonce), + SecretValueTag: base64.StdEncoding.EncodeToString(encryptedValue.AuthTag), + SecretValueHash: hashedValue, + } + + // Only add to modifications if the value is different + if existingSecret.Value != value { + secretsToModify = append(secretsToModify, encryptedSecretDetails) + secretOperations = append(secretOperations, SecretSetOperation{ + SecretKey: key, + SecretValue: value, + SecretOperation: "SECRET VALUE MODIFIED", + }) + } else { + // Current value is same as exisitng so no change + secretOperations = append(secretOperations, SecretSetOperation{ + SecretKey: key, + SecretValue: value, + SecretOperation: "SECRET VALUE UNCHANGED", + }) + } + + } else { + // case: secret doesn't exist in project so it needs to be created + encryptedSecretDetails := api.Secret{ + SecretKeyCiphertext: base64.StdEncoding.EncodeToString(encryptedKey.CipherText), + SecretKeyIV: base64.StdEncoding.EncodeToString(encryptedKey.Nonce), + SecretKeyTag: base64.StdEncoding.EncodeToString(encryptedKey.AuthTag), + SecretKeyHash: hashedKey, + SecretValueCiphertext: base64.StdEncoding.EncodeToString(encryptedValue.CipherText), + SecretValueIV: base64.StdEncoding.EncodeToString(encryptedValue.Nonce), + SecretValueTag: base64.StdEncoding.EncodeToString(encryptedValue.AuthTag), + SecretValueHash: hashedValue, + Type: util.SECRET_TYPE_SHARED, + } + secretsToCreate = append(secretsToCreate, encryptedSecretDetails) + secretOperations = append(secretOperations, SecretSetOperation{ + SecretKey: key, + SecretValue: value, + SecretOperation: "SECRET CREATED", + }) + } + } + + if len(secretsToCreate) > 0 { + batchCreateRequest := api.BatchCreateSecretsByWorkspaceAndEnvRequest{ + WorkspaceId: workspaceFile.WorkspaceId, + Environment: environmentName, + Secrets: secretsToCreate, + } + + err = api.CallBatchCreateSecretsByWorkspaceAndEnv(httpClient, batchCreateRequest) + if err != nil { + util.HandleError(err, "Unable to process new secret creations") + return + } + } + + if len(secretsToModify) > 0 { + batchModifyRequest := api.BatchModifySecretsByWorkspaceAndEnvRequest{ + WorkspaceId: workspaceFile.WorkspaceId, + Environment: environmentName, + Secrets: secretsToModify, + } + + err = api.CallBatchModifySecretsByWorkspaceAndEnv(httpClient, batchModifyRequest) + if err != nil { + util.HandleError(err, "Unable to process the modifications to your secrets") + return + } + } + + // Print secret operations + headers := []string{"SECRET NAME", "SECRET VALUE", "STATUS"} + rows := [][]string{} + for _, secretOperation := range secretOperations { + rows = append(rows, []string{secretOperation.SecretKey, secretOperation.SecretValue, secretOperation.SecretOperation}) + } + + visualize.Table(headers, rows) + }, +} + +var secretsDeleteCmd = &cobra.Command{ + Example: `secrets delete ..."`, + Short: "Used to delete secrets by name", + Use: "delete [secrets]", + DisableFlagsInUseLine: true, + PreRun: toggleDebug, + Args: cobra.MinimumNArgs(1), + Run: func(cmd *cobra.Command, args []string) { + environmentName, err := cmd.Flags().GetString("env") + if err != nil { + log.Errorln("Unable to parse the environment name flag") + log.Debugln(err) + return + } + + loggedInUserDetails, err := util.GetCurrentLoggedInUserDetails() + if err != nil { + util.HandleError(err, "Unable to authenticate") + } + + workspaceFile, err := util.GetWorkSpaceFromFile() + if err != nil { + util.HandleError(err, "Unable to get local project details") + } + + secrets, err := util.GetAllEnvironmentVariables(environmentName) + if err != nil { + util.HandleError(err, "Unable to fetch secrets") + } + + secretByKey := getSecretsByKeys(secrets) + validSecretIdsToDelete := []string{} + invalidSecretNamesThatDoNotExist := []string{} + + for _, secretKeyFromArg := range args { + if value, ok := secretByKey[strings.ToUpper(secretKeyFromArg)]; ok { + validSecretIdsToDelete = append(validSecretIdsToDelete, value.ID) + } else { + invalidSecretNamesThatDoNotExist = append(invalidSecretNamesThatDoNotExist, secretKeyFromArg) + } + } + + if len(invalidSecretNamesThatDoNotExist) != 0 { + message := fmt.Sprintf("secret name(s) [%v] does not exist in your project. To see which secrets exist run [infisical secrets]", strings.Join(invalidSecretNamesThatDoNotExist, ", ")) + util.PrintMessageAndExit(message) + } + + request := api.BatchDeleteSecretsBySecretIdsRequest{ + WorkspaceId: workspaceFile.WorkspaceId, + EnvironmentName: environmentName, + SecretIds: validSecretIdsToDelete, + } + + httpClient := resty.New(). + SetAuthToken(loggedInUserDetails.UserCredentials.JTWToken). + SetHeader("Accept", "application/json") + + err = api.CallBatchDeleteSecretsByWorkspaceAndEnv(httpClient, request) + if err != nil { + util.HandleError(err, "Unable to complete your batch delete request") + } + + fmt.Printf("secret name(s) [%v] have been deleted from your project \n", strings.Join(args, ", ")) + + }, +} + +func init() { + secretsCmd.AddCommand(secretsGetCmd) + secretsGetCmd.PersistentPreRun = func(cmd *cobra.Command, args []string) { + util.RequireLogin() + util.RequireLocalWorkspaceFile() + } + + secretsCmd.AddCommand(secretsSetCmd) + secretsSetCmd.PersistentPreRun = func(cmd *cobra.Command, args []string) { + util.RequireLogin() + util.RequireLocalWorkspaceFile() + } + + secretsCmd.AddCommand(secretsDeleteCmd) + secretsDeleteCmd.PersistentPreRun = func(cmd *cobra.Command, args []string) { + util.RequireLogin() + util.RequireLocalWorkspaceFile() + } + + secretsCmd.PersistentFlags().String("env", "dev", "Used to select the environment name on which actions should be taken on") + secretsCmd.Flags().Bool("expand", true, "Parse shell parameter expansions in your secrets") + rootCmd.AddCommand(secretsCmd) +} + +func getSecretsByNames(cmd *cobra.Command, args []string) { + environmentName, err := cmd.Flags().GetString("env") + if err != nil { + util.HandleError(err, "Unable to parse flag") + } + + workspaceFileExists := util.WorkspaceConfigFileExistsInCurrentPath() + if !workspaceFileExists { + util.HandleError(err, "Unable to parse flag") + } + + secrets, err := util.GetAllEnvironmentVariables(environmentName) + if err != nil { + util.HandleError(err, "To fetch all secrets") + } + + requestedSecrets := []models.SingleEnvironmentVariable{} + + secretsMap := make(map[string]models.SingleEnvironmentVariable) + for _, secret := range secrets { + secretsMap[secret.Key] = secret + } + + for _, secretKeyFromArg := range args { + if value, ok := secretsMap[strings.ToUpper(secretKeyFromArg)]; ok { + requestedSecrets = append(requestedSecrets, value) + } else { + requestedSecrets = append(requestedSecrets, models.SingleEnvironmentVariable{ + Key: secretKeyFromArg, + Type: "*not found*", + Value: "*not found*", + }) + } + } + + visualize.PrintAllSecretDetails(requestedSecrets) +} + +func getSecretsByKeys(secrets []models.SingleEnvironmentVariable) map[string]models.SingleEnvironmentVariable { + secretMapByName := make(map[string]models.SingleEnvironmentVariable) + + for _, secret := range secrets { + secretMapByName[secret.Key] = secret + } + + return secretMapByName +} diff --git a/cli/packages/cmd/vault.go b/cli/packages/cmd/vault.go new file mode 100644 index 000000000..d9e32769e --- /dev/null +++ b/cli/packages/cmd/vault.go @@ -0,0 +1,98 @@ +/* +Copyright (c) 2023 Infisical Inc. +*/ +package cmd + +import ( + "github.com/99designs/keyring" + "github.com/Infisical/infisical-merge/packages/util" + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" +) + +var vaultSetCmd = &cobra.Command{ + Example: `infisical vault set pass`, + Use: "set [vault-name]", + Short: "Used to set the vault backend to store your login details securely at rest", + DisableFlagsInUseLine: true, + PreRun: toggleDebug, + Args: cobra.MinimumNArgs(1), + Run: func(cmd *cobra.Command, args []string) { + wantedVaultTypeName := args[0] + currentVaultBackend, err := util.GetCurrentVaultBackend() + if err != nil { + log.Errorf("Unable to set vault to [%s] because of [err=%s]", wantedVaultTypeName, err) + return + } + + if wantedVaultTypeName == string(currentVaultBackend) { + log.Errorf("You are already on vault backend [%s]", currentVaultBackend) + return + } + + if isVaultToSwitchToValid(wantedVaultTypeName) { + configFile, err := util.GetConfigFile() + if err != nil { + log.Errorf("Unable to set vault to [%s] because of [err=%s]", wantedVaultTypeName, err) + return + } + + configFile.VaultBackendType = keyring.BackendType(wantedVaultTypeName) // save selected vault + configFile.LoggedInUserEmail = "" // reset the logged in user to prompt them to re login + + err = util.WriteConfigFile(&configFile) + if err != nil { + log.Errorf("Unable to set vault to [%s] because an error occurred when saving the config file [err=%s]", wantedVaultTypeName, err) + return + } + + log.Infof("Successfully, switched vault backend from [%s] to [%s]. Please login in again to store your login details in the new vault with [infisical login]", currentVaultBackend, wantedVaultTypeName) + } else { + log.Errorf("The requested vault type [%s] is not available on this system. Only the following vault backends are available for you system: %s", wantedVaultTypeName, keyring.AvailableBackends()) + } + }, +} + +// runCmd represents the run command +var vaultCmd = &cobra.Command{ + Use: "vault", + Short: "Used to manage where your Infisical login token is saved on your machine", + DisableFlagsInUseLine: true, + PreRun: toggleDebug, + Args: cobra.NoArgs, + Run: func(cmd *cobra.Command, args []string) { + printAvailableVaultBackends() + }, +} + +func printAvailableVaultBackends() { + log.Infof("The following vaults are available on your system:") + for _, backend := range keyring.AvailableBackends() { + log.Infof("- %s", backend) + } + + currentVaultBackend, err := util.GetCurrentVaultBackend() + if err != nil { + log.Errorf("printAvailableVaultBackends: unable to print the available vault backend because of error [err=%s]", err) + } + + log.Infof("\nYou are currently using [%s] vault to store your login credentials", string(currentVaultBackend)) +} + +// Checks if the vault that the user wants to switch to is a valid available vault +func isVaultToSwitchToValid(vaultNameToSwitchTo string) bool { + isFound := false + for _, backend := range keyring.AvailableBackends() { + if vaultNameToSwitchTo == string(backend) { + isFound = true + break + } + } + + return isFound +} + +func init() { + vaultCmd.AddCommand(vaultSetCmd) + rootCmd.AddCommand(vaultCmd) +} diff --git a/cli/packages/config/config.go b/cli/packages/config/config.go new file mode 100644 index 000000000..6c56858e6 --- /dev/null +++ b/cli/packages/config/config.go @@ -0,0 +1,3 @@ +package config + +var INFISICAL_URL string diff --git a/cli/packages/crypto/crypto.go b/cli/packages/crypto/crypto.go new file mode 100644 index 000000000..f9589347a --- /dev/null +++ b/cli/packages/crypto/crypto.go @@ -0,0 +1,81 @@ +package crypto + +import ( + "crypto/aes" + "crypto/cipher" + "crypto/rand" + "io" + + "github.com/Infisical/infisical-merge/packages/models" + "golang.org/x/crypto/nacl/box" +) + +// will decrypt cipher text to plain text using iv and tag +func DecryptSymmetric(key []byte, cipherText []byte, tag []byte, iv []byte) ([]byte, error) { + block, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + + aesgcm, err := cipher.NewGCMWithNonceSize(block, len(iv)) + if err != nil { + return nil, err + } + + var nonce = iv + var ciphertext = append(cipherText, tag...) // the aesgcm open method expects auth tag at the end of the cipher text + + plaintext, err := aesgcm.Open(nil, nonce, ciphertext, nil) + if err != nil { + return nil, err + } + + return plaintext, nil +} + +func GenerateNewKey() (newKey []byte, keyErr error) { + key := make([]byte, 16) // block size defaults to 16 so this is fine + _, err := rand.Read(key) + return key, err +} + +// Will encrypt a plain text with the provided key +func EncryptSymmetric(plaintext []byte, key []byte) (result models.SymmetricEncryptionResult, err error) { + block, err := aes.NewCipher(key) + if err != nil { + return models.SymmetricEncryptionResult{}, err + } + + aesgcm, err := cipher.NewGCMWithNonceSize(block, 16) // default is 12, 16 because https://github.com/Infisical/infisical/blob/bea0ff6e05a4de73a5db625d4ae181a015b50855/backend/src/utils/aes-gcm.ts#L4 + if err != nil { + return models.SymmetricEncryptionResult{}, err + } + + // create a nonce + nonce := make([]byte, aesgcm.NonceSize()) + if _, err := io.ReadFull(rand.Reader, nonce); err != nil { + panic(err) + } + + ciphertext := aesgcm.Seal(nil, nonce, plaintext, nil) + + ciphertextOnly := ciphertext[:len(ciphertext)-16] // combines the auth tag with the cipher text so we need to extract it + + authTag := ciphertext[len(ciphertext)-16:] + + return models.SymmetricEncryptionResult{ + CipherText: ciphertextOnly, + AuthTag: authTag, + Nonce: nonce, + }, nil +} + +func DecryptAsymmetric(ciphertext []byte, nonce []byte, publicKey []byte, privateKey []byte) (plainText []byte) { + plainTextToReturn, _ := box.Open(nil, ciphertext, (*[24]byte)(nonce), (*[32]byte)(publicKey), (*[32]byte)(privateKey)) + return plainTextToReturn +} + +func EncryptAssymmetric(message []byte, nonce []byte, publicKey []byte, privateKey []byte) (encryptedMessage []byte) { + encryptedPlainText := box.Seal(nil, message, (*[24]byte)(nonce), (*[32]byte)(publicKey), (*[32]byte)(privateKey)) + return encryptedPlainText +} diff --git a/cli/packages/models/api.go b/cli/packages/models/api.go deleted file mode 100644 index 552c7b9bc..000000000 --- a/cli/packages/models/api.go +++ /dev/null @@ -1,130 +0,0 @@ -package models - -import "time" - -// Stores info for login one -type LoginOneRequest struct { - Email string `json:"email"` - ClientPublicKey string `json:"clientPublicKey"` -} - -type LoginOneResponse struct { - ServerPublicKey string `json:"serverPublicKey"` - ServerSalt string `json:"salt"` -} - -// Stores info for login two - -type LoginTwoRequest struct { - Email string `json:"email"` - ClientProof string `json:"clientProof"` -} - -type LoginTwoResponse struct { - JTWToken string `json:"token"` - RefreshToken string `json:"refreshToken"` - PublicKey string `json:"publicKey"` - EncryptedPrivateKey string `json:"encryptedPrivateKey"` - IV string `json:"iv"` - Tag string `json:"tag"` -} - -type PullSecretsRequest struct { - Environment string `json:"environment"` -} - -type PullSecretsResponse struct { - Secrets []struct { - ID string `json:"_id"` - Workspace string `json:"workspace"` - Type string `json:"type"` - Environment string `json:"environment"` - SecretKeyCiphertext string `json:"secretKeyCiphertext"` - SecretKeyIV string `json:"secretKeyIV"` - SecretKeyTag string `json:"secretKeyTag"` - SecretKeyHash string `json:"secretKeyHash"` - SecretValueCiphertext string `json:"secretValueCiphertext"` - SecretValueIV string `json:"secretValueIV"` - SecretValueTag string `json:"secretValueTag"` - SecretValueHash string `json:"secretValueHash"` - V int `json:"__v"` - CreatedAt time.Time `json:"createdAt"` - UpdatedAt time.Time `json:"updatedAt"` - User string `json:"user,omitempty"` - } `json:"secrets"` - Key struct { - ID string `json:"_id"` - EncryptedKey string `json:"encryptedKey"` - Nonce string `json:"nonce"` - Sender struct { - ID string `json:"_id"` - Email string `json:"email"` - CustomerID string `json:"customerId"` - CreatedAt time.Time `json:"createdAt"` - UpdatedAt time.Time `json:"updatedAt"` - V int `json:"__v"` - FirstName string `json:"firstName"` - LastName string `json:"lastName"` - PublicKey string `json:"publicKey"` - } `json:"sender"` - Receiver string `json:"receiver"` - Workspace string `json:"workspace"` - V int `json:"__v"` - CreatedAt time.Time `json:"createdAt"` - UpdatedAt time.Time `json:"updatedAt"` - } `json:"key"` -} - -type PullSecretsByInfisicalTokenResponse struct { - Secrets []struct { - ID string `json:"_id"` - Workspace string `json:"workspace"` - Type string `json:"type"` - Environment string `json:"environment"` - SecretKey struct { - Workspace string `json:"workspace"` - Ciphertext string `json:"ciphertext"` - Iv string `json:"iv"` - Tag string `json:"tag"` - Hash string `json:"hash"` - } `json:"secretKey"` - SecretValue struct { - Workspace string `json:"workspace"` - Ciphertext string `json:"ciphertext"` - Iv string `json:"iv"` - Tag string `json:"tag"` - Hash string `json:"hash"` - } `json:"secretValue"` - } `json:"secrets"` - Key struct { - EncryptedKey string `json:"encryptedKey"` - Nonce string `json:"nonce"` - Sender struct { - PublicKey string `json:"publicKey"` - } `json:"sender"` - Receiver struct { - RefreshVersion int `json:"refreshVersion"` - ID string `json:"_id"` - Email string `json:"email"` - CustomerID string `json:"customerId"` - CreatedAt time.Time `json:"createdAt"` - UpdatedAt time.Time `json:"updatedAt"` - V int `json:"__v"` - FirstName string `json:"firstName"` - LastName string `json:"lastName"` - PublicKey string `json:"publicKey"` - } `json:"receiver"` - Workspace string `json:"workspace"` - } `json:"key"` -} - -type GetWorkSpacesResponse struct { - Workspaces []Workspace `json:"workspaces"` -} -type Workspace struct { - ID string `json:"_id"` - Name string `json:"name"` - Plan string `json:"plan,omitempty"` - V int `json:"__v"` - Organization string `json:"organization,omitempty"` -} diff --git a/cli/packages/models/cli.go b/cli/packages/models/cli.go index 708a9ed8e..7bc31cab2 100644 --- a/cli/packages/models/cli.go +++ b/cli/packages/models/cli.go @@ -1,5 +1,7 @@ package models +import "github.com/99designs/keyring" + type UserCredentials struct { Email string `json:"email"` PrivateKey string `json:"privateKey"` @@ -8,14 +10,31 @@ type UserCredentials struct { // The file struct for Infisical config file type ConfigFile struct { - LoggedInUserEmail string `json:"loggedInUserEmail"` + LoggedInUserEmail string `json:"loggedInUserEmail"` + VaultBackendType keyring.BackendType `json:"vaultBackendType"` } type SingleEnvironmentVariable struct { Key string `json:"key"` Value string `json:"value"` + Type string `json:"type"` + ID string `json:"_id"` +} + +type Workspace struct { + ID string `json:"_id"` + Name string `json:"name"` + Plan string `json:"plan,omitempty"` + V int `json:"__v"` + Organization string `json:"organization,omitempty"` } type WorkspaceConfigFile struct { WorkspaceId string `json:"workspaceId"` } + +type SymmetricEncryptionResult struct { + CipherText []byte + Nonce []byte + AuthTag []byte +} diff --git a/cli/packages/util/check-for-update.go b/cli/packages/util/check-for-update.go new file mode 100644 index 000000000..5fbf39a1e --- /dev/null +++ b/cli/packages/util/check-for-update.go @@ -0,0 +1,46 @@ +package util + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "errors" +) + +func CheckForUpdate() { + latestVersion, err := getLatestTag("Infisical", "infisical") + if err != nil { + // do nothing and continue + return + } + if latestVersion != CLI_VERSION { + PrintWarning(fmt.Sprintf("Please update your CLI. You are running version %s but the latest version is %s", CLI_VERSION, latestVersion)) + } +} + +func getLatestTag(repoOwner string, repoName string) (string, error) { + url := fmt.Sprintf("https://api.github.com/repos/%s/%s/tags", repoOwner, repoName) + resp, err := http.Get(url) + if err != nil { + return "", err + } + if resp.StatusCode != 200 { + return "", errors.New(fmt.Sprintf("GitHub API returned status code %d", resp.StatusCode)) + } + + defer resp.Body.Close() + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return "", err + } + + var tags []struct { + Name string `json:"name"` + } + + json.Unmarshal(body, &tags) + + return tags[0].Name, nil +} diff --git a/cli/packages/util/common.go b/cli/packages/util/common.go index 37c881994..2d420ac6f 100644 --- a/cli/packages/util/common.go +++ b/cli/packages/util/common.go @@ -5,24 +5,16 @@ import ( "os" ) -const ( - CONFIG_FILE_NAME = "infisical-config.json" - CONFIG_FOLDER_NAME = ".infisical" - INFISICAL_WORKSPACE_CONFIG_FILE_NAME = ".infisical.json" - INFISICAL_TOKEN_NAME = "INFISICAL_TOKEN" -) - -var INFISICAL_URL = "https://app.infisical.com/api" - func GetHomeDir() (string, error) { directory, err := os.UserHomeDir() return directory, err } +// write file to given path. If path does not exist throw error func WriteToFile(fileName string, dataToWrite []byte, filePerm os.FileMode) error { err := os.WriteFile(fileName, dataToWrite, filePerm) if err != nil { - return fmt.Errorf("Unable to wrote to file", err) + return fmt.Errorf("unable to wrote to file [err=%v]", err) } return nil diff --git a/cli/packages/util/config.go b/cli/packages/util/config.go index 0ee04b013..48bb57241 100644 --- a/cli/packages/util/config.go +++ b/cli/packages/util/config.go @@ -24,8 +24,15 @@ func WriteInitalConfig(userCredentials *models.UserCredentials) error { } } + // get existing config + existingConfigFile, err := GetConfigFile() + if err != nil { + return fmt.Errorf("writeInitalConfig: unable to write config file because [err=%s]", err) + } + configFile := models.ConfigFile{ LoggedInUserEmail: userCredentials.Email, + VaultBackendType: existingConfigFile.VaultBackendType, } configFileMarshalled, err := json.Marshal(configFile) @@ -152,3 +159,62 @@ func GetAllWorkSpaceConfigsStartingFromCurrentPath() (workspaces []models.Worksp return listOfWorkSpaceConfigs, nil } + +// Get the infisical config file and if it doesn't exist, return empty config model, otherwise raise error +func GetConfigFile() (models.ConfigFile, error) { + fullConfigFilePath, _, err := GetFullConfigFilePath() + if err != nil { + return models.ConfigFile{}, err + } + + configFileAsBytes, err := os.ReadFile(fullConfigFilePath) + if err != nil { + if err, ok := err.(*os.PathError); ok { + return models.ConfigFile{}, nil + } else { + return models.ConfigFile{}, err + } + } + + var configFile models.ConfigFile + err = json.Unmarshal(configFileAsBytes, &configFile) + if err != nil { + return models.ConfigFile{}, err + } + + return configFile, nil +} + +// Write a ConfigFile to disk. Raise error if unable to save the model to ask +func WriteConfigFile(configFile *models.ConfigFile) error { + fullConfigFilePath, fullConfigFileDirPath, err := GetFullConfigFilePath() + if err != nil { + return fmt.Errorf("writeConfigFile: unable to write config file because an error occurred when getting config file path [err=%s]", err) + } + + configFileMarshalled, err := json.Marshal(configFile) + if err != nil { + return fmt.Errorf("writeConfigFile: unable to write config file because an error occurred when marshalling the config file [err=%s]", err) + } + + // check if config folder exists and if not create it + if _, err := os.Stat(fullConfigFileDirPath); errors.Is(err, os.ErrNotExist) { + err := os.Mkdir(fullConfigFileDirPath, os.ModePerm) + if err != nil { + return err + } + } + + // Create file in directory + err = os.WriteFile(fullConfigFilePath, configFileMarshalled, os.ModePerm) + if err != nil { + return fmt.Errorf("writeConfigFile: Unable to write to file [err=%s]", err) + } + + if err != nil { + return fmt.Errorf("writeConfigFile: unable to write config file because an error occurred when write the config to file [err=%s]", err) + + } + + return nil +} diff --git a/cli/packages/util/constants.go b/cli/packages/util/constants.go new file mode 100644 index 000000000..5c169f6d5 --- /dev/null +++ b/cli/packages/util/constants.go @@ -0,0 +1,18 @@ +package util + +const ( + CONFIG_FILE_NAME = "infisical-config.json" + CONFIG_FOLDER_NAME = ".infisical" + INFISICAL_DEFAULT_API_URL = "https://app.infisical.com/api" + INFISICAL_WORKSPACE_CONFIG_FILE_NAME = ".infisical.json" + INFISICAL_TOKEN_NAME = "INFISICAL_TOKEN" + SECRET_TYPE_PERSONAL = "personal" + SECRET_TYPE_SHARED = "shared" + KEYRING_SERVICE_NAME = "infisical" + PERSONAL_SECRET_TYPE_NAME = "personal" + SHARED_SECRET_TYPE_NAME = "shared" +) + +var ( + CLI_VERSION = "devel" +) diff --git a/cli/packages/util/credentials.go b/cli/packages/util/credentials.go index c5396f698..1766f04c7 100644 --- a/cli/packages/util/credentials.go +++ b/cli/packages/util/credentials.go @@ -3,75 +3,83 @@ package util import ( "encoding/json" "fmt" - "os" + "github.com/99designs/keyring" + "github.com/Infisical/infisical-merge/packages/api" "github.com/Infisical/infisical-merge/packages/models" "github.com/go-resty/resty/v2" - log "github.com/sirupsen/logrus" - "github.com/zalando/go-keyring" ) -const SERVICE_NAME = "infisical" +type LoggedInUserDetails struct { + IsUserLoggedIn bool + LoginExpired bool + UserCredentials models.UserCredentials +} -// To do: what happens if the user doesn't have a keyring in their system? func StoreUserCredsInKeyRing(userCred *models.UserCredentials) error { userCredMarshalled, err := json.Marshal(userCred) if err != nil { - return fmt.Errorf("Something went wrong when marshalling user creds:", err) + return fmt.Errorf("StoreUserCredsInKeyRing: something went wrong when marshalling user creds [err=%s]", err) } - err = keyring.Set(SERVICE_NAME, userCred.Email, string(userCredMarshalled)) + // Get keyring + configuredKeyring, err := GetKeyRing() if err != nil { - return fmt.Errorf("Unable to store user credentials:", err) + return fmt.Errorf("StoreUserCredsInKeyRing: unable to get keyring instance with [err=%s]", err) + } + + err = configuredKeyring.Set(keyring.Item{ + Key: userCred.Email, + Data: []byte(string(userCredMarshalled)), + }) + + if err != nil { + return fmt.Errorf("StoreUserCredsInKeyRing: unable to store user credentials because [err=%s]", err) } return err } func GetUserCredsFromKeyRing(userEmail string) (credentials models.UserCredentials, err error) { - credentialsString, err := keyring.Get(SERVICE_NAME, userEmail) + // Get keyring + configuredKeyring, err := GetKeyRing() if err != nil { - return models.UserCredentials{}, fmt.Errorf("Unable to get key from Keyring:", err) + return models.UserCredentials{}, fmt.Errorf("GetUserCredsFromKeyRing: unable to get keyring instance with [err=%s]", err) + } + + credentialsValue, err := configuredKeyring.Get(userEmail) + if err != nil { + return models.UserCredentials{}, fmt.Errorf("GetUserCredsFromKeyRing: unable to get key from Keyring. could not find login credentials in your Keyring. This is common if you have switched vault backend recently. If so, please login in again and retry [err=%s]", err) } var userCredentials models.UserCredentials - err = json.Unmarshal([]byte(credentialsString), &userCredentials) + err = json.Unmarshal([]byte(credentialsValue.Data), &userCredentials) if err != nil { - return models.UserCredentials{}, fmt.Errorf("Something went wrong when unmarshalling user creds:", err) + return models.UserCredentials{}, fmt.Errorf("getUserCredsFromKeyRing: Something went wrong when unmarshalling user creds [err=%s]", err) } if err != nil { - return models.UserCredentials{}, fmt.Errorf("Unable to store user credentials", err) + return models.UserCredentials{}, fmt.Errorf("GetUserCredsFromKeyRing: Unable to store user credentials [err=%s]", err) } return userCredentials, err } -func IsUserLoggedIn() (hasUserLoggedIn bool, theUsersEmail string, err error) { +func GetCurrentLoggedInUserDetails() (LoggedInUserDetails, error) { if ConfigFileExists() { - fullConfigFilePath, _, err := GetFullConfigFilePath() + configFile, err := GetConfigFile() if err != nil { - log.Debugln("Error gettting full path:", err) - return false, "", err + return LoggedInUserDetails{}, fmt.Errorf("getCurrentLoggedInUserDetails: unable to get logged in user from config file [err=%s]", err) } - configFileAsBytes, err := os.ReadFile(fullConfigFilePath) - if err != nil { - log.Debugln("Unable to read config file:", err) - return false, "", err - } - - var configFile models.ConfigFile - err = json.Unmarshal(configFileAsBytes, &configFile) - if err != nil { - log.Debugln("Unable to unmarshal config file:", err) - return false, "", err + if configFile.LoggedInUserEmail == "" { + return LoggedInUserDetails{}, nil } userCreds, err := GetUserCredsFromKeyRing(configFile.LoggedInUserEmail) if err != nil { - return false, "", err + return LoggedInUserDetails{}, fmt.Errorf("getCurrentLoggedInUserDetails: unable to your credentials from Keyring [err=%s]", err) } // check to to see if the JWT is still valid @@ -79,21 +87,21 @@ func IsUserLoggedIn() (hasUserLoggedIn bool, theUsersEmail string, err error) { SetAuthToken(userCreds.JTWToken). SetHeader("Accept", "application/json") - response, err := httpClient. - R(). - Post(fmt.Sprintf("%v/v1/auth/checkAuth", INFISICAL_URL)) - - if err != nil { - return false, "", err + isAuthenticated := api.CallIsAuthenticated(httpClient) + if !isAuthenticated { + return LoggedInUserDetails{ + IsUserLoggedIn: true, // was logged in + LoginExpired: true, + UserCredentials: userCreds, + }, nil } - if response.StatusCode() > 299 { - log.Infoln("Login expired, please login again.") - return false, "", fmt.Errorf("Login expired, please login again.") - } - - return true, configFile.LoggedInUserEmail, nil + return LoggedInUserDetails{ + IsUserLoggedIn: true, + LoginExpired: false, + UserCredentials: userCreds, + }, nil } else { - return false, "", nil + return LoggedInUserDetails{}, nil } } diff --git a/cli/packages/util/crypto.go b/cli/packages/util/crypto.go deleted file mode 100644 index c6eee2d0c..000000000 --- a/cli/packages/util/crypto.go +++ /dev/null @@ -1,28 +0,0 @@ -package util - -import ( - "crypto/aes" - "crypto/cipher" -) - -func DecryptSymmetric(key []byte, encryptedPrivateKey []byte, tag []byte, IV []byte) ([]byte, error) { - block, err := aes.NewCipher(key) - if err != nil { - return nil, err - } - - aesgcm, err := cipher.NewGCMWithNonceSize(block, len(IV)) - if err != nil { - return nil, err - } - - var nonce = IV - var ciphertext = append(encryptedPrivateKey, tag...) - - plaintext, err := aesgcm.Open(nil, nonce, ciphertext, nil) - if err != nil { - return nil, err - } - - return plaintext, nil -} diff --git a/cli/packages/util/helper.go b/cli/packages/util/helper.go new file mode 100644 index 000000000..a6e7e35fc --- /dev/null +++ b/cli/packages/util/helper.go @@ -0,0 +1,100 @@ +package util + +import ( + "encoding/base64" + "fmt" + "os" +) + +type DecodedSymmetricEncryptionDetails = struct { + Cipher []byte + IV []byte + Tag []byte + Key []byte +} + +func GetBase64DecodedSymmetricEncryptionDetails(key string, cipher string, IV string, tag string) (DecodedSymmetricEncryptionDetails, error) { + cipherx, err := base64.StdEncoding.DecodeString(cipher) + if err != nil { + return DecodedSymmetricEncryptionDetails{}, fmt.Errorf("Base64DecodeSymmetricEncryptionDetails: Unable to decode cipher text [err=%v]", err) + } + + keyx, err := base64.StdEncoding.DecodeString(key) + if err != nil { + return DecodedSymmetricEncryptionDetails{}, fmt.Errorf("Base64DecodeSymmetricEncryptionDetails: Unable to decode key [err=%v]", err) + } + + IVx, err := base64.StdEncoding.DecodeString(IV) + if err != nil { + return DecodedSymmetricEncryptionDetails{}, fmt.Errorf("Base64DecodeSymmetricEncryptionDetails: Unable to decode IV [err=%v]", err) + } + + tagx, err := base64.StdEncoding.DecodeString(tag) + if err != nil { + return DecodedSymmetricEncryptionDetails{}, fmt.Errorf("Base64DecodeSymmetricEncryptionDetails: Unable to decode tag [err=%v]", err) + } + + return DecodedSymmetricEncryptionDetails{ + Key: keyx, + Cipher: cipherx, + IV: IVx, + Tag: tagx, + }, nil +} + +func IsSecretEnvironmentValid(env string) bool { + if env == "prod" || env == "dev" || env == "test" || env == "staging" { + return true + } + return false +} + +func IsSecretTypeValid(s string) bool { + if s == "personal" || s == "shared" { + return true + } + return false +} + +func RequireLogin() { + currentUserDetails, err := GetCurrentLoggedInUserDetails() + + if err != nil { + HandleError(err, "unable to retrieve your login details") + } + + if !currentUserDetails.IsUserLoggedIn { + PrintMessageAndExit("You must be logged in to run this command. To login, run [infisical login]") + } + + if currentUserDetails.LoginExpired { + PrintMessageAndExit("Your login expired, please login in again. To login, run [infisical login]") + } + + if currentUserDetails.UserCredentials.Email == "" && currentUserDetails.UserCredentials.JTWToken == "" && currentUserDetails.UserCredentials.PrivateKey == "" { + PrintMessageAndExit("One or more of your login details is empty. Please try logging in again via by running [infisical login]") + } +} + +func RequireServiceToken() { + serviceToken := os.Getenv(INFISICAL_TOKEN_NAME) + if serviceToken == "" { + PrintMessageAndExit("No service token is found in your terminal") + } +} + +func RequireLocalWorkspaceFile() { + workspaceFileExists := WorkspaceConfigFileExistsInCurrentPath() + if !workspaceFileExists { + PrintMessageAndExit("It looks you have not yet connected this project to Infisical", "To do so, run [infisical init] then run your command again") + } + + workspaceFile, err := GetWorkSpaceFromFile() + if err != nil { + HandleError(err, "Unable to read your project configuration, please try initializing this project again.", "Run [infisical init]") + } + + if workspaceFile.WorkspaceId == "" { + PrintMessageAndExit("Your project id is missing in your local config file. Please add it or run again [infisical init]") + } +} diff --git a/cli/packages/util/log.go b/cli/packages/util/log.go new file mode 100644 index 000000000..a701987fc --- /dev/null +++ b/cli/packages/util/log.go @@ -0,0 +1,42 @@ +package util + +import ( + "fmt" + "os" + + "github.com/fatih/color" +) + +func HandleError(err error, messages ...string) { + PrintErrorAndExit(1, err, messages...) +} + +func PrintErrorAndExit(exitCode int, err error, messages ...string) { + printError(err) + + if len(messages) > 0 { + for _, message := range messages { + fmt.Println(message) + } + } + + os.Exit(exitCode) +} + +func PrintWarning(message string) { + color.Yellow("Warning: %v", message) +} + +func PrintMessageAndExit(messages ...string) { + if len(messages) > 0 { + for _, message := range messages { + fmt.Println(message) + } + } + + os.Exit(1) +} + +func printError(e error) { + color.Red("Hmm, we ran into an error: %v", e) +} diff --git a/cli/packages/util/secrets.go b/cli/packages/util/secrets.go index c127111b1..1cf8a7ab5 100644 --- a/cli/packages/util/secrets.go +++ b/cli/packages/util/secrets.go @@ -2,276 +2,128 @@ package util import ( "encoding/base64" - "errors" "fmt" "os" "regexp" "strings" + "github.com/Infisical/infisical-merge/packages/api" + "github.com/Infisical/infisical-merge/packages/crypto" "github.com/Infisical/infisical-merge/packages/models" - "github.com/go-resty/resty/v2" log "github.com/sirupsen/logrus" - "golang.org/x/crypto/nacl/box" + + "github.com/go-resty/resty/v2" ) -func getSecretsByWorkspaceIdAndEnvName(httpClient resty.Client, envName string, workspace models.WorkspaceConfigFile, userCreds models.UserCredentials) (listOfSecrets []models.SingleEnvironmentVariable, err error) { - var pullSecretsRequestResponse models.PullSecretsResponse - response, err := httpClient. - R(). - SetQueryParam("environment", envName). - SetQueryParam("channel", "cli"). - SetResult(&pullSecretsRequestResponse). - Get(fmt.Sprintf("%v/v1/secret/%v", INFISICAL_URL, workspace.WorkspaceId)) // need to change workspace id - - if err != nil { - return nil, err +func GetPlainTextSecretsViaServiceToken(fullServiceToken string) ([]models.SingleEnvironmentVariable, error) { + serviceTokenParts := strings.SplitN(fullServiceToken, ".", 4) + if len(serviceTokenParts) < 4 { + return nil, fmt.Errorf("invalid service token entered. Please double check your service token and try again") } - if response.StatusCode() > 299 { - return nil, fmt.Errorf(response.Status()) - } + serviceToken := fmt.Sprintf("%v.%v.%v", serviceTokenParts[0], serviceTokenParts[1], serviceTokenParts[2]) - // Get workspace key - workspaceKey, err := base64.StdEncoding.DecodeString(pullSecretsRequestResponse.Key.EncryptedKey) - if err != nil { - return nil, err - } + httpClient := resty.New() - nonce, err := base64.StdEncoding.DecodeString(pullSecretsRequestResponse.Key.Nonce) - if err != nil { - return nil, err - } - - senderPublicKey, err := base64.StdEncoding.DecodeString(pullSecretsRequestResponse.Key.Sender.PublicKey) - if err != nil { - return nil, err - } - - currentUsersPrivateKey, err := base64.StdEncoding.DecodeString(userCreds.PrivateKey) - if err != nil { - return nil, err - } - - // log.Debugln("workspaceKey", workspaceKey, "nonce", nonce, "senderPublicKey", senderPublicKey, "currentUsersPrivateKey", currentUsersPrivateKey) - workspaceKeyInBytes, _ := box.Open(nil, workspaceKey, (*[24]byte)(nonce), (*[32]byte)(senderPublicKey), (*[32]byte)(currentUsersPrivateKey)) - var listOfEnv []models.SingleEnvironmentVariable - - for _, secret := range pullSecretsRequestResponse.Secrets { - key_iv, _ := base64.StdEncoding.DecodeString(secret.SecretKeyIV) - key_tag, _ := base64.StdEncoding.DecodeString(secret.SecretKeyTag) - key_ciphertext, _ := base64.StdEncoding.DecodeString(secret.SecretKeyCiphertext) - - plainTextKey, err := DecryptSymmetric(workspaceKeyInBytes, key_ciphertext, key_tag, key_iv) - if err != nil { - return nil, err - } - - value_iv, _ := base64.StdEncoding.DecodeString(secret.SecretValueIV) - value_tag, _ := base64.StdEncoding.DecodeString(secret.SecretValueTag) - value_ciphertext, _ := base64.StdEncoding.DecodeString(secret.SecretValueCiphertext) - - plainTextValue, err := DecryptSymmetric(workspaceKeyInBytes, value_ciphertext, value_tag, value_iv) - if err != nil { - return nil, err - } - - env := models.SingleEnvironmentVariable{ - Key: string(plainTextKey), - Value: string(plainTextValue), - } - - listOfEnv = append(listOfEnv, env) - } - - return listOfEnv, nil -} - -func GetSecretsFromAPIUsingCurrentLoggedInUser(envName string, userCreds models.UserCredentials) ([]models.SingleEnvironmentVariable, error) { - log.Debugln("GetSecretsFromAPIUsingCurrentLoggedInUser", "envName", envName, "userCreds", userCreds) - // check if user has configured a workspace - workspaces, err := GetAllWorkSpaceConfigsStartingFromCurrentPath() - if err != nil { - return nil, fmt.Errorf("Unable to read workspace file(s):", err) - } - - // create http client - httpClient := resty.New(). - SetAuthToken(userCreds.JTWToken). + httpClient.SetAuthToken(serviceToken). SetHeader("Accept", "application/json") - secrets := []models.SingleEnvironmentVariable{} - for _, workspace := range workspaces { - secretsFromAPI, err := getSecretsByWorkspaceIdAndEnvName(*httpClient, envName, workspace, userCreds) - if err != nil { - return nil, fmt.Errorf("GetSecretsFromAPIUsingCurrentLoggedInUser: Unable to get secrets by workspace id and env name") - } - - secrets = append(secrets, secretsFromAPI...) + serviceTokenDetails, err := api.CallGetServiceTokenDetailsV2(httpClient) + if err != nil { + return nil, fmt.Errorf("unable to get service token details. [err=%v]", err) } - return secrets, nil + encryptedSecrets, err := api.CallGetSecretsV2(httpClient, api.GetEncryptedSecretsV2Request{ + WorkspaceId: serviceTokenDetails.Workspace, + Environment: serviceTokenDetails.Environment, + }) + + if err != nil { + return nil, err + } + + decodedSymmetricEncryptionDetails, err := GetBase64DecodedSymmetricEncryptionDetails(serviceTokenParts[3], serviceTokenDetails.EncryptedKey, serviceTokenDetails.Iv, serviceTokenDetails.Tag) + if err != nil { + return nil, fmt.Errorf("unable to decode symmetric encryption details [err=%v]", err) + } + + plainTextWorkspaceKey, err := crypto.DecryptSymmetric([]byte(serviceTokenParts[3]), decodedSymmetricEncryptionDetails.Cipher, decodedSymmetricEncryptionDetails.Tag, decodedSymmetricEncryptionDetails.IV) + if err != nil { + return nil, fmt.Errorf("unable to decrypt the required workspace key") + } + + plainTextSecrets, err := GetPlainTextSecrets(plainTextWorkspaceKey, encryptedSecrets) + if err != nil { + return nil, fmt.Errorf("unable to decrypt your secrets [err=%v]", err) + } + + return plainTextSecrets, nil } -func GetSecretsFromAPIUsingInfisicalToken(infisicalToken string, envName string, projectId string) ([]models.SingleEnvironmentVariable, error) { - if infisicalToken == "" || projectId == "" || envName == "" { - return nil, errors.New("infisical token, project id and or environment name cannot be empty") - } - splitToken := strings.Split(infisicalToken, ",") - JTWToken := splitToken[0] - temPrivateKey := splitToken[1] - - // create http client - httpClient := resty.New(). - SetAuthToken(JTWToken). +func GetPlainTextSecretsViaJTW(JTWToken string, receiversPrivateKey string, workspaceId string, environmentName string) ([]models.SingleEnvironmentVariable, error) { + httpClient := resty.New() + httpClient.SetAuthToken(JTWToken). SetHeader("Accept", "application/json") - var pullSecretsByInfisicalTokenResponse models.PullSecretsByInfisicalTokenResponse - response, err := httpClient. - R(). - SetQueryParam("environment", envName). - SetQueryParam("channel", "cli"). - SetResult(&pullSecretsByInfisicalTokenResponse). - Get(fmt.Sprintf("%v/v1/secret/%v/service-token", INFISICAL_URL, projectId)) + request := api.GetEncryptedWorkspaceKeyRequest{ + WorkspaceId: workspaceId, + } + + workspaceKeyResponse, err := api.CallGetEncryptedWorkspaceKey(httpClient, request) + if err != nil { + return nil, fmt.Errorf("unable to get your encrypted workspace key. [err=%v]", err) + } + + encryptedWorkspaceKey, _ := base64.StdEncoding.DecodeString(workspaceKeyResponse.EncryptedKey) + encryptedWorkspaceKeySenderPublicKey, _ := base64.StdEncoding.DecodeString(workspaceKeyResponse.Sender.PublicKey) + encryptedWorkspaceKeyNonce, _ := base64.StdEncoding.DecodeString(workspaceKeyResponse.Nonce) + currentUsersPrivateKey, _ := base64.StdEncoding.DecodeString(receiversPrivateKey) + plainTextWorkspaceKey := crypto.DecryptAsymmetric(encryptedWorkspaceKey, encryptedWorkspaceKeyNonce, encryptedWorkspaceKeySenderPublicKey, currentUsersPrivateKey) + + encryptedSecrets, err := api.CallGetSecretsV2(httpClient, api.GetEncryptedSecretsV2Request{ + WorkspaceId: workspaceId, + Environment: environmentName, + }) if err != nil { return nil, err } - if response.StatusCode() > 299 { - return nil, fmt.Errorf(response.Status()) - } - - // Get workspace key - workspaceKey, err := base64.StdEncoding.DecodeString(pullSecretsByInfisicalTokenResponse.Key.EncryptedKey) + plainTextSecrets, err := GetPlainTextSecrets(plainTextWorkspaceKey, encryptedSecrets) if err != nil { - return nil, err + return nil, fmt.Errorf("unable to decrypt your secrets [err=%v]", err) } - nonce, err := base64.StdEncoding.DecodeString(pullSecretsByInfisicalTokenResponse.Key.Nonce) - if err != nil { - return nil, err - } - - senderPublicKey, err := base64.StdEncoding.DecodeString(pullSecretsByInfisicalTokenResponse.Key.Sender.PublicKey) - if err != nil { - return nil, err - } - - currentUsersPrivateKey, err := base64.StdEncoding.DecodeString(temPrivateKey) - if err != nil { - return nil, err - } - - workspaceKeyInBytes, _ := box.Open(nil, workspaceKey, (*[24]byte)(nonce), (*[32]byte)(senderPublicKey), (*[32]byte)(currentUsersPrivateKey)) - var listOfEnv []models.SingleEnvironmentVariable - - for _, secret := range pullSecretsByInfisicalTokenResponse.Secrets { - key_iv, _ := base64.StdEncoding.DecodeString(secret.SecretKey.Iv) - key_tag, _ := base64.StdEncoding.DecodeString(secret.SecretKey.Tag) - key_ciphertext, _ := base64.StdEncoding.DecodeString(secret.SecretKey.Ciphertext) - - plainTextKey, err := DecryptSymmetric(workspaceKeyInBytes, key_ciphertext, key_tag, key_iv) - if err != nil { - return nil, err - } - - value_iv, _ := base64.StdEncoding.DecodeString(secret.SecretValue.Iv) - value_tag, _ := base64.StdEncoding.DecodeString(secret.SecretValue.Tag) - value_ciphertext, _ := base64.StdEncoding.DecodeString(secret.SecretValue.Ciphertext) - - plainTextValue, err := DecryptSymmetric(workspaceKeyInBytes, value_ciphertext, value_tag, value_iv) - if err != nil { - return nil, err - } - - env := models.SingleEnvironmentVariable{ - Key: string(plainTextKey), - Value: string(plainTextValue), - } - - listOfEnv = append(listOfEnv, env) - } - - return listOfEnv, nil + return plainTextSecrets, nil } -func GetAllEnvironmentVariables(projectId string, envName string) ([]models.SingleEnvironmentVariable, error) { +func GetAllEnvironmentVariables(envName string) ([]models.SingleEnvironmentVariable, error) { infisicalToken := os.Getenv(INFISICAL_TOKEN_NAME) if infisicalToken == "" { - hasUserLoggedInbefore, loggedInUserEmail, err := IsUserLoggedIn() + RequireLocalWorkspaceFile() + RequireLogin() + log.Debug("Trying to fetch secrets using logged in details") + + loggedInUserDetails, err := GetCurrentLoggedInUserDetails() if err != nil { - log.Info("Unexpected issue occurred while checking login status. To see more details, add flag --debug") - log.Debugln(err) return nil, err } - if !hasUserLoggedInbefore { - log.Infoln("No logged in user. To login, please run command [infisical login]") - return nil, fmt.Errorf("user not logged in") - } - - userCreds, err := GetUserCredsFromKeyRing(loggedInUserEmail) + workspaceFile, err := GetWorkSpaceFromFile() if err != nil { - log.Infoln("Unable to get user creds from key ring") - log.Debug(err) return nil, err } - workspaceConfigs, err := GetAllWorkSpaceConfigsStartingFromCurrentPath() - if err != nil { - return nil, fmt.Errorf("unable to check if you have a %s file in your current directory", INFISICAL_WORKSPACE_CONFIG_FILE_NAME) - } - - if len(workspaceConfigs) == 0 { - log.Infoln("Your local project is not connected to a Infisical project yet. Run command [infisical init]") - return nil, fmt.Errorf("project not initialized") - } - - envsFromApi, err := GetSecretsFromAPIUsingCurrentLoggedInUser(envName, userCreds) - if err != nil { - log.Errorln("Something went wrong when pulling secrets using your logged in credentials. If the issue persists, double check your project id/try logging in again.") - log.Debugln(err) - return nil, err - } - - return envsFromApi, nil + secrets, err := GetPlainTextSecretsViaJTW(loggedInUserDetails.UserCredentials.JTWToken, loggedInUserDetails.UserCredentials.PrivateKey, workspaceFile.WorkspaceId, envName) + return secrets, err } else { - envsFromApi, err := GetSecretsFromAPIUsingInfisicalToken(infisicalToken, envName, projectId) - if err != nil { - log.Errorln("Something went wrong when pulling secrets using your Infisical token. Double check the token, project id or environment name (dev, prod, ect.)") - log.Debugln(err) - return nil, err - } - - return envsFromApi, nil + log.Debug("Trying to fetch secrets using service token") + return GetPlainTextSecretsViaServiceToken(infisicalToken) } } -func GetWorkSpacesFromAPI(userCreds models.UserCredentials) (workspaces []models.Workspace, err error) { - // create http client - httpClient := resty.New(). - SetAuthToken(userCreds.JTWToken). - SetHeader("Accept", "application/json") - - var getWorkSpacesResponse models.GetWorkSpacesResponse - response, err := httpClient. - R(). - SetResult(&getWorkSpacesResponse). - Get(fmt.Sprintf("%v/v1/workspace", INFISICAL_URL)) - - if err != nil { - return nil, err - } - - if response.StatusCode() > 299 { - return nil, fmt.Errorf("ops, unsuccessful response code. [response=%v]", response) - } - - return getWorkSpacesResponse.Workspaces, nil -} - func getExpandedEnvVariable(secrets []models.SingleEnvironmentVariable, variableWeAreLookingFor string, hashMapOfCompleteVariables map[string]string, hashMapOfSelfRefs map[string]string) string { if value, found := hashMapOfCompleteVariables[variableWeAreLookingFor]; found { return value @@ -335,9 +187,111 @@ func SubstituteSecrets(secrets []models.SingleEnvironmentVariable) []models.Sing expandedSecrets = append(expandedSecrets, models.SingleEnvironmentVariable{ Key: secret.Key, Value: expandedVariable, + Type: secret.Type, }) } return expandedSecrets } + +func OverrideSecrets(secrets []models.SingleEnvironmentVariable, secretType string) []models.SingleEnvironmentVariable { + personalSecrets := make(map[string]models.SingleEnvironmentVariable) + sharedSecrets := make(map[string]models.SingleEnvironmentVariable) + secretsToReturn := []models.SingleEnvironmentVariable{} + secretsToReturnMap := make(map[string]models.SingleEnvironmentVariable) + + for _, secret := range secrets { + if secret.Type == PERSONAL_SECRET_TYPE_NAME { + personalSecrets[secret.Key] = secret + } + if secret.Type == SHARED_SECRET_TYPE_NAME { + sharedSecrets[secret.Key] = secret + } + } + + if secretType == PERSONAL_SECRET_TYPE_NAME { + for _, secret := range secrets { + if personalSecret, exists := personalSecrets[secret.Key]; exists { + secretsToReturnMap[secret.Key] = personalSecret + } else { + if _, exists = secretsToReturnMap[secret.Key]; !exists { + secretsToReturnMap[secret.Key] = secret + } + } + } + } else if secretType == SHARED_SECRET_TYPE_NAME { + for _, secret := range secrets { + if sharedSecret, exists := sharedSecrets[secret.Key]; exists { + secretsToReturnMap[secret.Key] = sharedSecret + } else { + if _, exists := secretsToReturnMap[secret.Key]; !exists { + secretsToReturnMap[secret.Key] = secret + } + } + } + } + + for _, secret := range secretsToReturnMap { + secretsToReturn = append(secretsToReturn, secret) + } + return secretsToReturn +} + +func GetPlainTextSecrets(key []byte, encryptedSecrets api.GetEncryptedSecretsV2Response) ([]models.SingleEnvironmentVariable, error) { + plainTextSecrets := []models.SingleEnvironmentVariable{} + for _, secret := range encryptedSecrets.Secrets { + // Decrypt key + key_iv, err := base64.StdEncoding.DecodeString(secret.SecretKeyIV) + if err != nil { + return nil, fmt.Errorf("unable to decode secret IV for secret key") + } + + key_tag, err := base64.StdEncoding.DecodeString(secret.SecretKeyTag) + if err != nil { + return nil, fmt.Errorf("unable to decode secret authentication tag for secret key") + } + + key_ciphertext, err := base64.StdEncoding.DecodeString(secret.SecretKeyCiphertext) + if err != nil { + return nil, fmt.Errorf("unable to decode secret cipher text for secret key") + } + + plainTextKey, err := crypto.DecryptSymmetric(key, key_ciphertext, key_tag, key_iv) + if err != nil { + return nil, fmt.Errorf("unable to symmetrically decrypt secret key") + } + + // Decrypt value + value_iv, err := base64.StdEncoding.DecodeString(secret.SecretValueIV) + if err != nil { + return nil, fmt.Errorf("unable to decode secret IV for secret value") + } + + value_tag, err := base64.StdEncoding.DecodeString(secret.SecretValueTag) + if err != nil { + return nil, fmt.Errorf("unable to decode secret authentication tag for secret value") + } + + value_ciphertext, _ := base64.StdEncoding.DecodeString(secret.SecretValueCiphertext) + if err != nil { + return nil, fmt.Errorf("unable to decode secret cipher text for secret key") + } + + plainTextValue, err := crypto.DecryptSymmetric(key, value_ciphertext, value_tag, value_iv) + if err != nil { + return nil, fmt.Errorf("unable to symmetrically decrypt secret value") + } + + plainTextSecret := models.SingleEnvironmentVariable{ + Key: string(plainTextKey), + Value: string(plainTextValue), + Type: string(secret.Type), + ID: secret.ID, + } + + plainTextSecrets = append(plainTextSecrets, plainTextSecret) + } + + return plainTextSecrets, nil +} diff --git a/cli/packages/util/vault.go b/cli/packages/util/vault.go new file mode 100644 index 000000000..7e4ce1b31 --- /dev/null +++ b/cli/packages/util/vault.go @@ -0,0 +1,70 @@ +package util + +import ( + "fmt" + "os" + + "github.com/99designs/keyring" + "golang.org/x/term" +) + +func GetCurrentVaultBackend() (keyring.BackendType, error) { + configFile, err := GetConfigFile() + if err != nil { + return "", fmt.Errorf("getCurrentVaultBackend: unable to get config file [err=%s]", err) + } + + if configFile.VaultBackendType == "" { + return keyring.AvailableBackends()[0], nil + } + + return configFile.VaultBackendType, nil +} + +func GetKeyRing() (keyring.Keyring, error) { + currentVaultBackend, err := GetCurrentVaultBackend() + if err != nil { + return nil, fmt.Errorf("GetKeyRing: unable to get the current vault backend, [err=%s]", err) + } + + keyringInstanceConfig := keyring.Config{ + FilePasswordFunc: fileKeyringPassphrasePrompt, + ServiceName: KEYRING_SERVICE_NAME, + LibSecretCollectionName: KEYRING_SERVICE_NAME, + KWalletAppID: KEYRING_SERVICE_NAME, + KWalletFolder: KEYRING_SERVICE_NAME, + KeychainName: "login", // default so user will not be prompted + KeychainTrustApplication: true, + WinCredPrefix: KEYRING_SERVICE_NAME, + FileDir: fmt.Sprintf("~/%s-file-vault", KEYRING_SERVICE_NAME), + KeychainAccessibleWhenUnlocked: true, + } + + // if the user explicitly sets a vault backend, then only use that + if currentVaultBackend != "" { + keyringInstanceConfig.AllowedBackends = []keyring.BackendType{keyring.BackendType(currentVaultBackend)} + } + + keyringInstance, err := keyring.Open(keyringInstanceConfig) + if err != nil { + return nil, fmt.Errorf("GetKeyRing: Unable to create instance of Keyring because of [err=%s]", err) + } + + return keyringInstance, nil +} + +func fileKeyringPassphrasePrompt(prompt string) (string, error) { + if password, ok := os.LookupEnv("INFISICAL_VAULT_FILE_PASSPHRASE"); ok { + return password, nil + } else { + fmt.Println("You may set the `INFISICAL_VAULT_FILE_PASSPHRASE` environment variable to avoid typing password") + } + + fmt.Fprintf(os.Stderr, "%s:", prompt) + b, err := term.ReadPassword(int(os.Stdin.Fd())) + if err != nil { + return "", err + } + fmt.Println("") + return string(b), nil +} diff --git a/cli/packages/visualize/secrets.go b/cli/packages/visualize/secrets.go new file mode 100644 index 000000000..e9ac5d297 --- /dev/null +++ b/cli/packages/visualize/secrets.go @@ -0,0 +1,14 @@ +package visualize + +import "github.com/Infisical/infisical-merge/packages/models" + +func PrintAllSecretDetails(secrets []models.SingleEnvironmentVariable) { + rows := [][]string{} + for _, secret := range secrets { + rows = append(rows, []string{secret.Key, secret.Value, secret.Type}) + } + + headers := []string{"SECRET NAME", "SECRET VALUE", "SECRET TYPE"} + + Table(headers, rows) +} diff --git a/cli/packages/visualize/visualize.go b/cli/packages/visualize/visualize.go new file mode 100644 index 000000000..5658197ee --- /dev/null +++ b/cli/packages/visualize/visualize.go @@ -0,0 +1,45 @@ +package visualize + +import ( + "os" + + "github.com/jedib0t/go-pretty/table" +) + +type TableOptions struct { + Title string +} + +// func GetDefaultTableOptions() TableOptions{ +// return TableOptions{ +// Title: "", +// } +// } + +// Given headers and rows, this function will print out a table +func Table(headers []string, rows [][]string) { + t := table.NewWriter() + t.SetOutputMirror(os.Stdout) + t.SetStyle(table.StyleLight) + + // t.SetTitle(tableOptions.Title) + t.Style().Options.DrawBorder = true + t.Style().Options.SeparateHeader = true + t.Style().Options.SeparateColumns = true + + tableHeaders := table.Row{} + for _, header := range headers { + tableHeaders = append(tableHeaders, header) + } + + t.AppendHeader(tableHeaders) + for _, row := range rows { + tableRow := table.Row{} + for _, val := range row { + tableRow = append(tableRow, val) + } + t.AppendRow(tableRow) + } + + t.Render() +} diff --git a/cli/scripts/completions.sh b/cli/scripts/completions.sh new file mode 100755 index 000000000..6e69a1508 --- /dev/null +++ b/cli/scripts/completions.sh @@ -0,0 +1,8 @@ +#!/bin/sh +set -e +rm -rf completions +mkdir completions +cd cli +for sh in bash zsh fish; do + go run . completion "$sh" > "../completions/infisical.$sh" +done \ No newline at end of file diff --git a/cli/scripts/manpages.sh b/cli/scripts/manpages.sh new file mode 100755 index 000000000..db7e5c1b5 --- /dev/null +++ b/cli/scripts/manpages.sh @@ -0,0 +1,6 @@ +#!/bin/sh +set -e +rm -rf manpages +mkdir manpages +cd cli +go run . man | gzip -c > "../manpages/infisical.1.gz" \ No newline at end of file diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index 623462d5b..007884694 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -28,6 +28,8 @@ services: - ./backend/src:/app/src - ./backend/nodemon.json:/app/nodemon.json - /app/node_modules + - ./backend/api-documentation.json:/app/api-documentation.json + - ./backend/swagger.ts:/app/swagger.ts command: npm run dev env_file: .env environment: @@ -44,14 +46,15 @@ services: context: ./frontend dockerfile: Dockerfile.dev volumes: - - ./frontend/pages:/app/pages + - ./frontend/src:/app/src/ # mounted whole src to avoid missing reload on new files - ./frontend/public:/app/public - - ./frontend/styles:/app/styles - - ./frontend/components:/app/components + - ./frontend/next-i18next.config.js:/app/next-i18next.config.js env_file: .env environment: - NEXT_PUBLIC_ENV=development + - INFISICAL_TELEMETRY_ENABLED=${TELEMETRY_ENABLED} - NEXT_PUBLIC_STRIPE_PRODUCT_PRO=${STRIPE_PRODUCT_PRO} + - NEXT_PUBLIC_STRIPE_PRODUCT_TEAM=${STRIPE_PRODUCT_TEAM} - NEXT_PUBLIC_STRIPE_PRODUCT_STARTER=${STRIPE_PRODUCT_STARTER} networks: - infisical-dev @@ -87,7 +90,7 @@ services: smtp-server: container_name: infisical-dev-smtp-server - image: mailhog/mailhog + image: lytrax/mailhog:latest # https://github.com/mailhog/MailHog/issues/353#issuecomment-821137362 restart: always logging: driver: 'none' # disable saving logs diff --git a/docker-compose.yml b/docker-compose.yml index bd9022cef..6143695f5 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -40,6 +40,7 @@ services: # - NEXT_PUBLIC_POSTHOG_API_KEY=${POSTHOG_PROJECT_API_KEY} - INFISICAL_TELEMETRY_ENABLED=${TELEMETRY_ENABLED} - NEXT_PUBLIC_STRIPE_PRODUCT_PRO=${STRIPE_PRODUCT_PRO} + - NEXT_PUBLIC_STRIPE_PRODUCT_TEAM=${STRIPE_PRODUCT_TEAM} - NEXT_PUBLIC_STRIPE_PRODUCT_STARTER=${STRIPE_PRODUCT_STARTER} networks: - infisical diff --git a/docs/api-reference/endpoints/organizations/delete-membership.mdx b/docs/api-reference/endpoints/organizations/delete-membership.mdx new file mode 100644 index 000000000..d9862e854 --- /dev/null +++ b/docs/api-reference/endpoints/organizations/delete-membership.mdx @@ -0,0 +1,4 @@ +--- +title: "Delete Membership" +openapi: "DELETE /api/v2/organizations/{organizationId}/memberships/{membershipId}" +--- diff --git a/docs/api-reference/endpoints/organizations/memberships.mdx b/docs/api-reference/endpoints/organizations/memberships.mdx new file mode 100644 index 000000000..b4b6f3d33 --- /dev/null +++ b/docs/api-reference/endpoints/organizations/memberships.mdx @@ -0,0 +1,4 @@ +--- +title: "Get Memberships" +openapi: "GET /api/v2/organizations/{organizationId}/memberships" +--- diff --git a/docs/api-reference/endpoints/organizations/update-membership.mdx b/docs/api-reference/endpoints/organizations/update-membership.mdx new file mode 100644 index 000000000..1654d59c2 --- /dev/null +++ b/docs/api-reference/endpoints/organizations/update-membership.mdx @@ -0,0 +1,4 @@ +--- +title: "Update Membership" +openapi: "PATCH /api/v2/organizations/{organizationId}/memberships/{membershipId}" +--- diff --git a/docs/api-reference/endpoints/organizations/workspaces.mdx b/docs/api-reference/endpoints/organizations/workspaces.mdx new file mode 100644 index 000000000..0950a84e0 --- /dev/null +++ b/docs/api-reference/endpoints/organizations/workspaces.mdx @@ -0,0 +1,4 @@ +--- +title: "Get Projects" +openapi: "GET /api/v2/organizations/{organizationId}/workspaces" +--- diff --git a/docs/api-reference/endpoints/secrets/create.mdx b/docs/api-reference/endpoints/secrets/create.mdx new file mode 100644 index 000000000..2fba642a7 --- /dev/null +++ b/docs/api-reference/endpoints/secrets/create.mdx @@ -0,0 +1,11 @@ +--- +title: "Create" +openapi: "POST /api/v2/secrets/" +--- + + + Using this route requires understanding Infisical's system and cryptography. + It may be helpful to read through the + [introduction](/api-reference/overview/introduction) and [guide for creating + secrets](/api-reference/overview/examples/create-secrets). + diff --git a/docs/api-reference/endpoints/secrets/delete.mdx b/docs/api-reference/endpoints/secrets/delete.mdx new file mode 100644 index 000000000..af87e7120 --- /dev/null +++ b/docs/api-reference/endpoints/secrets/delete.mdx @@ -0,0 +1,4 @@ +--- +title: "Delete" +openapi: "DELETE /api/v2/secrets/" +--- diff --git a/docs/api-reference/endpoints/secrets/read.mdx b/docs/api-reference/endpoints/secrets/read.mdx new file mode 100644 index 000000000..bc30ec8f2 --- /dev/null +++ b/docs/api-reference/endpoints/secrets/read.mdx @@ -0,0 +1,11 @@ +--- +title: "Retrieve" +openapi: "GET /api/v2/secrets/" +--- + + + Using this route requires understanding Infisical's system and cryptography. + It may be helpful to read through the + [introduction](/api-reference/overview/introduction) and [guide for retrieving + secrets](/api-reference/overview/examples/retrieve-secrets). + diff --git a/docs/api-reference/endpoints/secrets/rollback-version.mdx b/docs/api-reference/endpoints/secrets/rollback-version.mdx new file mode 100644 index 000000000..dff577fe1 --- /dev/null +++ b/docs/api-reference/endpoints/secrets/rollback-version.mdx @@ -0,0 +1,4 @@ +--- +title: "Roll Back to Version" +openapi: "POST /api/v1/secret/{secretId}/secret-versions/rollback" +--- diff --git a/docs/api-reference/endpoints/secrets/update.mdx b/docs/api-reference/endpoints/secrets/update.mdx new file mode 100644 index 000000000..c77a9de12 --- /dev/null +++ b/docs/api-reference/endpoints/secrets/update.mdx @@ -0,0 +1,11 @@ +--- +title: "Update" +openapi: "PATCH /api/v2/secrets/" +--- + + + Using this route requires understanding Infisical's system and cryptography. + It may be helpful to read through the + [introduction](/api-reference/overview/introduction) and [guide for updating + secrets](/api-reference/overview/examples/update-secrets). + diff --git a/docs/api-reference/endpoints/secrets/versions.mdx b/docs/api-reference/endpoints/secrets/versions.mdx new file mode 100644 index 000000000..e8693684c --- /dev/null +++ b/docs/api-reference/endpoints/secrets/versions.mdx @@ -0,0 +1,4 @@ +--- +title: "Get Versions" +openapi: "GET /api/v1/secret/{secretId}/secret-versions" +--- diff --git a/docs/api-reference/endpoints/users/me.mdx b/docs/api-reference/endpoints/users/me.mdx new file mode 100644 index 000000000..9dab56dfd --- /dev/null +++ b/docs/api-reference/endpoints/users/me.mdx @@ -0,0 +1,4 @@ +--- +title: "Get My User" +openapi: "GET /api/v2/users/me" +--- diff --git a/docs/api-reference/endpoints/users/my-organizations.mdx b/docs/api-reference/endpoints/users/my-organizations.mdx new file mode 100644 index 000000000..d1ced8124 --- /dev/null +++ b/docs/api-reference/endpoints/users/my-organizations.mdx @@ -0,0 +1,4 @@ +--- +title: "Get My Organizations" +openapi: "GET /api/v2/users/me/organizations" +--- diff --git a/docs/api-reference/endpoints/workspaces/delete-membership.mdx b/docs/api-reference/endpoints/workspaces/delete-membership.mdx new file mode 100644 index 000000000..826eafa83 --- /dev/null +++ b/docs/api-reference/endpoints/workspaces/delete-membership.mdx @@ -0,0 +1,4 @@ +--- +title: "Delete Membership" +openapi: "DELETE /api/v2/workspace/{workspaceId}/memberships/{membershipId}" +--- diff --git a/docs/api-reference/endpoints/workspaces/logs.mdx b/docs/api-reference/endpoints/workspaces/logs.mdx new file mode 100644 index 000000000..d5921c1c0 --- /dev/null +++ b/docs/api-reference/endpoints/workspaces/logs.mdx @@ -0,0 +1,4 @@ +--- +title: "Get Logs" +openapi: "GET /api/v1/workspace/{workspaceId}/logs" +--- diff --git a/docs/api-reference/endpoints/workspaces/memberships.mdx b/docs/api-reference/endpoints/workspaces/memberships.mdx new file mode 100644 index 000000000..38b86d616 --- /dev/null +++ b/docs/api-reference/endpoints/workspaces/memberships.mdx @@ -0,0 +1,4 @@ +--- +title: "Get Memberships" +openapi: "GET /api/v2/workspace/{workspaceId}/memberships" +--- diff --git a/docs/api-reference/endpoints/workspaces/rollback-snapshot.mdx b/docs/api-reference/endpoints/workspaces/rollback-snapshot.mdx new file mode 100644 index 000000000..8b648a400 --- /dev/null +++ b/docs/api-reference/endpoints/workspaces/rollback-snapshot.mdx @@ -0,0 +1,4 @@ +--- +title: "Roll Back to Snapshot" +openapi: "POST /api/v1/workspace/{workspaceId}/secret-snapshots/rollback" +--- diff --git a/docs/api-reference/endpoints/workspaces/secret-snapshots.mdx b/docs/api-reference/endpoints/workspaces/secret-snapshots.mdx new file mode 100644 index 000000000..2d645d4d0 --- /dev/null +++ b/docs/api-reference/endpoints/workspaces/secret-snapshots.mdx @@ -0,0 +1,4 @@ +--- +title: "Get Snapshots" +openapi: "GET /api/v1/workspace/{workspaceId}/secret-snapshots" +--- diff --git a/docs/api-reference/endpoints/workspaces/update-membership.mdx b/docs/api-reference/endpoints/workspaces/update-membership.mdx new file mode 100644 index 000000000..367793847 --- /dev/null +++ b/docs/api-reference/endpoints/workspaces/update-membership.mdx @@ -0,0 +1,4 @@ +--- +title: "Update Membership" +openapi: "PATCH /api/v2/workspace/{workspaceId}/memberships/{membershipId}" +--- diff --git a/docs/api-reference/endpoints/workspaces/workspace-key.mdx b/docs/api-reference/endpoints/workspaces/workspace-key.mdx new file mode 100644 index 000000000..05313eb8f --- /dev/null +++ b/docs/api-reference/endpoints/workspaces/workspace-key.mdx @@ -0,0 +1,4 @@ +--- +title: "Get Key" +openapi: "GET /api/v2/workspace/{workspaceId}/encrypted-key" +--- diff --git a/docs/api-reference/overview/authentication.mdx b/docs/api-reference/overview/authentication.mdx new file mode 100644 index 000000000..9c155a96a --- /dev/null +++ b/docs/api-reference/overview/authentication.mdx @@ -0,0 +1,15 @@ +--- +title: "Authentication" +--- + +To authenticate requests with Infisical, you must include an API key in the `X-API-KEY` header of HTTP requests made to the platform. You can obtain an API key in User Settings > API Keys + +![API key dashboard](../../images/api-key-dashboard.png) +![API key in personal settings](../../images/api-key-settings.png) +![Adding an API key](../../images/api-key-add.png) + + + It's important to keep your API key secure, as it grants access to your + secrets in Infisical. For added security, set a reasonable expiration time and + rotate your API key on a regular basis. + diff --git a/docs/api-reference/overview/examples/create-secrets.mdx b/docs/api-reference/overview/examples/create-secrets.mdx new file mode 100644 index 000000000..319bd9d46 --- /dev/null +++ b/docs/api-reference/overview/examples/create-secrets.mdx @@ -0,0 +1,152 @@ +--- +title: "Create secrets" +--- + +In this example, we demonstrate how to add secrets to a project and environment. + +Prerequisites: + +- Set up and add envars to [Infisical Cloud](https://app.infisical.com) +- Grasp a basic understanding of the system and its underlying cryptography [here](/api-reference/overview/introduction). + +## Flow + +1. [Get your (encrypted) private key](/api-reference/endpoints/users/me). +2. Decrypt your (encrypted) private key with your password. +3. [Get the (encrypted) project key for the project.](/api-reference/endpoints/workspaces/workspace-key) +4. Decrypt the (encrypted) project key with your private key. +5. Encrypt your secret(s) with the project key. +6. [Send (encrypted) secret(s) to the Infical API](/api-reference/endpoints/secrets/create) + +## Example + +```js +const crypto = require('crypto'); +const axios = require('axios'); + +const ALGORITHM = 'aes-256-gcm'; +const BLOCK_SIZE_BYTES = 16; + +const encrypt = ( + text, + secret +) => { + const iv = crypto.randomBytes(BLOCK_SIZE_BYTES); + const cipher = crypto.createCipheriv(ALGORITHM, secret, iv); + + let ciphertext = cipher.update(text, 'utf8', 'base64'); + ciphertext += cipher.final('base64'); + return { + ciphertext, + iv: iv.toString('base64'), + tag: cipher.getAuthTag().toString('base64') + }; +} + +const decrypt = (ciphertext, iv, tag, secret) => { + const decipher = crypto.createDecipheriv( + ALGORITHM, + secret, + Buffer.from(iv, 'base64') + ); + decipher.setAuthTag(Buffer.from(tag, 'base64')); + + let cleartext = decipher.update(ciphertext, 'base64', 'utf8'); + cleartext += decipher.final('utf8'); + + return cleartext; +} + +const createSecrets = async () => { + const API_KEY = 'your_api_key'; + const PSWD = 'your_pswd'; + const WORKSPACE_ID = 'your_workspace_id'; + + const SECRET_KEY = 'SOME_KEY'; + const SECRET_VALUE = 'SOME_VALUE'; + + // 1. get (encrypted) private key + const user = await axios.get( + 'https://api.infisical.com/api/v2/users/me', { + headers: { + 'X-API-KEY': API_KEY + } + } + ); + + // 2. decrypt your (encrypted) private key with your password + const privateKey = decrypt({ + ciphertext: user.encryptedPrivateKey, + iv: user.iv, + tag: user.tag, + secret: PSWD.slice(0, 32).padStart(32, '0'); + }); + + // 3. get the (encrypted) project key for the project + const encryptedProjectKey = await axios.get( + `https://api.infisical.com/api/v2/workspace/${WORKSPACE_ID}`, { + headers: { + 'X-API-KEY': API_KEY + } + } + ); + + // 4. decrypt the project key with your private key + const projectKey = nacl.box.open( + util.decodeBase64(encryptedProjectKey), + util.decodeBase64(projectKey.nonce), + util.decodeBase64(projectKey.sender.publicKey), + util.decodeBase64(privateKey) + ); + + // 5. encrypt your secret(s) with the project key + const { + ciphertext: secretKeyCiphertext, + iv: secretKeyIV, + tag: secretKeyTag + } = encrypt(SECRET_KEY, projectKey); + + const { + ciphertext: secretValueCiphertext, + iv: secretValueIV, + tag: secretValueTag + } = encrypt(SECRET_VALUE, projectKey); + + const secret = { + secretKeyCiphertext, + secretKeyIV, + secretKeyTag, + secretValueCiphertext, + secretValueIV, + secretValueTag + } + + // 6. Send (encrypted) secret(s) to the Infisical API + await axios.post( + `https://api.infisical.com/api/v2/secrets`, + { + workspaceId: WORKSPACE_ID, + environment: 'dev', + secrets: secret + }, + { + headers: { + 'X-API-KEY': API_KEY + } + } + ); +} + +createSecrets(); +``` + + + This example uses [TweetNaCl.js](https://tweetnacl.js.org/#/), a port of + TweetNacl/Nacl, to perform asymmeric decryption of the project key but there + are ports of NaCl available in every major language. + + + It can be useful to perform steps 1-4 ahead of time and store away your + private key (and even project key) for later use. The Infisical CLI works by + securely storing your private key via your OS keyring. + diff --git a/docs/api-reference/overview/examples/delete-secrets.mdx b/docs/api-reference/overview/examples/delete-secrets.mdx new file mode 100644 index 000000000..c602cef7e --- /dev/null +++ b/docs/api-reference/overview/examples/delete-secrets.mdx @@ -0,0 +1,34 @@ +--- +title: "Delete secrets" +--- + +In this example, we demonstrate how to delete secrets + +Prerequisites: + +- Set up and add envars to [Infisical Cloud](https://app.infisical.com) +- Grasp a basic understanding of the system and its underlying cryptography [here](/api-reference/overview/introduction). + +## Example + +```js +const deleteSecrets = async () => { + const API_KEY = "your_api_key"; + const SECRET_ID = "ID"; // ID of secret to delete + + // 6. Send ID(s) of secret(s) to delete to the Infisical API + await axios.delete( + `https://api.infisical.com/api/v2/secrets`, + { + secretIds: SECRET_ID, + }, + { + headers: { + "X-API-KEY": API_KEY, + }, + } + ); +}; + +deleteSecrets(); +``` diff --git a/docs/api-reference/overview/examples/retrieve-secrets.mdx b/docs/api-reference/overview/examples/retrieve-secrets.mdx new file mode 100644 index 000000000..19d2d777b --- /dev/null +++ b/docs/api-reference/overview/examples/retrieve-secrets.mdx @@ -0,0 +1,142 @@ +--- +title: "Retrieve secrets" +--- + +In this example, we demonstrate how to retrieve secrets from a project and environment. + +Prerequisites: + +- Set up and add envars to [Infisical Cloud](https://app.infisical.com) +- Grasp a basic understanding of the system and its underlying cryptography [here](/api-reference/overview/introduction). + +## Flow + +1. [Get your (encrypted) private key.](/api-reference/endpoints/users/me) +2. Decrypt your (encrypted) private key with your password. +3. [Get the (encrypted) project key for the project.](/api-reference/endpoints/workspaces/workspace-key) +4. Decrypt the (encrypted) project key with your private key. +5. [Get secrets for a project and environment.](/api-reference/endpoints/secrets/read) +6. Decrypt the (encrypted) secrets + +## Example + +```js +const crypto = require('crypto'); +const axios = require('axios'); + +const ALGORITHM = 'aes-256-gcm'; +const BLOCK_SIZE_BYTES = 16; + +const encrypt = ( + text, + secret +) => { + const iv = crypto.randomBytes(BLOCK_SIZE_BYTES); + const cipher = crypto.createCipheriv(ALGORITHM, secret, iv); + + let ciphertext = cipher.update(text, 'utf8', 'base64'); + ciphertext += cipher.final('base64'); + return { + ciphertext, + iv: iv.toString('base64'), + tag: cipher.getAuthTag().toString('base64') + }; +} + +const decrypt = (ciphertext, iv, tag, secret) => { + const decipher = crypto.createDecipheriv( + ALGORITHM, + secret, + Buffer.from(iv, 'base64') + ); + decipher.setAuthTag(Buffer.from(tag, 'base64')); + + let cleartext = decipher.update(ciphertext, 'base64', 'utf8'); + cleartext += decipher.final('utf8'); + + return cleartext; +} + +const retrieveSecrets = async () => { + const API_KEY = 'your_api_key'; + const PSWD = 'your_pswd'; + const WORKSPACE_ID = 'your_workspace_id'; + + // 1. get (encrypted) private key + const user = await axios.get( + 'https://api.infisical.com/api/v2/users/me', { + headers: { + 'X-API-KEY': API_KEY + } + } + ); + + // 2. decrypt your (encrypted) private key with your password + const privateKey = decrypt({ + ciphertext: user.encryptedPrivateKey, + iv: user.iv, + tag: user.tag, + secret: PSWD.slice(0, 32).padStart(32, '0'); + }); + + // 3. get the (encrypted) project key for the project + const encryptedProjectKey = await axios.get( + `https://api.infisical.com/api/v2/workspace/${WORKSPACE_ID}`, { + headers: { + 'X-API-KEY': API_KEY + } + } + ); + + // 4. decrypt the project key with your private key + const projectKey = nacl.box.open( + util.decodeBase64(encryptedProjectKey), + util.decodeBase64(projectKey.nonce), + util.decodeBase64(projectKey.sender.publicKey), + util.decodeBase64(privateKey) + ); + + // 5. get (encrypted) secrets for a project and environment. + const encryptedSecrets = await axios.get( + 'https://api.infisical.com/api/v2/secrets', { + headers: { + 'X-API-KEY': API_KEY + } + } + ); + + // 6. decrypt the (encrypted) secrets + const secrets = encryptedSecrets.map((encryptedSecret) => { + const secretKey = decrypt({ + ciphertext: encryptedSecret.secretKeyCiphertext, + iv: encryptedSecret.secretKeyIV, + tag: encryptedSecret.secretKeyTag + secret: projectKey + }); + const secretValue = decrypt({ + ciphertext: encryptedSecret.secretValueCiphertext, + iv: encryptedSecret.secretValueIV, + tag: encryptedSecret.secretValueTag + secret: projectKey + }); + + return ({ + secretKey, + secretValue + }); + }); +} + +retrieveSecrets(); +``` + + + This example uses [TweetNaCl.js](https://tweetnacl.js.org/#/), a port of + TweetNacl/Nacl, to perform asymmeric decryption of the project key but there + are ports of NaCl available in every major language. + + + It can be useful to perform steps 1-4 ahead of time and store away your + private key (and even project key) for later use. The Infisical CLI works by + securely storing your private key via your OS keyring. + diff --git a/docs/api-reference/overview/examples/update-secrets.mdx b/docs/api-reference/overview/examples/update-secrets.mdx new file mode 100644 index 000000000..99e3530ee --- /dev/null +++ b/docs/api-reference/overview/examples/update-secrets.mdx @@ -0,0 +1,152 @@ +--- +title: "Update secrets" +--- + +In this example, we demonstrate how to update secrets + +Prerequisites: + +- Set up and add envars to [Infisical Cloud](https://app.infisical.com) +- Grasp a basic understanding of the system and its underlying cryptography [here](/api-reference/overview/introduction). + +## Flow + +1. [Get your (encrypted) private key.](/api-reference/endpoints/users/me) +2. Decrypt your (encrypted) private key with your password. +3. [Get the (encrypted) project key for the project.](/api-reference/endpoints/workspaces/workspace-key) +4. Decrypt the (encrypted) project key with your private key. +5. Encrypt your secret(s) with the project key. +6. [Send (encrypted) updated secret(s) to the Infical API.](/api-reference/endpoints/secrets/update) + +## Example + +```js +const crypto = require('crypto'); +const axios = require('axios'); + +const ALGORITHM = 'aes-256-gcm'; +const BLOCK_SIZE_BYTES = 16; + +const encrypt = ( + text, + secret +) => { + const iv = crypto.randomBytes(BLOCK_SIZE_BYTES); + const cipher = crypto.createCipheriv(ALGORITHM, secret, iv); + + let ciphertext = cipher.update(text, 'utf8', 'base64'); + ciphertext += cipher.final('base64'); + return { + ciphertext, + iv: iv.toString('base64'), + tag: cipher.getAuthTag().toString('base64') + }; +} + +const decrypt = (ciphertext, iv, tag, secret) => { + const decipher = crypto.createDecipheriv( + ALGORITHM, + secret, + Buffer.from(iv, 'base64') + ); + decipher.setAuthTag(Buffer.from(tag, 'base64')); + + let cleartext = decipher.update(ciphertext, 'base64', 'utf8'); + cleartext += decipher.final('utf8'); + + return cleartext; +} + +const updateSecrets = async () => { + const API_KEY = 'your_api_key'; + const PSWD = 'your_pswd'; + const WORKSPACE_ID = 'your_workspace_id'; + + const SECRET_ID = 'ID' // ID of secret to update + const SECRET_KEY = 'SOME_KEY'; + const SECRET_VALUE = 'SOME_VALUE'; + + // 1. get (encrypted) private key + const user = await axios.get( + 'https://api.infisical.com/api/v2/users/me', { + headers: { + 'X-API-KEY': API_KEY + } + } + ); + + // 2. decrypt your (encrypted) private key with your password + const privateKey = decrypt({ + ciphertext: user.encryptedPrivateKey, + iv: user.iv, + tag: user.tag, + secret: PSWD.slice(0, 32).padStart(32, '0'); + }); + + // 3. get the (encrypted) project key for the project + const encryptedProjectKey = await axios.get( + `https://api.infisical.com/api/v2/workspace/${WORKSPACE_ID}`, { + headers: { + 'X-API-KEY': API_KEY + } + } + ); + + // 4. decrypt the project key with your private key + const projectKey = nacl.box.open( + util.decodeBase64(encryptedProjectKey), + util.decodeBase64(projectKey.nonce), + util.decodeBase64(projectKey.sender.publicKey), + util.decodeBase64(privateKey) + ); + + // 5. encrypt your secret(s) with the project key + const { + ciphertext: secretKeyCiphertext, + iv: secretKeyIV, + tag: secretKeyTag + } = encrypt(SECRET_KEY, projectKey); + + const { + ciphertext: secretValueCiphertext, + iv: secretValueIV, + tag: secretValueTag + } = encrypt(SECRET_VALUE, projectKey); + + const secret = { + id: SECRET_ID, + secretKeyCiphertext, + secretKeyIV, + secretKeyTag, + secretValueCiphertext, + secretValueIV, + secretValueTag + } + + // 6. Send (encrypted) secret(s) to the Infisical API + await axios.patch( + `https://api.infisical.com/api/v2/secrets`, + { + secrets: secret + }, + { + headers: { + 'X-API-KEY': API_KEY + } + } + ); +} + +updateSecrets(); +``` + + + This example uses [TweetNaCl.js](https://tweetnacl.js.org/#/), a port of + TweetNacl/Nacl, to perform asymmeric decryption of the project key but there + are ports of NaCl available in every major language. + + + It can be useful to perform steps 1-4 ahead of time and store away your + private key (and even project key) for later use. The Infisical CLI works by + securely storing your private key via your OS keyring. + diff --git a/docs/api-reference/overview/introduction.mdx b/docs/api-reference/overview/introduction.mdx new file mode 100644 index 000000000..9865a644a --- /dev/null +++ b/docs/api-reference/overview/introduction.mdx @@ -0,0 +1,27 @@ +--- +title: "Introduction" +--- + +Infisical's REST API provides users an alternative way to programmatically access and manage +secrets via HTTPS requests. This can be useful for automating tasks, such as +rotating credentials, or for integrating secret management into a larger system. + +With the REST API, users can create, read, update, and delete secrets, as well as manage access control, query audit logs, and more. + +## Concepts + +Using Infisical's API to manage secrets requires a basic understanding of the system and its underlying cryptography detailed [here](/security/overview). + +- Each user has a public/private key pair that is stored with the platform; private keys are encrypted locally by the user's password before being sent off to the server during the account signup process. +- Each (encrypted) secret belongs to a project and environment. +- Each project has an (encrypted) project key used to encrypt the secrets within that project; Infisical stores copies of the project key, for each member of that project, encrypted under each member's public key. +- Secrets are encrypted symmetrically by your copy of the project key belonging to the project containing. +- Infisical uses AES256-GCM and [TweetNaCl.js](https://tweetnacl.js.org/#/) for symmetric and asymmetric encryption/decryption operations. + + + Infisical's system requires that secrets be encrypted/decrypted on the + client-side to maintain E2EE. We strongly recommend you read up on the system + prior to using the Infisical API. The (opt-in) ability to retrieve secrets + back in decrypted format if you choose to share secrets with Infisical is on + our roadmap. + diff --git a/docs/api-reference/overview/usage.mdx b/docs/api-reference/overview/usage.mdx new file mode 100644 index 000000000..9f23080c7 --- /dev/null +++ b/docs/api-reference/overview/usage.mdx @@ -0,0 +1,18 @@ +--- +title: "Usage" +--- + +Prerequisites: + +- Set up and add envars to [Infisical Cloud](https://app.infisical.com) or your self-hosted instance. +- Obtain an API Key in your user settings to be included in requests to the Infisical API. + +Using Infisical's API to manage secrets requires a basic understanding of the system and its underlying cryptography detailed [here](/security/overview). + +## Concepts + +- Each user has a public/private key pair that is stored with the platform; private keys are encrypted locally by the user's password before being sent off to the server during the account signup process. +- Each (encrypted) secret belongs to a project and environment. +- Each project has an (encrypted) project key used to encrypt the secrets within that project; Infisical stores copies of the project key, for each member of that project, encrypted under each member's public key. +- Secrets are encrypted symmetrically by your copy of the project key belonging to the project containing. +- Infisical uses AES256-GCM and [TweetNaCl.js](https://tweetnacl.js.org/#/) for symmetric and asymmetric encryption/decryption operations. diff --git a/docs/cli/commands/commands.mdx b/docs/cli/commands/commands.mdx index acefdfa7e..78870defc 100644 --- a/docs/cli/commands/commands.mdx +++ b/docs/cli/commands/commands.mdx @@ -1,5 +1,6 @@ --- title: "Commands" +description: "Infisical CLI command overview" --- ## Commands @@ -9,7 +10,7 @@ title: "Commands" | `login` | Used to authenticate and set the logged in user. | | `init` | Used to link a local project to the platform. | | `run` | Used to inject envars from the platform into an application process. | - +| `vault` | Used to manage where your login credentials are stored at rest | ## Global options | Option | Description | diff --git a/docs/cli/commands/export.mdx b/docs/cli/commands/export.mdx index fd58868ff..d85057eba 100644 --- a/docs/cli/commands/export.mdx +++ b/docs/cli/commands/export.mdx @@ -1,5 +1,6 @@ --- title: "infisical export" +description: "Export Infisical secrets from CLI into different file formats" --- ```bash @@ -12,12 +13,12 @@ Export environment variables from the platform into a file format. ## Options -| Option | Description | Default value | -| ------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | ------------- | -| `--env` | Used to set the environment that secrets are pulled from. Accepted values: `dev`, `staging`, `test`, `prod` | `dev` | -| `--projectId` | Only required if injecting via the [service token method](../token). If you are not using service token, the project id will be automatically retrieved from the `.infisical.json` located at the root of your local project. | `None` | -| `--expand` | Parse shell parameter expansions in your secrets (e.g., `${DOMAIN}`) | `true` | -| `--format` | Format of the output file. Accepted values: `dotenv`, `csv` and `json` | `dotenv` | +| Option | Description | Default value | +| ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- | +| `--env` | Used to set the environment that secrets are pulled from. Accepted values: `dev`, `staging`, `test`, `prod` | `dev` | +| `--projectId` | Only required if injecting via the [service token method](../token). If you are not using service token, the project id will be automatically retrieved from the `.infisical.json` located at the root of your local project. | `None` | +| `--expand` | Parse shell parameter expansions in your secrets (e.g., `${DOMAIN}`) | `true` | +| `--format` | Format of the output file. Accepted values: `dotenv`, `dotenv-export`, `csv` and `json` | `dotenv` | ## Examples @@ -25,9 +26,16 @@ Export environment variables from the platform into a file format. # Export variables to a .env file infisical export > .env +# Export variables to a .env file (with export keyword) +infisical export --format=dotenv-export > .env + # Export variables to a CSV file infisical export --format=csv > secrets.csv # Export variables to a JSON file infisical export --format=json > secrets.json + +# Export variables to a YAML file +infisical export --format=yaml > secrets.yaml + ``` diff --git a/docs/cli/commands/init.mdx b/docs/cli/commands/init.mdx index 8d1c03061..d477541b8 100644 --- a/docs/cli/commands/init.mdx +++ b/docs/cli/commands/init.mdx @@ -1,5 +1,6 @@ --- title: "infisical init" +description: "Switch between Infisical projects within CLI" --- ```bash diff --git a/docs/cli/commands/login.mdx b/docs/cli/commands/login.mdx index 32c1bedba..36abaf94e 100644 --- a/docs/cli/commands/login.mdx +++ b/docs/cli/commands/login.mdx @@ -1,5 +1,6 @@ --- title: "infisical login" +description: "Login into Infisical from the CLI" --- ```bash @@ -7,7 +8,5 @@ infisical login ``` ## Description - -Verify a user and save credentials to the system keyring. - -To change the logged in user, run the command again to overwrite the previous login. +The CLI uses authentication to verify your identity. When you enter the correct email and password for your account, a token is generated and saved in your system Keyring to allow you to make future interactions with the CLI. +If you want to change where the login credentials are stored, visit the [vaults command](./vault) \ No newline at end of file diff --git a/docs/cli/commands/run.mdx b/docs/cli/commands/run.mdx index 7fb207612..a3f02cf44 100644 --- a/docs/cli/commands/run.mdx +++ b/docs/cli/commands/run.mdx @@ -1,10 +1,27 @@ --- title: "infisical run" +description: "The command that injects your secrets into local environment" --- -```bash -infisical run [options] -- [your application start command] -``` + + + ```bash + infisical run [options] -- [your application start command] + + # Example + infisical run [options] -- npm run dev + ``` + + + + ```bash + infisical run [options] --command [string command] + + # Example + infisical run [options] --command "npm run bootstrap && npm run dev start; other-bash-command" + ``` + + ## Description @@ -15,5 +32,6 @@ Inject environment variables from the platform into an application process. | Option | Description | Default value | | -------------- | ----------------------------------------------------------------------------------------------------------- | ------------- | | `--env` | Used to set the environment that secrets are pulled from. Accepted values: `dev`, `staging`, `test`, `prod` | `dev` | -| `--projectId` | Used to link a local project to the platform (required only if injecting via the service token method) | `None` | | `--expand` | Parse shell parameter expansions in your secrets (e.g., `${DOMAIN}`) | `true` | +| `--command` | Pass secrets into chained commands (e.g., `"first-command && second-command; more-commands..."`) | None | +| `--secret-overriding`| Prioritizes personal secrets with the same name over shared secrets | `true` | diff --git a/docs/cli/commands/secrets.mdx b/docs/cli/commands/secrets.mdx new file mode 100644 index 000000000..0556e1866 --- /dev/null +++ b/docs/cli/commands/secrets.mdx @@ -0,0 +1,112 @@ +--- +title: "infisical secrets" +description: "Perform CRUD operations with Infisical secrets" +--- + +``` +infisical secrets +``` + +## Description +This command enables you to perform CRUD (create, read, update, delete) operations on secrets within your Infisical project. With it, you can view, create, update, and delete secrets in your environment. + +### Sub-commands + + Use this command to print out all of the secrets in your project + + ``` + $ infisical secrets + + ## Example + $ infisical secrets + โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” + โ”‚ SECRET NAME โ”‚ SECRET VALUE โ”‚ SECRET TYPE โ”‚ + โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค + โ”‚ DOMAIN โ”‚ example.com โ”‚ shared โ”‚ + โ”‚ HASH โ”‚ jebhfbwe โ”‚ shared โ”‚ + โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ + ``` + + ### flags + + Parse shell parameter expansions in your secrets + + Default value: `true` + + + + Used to select the environment name on which actions should be taken on + + Default value: `dev` + + + + + + This command allows you selectively print the requested secrets by name + + ``` + $ infisical secrets get ... + + # Example + $ infisical secrets get DOMAIN + โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” + โ”‚ SECRET NAME โ”‚ SECRET VALUE โ”‚ SECRET TYPE โ”‚ + โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค + โ”‚ DOMAIN โ”‚ example.com โ”‚ shared โ”‚ + โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ + + ``` + + ### Flags + + Used to select the environment name on which actions should be taken on + + Default value: `dev` + + + + +This command allows you to set or update secrets in your environment. If the secret key provided already exists, its value will be updated with the new value. +If the secret key does not exist, a new secret will be created using both the key and value provided. + +``` +$ infisical secrets set ... + +## Example +$ infisical secrets set STRIPE_API_KEY=sjdgwkeudyjwe DOMAIN=example.com HASH=jebhfbwe +โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” +โ”‚ SECRET NAME โ”‚ SECRET VALUE โ”‚ STATUS โ”‚ +โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค +โ”‚ STRIPE_API_KEY โ”‚ sjdgwkeudyjwe โ”‚ SECRET VALUE UNCHANGED โ”‚ +โ”‚ DOMAIN โ”‚ example.com โ”‚ SECRET VALUE MODIFIED โ”‚ +โ”‚ HASH โ”‚ jebhfbwe โ”‚ SECRET CREATED โ”‚ +โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ +``` + + ### Flags + + Used to select the environment name on which actions should be taken on + + Default value: `dev` + + + + + This command allows you to delete secrets by their name(s). + + ``` + $ infisical secrets delete ... + + ## Example + $ infisical secrets delete STRIPE_API_KEY DOMAIN HASH + secret name(s) [STRIPE_API_KEY, DOMAIN, HASH] have been deleted from your project + ``` + + ### Flags + + Used to select the environment name on which actions should be taken on + + Default value: `dev` + + \ No newline at end of file diff --git a/docs/cli/commands/vault.mdx b/docs/cli/commands/vault.mdx new file mode 100644 index 000000000..2289c629c --- /dev/null +++ b/docs/cli/commands/vault.mdx @@ -0,0 +1,51 @@ +--- +title: "infisical vault" +description: "Change the vault type in Infisical" +--- + + + + ```bash + infisical vault + + # Example output + The following vaults are available on your system: + - keychain + - pass + - file + + You are currently using [keychain] vault to store your login credentials + ``` + + + + ```bash + infisical vault set + + # Example + infisical vault set keychain + ``` + + + + +## Description + +To ensure secure storage of your login credentials when using the CLI, Infisical stores login credentials securely in a system vault or encrypted text file with a passphrase known only by the user. + + + By default, the most appropriate vault is chosen to store your login credentials. + For example, if you are on macOS, KeyChain will be automatically selected. + +- [macOS Keychain](https://support.apple.com/en-au/guide/keychain-access/welcome/mac) +- [Windows Credential Manager](https://support.microsoft.com/en-au/help/4026814/windows-accessing-credential-manager) +- Secret Service ([Gnome Keyring](https://wiki.gnome.org/Projects/GnomeKeyring), [KWallet](https://kde.org/applications/system/org.kde.kwalletmanager5)) +- [KWallet](https://kde.org/applications/system/org.kde.kwalletmanager5) +- [Pass](https://www.passwordstore.org/) +- [KeyCtl]() +- Encrypted file (JWT) + + +To avoid constantly entering your passphrase when using the `file` vault type, set the `INFISICAL_VAULT_FILE_PASSPHRASE` environment variable with your password in your shell + + diff --git a/docs/cli/faq.mdx b/docs/cli/faq.mdx new file mode 100644 index 000000000..6a98d8dc3 --- /dev/null +++ b/docs/cli/faq.mdx @@ -0,0 +1,16 @@ +--- +title: "FAQ" +description: "Frequently Asked Questions about Infisical" +--- + +Frequently asked questions about the CLI can be found on this page. +If you can't find the answer you're looking for, please create an issue on our GitHub repository or join our Slack channel for additional support. + + +By default, the CLI will choose the most suitable store available on your system. +If you experience issues with the default store, you can switch to a different one. +If none of the available stores work for you, you can try using the `file` store type by running `infisical vault set file`, which should work in most cases. +If you are still experiencing trouble, please seek support. + +[Learn more about vault command](./commands/vault) + \ No newline at end of file diff --git a/docs/cli/overview.mdx b/docs/cli/overview.mdx index 144259023..18f2f1396 100644 --- a/docs/cli/overview.mdx +++ b/docs/cli/overview.mdx @@ -1,5 +1,6 @@ --- title: 'Install' +description: "Infisical's CLI is one of the best way to manage environments and secrets. Install it here" --- Prerequisite: Set up an account with [Infisical Cloud](https://app.infisical.com) or via a [self-hosted installation](/self-hosting/overview). @@ -16,7 +17,7 @@ The Infisical CLI provides a way to inject environment variables from the platfo brew install infisical/get-cli/infisical ``` - ## Updates + ### Updates ```bash brew upgrade infisical @@ -34,7 +35,7 @@ The Infisical CLI provides a way to inject environment variables from the platfo scoop install infisical ``` - ## Updates + ### Updates ```bash scoop update infisical @@ -88,11 +89,39 @@ The Infisical CLI provides a way to inject environment variables from the platfo sudo apt-get update && sudo apt-get install -y infisical ``` + + + Use the `yay` package manager to install from the [Arch User Repository](https://aur.archlinux.org/packages/infisical-bin) + + ```bash + yay -S infisical-bin + ``` + -## Log in to the Infisical CLI +### Log in to the Infisical CLI ```bash infisical login ``` + + +The CLI is set to connect to Infisical Cloud by default, but if you're running your own instance of Infisical, you can direct the CLI to it using one of the methods provided below. + +#### Export environment variable +You can point the CLI to the self hosted Infisical instance by exporting the environment variable `INFISICAL_API_URL` in your terminal. + +```bash +# Example +export INFISICAL_API_URL="https://your-self-hosted-infisical.com/api" +``` + +#### Set manually on every command +Another option to point the CLI to your self hosted Infisical instance is to set it via a flag on every command you run. + +```bash +# Example +infisical --domain="https://your-self-hosted-infisical.com/api" +``` + diff --git a/docs/cli/token.mdx b/docs/cli/token.mdx index 5b3d2fd6b..38acab208 100644 --- a/docs/cli/token.mdx +++ b/docs/cli/token.mdx @@ -1,5 +1,6 @@ --- title: "Infisical Token" +description: "How to use Infical service token within the CLI." --- Prerequisite: [Infisical Token and How to Generate One](../../getting-started/dashboard/token). diff --git a/docs/cli/usage.mdx b/docs/cli/usage.mdx index 4237f8154..6cb460874 100644 --- a/docs/cli/usage.mdx +++ b/docs/cli/usage.mdx @@ -1,13 +1,31 @@ --- title: "Usage" +description: "How to manage you secrets with Infisical's CLI?" --- Prerequisite: [Install the CLI](/cli/overview) +## Authenticate + + + To use the Infisical CLI in your development environment, you can run the command below. + This will allow you to access the features and functionality provided by the CLI. + + ```bash + infisical login + ``` + + + + To use Infisical CLI in environments where you cannot run the `infisical login` command, you can authenticate via a + Infisical Token instead. Learn more about [Infisical Token](../getting-started/dashboard/token). + + + ## Initialize Infisical for your project ```bash -# move to your project +# navigate to your project cd /path/to/project # initialize infisical @@ -21,13 +39,7 @@ infisical init infisical run -- [your application start command] ``` -Options you can specify: - -| Option | Description | Default value | -| ------------- | ----------------------------------------------------------------------------------------------------------- | ------------- | -| `--env` | Used to set the environment that secrets are pulled from. Accepted values: `dev`, `staging`, `test`, `prod` | `dev` | -| `--projectId` | Used to link a local project to the platform (required only if injecting via the service token method) | `None` | -| `--expand` | Parse shell parameter expansions in your secrets (e.g., `${DOMAIN}`) | `true` | +View all available options for `run` command [here](./commands/run) ## Examples: diff --git a/docs/contributing/FAQ.mdx b/docs/contributing/FAQ.mdx deleted file mode 100644 index 9f4f7aee9..000000000 --- a/docs/contributing/FAQ.mdx +++ /dev/null @@ -1,18 +0,0 @@ ---- -title: 'Frequently Asked Questions' -description: 'Have any questions? [Join our Slack community](https://join.slack.com/t/infisical-users/shared_invite/zt-1kdbk07ro-RtoyEt_9E~fyzGo_xQYP6g).' ---- - -## Problem with SMTP - -If you opt for actual SMTP server (not the local MailHog), you have to have the right environment variables set. - -You can normally populate `SMTP_USERNAME` and `SMTP_PASSWORD` with your usual login and password (you could also create a 'burner' email). Sometimes, there still are problems. - -You can go to your Gmail account settings > security and enable โ€œless secure appsโ€. This would allow Infisical to use your Gmail to send emails. - -If it still doesn't work, [this](https://stackoverflow.com/questions/72547853/unable-to-send-email-in-c-sharp-less-secure-app-access-not-longer-available/72553362#72553362) should help. - -## `MONGO_URL` issues - -Your `MONGO_URL` should be something like `mongodb://root:example@mongo:27017/?authSource=admin`. If you want to change it (not recommended), you should make sure that you keep this URL in line with `MONGO_USERNAME=root` and `MONGO_PASSWORD=example`. diff --git a/docs/contributing/code-of-conduct.mdx b/docs/contributing/code-of-conduct.mdx index 439b49ee7..b9f1a1b7e 100644 --- a/docs/contributing/code-of-conduct.mdx +++ b/docs/contributing/code-of-conduct.mdx @@ -1,6 +1,6 @@ --- title: "Code of Conduct" -description: "" +description: "What you should know before contributing to Infisical?" --- ## Our Pledge diff --git a/docs/contributing/developing.mdx b/docs/contributing/developing.mdx index 3be1a1b6b..64779587e 100644 --- a/docs/contributing/developing.mdx +++ b/docs/contributing/developing.mdx @@ -1,13 +1,12 @@ --- -title: 'Developing' +title: 'Local development' description: 'This guide will help you set up and run Infisical in development mode.' --- ## Clone the repo ```bash -# change location to the path you want Infisical to be installed -cd ~ +# navigate location to the path you want Infisical to be installed # clone the repo and cd to Infisical dir git clone https://github.com/Infisical/infisical @@ -16,80 +15,71 @@ cd infisical ## Set up environment variables -Before running the docker-compose we have to generate the .env file with the environment variables, you can create your own file or start with the -`.env.example` as an example guide. -Mandatory variables in the `.env` file: +Start by creating a .env file at the root of the Infisical directory then copy the contents of the file below into the .env file. -1. Keys and JWT variables + + ```env + # Keys + # Required key for platform encryption/decryption ops + ENCRYPTION_KEY=6c1fe4e407b8911c104518103505b218 -![image](https://user-images.githubusercontent.com/118568289/206791534-9c9d1431-e83d-49c0-8a54-b373ed0df820.png) + # JWT + # Required secrets to sign JWT tokens + JWT_SIGNUP_SECRET=3679e04ca949f914c03332aaaeba805a + JWT_REFRESH_SECRET=5f2f3c8f0159068dc2bbb3a652a716ff + JWT_AUTH_SECRET=4be6ba5602e0fa0ac6ac05c3cd4d247f + JWT_SERVICE_SECRET=f32f716d70a42c5703f4656015e76200 -The `.env.example` has these variables empty, you can self generate the `JWT and ENCRYPTION_KEY` with this [32-byte random hex strings generator](https://www.browserling.com/tools/random-hex). + # MongoDB + # Backend will connect to the MongoDB instance at connection string MONGO_URL which can either be a ref + # to the MongoDB container instance or Mongo Cloud + # Required + MONGO_URL=mongodb://root:example@mongo:27017/?authSource=admin -For the `PRIVATE_KEY and PUBLIC_KEY` you can use the ones shown in the screenshot: + # Optional credentials for MongoDB container instance and Mongo-Express + MONGO_USERNAME=root + MONGO_PASSWORD=example -``` -PRIVATE_KEY='oGVv5rThrpZ7WLgQW27chY1cXngr4wLQIZnGfSKgHPk=' -PUBLIC_KEY='ldr6JaC7AY+tun3omGLdE4SWpkJbtVBOI54KfUP53Xc=' -``` + # Website URL + # Required + SITE_URL=http://localhost:8080 -2. Mongo variables and site URL + # Mail/SMTP + SMTP_HOST='smtp-server' + SMTP_PORT='1025' + SMTP_NAME='local' + SMTP_USERNAME='team@infisical.com' + SMTP_PASSWORD= + ``` + -![image](https://user-images.githubusercontent.com/118568289/206792171-3376e3c6-c3ac-4d5d-8776-d78ee089b520.png) + + The pre-populated environment variable values above are meant to be used in development only. They should never be used in production. + -These variables are used to connect the MongoDB and set the URL for the localhost. +View all available [environment variables](https://infisical.com/docs/self-hosting/configuration/envars) and guidance for each. -For development, you can use `root` for the `MONGO_USERNAME` and `example` for the `MONGO_PASSWORD` as shown in the screenshot. +## Starting Infisical for development -Take into account that if you use your own `MONGO_USERNAME` and `MONGO_PASSWORD`, you also have to change the `MONGO_URL` with the form of `MONGO_USERNAME:MONGO_PASSWORD` after the `//` part of the URL. +We use use Docker to easily spin up all required services to have Infisical up and running for development. If you are unfamiliar with Docker, don't worry, all you have to do is install [Docker](https://docs.docker.com/get-docker/) for your +machine and run the commands below to start up the development server. -3. Mail SMTP service variables - -![image](https://user-images.githubusercontent.com/118568289/206792653-ba3211d1-1071-43f2-93a7-8b408bbd9e0e.png) - -If you want to receive actual emails (e.g. you want to test how the email message will look like), take note of the following. - -For the `SMTP_USERNAME` variable, you will need an email with 2-steps-verification. - -For the `SMTP_PASSWORD` variable, you will need to [generate an app password](https://support.google.com/mail/answer/185833?hl=en) with the email you used in the `SMTP_USERNAME` variable. - -Otherwise, a local SMTP server (MailHog) is available for testing purposes. Set the following values to use this: - -``` -SMTP_HOST=smtp-server -SMTP_PORT=1025 -SMTP_NAME= -SMTP_USERNAME=team@infisical.com -SMTP_PASSWORD= -``` - -Make sure to leave the `SMTP_PASSWORD` blank so the backend will be able to connect to MailHog - -You can browse `http://localhost:8025/` to browse email messages sent by the backend. - -With these environment variables, you will be ready to run the docker-compose. - -## Docker for development +#### Start local server ```bash -# build and start the services docker-compose -f docker-compose.dev.yml up --build --force-recreate ``` +#### Access local server -Then browse http://localhost:8080 +Once all the services have spun up, browse to http://localhost:8080. To sign in, you may use the default credentials listed below. + +Email: `test@localhost.local` +Password: `testInfisical1` + +#### Shutdown local server ```bash # To stop environment use Control+C (on Mac) CTRL+C (on Win) or docker-compose -f docker-compose.dev.yml down -# start services -docker-compose -f docker-compose.dev.yml up -``` - -The docker-compose development environment consists of: - -- nginx -- frontend -- backend -- mongo -- mongo-express +``` \ No newline at end of file diff --git a/docs/getting-started/dashboard/audit-logs.mdx b/docs/getting-started/dashboard/audit-logs.mdx new file mode 100644 index 000000000..6a48d98ff --- /dev/null +++ b/docs/getting-started/dashboard/audit-logs.mdx @@ -0,0 +1,12 @@ +--- +title: "Activity Logs" +description: "See which events are triggered within your Infisical project." +--- + +Activity logs record all actions going through Infisical including who performed which CRUD operations on environment variables and from what IP address. They help answer questions like: + +- Who added or updated environment variables recently? +- Did Bob read environment variables last week (if at all)? +- What IP address was used for that action? + +![Activity logs](../../images/activity-logs.png) diff --git a/docs/getting-started/dashboard/create-account.mdx b/docs/getting-started/dashboard/create-account.mdx index ddc1654e3..a4be2c847 100644 --- a/docs/getting-started/dashboard/create-account.mdx +++ b/docs/getting-started/dashboard/create-account.mdx @@ -1,5 +1,6 @@ --- title: "Sign up" +description: "How to create an account in Infisical?" --- ## Self-hosted diff --git a/docs/getting-started/dashboard/integrations.mdx b/docs/getting-started/dashboard/integrations.mdx index de25fa861..18a5aa8a8 100644 --- a/docs/getting-started/dashboard/integrations.mdx +++ b/docs/getting-started/dashboard/integrations.mdx @@ -1,14 +1,14 @@ --- title: "Integrations" +description: "How to sync your secrets among various 3rd-party services with Infisical." --- Integrations allow environment variables to be synced across your entire infrastructure from local development to CI/CD and production. -We're still early with integrations, but expect more soon. +We're still relatively early with integrations. 6+ integrations are already avaiable but expect more coming very soon. - - View all available integrations and their guide + + View all available integrations and their guides -![integrations](../../images/project-integrations.png) - +![integrations](../../images/integrations.png) diff --git a/docs/getting-started/dashboard/organization.mdx b/docs/getting-started/dashboard/organization.mdx index c58922daa..63ec2cd49 100644 --- a/docs/getting-started/dashboard/organization.mdx +++ b/docs/getting-started/dashboard/organization.mdx @@ -1,5 +1,6 @@ --- title: "Organization" +description: "How Infisical structures its organizations." --- An organization houses projects and members. diff --git a/docs/getting-started/dashboard/pit-recovery.mdx b/docs/getting-started/dashboard/pit-recovery.mdx new file mode 100644 index 000000000..eeba72d60 --- /dev/null +++ b/docs/getting-started/dashboard/pit-recovery.mdx @@ -0,0 +1,24 @@ +--- +title: "Point-in-Time Recovery" +description: "How to rollback secrets and configs to any commit with Infisical." +--- + +Point-in-time recovery allows environment variables to be rolled back to any point in time. It's powered by snapshots that get captured after mutations to environment variables. + +## Commits + +Similar to Git, a commit in Infisical is a snapshot of your project's secrets at a specific point in time. You can browse and view your project's snapshots via the "Point-in-Time Recovery" sidebar. + +![PIT commits](../../images/pit-commits.png) +![PIT snapshots](../../images/pit-snapshots.png) + +## Rolling back + +Environment variables can be rolled back to any point in time via the "Rollback to this snapshot" button. + +![PIT snapshot](../../images/pit-snapshot.png) + + + Rolling back environment variables to a past snapshot creates a new commit and + snapshot at the top of the stack and updates secret versions. + diff --git a/docs/getting-started/dashboard/project.mdx b/docs/getting-started/dashboard/project.mdx index aa64d635b..ce7df57e3 100644 --- a/docs/getting-started/dashboard/project.mdx +++ b/docs/getting-started/dashboard/project.mdx @@ -1,5 +1,6 @@ --- title: "Project" +description: "How Infisical organizes secrets into projects." --- A project houses environment variables for an application. diff --git a/docs/getting-started/dashboard/secret-versioning.mdx b/docs/getting-started/dashboard/secret-versioning.mdx new file mode 100644 index 000000000..04c3086cd --- /dev/null +++ b/docs/getting-started/dashboard/secret-versioning.mdx @@ -0,0 +1,15 @@ +--- +title: "Secret Versioning" +description: "Version secrets and configurations with Infisical" +--- + +Secret versioning records changes made to every secret. + +![secret versioning](../../images/secret-versioning.png) + + + You can copy and paste a secret version value to the "Value" input field "roll + back" to that secret version. This creates a new secret version at the top of + the stack. We're releasing the ability to press and automatically roll back to + a secret version soon. + diff --git a/docs/getting-started/dashboard/token.mdx b/docs/getting-started/dashboard/token.mdx index 9b3ddf79f..0caaa81d7 100644 --- a/docs/getting-started/dashboard/token.mdx +++ b/docs/getting-started/dashboard/token.mdx @@ -1,5 +1,6 @@ --- title: "Infisical Token" +description: "Use Infisical service token as one of the authentication methods." --- An Infisical Token is needed to authenticate the CLI when there isn't an easy way to input your login credentials. @@ -11,6 +12,12 @@ To generate the the token, head over to your project settings as shown below. ![token add](../../images/project-token-add.png) +## Feeding Infisical Token to the CLI + +The Infisical CLI checks for the presence of an environment variable called `INFISICAL_TOKEN`. +If it detects this variable in the terminal where it is being run, it will use it to authenticate and retrieve the environment variables that the token is authorized to access. +This allows you to use the CLI in environments where you are unable to run the `infisical login` command. + The token grants read-only access to a particular environment and project for a specified amount of time. Once the token is expired, the CLI using it will no longer be able to make diff --git a/docs/getting-started/features.mdx b/docs/getting-started/features.mdx index c520dd905..7eaf6f267 100644 --- a/docs/getting-started/features.mdx +++ b/docs/getting-started/features.mdx @@ -1,17 +1,18 @@ --- title: "Features" +description: "A list of features that Infisical has to offer." --- This is a non-exhaustive list of features that Infisical offers: -## Web UI +## Platform -The Web UI is used to manage teams and environment variables. - -- Provision access to organizations and projects. -- Add/delete/update, scope, search, sort, hide-unhide environment variables. -- Separate environment variables by environment. -- Import environment variables via drag-and-drop, export them as a .env file. +- Provision members access to organizations and projects. +- Manage secrets by adding, deleting, updating them across environments; search, sort, hide/un-hide, export/import them. +- Sync secrets to platforms via integrations to platforms like GitHub, Vercel, and Netlify. +- Rollback secrets to any point in time. +- Rollback each secrets to any version. +- Track actions through activity logs. ## CLI @@ -30,9 +31,9 @@ We're building the future of secret management, one that's comprehensive and acc | More hosting options | Ongoing | | 1-Click Deploys | Ongoing | | Account recovery: Backup key | Ongoing | +| Access logs | Ongoing | | Account recovery: Member-assisted | Coming soon | | Slack & MS teams integrations | Coming soon | -| Access logs | Coming soon | | Version control for secrets | Coming soon | | 2FA | Coming soon | | Restricted IPs | Coming soon | diff --git a/docs/getting-started/introduction.mdx b/docs/getting-started/introduction.mdx index 72b86bf05..ff8b72c4d 100644 --- a/docs/getting-started/introduction.mdx +++ b/docs/getting-started/introduction.mdx @@ -1,5 +1,6 @@ --- title: "Introduction" +description: "What is Infisical?" --- Infisical is an [open-source](https://opensource.com/resources/what-open-source), [end-to-end encrypted](https://en.wikipedia.org/wiki/End-to-end_encryption) secret manager that enables teams to easily manage and sync their environment variables. @@ -35,3 +36,8 @@ Start syncing environment variables with [Infisical Cloud](https://app.infisical Explore integrations for Docker, AWS, Heroku, etc. + + + + Our team is happy to help you get started with Infisical. If you have any questions or want to learn how you can leverage Infisical within your infrastructure, **[set up a 1-on-1 with an Infisical engineer](https://cal.com/maidul/15min)**. + diff --git a/docs/getting-started/quickstart.mdx b/docs/getting-started/quickstart.mdx index 307127ab2..e3acd440d 100644 --- a/docs/getting-started/quickstart.mdx +++ b/docs/getting-started/quickstart.mdx @@ -1,5 +1,6 @@ --- title: "Quickstart" +description: "Start managing your developer secrets and configs with Infisical in 10 minutes." --- This example demonstrates how to store and inject environment variables from [Infisical Cloud](https://app.infisical.com) into your application. @@ -8,7 +9,7 @@ Note that the Infisical CLI is platform-agnostic and can inject environment vari ## Set up Infisical Cloud -1. Login or create an accout at `app.infisical.com`. +1. Login or create an account at `app.infisical.com`. 2. Create a new project. 3. Populate your environment variables as in the image below. diff --git a/docs/images/activity-logs.png b/docs/images/activity-logs.png new file mode 100644 index 000000000..29349c82b Binary files /dev/null and b/docs/images/activity-logs.png differ diff --git a/docs/images/api-key-add.png b/docs/images/api-key-add.png new file mode 100644 index 000000000..a59e59cbe Binary files /dev/null and b/docs/images/api-key-add.png differ diff --git a/docs/images/api-key-dashboard.png b/docs/images/api-key-dashboard.png new file mode 100644 index 000000000..29fb26519 Binary files /dev/null and b/docs/images/api-key-dashboard.png differ diff --git a/docs/images/api-key-settings.png b/docs/images/api-key-settings.png new file mode 100644 index 000000000..847a1e7b3 Binary files /dev/null and b/docs/images/api-key-settings.png differ diff --git a/docs/images/email-aws-ses-console.png b/docs/images/email-aws-ses-console.png new file mode 100644 index 000000000..2882ba4d5 Binary files /dev/null and b/docs/images/email-aws-ses-console.png differ diff --git a/docs/images/email-aws-ses-user.png b/docs/images/email-aws-ses-user.png new file mode 100644 index 000000000..f740e58a5 Binary files /dev/null and b/docs/images/email-aws-ses-user.png differ diff --git a/docs/images/email-mailhog-credentials.png b/docs/images/email-mailhog-credentials.png new file mode 100644 index 000000000..8d5a11295 Binary files /dev/null and b/docs/images/email-mailhog-credentials.png differ diff --git a/docs/images/email-sendgrid-create-key.png b/docs/images/email-sendgrid-create-key.png new file mode 100644 index 000000000..1caa977a8 Binary files /dev/null and b/docs/images/email-sendgrid-create-key.png differ diff --git a/docs/images/email-sendgrid-restrictions.png b/docs/images/email-sendgrid-restrictions.png new file mode 100644 index 000000000..a70891a60 Binary files /dev/null and b/docs/images/email-sendgrid-restrictions.png differ diff --git a/docs/images/integrations-flyio-auth.png b/docs/images/integrations-flyio-auth.png new file mode 100644 index 000000000..2db68e61a Binary files /dev/null and b/docs/images/integrations-flyio-auth.png differ diff --git a/docs/images/integrations-flyio-dashboard.png b/docs/images/integrations-flyio-dashboard.png new file mode 100644 index 000000000..e27315238 Binary files /dev/null and b/docs/images/integrations-flyio-dashboard.png differ diff --git a/docs/images/integrations-flyio-token.png b/docs/images/integrations-flyio-token.png new file mode 100644 index 000000000..7766738e4 Binary files /dev/null and b/docs/images/integrations-flyio-token.png differ diff --git a/docs/images/integrations-flyio.png b/docs/images/integrations-flyio.png new file mode 100644 index 000000000..cae945c29 Binary files /dev/null and b/docs/images/integrations-flyio.png differ diff --git a/docs/images/integrations-github-auth.png b/docs/images/integrations-github-auth.png new file mode 100644 index 000000000..92d7158ac Binary files /dev/null and b/docs/images/integrations-github-auth.png differ diff --git a/docs/images/integrations-github.png b/docs/images/integrations-github.png new file mode 100644 index 000000000..dccc42c0d Binary files /dev/null and b/docs/images/integrations-github.png differ diff --git a/docs/images/integrations-heroku-auth.png b/docs/images/integrations-heroku-auth.png new file mode 100644 index 000000000..da9b4cf52 Binary files /dev/null and b/docs/images/integrations-heroku-auth.png differ diff --git a/docs/images/integrations-heroku.png b/docs/images/integrations-heroku.png new file mode 100644 index 000000000..42229627c Binary files /dev/null and b/docs/images/integrations-heroku.png differ diff --git a/docs/images/integrations-netlify-auth.png b/docs/images/integrations-netlify-auth.png new file mode 100644 index 000000000..fe25d7acf Binary files /dev/null and b/docs/images/integrations-netlify-auth.png differ diff --git a/docs/images/integrations-netlify.png b/docs/images/integrations-netlify.png new file mode 100644 index 000000000..7f808eeb4 Binary files /dev/null and b/docs/images/integrations-netlify.png differ diff --git a/docs/images/integrations-render-auth.png b/docs/images/integrations-render-auth.png new file mode 100644 index 000000000..eb877f9bd Binary files /dev/null and b/docs/images/integrations-render-auth.png differ diff --git a/docs/images/integrations-render-dashboard.png b/docs/images/integrations-render-dashboard.png new file mode 100644 index 000000000..c6ce15d42 Binary files /dev/null and b/docs/images/integrations-render-dashboard.png differ diff --git a/docs/images/integrations-render-token.png b/docs/images/integrations-render-token.png new file mode 100644 index 000000000..813735e9a Binary files /dev/null and b/docs/images/integrations-render-token.png differ diff --git a/docs/images/integrations-render.png b/docs/images/integrations-render.png new file mode 100644 index 000000000..771ff9534 Binary files /dev/null and b/docs/images/integrations-render.png differ diff --git a/docs/images/integrations-vercel-auth.png b/docs/images/integrations-vercel-auth.png new file mode 100644 index 000000000..d8f3d2d18 Binary files /dev/null and b/docs/images/integrations-vercel-auth.png differ diff --git a/docs/images/integrations-vercel.png b/docs/images/integrations-vercel.png new file mode 100644 index 000000000..f769ae4d9 Binary files /dev/null and b/docs/images/integrations-vercel.png differ diff --git a/docs/images/integrations.png b/docs/images/integrations.png new file mode 100644 index 000000000..556e6995a Binary files /dev/null and b/docs/images/integrations.png differ diff --git a/docs/images/pit-commits.png b/docs/images/pit-commits.png new file mode 100644 index 000000000..19cfa4976 Binary files /dev/null and b/docs/images/pit-commits.png differ diff --git a/docs/images/pit-snapshot.png b/docs/images/pit-snapshot.png new file mode 100644 index 000000000..7e790e875 Binary files /dev/null and b/docs/images/pit-snapshot.png differ diff --git a/docs/images/pit-snapshots.png b/docs/images/pit-snapshots.png new file mode 100644 index 000000000..f22231648 Binary files /dev/null and b/docs/images/pit-snapshots.png differ diff --git a/docs/images/secret-versioning.png b/docs/images/secret-versioning.png new file mode 100644 index 000000000..ec1734289 Binary files /dev/null and b/docs/images/secret-versioning.png differ diff --git a/docs/integrations/cicd/circleci.mdx b/docs/integrations/cicd/circleci.mdx new file mode 100644 index 000000000..7ded52d8a --- /dev/null +++ b/docs/integrations/cicd/circleci.mdx @@ -0,0 +1,5 @@ +--- +title: "Circle CI" +--- + +Coming soon. diff --git a/docs/integrations/cicd/githubactions.mdx b/docs/integrations/cicd/githubactions.mdx new file mode 100644 index 000000000..8f93d8162 --- /dev/null +++ b/docs/integrations/cicd/githubactions.mdx @@ -0,0 +1,35 @@ +--- +title: "GitHub Actions" +description: "How to automatically sync secrets from Infisical into your GitHub Actions." +--- + + + Infisical can sync secrets to GitHub repo secrets only. If your repo uses environment secrets, then stay tuned with this [issue](https://github.com/Infisical/infisical/issues/54). + + +Prerequisites: + +- Set up and add envars to [Infisical Cloud](https://app.infisical.com) +- Ensure you have admin privileges to the repo you want to sync secrets to. + +## Navigate to your project's integrations tab + +![integrations](../../images/integrations.png) + +## Authorize Infisical for GitHub + +Press on the GitHub tile and grant Infisical access to your GitHub account (repo privileges only). + +![integrations github authorization](../../images/integrations-github-auth.png) + + + If this is your project's first cloud integration, then you'll have to grant Infisical access to your project's environment variables. + Although this step breaks E2EE, it's necessary for Infisical to sync the environment variables to the cloud platform. + + +## Start integration + +Select which Infisical environment secrets you want to sync to which GitHub repo and press start integration to start syncing secrets to the repo. + +![integrations github](../../images/integrations-github.png) + diff --git a/docs/integrations/cloud/flyio.mdx b/docs/integrations/cloud/flyio.mdx new file mode 100644 index 000000000..e6d9afcef --- /dev/null +++ b/docs/integrations/cloud/flyio.mdx @@ -0,0 +1,36 @@ +--- +title: "Fly.io" +description: "How to automatically sync secrets from Infisical into your Fly.io project." +--- + +Prerequisites: + +- Set up and add envars to [Infisical Cloud](https://app.infisical.com) + +## Navigate to your project's integrations tab + +![integrations](../../images/integrations.png) + +## Authorize Infisical for Fly.io + +Obtain a Fly.io access token in Access Tokens + +![integrations fly dashboard](../../images/integrations-flyio-dashboard.png) +![integrations fly token](../../images/integrations-flyio-token.png) + +Press on the Fly.io tile and input your Fly.io access token to grant Infisical access to your Fly.io account. + +![integrations fly authorization](../../images/integrations-flyio-auth.png) + + + If this is your project's first cloud integration, then you'll have to grant + Infisical access to your project's environment variables. Although this step + breaks E2EE, it's necessary for Infisical to sync the environment variables to + the cloud platform. + + +## Start integration + +Select which Infisical environment secrets you want to sync to which Fly.io app and press start integration to start syncing secrets to Fly.io. + +![integrations fly](../../images/integrations-flyio.png) diff --git a/docs/integrations/cloud/heroku.mdx b/docs/integrations/cloud/heroku.mdx index 5f0debd3e..bbbaaf5a8 100644 --- a/docs/integrations/cloud/heroku.mdx +++ b/docs/integrations/cloud/heroku.mdx @@ -1,26 +1,30 @@ --- title: "Heroku" -description: "With this integration, you can automatically sync your secrets to Heroku as soon as you update secrets in Infisical." +description: "How to automatically sync secrets from Infisical into your Heroku project." --- -## Instructions +Prerequisites: -### Step 1: Open the integrations console +- Set up and add envars to [Infisical Cloud](https://app.infisical.com) -Open the Infisical Dashboard. Choose the project in which you want to set up the intergation. Go to the integrations tab in the left sidebar. +## Navigate to your project's integrations tab -### Step 2: Authenticate with Heroku +![integrations](../../images/integrations.png) -Click on "Heroku" tile. Log in if required and provide the necessary permissions to Infisical. You will afterwards be redirected back to the integrations page. +## Authorize Infisical for Heroku -Note: during an integration with Heroku, for security reasons, it is impossible to maintain end-to-end encryption. In theory, this lets Infisical decrypt yor environment variables. In practice, we can assure you that this will never be done, and it allows us to protect your secrets from bad actors online. With any questions, reach out support@infisical.com. +Press on the Heroku tile and grant Infisical access to your Heroku account. -### Step 3: Start integration +![integrations heroku authorization](../../images/integrations-heroku-auth.png) -Choose a Heroku App that you want to sync the secrets to, and the Infisical project environment that you want to sync the secrets from. Start the integration. - -The integration should now show status 'In Sync'. Every time you edit secrets, they will be automatically pushed to Heroku. - - - If you need to update your integration, you will have to delete the current one and create a new one. + + If this is your project's first cloud integration, then you'll have to grant Infisical access to your project's environment variables. + Although this step breaks E2EE, it's necessary for Infisical to sync the environment variables to the cloud platform. + +## Start integration + +Select which Infisical environment secrets you want to sync to which Heroku app and press start integration to start syncing secrets to Heroku. + +![integrations heroku](../../images/integrations-heroku.png) + diff --git a/docs/integrations/cloud/netlify.mdx b/docs/integrations/cloud/netlify.mdx new file mode 100644 index 000000000..f6b0e41e8 --- /dev/null +++ b/docs/integrations/cloud/netlify.mdx @@ -0,0 +1,33 @@ +--- +title: "Netlify" +description: "How to automatically sync secrets from Infisical into your Netlify project." +--- + + + Infisical integrates with Netlify's new environment variable experience. If your site uses Netlify's old environment variable experience, you'll have to upgrade it to the new one to use this integration. + + +Prerequisites: + +- Set up and add envars to [Infisical Cloud](https://app.infisical.com) + +## Navigate to your project's integrations tab + +![integrations](../../images/integrations.png) + +## Authorize Infisical for Netlify + +Press on the Netlify tile and grant Infisical access to your Netlify account. + +![integrations netlify authorization](../../images/integrations-netlify-auth.png) + + + If this is your project's first cloud integration, then you'll have to grant Infisical access to your project's environment variables. + Although this step breaks E2EE, it's necessary for Infisical to sync the environment variables to the cloud platform. + + +## Start integration + +Select which Infisical environment secrets you want to sync to which Netlify app and context. Lastly, press start integration to start syncing secrets to Netlify. + +![integrations netlify](../../images/integrations-netlify.png) \ No newline at end of file diff --git a/docs/integrations/cloud/render.mdx b/docs/integrations/cloud/render.mdx new file mode 100644 index 000000000..9f9dbd08e --- /dev/null +++ b/docs/integrations/cloud/render.mdx @@ -0,0 +1,36 @@ +--- +title: "Render" +description: "How to automatically sync secrets from Infisical into your Render project." +--- + +Prerequisites: + +- Set up and add envars to [Infisical Cloud](https://app.infisical.com) + +## Navigate to your project's integrations tab + +![integrations](../../images/integrations.png) + +## Enter your Render API Key + +Obtain a Render API Key in your Render Account Settings > API Keys. + +![integrations render dashboard](../../images/integrations-render-dashboard.png) +![integrations render token](../../images/integrations-render-token.png) + +Press on the Render tile and input your Render API Key to grant Infisical access to your Render account. + +![integrations render authorization](../../images/integrations-render-auth.png) + + + If this is your project's first cloud integration, then you'll have to grant + Infisical access to your project's environment variables. Although this step + breaks E2EE, it's necessary for Infisical to sync the environment variables to + the cloud platform. + + +## Start integration + +Select which Infisical environment secrets you want to sync to which Render service and press start integration to start syncing secrets to Render. + +![integrations heroku](../../images/integrations-render.png) diff --git a/docs/integrations/cloud/vercel.mdx b/docs/integrations/cloud/vercel.mdx index eb09203b5..804e3c50a 100644 --- a/docs/integrations/cloud/vercel.mdx +++ b/docs/integrations/cloud/vercel.mdx @@ -1,5 +1,24 @@ --- title: "Vercel" +description: "How to automatically sync secrets from Infisical into your Vercel project." --- -Coming soon. +Prerequisites: + +- Set up and add envars to [Infisical Cloud](https://app.infisical.com) + +## Navigate to your project's integrations tab + +![integrations](../../images/integrations.png) + +## Authorize Infisical for Vercel + +Press on the Vercel tile and grant Infisical access to your Vercel account. + +![integrations vercel authorization](../../images/integrations-vercel-auth.png) + +## Start integration + +Select which Infisical environment secrets you want to sync to which Vercel app and environment. Lastly, press start integration to start syncing secrets to Vercel. + +![integrations vercel](../../images/integrations-vercel.png) diff --git a/docs/integrations/frameworks/django.mdx b/docs/integrations/frameworks/django.mdx index ea786a0f7..2a62ea2f5 100644 --- a/docs/integrations/frameworks/django.mdx +++ b/docs/integrations/frameworks/django.mdx @@ -1,5 +1,6 @@ --- title: "Django" +description: "How to use Infisical to inject environment variables and secrets into a Django app." --- Prerequisites: diff --git a/docs/integrations/frameworks/dotnet.mdx b/docs/integrations/frameworks/dotnet.mdx new file mode 100644 index 000000000..7496a9d13 --- /dev/null +++ b/docs/integrations/frameworks/dotnet.mdx @@ -0,0 +1,28 @@ +--- +title: ".NET" +description: "How to use Infisical to inject environment variables and secrets into a .NET app." +--- + +Prerequisites: + +- Set up and add envars to [Infisical Cloud](https://app.infisical.com) +- [Install the CLI](/cli/overview) + +## Initialize Infisical for your [.NET](https://dotnet.microsoft.com) app + +```bash +# navigate to the root of your of your project +cd /path/to/project + +# then initialize infisical +infisical init +``` + +## Start your application as usual but with Infisical + +```bash +infisical run -- + +# Example +infisical run -- dotnet run +``` diff --git a/docs/integrations/frameworks/express.mdx b/docs/integrations/frameworks/express.mdx index 363decf09..f73dd68e0 100644 --- a/docs/integrations/frameworks/express.mdx +++ b/docs/integrations/frameworks/express.mdx @@ -1,5 +1,6 @@ --- title: "Express, Fastify, Koa" +description: "How to use Infisical to inject environment variables and secrets into an Express app." --- Prerequisites: diff --git a/docs/integrations/frameworks/fiber.mdx b/docs/integrations/frameworks/fiber.mdx index 0c7d6aab2..896c015fb 100644 --- a/docs/integrations/frameworks/fiber.mdx +++ b/docs/integrations/frameworks/fiber.mdx @@ -1,5 +1,6 @@ --- title: "Fiber" +description: "How to use Infisical to inject environment variables and secrets into a Fiber app." --- Prerequisites: diff --git a/docs/integrations/frameworks/flask.mdx b/docs/integrations/frameworks/flask.mdx index e80a993e8..70759b1bf 100644 --- a/docs/integrations/frameworks/flask.mdx +++ b/docs/integrations/frameworks/flask.mdx @@ -1,5 +1,6 @@ --- title: "Flask" +description: "How to use Infisical to inject environment variables and secrets into a Flask app." --- Prerequisites: diff --git a/docs/integrations/frameworks/gatsby.mdx b/docs/integrations/frameworks/gatsby.mdx index 4e12265de..87be9691b 100644 --- a/docs/integrations/frameworks/gatsby.mdx +++ b/docs/integrations/frameworks/gatsby.mdx @@ -1,5 +1,6 @@ --- title: "Gatsby" +description: "How to use Infisical to inject environment variables and secrets into a Gatsby app." --- Prerequisites: diff --git a/docs/integrations/frameworks/laravel.mdx b/docs/integrations/frameworks/laravel.mdx index 0152e7c66..037d9ff73 100644 --- a/docs/integrations/frameworks/laravel.mdx +++ b/docs/integrations/frameworks/laravel.mdx @@ -1,5 +1,6 @@ --- title: "Laravel" +description: "How to use Infisical to inject environment variables and secrets into a Laravel app." --- Prerequisites: diff --git a/docs/integrations/frameworks/nestjs.mdx b/docs/integrations/frameworks/nestjs.mdx index 5e224587e..5f1ce6f8f 100644 --- a/docs/integrations/frameworks/nestjs.mdx +++ b/docs/integrations/frameworks/nestjs.mdx @@ -1,5 +1,6 @@ --- title: "NestJS" +description: "How to use Infisical to inject environment variables and secrets into a NestJS app." --- Prerequisites: diff --git a/docs/integrations/frameworks/nextjs.mdx b/docs/integrations/frameworks/nextjs.mdx index d6e46f54e..f3f99f86d 100644 --- a/docs/integrations/frameworks/nextjs.mdx +++ b/docs/integrations/frameworks/nextjs.mdx @@ -1,5 +1,6 @@ --- title: "Next.js" +description: "How to use Infisical to inject environment variables and secrets into a Next.js app." --- Prerequisites: diff --git a/docs/integrations/frameworks/nuxt.mdx b/docs/integrations/frameworks/nuxt.mdx index 8105940ee..3267d6542 100644 --- a/docs/integrations/frameworks/nuxt.mdx +++ b/docs/integrations/frameworks/nuxt.mdx @@ -1,5 +1,6 @@ --- title: "Nuxt" +description: "How to use Infisical to inject environment variables and secrets into a Nuxt app." --- Prerequisites: diff --git a/docs/integrations/frameworks/rails.mdx b/docs/integrations/frameworks/rails.mdx index 32e7cbd57..22dc471e3 100644 --- a/docs/integrations/frameworks/rails.mdx +++ b/docs/integrations/frameworks/rails.mdx @@ -1,5 +1,6 @@ --- title: "Ruby on Rails" +description: "How to use Infisical to inject environment variables and secrets into a Ruby on Rails app." --- Prerequisites: diff --git a/docs/integrations/frameworks/react.mdx b/docs/integrations/frameworks/react.mdx index 0c394ac7e..48ad5d74f 100644 --- a/docs/integrations/frameworks/react.mdx +++ b/docs/integrations/frameworks/react.mdx @@ -1,5 +1,6 @@ --- title: "React" +description: "How to use Infisical to inject environment variables and secrets into a React app." --- Prerequisites: diff --git a/docs/integrations/frameworks/remix.mdx b/docs/integrations/frameworks/remix.mdx index cc37a263e..d85844143 100644 --- a/docs/integrations/frameworks/remix.mdx +++ b/docs/integrations/frameworks/remix.mdx @@ -1,5 +1,6 @@ --- title: "Remix" +description: "How to use Infisical to inject environment variables and secrets into a Remix app." --- Prerequisites: diff --git a/docs/integrations/frameworks/vite.mdx b/docs/integrations/frameworks/vite.mdx index 2c6e80ff0..62a4bb2f6 100644 --- a/docs/integrations/frameworks/vite.mdx +++ b/docs/integrations/frameworks/vite.mdx @@ -1,5 +1,6 @@ --- title: "Vite" +description: "How to use Infisical to inject environment variables and secrets into a Vite app." --- Prerequisites: diff --git a/docs/integrations/frameworks/vue.mdx b/docs/integrations/frameworks/vue.mdx index 9bc17255c..240e4ae4b 100644 --- a/docs/integrations/frameworks/vue.mdx +++ b/docs/integrations/frameworks/vue.mdx @@ -1,5 +1,6 @@ --- title: "Vue" +description: "How to use Infisical to inject environment variables and secrets into a Vue.js app." --- Prerequisites: diff --git a/docs/integrations/overview.mdx b/docs/integrations/overview.mdx index 9323f8917..4f1e99227 100644 --- a/docs/integrations/overview.mdx +++ b/docs/integrations/overview.mdx @@ -1,5 +1,6 @@ --- title: "Overview" +description: "How to use Infisical to inject secrets and configs into various 3-rd party services and frameworks." --- Integrations allow environment variables to be synced from Infisical into your local development workflow, CI/CD pipelines, and production infrastructure. @@ -10,18 +11,13 @@ Missing an integration? Throw in a [request](https://github.com/Infisical/infisi | -------------------------------------------------------- | --------- | ----------- | | [Docker](/integrations/platforms/docker) | Platform | Available | | [Docker-Compose](/integrations/platforms/docker-compose) | Platform | Available | -| Kubernetes | Platform | Coming soon | +| [Kubernetes](/integrations/platforms/kubernetes) | Platform | Available | | [Heroku](/integrations/cloud/heroku) | Cloud | Available | -| [Vercel](/integrations/cloud/vercel) | Cloud | Coming soon | -| AWS | Cloud | Coming soon | -| GCP | Cloud | Coming soon | -| Azure | Cloud | Coming soon | -| DigitalOcean | Cloud | Coming soon | -| GitLab | CI/CD | Coming soon | -| CircleCI | CI/CD | Coming soon | -| TravisCI | CI/CD | Coming soon | -| GitHub Actions | CI/CD | Coming soon | -| Jenkins | CI/CD | Coming soon | +| [Vercel](/integrations/cloud/vercel) | Cloud | Available | +| [Netlify](/integrations/cloud/netlify) | Cloud | Available | +| [Render](/integrations/cloud/render) | Cloud | Available | +| [Fly.io](/integrations/cloud/flyio) | Cloud | Available | +| [GitHub Actions](/integrations/cicd/githubactions) | CI/CD | Available | | [React](/integrations/frameworks/react) | Framework | Available | | [Vue](/integrations/frameworks/vue) | Framework | Available | | [Express](/integrations/frameworks/express) | Framework | Available | @@ -36,3 +32,12 @@ Missing an integration? Throw in a [request](https://github.com/Infisical/infisi | [Flask](/integrations/frameworks/flask) | Framework | Available | | [Laravel](/integrations/frameworks/laravel) | Framework | Available | | [Ruby on Rails](/integrations/frameworks/rails) | Framework | Available | +| AWS | Cloud | Coming soon | +| GCP | Cloud | Coming soon | +| Azure | Cloud | Coming soon | +| DigitalOcean | Cloud | Coming soon | +| GitLab | CI/CD | Coming soon | +| [CircleCI](/integrations/cicd/circleci) | CI/CD | Coming soon | +| TravisCI | CI/CD | Coming soon | +| GitHub Actions | CI/CD | Coming soon | +| Jenkins | CI/CD | Coming soon | diff --git a/docs/integrations/platforms/docker-compose.mdx b/docs/integrations/platforms/docker-compose.mdx index f2cdd60c8..698316582 100644 --- a/docs/integrations/platforms/docker-compose.mdx +++ b/docs/integrations/platforms/docker-compose.mdx @@ -1,5 +1,6 @@ --- title: "Docker Compose" +description: "How to use Infisical to inject environment variables into container defined in your Docker Compose file." --- The Docker Compose integration enables you to inject environment variables from Infisical into the containers defined in your compose file. diff --git a/docs/integrations/platforms/docker.mdx b/docs/integrations/platforms/docker.mdx index 6f08c9ec8..8f53336ed 100644 --- a/docs/integrations/platforms/docker.mdx +++ b/docs/integrations/platforms/docker.mdx @@ -1,5 +1,6 @@ --- title: "Docker" +description: "How to use Infisical to inject environment variables into a Docker container." --- Infisical can be used in a Dockerfile to inject environment variables into a Docker container. @@ -31,25 +32,22 @@ Infisical can be used in a Dockerfile to inject environment variables into a Doc -## Modify the start command in your Dockerfile + ## Modify your Dockerfile start command -```dockerfile -CMD ["infisical", "--env=[env]", "projectId=[projectId]", "run", "---", "[your application start command]"] + To make your Docker container consume Infisical secrets, you can start your application with Infisical. + This will automatically pull the necessary secrets and make them available to your application as if they were natively exposed within the container. -# example -CMD ["infisical", "--env=prod", "projectId=62faf98ae0b05e83239b5da41", "run", "---", "npm run start"] -``` + ```dockerfile + CMD ["infisical", "run", "---", "[your application start command]"] -Required options: + # example with single single command + CMD ["infisical", "run", "---", "npm run start"] -| Option | Description | Default value | -| ------------- | ----------------------------------------------------------------------------------------------------------- | ------------- | -| `--env` | Used to set the environment that secrets are pulled from. Accepted values: `dev`, `staging`, `test`, `prod` | `dev` | -| `--projectId` | Used to link a local project to the platform | `None` | + # example with multiple commands + CMD ["infisical", "run", "--command", "npm run start && ..."] + ``` -## Generate an Infisical Token - -[Generate an Infisical Token](../../getting-started/dashboard/token) and keep it handy. + View more options for the `run` command [here](../../cli/commands/run) ## Feed Docker your Infisical Token @@ -58,3 +56,8 @@ The CLI looks out for an environment variable called `INFISICAL_TOKEN`. If the t ```bash docker run --env INFISICAL_TOKEN=[token]... ``` + +## Generate an Infisical Token + +[Generate an Infisical Token](../../getting-started/dashboard/token) and keep it handy. + diff --git a/docs/integrations/platforms/kubernetes.mdx b/docs/integrations/platforms/kubernetes.mdx new file mode 100644 index 000000000..189dc9d7b --- /dev/null +++ b/docs/integrations/platforms/kubernetes.mdx @@ -0,0 +1,336 @@ +--- +title: 'Kubernetes' +description: "This page explains how to use Infisical to inject secrets into Kubernetes clusters." +--- + +The Infisical Secrets Operator is a custom Kubernetes controller that helps keep secrets in a cluster up to date by synchronizing them. +It is installed in its own namespace within the cluster and follows strict RBAC policies. +The operator uses InfisicalSecret custom resources to identify which secrets to sync and where to store them. +It is responsible for continuously updating managed secrets, and in the future may also automatically reload deployments that use them as needed. + +## Install Operator + +The operator can be install via [Helm](helm.sh) or [kubectl](https://github.com/kubernetes/kubectl) + + + + Install Infisical Helm repository + ```bash + helm repo add infisical-helm-charts 'https://dl.cloudsmith.io/public/infisical/helm-charts/helm/charts/' + + helm repo update + ``` + + Install the Helm chart + ```bash + helm install --generate-name infisical-helm-charts/secrets-operator + ``` + + + + The operator will be installed in `infisical-operator-system` namespace + ``` + kubectl apply -f https://raw.githubusercontent.com/Infisical/infisical/main/k8-operator/kubectl-install/install-secrets-operator.yaml + ``` + + + +## Sync Infisical Secrets to your cluster + +To retrieve secrets from an Infisical project and store them in your Kubernetes cluster, you can use the InfisicalSecret custom resource. +This resource is available after installing the Infisical operator. In order to specify the Infisical Token location and the location where the retrieved secrets should be stored, you can use the `tokenSecretReference` and `managedSecretReference` fields within the InfisicalSecret resource. + +```yaml + +apiVersion: secrets.infisical.com/v1alpha1 +kind: InfisicalSecret +metadata: + # Name of of this InfisicalSecret resource + name: infisicalsecret-sample +spec: + # The host that should be used to pull secrets from. The default value is https://app.infisical.com/api. + hostAPI: https://app.infisical.com/api + + # The Kubernetes secret the stores the Infisical token + tokenSecretReference: + # Kubernetes secret name + secretName: service-token + # The secret namespace + secretNamespace: default + + # The Kubernetes secret that Infisical Operator will create and populate with secrets from the above project + managedSecretReference: + # The name of managed Kubernetes secret that should be created + secretName: managed-secret + # The namespace the managed secret should be installed in + secretNamespace: default +``` + + + The `tokenSecretReference` field in the InfisicalSecret resource is used to specify the location of the Infisical Token, which is required for authenticating and retrieving secrets from an Infisical project. + + To create a Kubernetes secret containing an [Infisical Token](../../getting-started/dashboard/token), you can run the command below. + ``` bash + kubectl create secret generic service-token --from-literal=infisicalToken= + ``` + +Once the secret is created, add the name and namespace of the secret under `tokenSecretReference` field in the InfisicalSecret custom resource. + +{' '} + + + No matter what the name of the secret is or its namespace, it must contain a + key named `infisicalToken` with a valid Infisical Token as the value + + + + + +The `managedSecretReference` field in the InfisicalSecret resource is used to specify the location where secrets retrieved from an Infisical project should be stored. +You should specify the name and namespace of the Kubernetes secret that will hold these secrets. The operator will create the secret for you, you just need to provide its name and namespace. + +It is recommended that the managed secret be created in the same namespace as the deployment that will use it. + + + +### Verify managed secret creation + +To verify that the operator has successfully created the managed secret, you can check the secrets in the namespace that was specified. + +```bash +# Verify managed secret is created +kubectl get secrets -n +``` + + + The Infisical secrets will be synced and stored into the managed secret every + 1 minutes. + + +### Using managed secret in your deployment +Incorporating the managed secret created by the operator into your deployment can be achieved through several methods. +Here, we will highlight three of the most common ways to utilize it. Learn more about Kubernetes secrets [here](https://kubernetes.io/docs/concepts/configuration/secret/) + + + This will take all the secrets from your managed secret and expose them to your container + + ```yaml + envFrom: + - secretRef: + name: managed-secret # managed secret name + ``` + + Example usage in a deployment + ```yaml + apiVersion: apps/v1 + kind: Deployment + metadata: + name: nginx-deployment + labels: + app: nginx + spec: + replicas: 1 + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: nginx:1.14.2 + envFrom: + - secretRef: + name: managed-secret # <- name of managed secret + ports: + - containerPort: 80 + ``` + + + + + This will allow you to select individual secrets by key name from your managed secret and expose them to your container + + ```yaml + env: + - name: SECRET_NAME # The environment variable's name which is made available in the container + valueFrom: + secretKeyRef: + name: managed-secret # managed secret name + key: SOME_SECRET_KEY # The name of the key which exists in the managed secret + ``` + + Example usage in a deployment + ```yaml + apiVersion: apps/v1 + kind: Deployment + metadata: + name: nginx-deployment + labels: + app: nginx + spec: + replicas: 1 + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: nginx:1.14.2 + env: + - name: STRIPE_API_SECRET + valueFrom: + secretKeyRef: + name: managed-secret # <- name of managed secret + key: STRIPE_API_SECRET + ports: + - containerPort: 80 + ``` + + + + This will allow you to create a volume on your container which comprises of files holding the secrets in your managed kubernetes secret + ```yaml + volumes: + - name: secrets-volume-name # The name of the volume under which secrets will be stored + secret: + secretName: managed-secret # managed secret name + ``` + + You can then mount this volume to the container's filesystem so that your deployment can access the files containing the managed secrets + ```yaml + volumeMounts: + - name: secrets-volume-name + mountPath: /etc/secrets + readOnly: true + ``` + + Example usage in a deployment + ```yaml + apiVersion: apps/v1 + kind: Deployment + metadata: + name: nginx-deployment + labels: + app: nginx + spec: + replicas: 1 + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: nginx:1.14.2 + volumeMounts: + - name: secrets-volume-name + mountPath: /etc/secrets + readOnly: true + ports: + - containerPort: 80 + volumes: + - name: secrets-volume-name + secret: + secretName: managed-secret # <- managed secrets + ``` + + +## Auto redeployment +Deployments using managed secrets don't reload automatically on updates, so they may use outdated secrets unless manually redeployed. +To address this, we added functionality to automatically redeploy your deployment when its managed secret updates. + +### Enabling auto redeploy +To enable auto redeployment you simply have to add the following annotation to the deployment that consumes a managed secret +```yaml +secrets.infisical.com/auto-reload: "true" +``` + + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-deployment + labels: + app: nginx + annotations: + secrets.infisical.com/auto-reload: "true" # <- redeployment annotation +spec: + replicas: 1 + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: nginx:1.14.2 + envFrom: + - secretRef: + name: managed-secret + ports: + - containerPort: 80 +``` + + + +## Troubleshoot + +If the operator is unable to fetch secrets from the API, it will not affect the managed Kubernetes secret. +It will continue attempting to reconnect to the API indefinitely. +The InfisicalSecret resource uses the `status.conditions` field to report its current state and any errors encountered. + +```yaml +$ kubectl get infisicalSecrets +NAME AGE +infisicalsecret-sample 12s + +$ kubectl describe infisicalSecret infisicalsecret-sample +... +Spec: +... +Status: + Conditions: + Last Transition Time: 2022-12-18T04:29:09Z + Message: Infisical controller has located the Infisical token in provided Kubernetes secret + Reason: OK + Status: True + Type: secrets.infisical.com/LoadedInfisicalToken + Last Transition Time: 2022-12-18T04:29:10Z + Message: Failed to update secret because: 400 Bad Request + Reason: Error + Status: False + Type: secrets.infisical.com/ReadyToSyncSecrets +Events: +``` + +## Uninstall Operator + +The managed secret created by the operator will not be deleted when the operator is uninstalled. + + + + Install Infisical Helm repository + ```bash + helm uninstall add + ``` + + + ``` + kubectl delete -f https://raw.githubusercontent.com/Infisical/infisical/main/k8-operator/kubectl-install/install-secrets-operator.yaml + ``` + + diff --git a/docs/mint.json b/docs/mint.json index 547291fa5..4ce1d6c03 100644 --- a/docs/mint.json +++ b/docs/mint.json @@ -21,7 +21,19 @@ "to": "#F8B7BD" } }, - "topbarLinks": [{ "name": "Log In", "url": "https://app.infisical.com/login" }], + "api": { + "baseUrl": [ + "https://app.infisical.com", + "http://localhost:8080" + ], + "auth": { + "method": "key", + "name": "X-API-KEY" + } + }, + "topbarLinks": [ + { "name": "Log In", "url": "https://app.infisical.com/login" } + ], "topbarCtaButton": { "name": "Start for Free", "url": "https://app.infisical.com/signup" @@ -37,6 +49,11 @@ "icon": "server", "url": "self-hosting" }, + { + "name": "API Reference", + "icon": "cloud", + "url": "api-reference" + }, { "name": "Integrations", "icon": "plug", @@ -78,6 +95,9 @@ "getting-started/dashboard/organization", "getting-started/dashboard/project", "getting-started/dashboard/integrations", + "getting-started/dashboard/pit-recovery", + "getting-started/dashboard/secret-versioning", + "getting-started/dashboard/audit-logs", "getting-started/dashboard/token" ] }, @@ -92,46 +112,121 @@ "cli/commands/login", "cli/commands/init", "cli/commands/run", - "cli/commands/export" + "cli/commands/secrets", + "cli/commands/export", + "cli/commands/vault" ] - } + }, + "cli/faq" ] }, { "group": "Self-hosting", "pages": [ - "self-hosting/overview", + "self-hosting/overview" + ] + }, + { + "group": "Deployment options", + "pages": [ + "self-hosting/deployments/linux", + "self-hosting/deployments/kubernetes" + ] + }, + { + "group": "Configuration", + "pages": [ + "self-hosting/configuration/envars", + "self-hosting/configuration/email" + ] + }, + { + "group": "Overview", + "pages": [ + "api-reference/overview/introduction", + "api-reference/overview/authentication", { - "group": "Deployments options", + "group": "Examples", "pages": [ - "self-hosting/deployments/linux", - "self-hosting/deployments/kubernetes" + "api-reference/overview/examples/create-secrets", + "api-reference/overview/examples/retrieve-secrets", + "api-reference/overview/examples/update-secrets", + "api-reference/overview/examples/delete-secrets" + ] + } + ] + }, + { + "group": "Endpoints", + "pages": [ + { + "group": "Users", + "pages": [ + "api-reference/endpoints/users/me", + "api-reference/endpoints/users/my-organizations" ] }, { - "group": "Configuration", - "pages": ["self-hosting/configuration/envars"] + "group": "Organizations", + "pages": [ + "api-reference/endpoints/organizations/memberships", + "api-reference/endpoints/organizations/update-membership", + "api-reference/endpoints/organizations/delete-membership", + "api-reference/endpoints/organizations/workspaces" + ] + }, + { + "group": "Projects", + "pages": [ + "api-reference/endpoints/workspaces/memberships", + "api-reference/endpoints/workspaces/update-membership", + "api-reference/endpoints/workspaces/delete-membership", + "api-reference/endpoints/workspaces/workspace-key", + "api-reference/endpoints/workspaces/logs", + "api-reference/endpoints/workspaces/secret-snapshots", + "api-reference/endpoints/workspaces/rollback-snapshot" + ] + }, + { + "group": "Secrets", + "pages": [ + "api-reference/endpoints/secrets/create", + "api-reference/endpoints/secrets/read", + "api-reference/endpoints/secrets/update", + "api-reference/endpoints/secrets/delete", + "api-reference/endpoints/secrets/versions", + "api-reference/endpoints/secrets/rollback-version" + ] } ] - }, + }, { "group": "Integrations", - "pages": [ - "integrations/overview" - ] + "pages": ["integrations/overview"] }, { "group": "Platforms", "pages": [ "integrations/platforms/docker", - "integrations/platforms/docker-compose" + "integrations/platforms/docker-compose", + "integrations/platforms/kubernetes" ] }, { "group": "Cloud", "pages": [ "integrations/cloud/heroku", - "integrations/cloud/vercel" + "integrations/cloud/vercel", + "integrations/cloud/netlify", + "integrations/cloud/render", + "integrations/cloud/flyio" + ] + }, + { + "group": "CI/CD", + "pages": [ + "integrations/cicd/githubactions", + "integrations/cicd/circleci" ] }, { @@ -150,7 +245,8 @@ "integrations/frameworks/django", "integrations/frameworks/flask", "integrations/frameworks/laravel", - "integrations/frameworks/rails" + "integrations/frameworks/rails", + "integrations/frameworks/dotnet" ] }, { @@ -166,10 +262,12 @@ "pages": [ "contributing/overview", "contributing/code-of-conduct", - "contributing/developing", - "contributing/FAQ" + "contributing/developing" ] } ], - "backgroundImage": "/images/background.png" + "backgroundImage": "/images/background.png", + "integrations": { + "intercom": "hsg644ru" + } } diff --git a/docs/security/data-model.mdx b/docs/security/data-model.mdx index 6c60f9e41..a8f8dd9b7 100644 --- a/docs/security/data-model.mdx +++ b/docs/security/data-model.mdx @@ -1,5 +1,6 @@ --- title: "Data Model" +description: "Infisical's current Data Structure." --- Infisical stores a range of data namely user, secrets, keys, organization, project, and membership data. diff --git a/docs/security/mechanics.mdx b/docs/security/mechanics.mdx index 814524d73..0fb25b8b2 100644 --- a/docs/security/mechanics.mdx +++ b/docs/security/mechanics.mdx @@ -1,5 +1,6 @@ --- title: "Mechanics" +description: "Quick explanation of how Infisical works." --- ## Signup diff --git a/docs/security/overview.mdx b/docs/security/overview.mdx index b4e1169df..643a54b38 100644 --- a/docs/security/overview.mdx +++ b/docs/security/overview.mdx @@ -1,12 +1,13 @@ --- title: "Overview" +description: "Infisical's security statement." --- ## Summary Infisical uses end-to-end encryption (E2EE) whenever possible to securely store and share secrets. It uses secure remote password (SRP) to handle authentication and public-key cryptography for secret sharing and syncing; secrets are symmetrically encrypted at rest by keys decryptable only by members of the project. -Infisical uses AES256-GCM for symmetric encryption and x2519-xsalsa20-poly1305 for asymmetric encryption operations mentioned in this brief; key generation and asymmetric algorithms are implemented with the [TweetNaCl.js](https://tweetnacl.js.org/#/) library which has been well-audited and recommended for use by cybersecurity firm Cure53. Lastly, the secure remote password (SRP) implementation uses [jsrp](https://github.com/alax/jsrp) package for user authentication. As part of our commitment to user privacy and security, we aim to conduct formal security and compliance audits in the following year. +Infisical uses AES256-GCM for symmetric encryption and x25519-xsalsa20-poly1305 for asymmetric encryption operations mentioned in this brief; key generation and asymmetric algorithms are implemented with the [TweetNaCl.js](https://tweetnacl.js.org/#/) library which has been well-audited and recommended for use by cybersecurity firm Cure53. Lastly, the secure remote password (SRP) implementation uses [jsrp](https://github.com/alax/jsrp) package for user authentication. As part of our commitment to user privacy and security, we aim to conduct formal security and compliance audits in the following year. ## Scope diff --git a/docs/self-hosting/configuration/email.mdx b/docs/self-hosting/configuration/email.mdx new file mode 100644 index 000000000..8cb6525d3 --- /dev/null +++ b/docs/self-hosting/configuration/email.mdx @@ -0,0 +1,97 @@ +--- +title: "Email" +description: "How to configure your email when self-hosting Infisical." +--- + +Infisical requires you to configure your own SMTP server for certain functionality like: + +- Sending email confirmation links to sign up. +- Sending invite links for projects. +- Sending alerts. + +We strongly recommend using an email service to act as your email server and provide examples for common providers. + +## General configuration + +By default, you need to configure the following SMTP [environment variables](https://infisical.com/docs/self-hosting/configuration/envars): + +- `SMTP_HOST`: Hostname to connect to for establishing SMTP connections. +- `SMTP_USERNAME`: Credential to connect to host (e.g. team@infisical.com) +- `SMTP_PASSWORD`: Credential to connect to host. +- `SMTP_PORT`: Port to connect to for establishing SMTP connections. +- `SMTP_SECURE`: If `true`, the connection will use TLS when connecting to server with special configs for SendGrid and Mailgun. If `false` (the default) then TLS is used if server supports the STARTTLS extension. +- `SMTP_FROM_ADDRESS`: Email address to be used for sending emails (e.g. team@infisical.com). +- `SMTP_FROM_NAME`: Name label to be used in `From` field (e.g. Team). + +Below you will find details on how to configure common email providers (not in any particular order). + +## Twilio SendGrid + +1. Create an account and configure [SendGrid](https://sendgrid.com) to send emails. +2. Create a SendGrid API Key under Settings > [API Keys](https://app.sendgrid.com/settings/api_keys) +3. Set a name for your API Key, we recommend using "Infisical," and select the "Restricted Key" option. You will need to enable the "Mail Send" permission as shown below: + +![creating sendgrid api key](../../images/email-sendgrid-create-key.png) + +![setting sendgrid api key restriction](../../images/email-sendgrid-restrictions.png) + +4. With the API Key, you can now set your SMTP environment variables: + +``` +SMTP_HOST=smtp.sendgrid.net +SMTP_USERNAME=apikey +SMTP_PASSWORD=SG.rqFsfjxYPiqE1lqZTgD_lz7x8IVLx # your SendGrid API Key from step above +SMTP_PORT=587 +SMTP_SECURE=true +SMTP_FROM_ADDRESS=hey@example.com # your email address being used to send out emails +SMTP_FROM_NAME=Infisical +``` + + + Remember that you will need to restart Infisical for this to work properly. + + +## Mailgun + +1. Create an account and configure [Mailgun](https://www.mailgun.com) to send emails. +2. Obtain your Mailgun credentials in Sending > Overview > SMTP + +![obtain mailhog api key estriction](../../images/email-mailhog-credentials.png) + +3. With your Mailgun credentials, you can now set up your SMTP environment variables: + +``` +SMTP_HOST=smtp.mailgun.org # obtained from credentials page +SMTP_USERNAME=postmaster@example.mailgun.org # obtained from credentials page +SMTP_PASSWORD=password # obtained from credentials page +SMTP_PORT=587 +SMTP_SECURE=true +SMTP_FROM_ADDRESS=hey@example.com # your email address being used to send out emails +SMTP_FROM_NAME=Infisical +``` + +## AWS SES + +1. Create an account and [configure AWS SES](https://aws.amazon.com/premiumsupport/knowledge-center/ses-set-up-connect-smtp/) to send emails in the Amazon SES console. +2. Create an IAM user for SMTP authentication and obtain SMTP credentials in SMTP settings > Create SMTP credentials + +![opening AWS SES console](../../images/email-aws-ses-console.png) + +![creating AWS IAM SES user](../../images/email-aws-ses-user.png) + +3. With your AWS SES SMTP credentials, you can now set up your SMTP environment variables: + +``` +SMTP_HOST=smtp.mailgun.org # obtained from credentials page +SMTP_HOST=email-smtp.ap-northeast-1.amazonaws.com # SMTP endpoint obtained from SMTP settings +SMTP_USERNAME=xxx # your SMTP username +SMTP_PASSWORD=xxx # your SMTP password +SMTP_PORT=587 +SMTP_SECURE=true +SMTP_FROM_ADDRESS=hey@example.com # your email address being used to send out emails +SMTP_FROM_NAME=Infisical +``` + + + Remember that you will need to restart Infisical for this to work properly. + diff --git a/docs/self-hosting/configuration/envars.mdx b/docs/self-hosting/configuration/envars.mdx index a55efbebc..39d6542c9 100644 --- a/docs/self-hosting/configuration/envars.mdx +++ b/docs/self-hosting/configuration/envars.mdx @@ -1,20 +1,17 @@ --- title: "Environment Variables" -description: "" +description: "How to configure your environment variables when self-hosting Infisical." --- -## The .env file - -Configuring Infisical requires setting some environment variables. There is a file called `.env.example` at the root directory of our main repo that you can use to create a `.env` before you start the server. +Configuring Infisical requires setting some environment variables. There is a file called [`.env.example`](https://github.com/Infisical/infisical/blob/main/.env.example) at the root directory of our main repo that you can use to create a `.env` file before you start the server. | Variable | Description | Default Value | | ---------------------------- | ----------------------------------------------------------------------------------------------------------- | ---------------- | -| `PRIVATE_KEY` | โ—๏ธ NaCl-generated server secret key | `None` | -| `PUBLIC_KEY` | โ—๏ธ NaCl-generated server public key | `None` | | `ENCRYPTION_KEY` | โ—๏ธ Strong hex encryption key | `None` | | `JWT_SIGNUP_SECRET` | โ—๏ธ JWT token secret | `None` | | `JWT_REFRESH_SECRET` | โ—๏ธ JWT token secret | `None` | | `JWT_AUTH_SECRET` | โ—๏ธ JWT token secret | `None` | +| `JWT_SERVICE_SECRET` | โ—๏ธ JWT token secret | `None` | | `JWT_SIGNUP_LIFETIME` | JWT token lifetime expressed in seconds or a string describing a time span (e.g. 60, "2 days", "10h", "7d") | `15m` | | `JWT_REFRESH_LIFETIME` | JWT token lifetime expressed in seconds or a string describing a time span (e.g. 60, "2 days", "10h", "7d") | `90d` | | `JWT_AUTH_LIFETIME` | JWT token lifetime expressed in seconds or a string describing a time span (e.g. 60, "2 days", "10h", "7d") | `10d` | @@ -23,11 +20,22 @@ Configuring Infisical requires setting some environment variables. There is a fi | `MONGO_USERNAME` | MongoDB username if using container | `None` | | `MONGO_PASSWORD` | MongoDB password if using container | `None` | | `SITE_URL` | โ—๏ธ Site URL - should be an absolute URL including the protocol (e.g. `https://app.infisical.com`) | `None` | -| `SMTP_HOST` | Hostname to connect to for establishing SMTP connections | `smtp.gmail.com` | -| `SMTP_NAME` | Name label to be used in From field (e.g. `Team`) | `None` | +| `SMTP_HOST` | โ—๏ธ Hostname to connect to for establishing SMTP connections | `None` | | `SMTP_USERNAME` | โ—๏ธ Credential to connect to host (e.g. `team@infisical.com`) | `None` | | `SMTP_PASSWORD` | โ—๏ธ Credential to connect to host | `None` | +| `SMTP_PORT` | Port to connect to for establishing SMTP connections | `587` | +| `SMTP_SECURE` | If true, use TLS when connecting to host. If false, TLS will be used if STARTTLS is supported | `false` | +| `SMTP_FROM_ADDRESS` | โ—๏ธ Email address to be used for sending emails (e.g. `team@infisical.com`) | `None` | +| `SMTP_FROM_NAME` | Name label to be used in From field (e.g. `Team`) | `Infisical` | | `TELEMETRY_ENABLED` | `true` or `false`. [More](../overview). | `true` | -| `OAUTH_CLIENT_SECRET_HEROKU` | OAuth client secret for Heroku integration | `None` | -| `OAUTH_TOKEN_URL_HEROKU` | OAuth token URL for Heroku integration | `None` | +| `LICENSE_KEY` | License key if using Infisical Enterprise Edition | `true` | +| `CLIENT_ID_HEROKU` | OAuth2 client ID for Heroku integration | `None` | +| `CLIENT_ID_VERCEL` | OAuth2 client ID for Vercel integration | `None` | +| `CLIENT_ID_NETLIFY` | OAuth2 client ID for Netlify integration | `None` | +| `CLIENT_ID_GITHUB` | OAuth2 client ID for GitHub integration | `None` | +| `CLIENT_SECRET_HEROKU` | OAuth2 client secret for Heroku integration | `None` | +| `CLIENT_SECRET_VERCEL` | OAuth2 client secret for Vercel integration | `None` | +| `CLIENT_SECRET_NETLIFY` | OAuth2 client secret for Netlify integration | `None` | +| `CLIENT_SECRET_GITHUB` | OAuth2 client secret for GitHub integration | `None` | +| `CLIENT_SLUG_VERCEL` | OAuth2 slug for Netlify integration | `None` | | `SENTRY_DSN` | DSN for error-monitoring with Sentry | `None` | diff --git a/docs/self-hosting/deployments/kubernetes.mdx b/docs/self-hosting/deployments/kubernetes.mdx index 8ed2c0e05..28bdc2416 100644 --- a/docs/self-hosting/deployments/kubernetes.mdx +++ b/docs/self-hosting/deployments/kubernetes.mdx @@ -1,6 +1,6 @@ --- title: "Kubernetes" -description: "Deploy with Kubernetes" +description: "How to deploy Infisical with Kubernetes" --- @@ -20,9 +20,120 @@ If you're less technical and looking for a hands-free experience with minimal ov #### 1. Fill our environment variables -Before you can deploy the Helm chart, you must fill out the required environment variables. To do so, please either download or copy the -contents of [this file](https://raw.githubusercontent.com/Infisical/infisical/main/helm-charts/infisical/values.yaml) to a `.yaml` file. -_Refer to the available [environment variables](../../self-hosting/configuration/envars)_ +Before you can deploy the Helm chart, you must fill out the required environment variables. To do so, please copy the below file to a `.yaml` file. +Refer to the available [environment variables](../../self-hosting/configuration/envars) to learn more + + +```yaml +##### +# INFISICAL K8 DEFAULT VALUES FILE +# PLEASE REPLACE VALUES/EDIT AS REQUIRED +##### + +nameOverride: "" + +frontend: + name: frontend + podAnnotations: {} + deploymentAnnotations: {} + replicaCount: 2 + image: + repository: infisical/frontend + pullPolicy: Always + tag: "latest" # It it highly recommended to select a specific tag for prod deployment so it is easy to rollback: https://hub.docker.com/r/infisical/frontend/tags + # kubeSecretRef: some-kube-secret-name + service: + # type of the frontend service + type: ClusterIP + # define the nodePort if service type is NodePort + # nodePort: + annotations: {} + +backend: + name: backend + podAnnotations: {} + deploymentAnnotations: {} + replicaCount: 2 + image: + repository: infisical/backend + pullPolicy: Always + tag: "latest" # It it highly recommended to select a specific tag for prod deployment so it is easy to rollback: https://hub.docker.com/r/infisical/backend/tags + # kubeSecretRef: some-kube-secret-name + service: + annotations: {} + +mongodb: + name: mongodb + podAnnotations: {} + image: + repository: mongo + pullPolicy: IfNotPresent + tag: "latest" + service: + annotations: {} + +# By default the backend will be connected to a Mongo instance in the cluster. +# However, it is recommended to add a managed document DB connection string because the DB instance in the cluster does not have persistence yet ( data will be deleted on next deploy). +# Learn about connection string type here https://www.mongodb.com/docs/manual/reference/connection-string/ +mongodbConnection: {} + # externalMongoDBConnectionString: <> + +ingress: + enabled: true + annotations: + kubernetes.io/ingress.class: "nginx" + hostName: example.com # replace with your domain + frontend: + path: / + pathType: Prefix + backend: + path: /api + pathType: Prefix + tls: [] + + +## Complete Ingress example +# ingress: +# enabled: true +# annotations: +# kubernetes.io/ingress.class: "nginx" +# cert-manager.io/issuer: letsencrypt-nginx +# hostName: k8.infisical.com +# frontend: +# path: / +# pathType: Prefix +# backend: +# path: /api +# pathType: Prefix +# tls: +# - secretName: letsencrypt-nginx +# hosts: +# - k8.infisical.com + +### +### YOU MUST FILL IN ALL SECRETS BELOW +### +backendEnvironmentVariables: + # Required keys for platform encryption/decryption ops. Replace with nacl sk keys + ENCRYPTION_KEY: MUST_REPLACE + + # JWT + # Required secrets to sign JWT tokens + JWT_SIGNUP_SECRET: MUST_REPLACE + JWT_REFRESH_SECRET: MUST_REPLACE + JWT_AUTH_SECRET: MUST_REPLACE + + # Mail/SMTP + # Required to send emails + SMTP_HOST: MUST_REPLACE + SMTP_NAME: MUST_REPLACE + SMTP_USERNAME: MUST_REPLACE + SMTP_PASSWORD: MUST_REPLACE + +frontendEnvironmentVariables: {} + +``` + Once you have a local copy of the values file, fill our the required environment variables and save the file. @@ -42,7 +153,7 @@ that by adding the `--namespace ` to your `helm install ```bash ## Installs to default namespace -helm install infisical-helm-charts/infisical --values +helm install infisical-helm-charts/infisical --generate-name --values ``` @@ -50,5 +161,4 @@ If you have not filled out all of the required environment variables, you will s do so. -4. Your Infisical installation is complete and should be running on the host name you specified in Ingress in `values.yaml`. -Note: Please allow an additional time (2 minutes) for the frontend pods to be fully ready. \ No newline at end of file +#### 4. Your Infisical installation is complete and should be running on the host name you specified in Ingress in `values.yaml`. \ No newline at end of file diff --git a/docs/self-hosting/deployments/linux.mdx b/docs/self-hosting/deployments/linux.mdx index 0282e46de..771a4104a 100644 --- a/docs/self-hosting/deployments/linux.mdx +++ b/docs/self-hosting/deployments/linux.mdx @@ -1,6 +1,6 @@ --- title: "Linux VM" -description: "Deploy with Docker-Compose" +description: "How to deploy Infisical with Docker-Compose" --- diff --git a/docs/self-hosting/overview.mdx b/docs/self-hosting/overview.mdx index b0729637c..7f3bc30bf 100644 --- a/docs/self-hosting/overview.mdx +++ b/docs/self-hosting/overview.mdx @@ -1,5 +1,6 @@ --- title: "Overview" +description: "Infisical is an open-source end-to-end encrypted secrets manager that developers can set up within 15 minutes." --- diff --git a/docs/spec.yaml b/docs/spec.yaml new file mode 100644 index 000000000..3d5ca4d7d --- /dev/null +++ b/docs/spec.yaml @@ -0,0 +1,2621 @@ +openapi: 3.0.0 +info: + title: Infisical API + description: List of all available APIs that can be consumed + version: 1.0.0 +servers: + - url: https://infisical.com + description: Production server + - url: http://localhost:8080 + description: Local server +paths: + /api/v1/secret/{secretId}/secret-versions: + get: + summary: Return secret versions + description: Return secret versions + parameters: + - name: secretId + in: path + required: true + schema: + type: string + description: ID of secret + - name: offset + description: Number of versions to skip + required: false + in: query + schema: + type: string + - name: limit + description: Maximum number of versions to return + required: false + in: query + schema: + type: string + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + properties: + secretVersions: + type: array + items: + $ref: '#/components/schemas/SecretVersion' + description: Secret versions + '400': + description: Bad Request + security: + - apiKeyAuth: [] + /api/v1/secret/{secretId}/secret-versions/rollback: + post: + summary: Roll back secret to a version. + description: Roll back secret to a version. + parameters: + - name: secretId + in: path + required: true + schema: + type: string + description: ID of secret + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + properties: + secret: + type: object + $ref: '#/components/schemas/Secret' + description: Secret rolled back to + '400': + description: Bad Request + security: + - apiKeyAuth: [] + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + version: + type: integer + description: Version of secret to roll back to + /api/v1/secret-snapshot/{secretSnapshotId}: + get: + description: '' + parameters: + - name: secretSnapshotId + in: path + required: true + schema: + type: string + responses: + '200': + description: OK + '400': + description: Bad Request + /api/v1/workspace/{workspaceId}/secret-snapshots: + get: + summary: Return project secret snapshot ids + description: Return project secret snapshots ids + parameters: + - name: workspaceId + in: path + required: true + schema: + type: string + description: ID of project + - name: offset + description: Number of secret snapshots to skip + required: false + in: query + schema: + type: string + - name: limit + description: Maximum number of secret snapshots to return + required: false + in: query + schema: + type: string + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + properties: + secretSnapshots: + type: array + items: + $ref: '#/components/schemas/SecretSnapshot' + description: Project secret snapshots + '400': + description: Bad Request + security: + - apiKeyAuth: [] + /api/v1/workspace/{workspaceId}/secret-snapshots/count: + get: + description: '' + parameters: + - name: workspaceId + in: path + required: true + schema: + type: string + responses: + '200': + description: OK + '400': + description: Bad Request + /api/v1/workspace/{workspaceId}/secret-snapshots/rollback: + post: + summary: >- + Roll back project secrets to those captured in a secret snapshot + version. + description: >- + Roll back project secrets to those captured in a secret snapshot + version. + parameters: + - name: workspaceId + in: path + required: true + schema: + type: string + description: ID of project + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + properties: + secrets: + type: array + items: + $ref: '#/components/schemas/Secret' + description: Secrets rolled back to + '400': + description: Bad Request + security: + - apiKeyAuth: [] + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + version: + type: integer + description: Version of secret snapshot to roll back to + /api/v1/workspace/{workspaceId}/logs: + get: + summary: Return project (audit) logs + description: Return project (audit) logs + parameters: + - name: workspaceId + in: path + required: true + schema: + type: string + description: ID of project + - name: userId + description: ID of project member + required: false + in: query + schema: + type: string + - name: offset + description: Number of logs to skip + required: false + in: query + schema: + type: string + - name: limit + description: Maximum number of logs to return + required: false + in: query + schema: + type: string + - name: sortBy + description: Order to sort the logs by + schema: + type: string + enum: + - oldest + - recent + required: false + in: query + - name: actionNames + description: Names of log actions (comma-separated) + required: false + in: query + schema: + type: string + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + properties: + logs: + type: array + items: + $ref: '#/components/schemas/Log' + description: Project logs + '400': + description: Bad Request + security: + - apiKeyAuth: [] + /api/v1/action/{actionId}: + get: + description: '' + parameters: + - name: actionId + in: path + required: true + schema: + type: string + responses: + '200': + description: OK + /api/v1/signup/email/signup: + post: + description: '' + parameters: [] + responses: + '200': + description: OK + '400': + description: Bad Request + '403': + description: Forbidden + requestBody: + content: + application/json: + schema: + type: object + properties: + email: + example: any + /api/v1/signup/email/verify: + post: + description: '' + parameters: [] + responses: + '200': + description: OK + '400': + description: Bad Request + '403': + description: Forbidden + requestBody: + content: + application/json: + schema: + type: object + properties: + email: + example: any + code: + example: any + /api/v1/signup/complete-account/signup: + post: + description: '' + parameters: [] + responses: + '200': + description: OK + '400': + description: Bad Request + '403': + description: Forbidden + requestBody: + content: + application/json: + schema: + type: object + properties: + email: + example: any + firstName: + example: any + lastName: + example: any + publicKey: + example: any + encryptedPrivateKey: + example: any + iv: + example: any + tag: + example: any + salt: + example: any + verifier: + example: any + organizationName: + example: any + /api/v1/signup/complete-account/invite: + post: + description: '' + parameters: [] + responses: + '200': + description: OK + '400': + description: Bad Request + '403': + description: Forbidden + requestBody: + content: + application/json: + schema: + type: object + properties: + email: + example: any + firstName: + example: any + lastName: + example: any + publicKey: + example: any + encryptedPrivateKey: + example: any + iv: + example: any + tag: + example: any + salt: + example: any + verifier: + example: any + /api/v1/auth/token: + post: + description: '' + parameters: [] + responses: + '200': + description: OK + '400': + description: Bad Request + /api/v1/auth/login1: + post: + description: '' + parameters: [] + responses: + '200': + description: OK + '400': + description: Bad Request + requestBody: + content: + application/json: + schema: + type: object + properties: + email: + example: any + clientPublicKey: + example: any + /api/v1/auth/login2: + post: + description: '' + parameters: [] + responses: + '200': + description: OK + '400': + description: Bad Request + requestBody: + content: + application/json: + schema: + type: object + properties: + email: + example: any + clientProof: + example: any + /api/v1/auth/logout: + post: + description: '' + parameters: [] + responses: + '200': + description: OK + '400': + description: Bad Request + /api/v1/auth/checkAuth: + post: + description: '' + parameters: [] + responses: + '200': + description: OK + /api/v1/bot/{workspaceId}: + get: + description: '' + parameters: + - name: workspaceId + in: path + required: true + schema: + type: string + responses: + '200': + description: OK + '400': + description: Bad Request + /api/v1/bot/{botId}/active: + patch: + description: '' + parameters: + - name: botId + in: path + required: true + schema: + type: string + responses: + '200': + description: OK + '400': + description: Bad Request + requestBody: + content: + application/json: + schema: + type: object + properties: + isActive: + example: any + botKey: + example: any + /api/v1/user/: + get: + description: '' + parameters: [] + responses: + '200': + description: OK + /api/v1/user-action/: + post: + description: '' + parameters: [] + responses: + '200': + description: OK + '400': + description: Bad Request + requestBody: + content: + application/json: + schema: + type: object + properties: + action: + example: any + get: + description: '' + parameters: + - name: action + in: query + schema: + type: string + responses: + '200': + description: OK + '400': + description: Bad Request + /api/v1/organization/: + get: + description: '' + parameters: [] + responses: + '200': + description: OK + '400': + description: Bad Request + post: + description: '' + parameters: [] + responses: + '200': + description: OK + '400': + description: Bad Request + requestBody: + content: + application/json: + schema: + type: object + properties: + organizationName: + example: any + /api/v1/organization/{organizationId}: + get: + description: '' + parameters: + - name: organizationId + in: path + required: true + schema: + type: string + responses: + '200': + description: OK + '400': + description: Bad Request + /api/v1/organization/{organizationId}/users: + get: + description: '' + parameters: + - name: organizationId + in: path + required: true + schema: + type: string + responses: + '200': + description: OK + '400': + description: Bad Request + /api/v1/organization/{organizationId}/my-workspaces: + get: + description: '' + parameters: + - name: organizationId + in: path + required: true + schema: + type: string + responses: + '200': + description: OK + '400': + description: Bad Request + /api/v1/organization/{organizationId}/name: + patch: + description: '' + parameters: + - name: organizationId + in: path + required: true + schema: + type: string + responses: + '200': + description: OK + '400': + description: Bad Request + requestBody: + content: + application/json: + schema: + type: object + properties: + name: + example: any + /api/v1/organization/{organizationId}/incidentContactOrg: + get: + description: '' + parameters: + - name: organizationId + in: path + required: true + schema: + type: string + responses: + '200': + description: OK + '400': + description: Bad Request + post: + description: '' + parameters: + - name: organizationId + in: path + required: true + schema: + type: string + responses: + '200': + description: OK + '400': + description: Bad Request + requestBody: + content: + application/json: + schema: + type: object + properties: + email: + example: any + delete: + description: '' + parameters: + - name: organizationId + in: path + required: true + schema: + type: string + responses: + '200': + description: OK + '400': + description: Bad Request + requestBody: + content: + application/json: + schema: + type: object + properties: + email: + example: any + /api/v1/organization/{organizationId}/customer-portal-session: + post: + description: '' + parameters: + - name: organizationId + in: path + required: true + schema: + type: string + responses: + '200': + description: OK + '400': + description: Bad Request + /api/v1/organization/{organizationId}/subscriptions: + get: + description: '' + parameters: + - name: organizationId + in: path + required: true + schema: + type: string + responses: + '200': + description: OK + '400': + description: Bad Request + /api/v1/workspace/{workspaceId}/keys: + get: + description: '' + parameters: + - name: workspaceId + in: path + required: true + schema: + type: string + responses: + '200': + description: OK + '400': + description: Bad Request + /api/v1/workspace/{workspaceId}/users: + get: + description: '' + parameters: + - name: workspaceId + in: path + required: true + schema: + type: string + responses: + '200': + description: OK + '400': + description: Bad Request + /api/v1/workspace/: + get: + description: '' + parameters: [] + responses: + '200': + description: OK + '400': + description: Bad Request + post: + description: '' + parameters: [] + responses: + '200': + description: OK + '400': + description: Bad Request + requestBody: + content: + application/json: + schema: + type: object + properties: + workspaceName: + example: any + organizationId: + example: any + /api/v1/workspace/{workspaceId}: + get: + description: '' + parameters: + - name: workspaceId + in: path + required: true + schema: + type: string + responses: + '200': + description: OK + '400': + description: Bad Request + delete: + description: '' + parameters: + - name: workspaceId + in: path + required: true + schema: + type: string + responses: + '200': + description: OK + '400': + description: Bad Request + /api/v1/workspace/{workspaceId}/name: + post: + description: '' + parameters: + - name: workspaceId + in: path + required: true + schema: + type: string + responses: + '200': + description: OK + '400': + description: Bad Request + requestBody: + content: + application/json: + schema: + type: object + properties: + name: + example: any + /api/v1/workspace/{workspaceId}/invite-signup: + post: + description: '' + parameters: + - name: workspaceId + in: path + required: true + schema: + type: string + responses: + '200': + description: OK + '400': + description: Bad Request + requestBody: + content: + application/json: + schema: + type: object + properties: + email: + example: any + /api/v1/workspace/{workspaceId}/integrations: + get: + description: '' + parameters: + - name: workspaceId + in: path + required: true + schema: + type: string + responses: + '200': + description: OK + '400': + description: Bad Request + /api/v1/workspace/{workspaceId}/authorizations: + get: + description: '' + parameters: + - name: workspaceId + in: path + required: true + schema: + type: string + responses: + '200': + description: OK + '400': + description: Bad Request + /api/v1/workspace/{workspaceId}/service-tokens: + get: + description: '' + parameters: + - name: workspaceId + in: path + required: true + schema: + type: string + responses: + '200': + description: OK + '400': + description: Bad Request + /api/v1/membership-org/membershipOrg/{membershipOrgId}/change-role: + post: + description: '' + parameters: + - name: membershipOrgId + in: path + required: true + schema: + type: string + responses: + '200': + description: OK + /api/v1/membership-org/{membershipOrgId}: + delete: + description: '' + parameters: + - name: membershipOrgId + in: path + required: true + schema: + type: string + responses: + '400': + description: Bad Request + /api/v1/membership/{workspaceId}/connect: + get: + description: '' + parameters: + - name: workspaceId + in: path + required: true + schema: + type: string + responses: + '200': + description: OK + '400': + description: Bad Request + /api/v1/membership/{membershipId}: + delete: + description: '' + parameters: + - name: membershipId + in: path + required: true + schema: + type: string + responses: + '200': + description: OK + '400': + description: Bad Request + /api/v1/membership/{membershipId}/change-role: + post: + description: '' + parameters: + - name: membershipId + in: path + required: true + schema: + type: string + responses: + '200': + description: OK + '400': + description: Bad Request + requestBody: + content: + application/json: + schema: + type: object + properties: + role: + example: any + /api/v1/key/{workspaceId}: + post: + description: '' + parameters: + - name: workspaceId + in: path + required: true + schema: + type: string + responses: + '200': + description: OK + '400': + description: Bad Request + requestBody: + content: + application/json: + schema: + type: object + properties: + key: + example: any + /api/v1/key/{workspaceId}/latest: + get: + description: '' + parameters: + - name: workspaceId + in: path + required: true + schema: + type: string + responses: + '200': + description: OK + '400': + description: Bad Request + /api/v1/invite-org/signup: + post: + description: '' + parameters: [] + responses: + '200': + description: OK + '400': + description: Bad Request + requestBody: + content: + application/json: + schema: + type: object + properties: + organizationId: + example: any + inviteeEmail: + example: any + /api/v1/invite-org/verify: + post: + description: '' + parameters: [] + responses: + '200': + description: OK + '400': + description: Bad Request + requestBody: + content: + application/json: + schema: + type: object + properties: + email: + example: any + code: + example: any + /api/v1/secret/{workspaceId}: + post: + description: '' + parameters: + - name: workspaceId + in: path + required: true + schema: + type: string + responses: + '200': + description: OK + '400': + description: Bad Request + requestBody: + content: + application/json: + schema: + type: object + properties: + secrets: + example: any + keys: + example: any + environment: + example: any + channel: + example: any + get: + description: '' + parameters: + - name: workspaceId + in: path + required: true + schema: + type: string + - name: environment + in: query + schema: + type: string + - name: channel + in: query + schema: + type: string + responses: + '200': + description: OK + '400': + description: Bad Request + /api/v1/secret/{workspaceId}/service-token: + get: + description: '' + parameters: + - name: workspaceId + in: path + required: true + schema: + type: string + - name: environment + in: query + schema: + type: string + - name: channel + in: query + schema: + type: string + responses: + '200': + description: OK + '400': + description: Bad Request + /api/v1/service-token/: + get: + description: '' + parameters: [] + responses: + '200': + description: OK + post: + description: '' + parameters: [] + responses: + '200': + description: OK + '400': + description: Bad Request + requestBody: + content: + application/json: + schema: + type: object + properties: + name: + example: any + workspaceId: + example: any + environment: + example: any + expiresIn: + example: any + publicKey: + example: any + encryptedKey: + example: any + nonce: + example: any + /api/v1/password/srp1: + post: + description: '' + parameters: [] + responses: + '200': + description: OK + '400': + description: Bad Request + requestBody: + content: + application/json: + schema: + type: object + properties: + clientPublicKey: + example: any + /api/v1/password/change-password: + post: + description: '' + parameters: [] + responses: + '200': + description: OK + '400': + description: Bad Request + requestBody: + content: + application/json: + schema: + type: object + properties: + clientProof: + example: any + encryptedPrivateKey: + example: any + iv: + example: any + tag: + example: any + salt: + example: any + verifier: + example: any + /api/v1/password/email/password-reset: + post: + description: '' + parameters: [] + responses: + '200': + description: OK + '400': + description: Bad Request + '403': + description: Forbidden + requestBody: + content: + application/json: + schema: + type: object + properties: + email: + example: any + /api/v1/password/email/password-reset-verify: + post: + description: '' + parameters: [] + responses: + '200': + description: OK + '400': + description: Bad Request + '403': + description: Forbidden + requestBody: + content: + application/json: + schema: + type: object + properties: + email: + example: any + code: + example: any + /api/v1/password/backup-private-key: + get: + description: '' + parameters: [] + responses: + '200': + description: OK + '400': + description: Bad Request + post: + description: '' + parameters: [] + responses: + '200': + description: OK + '400': + description: Bad Request + requestBody: + content: + application/json: + schema: + type: object + properties: + clientProof: + example: any + encryptedPrivateKey: + example: any + iv: + example: any + tag: + example: any + salt: + example: any + verifier: + example: any + /api/v1/password/password-reset: + post: + description: '' + parameters: [] + responses: + '200': + description: OK + '400': + description: Bad Request + requestBody: + content: + application/json: + schema: + type: object + properties: + encryptedPrivateKey: + example: any + iv: + example: any + tag: + example: any + salt: + example: any + verifier: + example: any + /api/v1/stripe/webhook: + post: + description: '' + parameters: + - name: stripe-signature + in: header + schema: + type: string + responses: + '200': + description: OK + '400': + description: Bad Request + /api/v1/integration/{integrationId}: + patch: + description: '' + parameters: + - name: integrationId + in: path + required: true + schema: + type: string + responses: + '200': + description: OK + '400': + description: Bad Request + requestBody: + content: + application/json: + schema: + type: object + properties: + app: + example: any + environment: + example: any + isActive: + example: any + target: + example: any + context: + example: any + siteId: + example: any + delete: + description: '' + parameters: + - name: integrationId + in: path + required: true + schema: + type: string + responses: + '200': + description: OK + '400': + description: Bad Request + /api/v1/integration-auth/integration-options: + get: + description: '' + parameters: [] + responses: + '200': + description: OK + /api/v1/integration-auth/oauth-token: + post: + description: '' + parameters: [] + responses: + '200': + description: OK + '400': + description: Bad Request + requestBody: + content: + application/json: + schema: + type: object + properties: + workspaceId: + example: any + code: + example: any + integration: + example: any + /api/v1/integration-auth/{integrationAuthId}/apps: + get: + description: '' + parameters: + - name: integrationAuthId + in: path + required: true + schema: + type: string + responses: + '200': + description: OK + '400': + description: Bad Request + /api/v1/integration-auth/{integrationAuthId}: + delete: + description: '' + parameters: + - name: integrationAuthId + in: path + required: true + schema: + type: string + responses: + '200': + description: OK + '400': + description: Bad Request + /api/v2/users/me: + get: + summary: Retrieve the current user on the request + description: Retrieve the current user on the request + parameters: [] + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + properties: + user: + type: object + $ref: '#/components/schemas/CurrentUser' + description: Current user on request + '400': + description: Bad Request + security: + - apiKeyAuth: [] + /api/v2/users/me/organizations: + get: + summary: Return organizations that current user is part of + description: Return organizations that current user is part of + parameters: [] + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + properties: + organizations: + type: array + items: + $ref: '#/components/schemas/Organization' + description: Organizations that user is part of + '400': + description: Bad Request + security: + - apiKeyAuth: [] + /api/v2/organizations/{organizationId}/memberships: + get: + summary: Return organization memberships + description: Return organization memberships + parameters: + - name: organizationId + in: path + required: true + schema: + type: string + description: ID of organization + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + properties: + memberships: + type: array + items: + $ref: '#/components/schemas/MembershipOrg' + description: Memberships of organization + '400': + description: Bad Request + security: + - apiKeyAuth: [] + /api/v2/organizations/{organizationId}/memberships/{membershipId}: + patch: + summary: Update organization membership + description: Update organization membership + parameters: + - name: organizationId + in: path + required: true + schema: + type: string + description: ID of organization + - name: membershipId + in: path + required: true + schema: + type: string + description: ID of organization membership to update + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + properties: + membership: + $ref: '#/components/schemas/MembershipOrg' + description: Updated organization membership + '400': + description: Bad Request + security: + - apiKeyAuth: [] + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + role: + type: string + description: >- + Role of organization membership - either owner, admin, or + member + delete: + summary: Delete organization membership + description: Delete organization membership + parameters: + - name: organizationId + in: path + required: true + schema: + type: string + description: ID of organization + - name: membershipId + in: path + required: true + schema: + type: string + description: ID of organization membership to delete + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + properties: + membership: + $ref: '#/components/schemas/MembershipOrg' + description: Deleted organization membership + '400': + description: Bad Request + security: + - apiKeyAuth: [] + /api/v2/organizations/{organizationId}/workspaces: + get: + summary: Return projects in organization that user is part of + description: Return projects in organization that user is part of + parameters: + - name: organizationId + in: path + required: true + schema: + type: string + description: ID of organization + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + properties: + workspaces: + type: array + items: + $ref: '#/components/schemas/Project' + description: Projects of organization + '400': + description: Bad Request + security: + - apiKeyAuth: [] + /api/v2/workspace/{workspaceId}/environments: + post: + description: '' + parameters: + - name: workspaceId + in: path + required: true + schema: + type: string + responses: + '200': + description: OK + '400': + description: Bad Request + requestBody: + content: + application/json: + schema: + type: object + properties: + environmentName: + example: any + environmentSlug: + example: any + put: + description: '' + parameters: + - name: workspaceId + in: path + required: true + schema: + type: string + responses: + '200': + description: OK + '400': + description: Bad Request + requestBody: + content: + application/json: + schema: + type: object + properties: + environmentName: + example: any + environmentSlug: + example: any + oldEnvironmentSlug: + example: any + delete: + description: '' + parameters: + - name: workspaceId + in: path + required: true + schema: + type: string + responses: + '200': + description: OK + '400': + description: Bad Request + requestBody: + content: + application/json: + schema: + type: object + properties: + environmentSlug: + example: any + /api/v2/workspace/{workspaceId}/secrets: + post: + description: '' + parameters: + - name: workspaceId + in: path + required: true + schema: + type: string + responses: + '200': + description: OK + '400': + description: Bad Request + requestBody: + content: + application/json: + schema: + type: object + properties: + secrets: + example: any + keys: + example: any + environment: + example: any + channel: + example: any + get: + description: '' + parameters: + - name: workspaceId + in: path + required: true + schema: + type: string + - name: environment + in: query + schema: + type: string + - name: channel + in: query + schema: + type: string + responses: + '200': + description: OK + '400': + description: Bad Request + /api/v2/workspace/{workspaceId}/encrypted-key: + get: + summary: Return encrypted project key + description: Return encrypted project key + parameters: + - name: workspaceId + in: path + required: true + schema: + type: string + description: ID of project + responses: + '200': + description: OK + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/ProjectKey' + description: Encrypted project key for the given project + '400': + description: Bad Request + security: + - apiKeyAuth: [] + /api/v2/workspace/{workspaceId}/service-token-data: + get: + description: '' + parameters: + - name: workspaceId + in: path + required: true + schema: + type: string + responses: + '200': + description: OK + '400': + description: Bad Request + /api/v2/workspace/{workspaceId}/memberships: + get: + summary: Return project memberships + description: Return project memberships + parameters: + - name: workspaceId + in: path + required: true + schema: + type: string + description: ID of project + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + properties: + memberships: + type: array + items: + $ref: '#/components/schemas/Membership' + description: Memberships of project + '400': + description: Bad Request + security: + - apiKeyAuth: [] + /api/v2/workspace/{workspaceId}/memberships/{membershipId}: + patch: + summary: Update project membership + description: Update project membership + parameters: + - name: workspaceId + in: path + required: true + schema: + type: string + description: ID of project + - name: membershipId + in: path + required: true + schema: + type: string + description: ID of project membership to update + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + properties: + membership: + $ref: '#/components/schemas/Membership' + description: Updated membership + '400': + description: Bad Request + security: + - apiKeyAuth: [] + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + role: + type: string + description: Role of membership - either admin or member + delete: + summary: Delete project membership + description: Delete project membership + parameters: + - name: workspaceId + in: path + required: true + schema: + type: string + description: ID of project + - name: membershipId + in: path + required: true + schema: + type: string + description: ID of project membership to delete + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + properties: + membership: + $ref: '#/components/schemas/Membership' + description: Deleted membership + '400': + description: Bad Request + security: + - apiKeyAuth: [] + /api/v2/secret/batch-create/workspace/{workspaceId}/environment/{environment}: + post: + description: '' + parameters: + - name: workspaceId + in: path + required: true + schema: + type: string + - name: environment + in: path + required: true + schema: + type: string + responses: + '200': + description: OK + requestBody: + content: + application/json: + schema: + type: object + properties: + secrets: + example: any + /api/v2/secret/workspace/{workspaceId}/environment/{environment}: + post: + description: '' + parameters: + - name: workspaceId + in: path + required: true + schema: + type: string + - name: environment + in: path + required: true + schema: + type: string + responses: + '200': + description: OK + requestBody: + content: + application/json: + schema: + type: object + properties: + secret: + example: any + /api/v2/secret/workspace/{workspaceId}: + get: + description: '' + parameters: + - name: workspaceId + in: path + required: true + schema: + type: string + - name: environment + in: query + schema: + type: string + responses: + '200': + description: OK + /api/v2/secret/{secretId}: + get: + description: '' + parameters: + - name: secretId + in: path + required: true + schema: + type: string + responses: + '200': + description: OK + delete: + description: '' + parameters: + - name: secretId + in: path + required: true + schema: + type: string + responses: + '200': + description: OK + /api/v2/secret/batch/workspace/{workspaceId}/environment/{environmentName}: + delete: + description: '' + parameters: + - name: workspaceId + in: path + required: true + schema: + type: string + - name: environmentName + in: path + required: true + schema: + type: string + responses: + '200': + description: OK + requestBody: + content: + application/json: + schema: + type: object + properties: + secretIds: + example: any + /api/v2/secret/batch-modify/workspace/{workspaceId}/environment/{environmentName}: + patch: + description: '' + parameters: + - name: workspaceId + in: path + required: true + schema: + type: string + - name: environmentName + in: path + required: true + schema: + type: string + responses: + '200': + description: OK + requestBody: + content: + application/json: + schema: + type: object + properties: + secrets: + example: any + /api/v2/secret/workspace/{workspaceId}/environment/{environmentName}: + patch: + description: '' + parameters: + - name: workspaceId + in: path + required: true + schema: + type: string + - name: environmentName + in: path + required: true + schema: + type: string + responses: + '200': + description: OK + requestBody: + content: + application/json: + schema: + type: object + properties: + secret: + example: any + /api/v2/secrets/: + post: + summary: Create new secret(s) + description: Create one or many secrets for a given project and environment. + parameters: [] + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + properties: + secrets: + type: array + items: + $ref: '#/components/schemas/Secret' + description: >- + Newly-created secrets for the given project and + environment + security: + - apiKeyAuth: [] + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + workspaceId: + type: string + description: ID of project + environment: + type: string + description: Environment within project + secrets: + $ref: '#/components/schemas/CreateSecret' + description: Secret(s) to create - object or array of objects + get: + summary: Read secrets + description: Read secrets from a project and environment + parameters: + - name: workspaceId + description: ID of project + required: true + in: query + schema: + type: string + - name: environment + description: Environment within project + required: true + in: query + schema: + type: string + - name: content + in: query + schema: + type: string + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + properties: + secrets: + type: array + items: + $ref: '#/components/schemas/Secret' + description: Secrets for the given project and environment + security: + - apiKeyAuth: [] + patch: + summary: Update secret(s) + description: Update secret(s) + parameters: [] + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + properties: + secrets: + type: array + items: + $ref: '#/components/schemas/Secret' + description: Updated secrets + security: + - apiKeyAuth: [] + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + secrets: + $ref: '#/components/schemas/UpdateSecret' + description: Secret(s) to update - object or array of objects + delete: + summary: Delete secret(s) + description: Delete one or many secrets by their ID(s) + parameters: [] + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + properties: + secrets: + type: array + items: + $ref: '#/components/schemas/Secret' + description: Deleted secrets + security: + - apiKeyAuth: [] + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + secretIds: + type: string + description: ID(s) of secrets - string or array of strings + /api/v2/service-token/: + get: + description: '' + parameters: [] + responses: + '200': + description: OK + '400': + description: Bad Request + post: + description: '' + parameters: [] + responses: + '200': + description: OK + '400': + description: Bad Request + requestBody: + content: + application/json: + schema: + type: object + properties: + name: + example: any + workspaceId: + example: any + environment: + example: any + encryptedKey: + example: any + iv: + example: any + tag: + example: any + expiresIn: + example: any + /api/v2/service-token/{serviceTokenDataId}: + delete: + description: '' + parameters: + - name: serviceTokenDataId + in: path + required: true + schema: + type: string + responses: + '200': + description: OK + '400': + description: Bad Request + /api/v2/api-key/: + get: + description: '' + parameters: [] + responses: + '200': + description: OK + '400': + description: Bad Request + post: + description: '' + parameters: [] + responses: + '200': + description: OK + '400': + description: Bad Request + requestBody: + content: + application/json: + schema: + type: object + properties: + name: + example: any + expiresIn: + example: any + /api/v2/api-key/{apiKeyDataId}: + delete: + description: '' + parameters: + - name: apiKeyDataId + in: path + required: true + schema: + type: string + responses: + '200': + description: OK + '400': + description: Bad Request + /api/status: + get: + description: '' + parameters: [] + responses: + '200': + description: OK +components: + schemas: + CurrentUser: + type: object + properties: + _id: + type: string + example: '' + email: + type: string + example: johndoe@gmail.com + firstName: + type: string + example: John + lastName: + type: string + example: Doe + publicKey: + type: string + example: johns_nacl_public_key + encryptedPrivateKey: + type: string + example: johns_enc_nacl_private_key + iv: + type: string + example: iv_of_enc_nacl_private_key + tag: + type: string + example: tag_of_enc_nacl_private_key + updatedAt: + type: string + example: '2023-01-13T14:16:12.210Z' + createdAt: + type: string + example: '2023-01-13T14:16:12.210Z' + Membership: + type: object + properties: + user: + type: object + properties: + _id: + type: string + example: '' + email: + type: string + example: johndoe@gmail.com + firstName: + type: string + example: John + lastName: + type: string + example: Doe + publicKey: + type: string + example: johns_nacl_public_key + updatedAt: + type: string + example: '2023-01-13T14:16:12.210Z' + createdAt: + type: string + example: '2023-01-13T14:16:12.210Z' + workspace: + type: string + example: '' + role: + type: string + example: admin + MembershipOrg: + type: object + properties: + user: + type: object + properties: + _id: + type: string + example: '' + email: + type: string + example: johndoe@gmail.com + firstName: + type: string + example: John + lastName: + type: string + example: Doe + publicKey: + type: string + example: johns_nacl_public_key + updatedAt: + type: string + example: '2023-01-13T14:16:12.210Z' + createdAt: + type: string + example: '2023-01-13T14:16:12.210Z' + organization: + type: string + example: '' + role: + type: string + example: owner + status: + type: string + example: accepted + Organization: + type: object + properties: + _id: + type: string + example: '' + name: + type: string + example: Acme Corp. + customerId: + type: string + example: '' + Project: + type: object + properties: + _id: + type: string + example: '' + name: + type: string + example: My Project + organization: + type: string + example: '' + environments: + type: array + items: + type: object + properties: + name: + type: string + example: development + slug: + type: string + example: dev + ProjectKey: + type: object + properties: + encryptedkey: + type: string + example: '' + nonce: + type: string + example: '' + sender: + type: object + properties: + publicKey: + type: string + example: senders_nacl_public_key + receiver: + type: string + example: '' + workspace: + type: string + example: '' + CreateSecret: + type: object + properties: + type: + type: string + example: shared + secretKeyCiphertext: + type: string + example: '' + secretKeyIV: + type: string + example: '' + secretKeyTag: + type: string + example: '' + secretValueCiphertext: + type: string + example: '' + secretValueIV: + type: string + example: '' + secretValueTag: + type: string + example: '' + secretCommentCiphertext: + type: string + example: '' + secretCommentIV: + type: string + example: '' + secretCommentTag: + type: string + example: '' + UpdateSecret: + type: object + properties: + id: + type: string + example: '' + secretKeyCiphertext: + type: string + example: '' + secretKeyIV: + type: string + example: '' + secretKeyTag: + type: string + example: '' + secretValueCiphertext: + type: string + example: '' + secretValueIV: + type: string + example: '' + secretValueTag: + type: string + example: '' + secretCommentCiphertext: + type: string + example: '' + secretCommentIV: + type: string + example: '' + secretCommentTag: + type: string + example: '' + Secret: + type: object + properties: + _id: + type: string + example: '' + version: + type: number + example: 1 + workspace: + type: string + example: '' + type: + type: string + example: shared + user: {} + secretKeyCiphertext: + type: string + example: '' + secretKeyIV: + type: string + example: '' + secretKeyTag: + type: string + example: '' + secretValueCiphertext: + type: string + example: '' + secretValueIV: + type: string + example: '' + secretValueTag: + type: string + example: '' + secretCommentCiphertext: + type: string + example: '' + secretCommentIV: + type: string + example: '' + secretCommentTag: + type: string + example: '' + updatedAt: + type: string + example: '2023-01-13T14:16:12.210Z' + createdAt: + type: string + example: '2023-01-13T14:16:12.210Z' + Log: + type: object + properties: + _id: + type: string + example: '' + user: + type: object + properties: + _id: + type: string + example: '' + email: + type: string + example: johndoe@gmail.com + firstName: + type: string + example: John + lastName: + type: string + example: Doe + workspace: + type: string + example: '' + actionNames: + type: array + example: + - addSecrets + items: + type: string + actions: + type: array + items: + type: object + properties: + name: + type: string + example: addSecrets + user: + type: string + example: '' + workspace: + type: string + example: '' + payload: + type: array + items: + type: object + properties: + oldSecretVersion: + type: string + example: '' + newSecretVersion: + type: string + example: '' + channel: + type: string + example: cli + ipAddress: + type: string + example: 192.168.0.1 + updatedAt: + type: string + example: '2023-01-13T14:16:12.210Z' + createdAt: + type: string + example: '2023-01-13T14:16:12.210Z' + SecretSnapshot: + type: object + properties: + workspace: + type: string + example: '' + version: + type: number + example: 1 + secretVersions: + type: array + items: + type: object + properties: + _id: + type: string + example: '' + SecretVersion: + type: object + properties: + _id: + type: string + example: '' + secret: + type: string + example: '' + version: + type: number + example: 1 + workspace: + type: string + example: '' + type: + type: string + example: shared + user: + type: string + example: '' + environment: + type: string + example: dev + isDeleted: + type: string + example: '' + secretKeyCiphertext: + type: string + example: '' + secretKeyIV: + type: string + example: '' + secretKeyTag: + type: string + example: '' + secretValueCiphertext: + type: string + example: '' + secretValueIV: + type: string + example: '' + secretValueTag: + type: string + example: '' + securitySchemes: + bearerAuth: + type: http + scheme: bearer + bearerFormat: JWT + description: >- + This security definition uses the HTTP 'bearer' scheme, which allows the + client to authenticate using a JSON Web Token (JWT) that is passed in + the Authorization header of the request. + apiKeyAuth: + type: apiKey + in: header + name: X-API-Key + description: >- + This security definition uses an API key, which is passed in the header + of the request as the value of the "X-API-Key" header. The client must + provide a valid key in order to access the API. diff --git a/frontend/.eslintrc b/frontend/.eslintrc deleted file mode 100644 index d5f35096c..000000000 --- a/frontend/.eslintrc +++ /dev/null @@ -1,49 +0,0 @@ -{ - "extends": [ - "eslint:recommended", - "plugin:@typescript-eslint/recommended", - "next", - "next/core-web-vitals" - ], - "parser": "@typescript-eslint/parser", - "plugins": ["simple-import-sort", "@typescript-eslint"], - "rules": { - "react-hooks/exhaustive-deps": "off", - "no-unused-vars": "warn", - "@typescript-eslint/ban-ts-comment": "warn", - "@typescript-eslint/no-unused-vars": "off", - "@typescript-eslint/no-var-requires": "off", - "@typescript-eslint/no-empty-function": "off", - "@typescript-eslint/no-explicit-any": "off", - "@typescript-eslint/no-non-null-assertion": "off", - "simple-import-sort/exports": "warn", - "simple-import-sort/imports": [ - "warn", - { - "groups": [ - // Node.js builtins. You could also generate this regex if you use a `.js` config. - // For example: `^(${require("module").builtinModules.join("|")})(/|$)` - // Note that if you use the `node:` prefix for Node.js builtins, - // you can avoid this complexity: You can simply use "^node:". - [ - "^(assert|buffer|child_process|cluster|console|constants|crypto|dgram|dns|domain|events|fs|http|https|module|net|os|path|punycode|querystring|readline|repl|stream|string_decoder|sys|timers|tls|tty|url|util|vm|zlib|freelist|v8|process|async_hooks|http2|perf_hooks)(/.*|$)" - ], - // Packages `react` related packages - ["^react", "^next", "^@?\\w"], - // Internal packages. - ["^~(/.*|$)"], - // Relative imports - [ - "^\\.\\.(?!/?$)", - "^\\.\\./?$", - "^\\./(?=.*/)(?!/?$)", - "^\\.(?!/?$)", - "^\\./?$" - ], - // Style imports. - ["^.+\\.?(css|scss)$"] - ] - } - ] - } -} diff --git a/frontend/.eslintrc.js b/frontend/.eslintrc.js new file mode 100644 index 000000000..7c471fdc6 --- /dev/null +++ b/frontend/.eslintrc.js @@ -0,0 +1,97 @@ +module.exports = { + root: true, + env: { + browser: true, + es2021: true + }, + extends: [ + 'airbnb', + 'airbnb-typescript', + 'airbnb/hooks', + 'plugin:react/recommended', + 'prettier', + 'plugin:storybook/recommended' + ], + parserOptions: { + ecmaVersion: 'latest', + sourceType: 'module', + project: './tsconfig.json', + ecmaFeatures: { + jsx: true + }, + tsconfigRootDir: __dirname + }, + plugins: ['react', 'prettier', 'simple-import-sort', 'import'], + rules: { + 'react/react-in-jsx-scope': 'off', + 'import/prefer-default-export': 'off', + 'react-hooks/exhaustive-deps': 'off', + '@typescript-eslint/ban-ts-comment': 'warn', + 'react/jsx-props-no-spreading': 'off', // switched off for component building + // TODO: This rule will be switched ON after complete revamp of frontend + '@typescript-eslint/no-explicit-any': 'off', + 'no-console': 'off', + 'arrow-body-style': 'off', + 'no-underscore-dangle': [ + 'error', + { + allow: ['_id'] + } + ], + 'jsx-a11y/anchor-is-valid': 'off', + // all those tags must be converted to label or a p component + // + 'react/require-default-props': 'off', + 'react/jsx-filename-extension': [ + 1, + { + extensions: ['.tsx', '.ts'] + } + ], + // TODO: turn this rule ON after migration. everything should use arrow functions + 'react/function-component-definition': [ + 0, + { + namedComponents: 'arrow-function' + } + ], + 'react/no-unknown-property': [ + 'error', + { + ignore: ['jsx'] + } + ], + '@typescript-eslint/no-non-null-assertion': 'off', + 'simple-import-sort/exports': 'warn', + 'simple-import-sort/imports': [ + 'warn', + { + groups: [ + // Node.js builtins. You could also generate this regex if you use a `.js` config. + // For example: `^(${require("module").builtinModules.join("|")})(/|$)` + // Note that if you use the `node:` prefix for Node.js builtins, + // you can avoid this complexity: You can simply use "^node:". + [ + '^(assert|buffer|child_process|cluster|console|constants|crypto|dgram|dns|domain|events|fs|http|https|module|net|os|path|punycode|querystring|readline|repl|stream|string_decoder|sys|timers|tls|tty|url|util|vm|zlib|freelist|v8|process|async_hooks|http2|perf_hooks)(/.*|$)' + ], + // Packages `react` related packages + ['^react', '^next', '^@?\\w'], + ['^@app'], + // Internal packages. + ['^~(/.*|$)'], + // Relative imports + ['^\\.\\.(?!/?$)', '^\\.\\./?$', '^\\./(?=.*/)(?!/?$)', '^\\.(?!/?$)', '^\\./?$'], + // Style imports. + ['^.+\\.?(css|scss)$'] + ] + } + ] + }, + settings: { + 'import/resolver': { + typescript: { + project: ['./tsconfig.json'] + } + } + } +}; diff --git a/frontend/.gitignore b/frontend/.gitignore index 83e774c8c..5edd5a7fa 100644 --- a/frontend/.gitignore +++ b/frontend/.gitignore @@ -32,3 +32,5 @@ yarn-error.log* .env.production.local .vercel .env.infisical + +.vscode \ No newline at end of file diff --git a/frontend/.prettierrc b/frontend/.prettierrc new file mode 100644 index 000000000..da5d26a53 --- /dev/null +++ b/frontend/.prettierrc @@ -0,0 +1,7 @@ +{ + "singleQuote": true, + "printWidth": 100, + "trailingComma": "none", + "tabWidth": 2, + "semi": true +} diff --git a/frontend/.storybook/main.js b/frontend/.storybook/main.js new file mode 100644 index 000000000..0e3e3f70d --- /dev/null +++ b/frontend/.storybook/main.js @@ -0,0 +1,21 @@ +const path = require('path'); +module.exports = { + stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'], + addons: [ + '@storybook/addon-links', + '@storybook/addon-essentials', + '@storybook/addon-interactions', + 'storybook-dark-mode', + '@storybook/addon-postcss' + ], + framework: { + name: '@storybook/nextjs', + options: {} + }, + core: { + disableTelemetry: true + }, + docs: { + autodocs: 'tag' + } +}; diff --git a/frontend/.storybook/preview.js b/frontend/.storybook/preview.js new file mode 100644 index 000000000..94133eee3 --- /dev/null +++ b/frontend/.storybook/preview.js @@ -0,0 +1,15 @@ +import { themes } from '@storybook/theming'; +import '../src/styles/globals.css'; + +export const parameters = { + actions: { argTypesRegex: '^on[A-Z].*' }, + controls: { + matchers: { + color: /(background|color)$/i, + date: /Date$/ + } + }, + darkMode: { + dark: { ...themes.dark, appContentBg: '#0e1014', appBg: '#0e1014' } + } +}; diff --git a/frontend/Dockerfile b/frontend/Dockerfile index 5deb468f7..520f0fb7f 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -10,7 +10,7 @@ WORKDIR /app COPY package.json package-lock.json next.config.js ./ # Install dependencies -RUN npm ci --only-production +RUN npm ci --only-production --ignore-scripts # Rebuild the source code only when needed diff --git a/frontend/Dockerfile.dev b/frontend/Dockerfile.dev index 2bae23823..cb462bbc4 100644 --- a/frontend/Dockerfile.dev +++ b/frontend/Dockerfile.dev @@ -9,7 +9,7 @@ COPY package.json ./ COPY package-lock.json ./ # Install -RUN npm install +RUN npm install --ignore-scripts # Copy over next.js config COPY next.config.js ./next.config.js @@ -17,4 +17,4 @@ COPY next.config.js ./next.config.js # Copy all files COPY . . -CMD ["npm", "run", "dev"] \ No newline at end of file +CMD ["npm", "run", "dev"] diff --git a/frontend/Dockerfile.prod b/frontend/Dockerfile.prod deleted file mode 100644 index d95c00883..000000000 --- a/frontend/Dockerfile.prod +++ /dev/null @@ -1,20 +0,0 @@ -# Base layer -FROM node:16-alpine - -# Set the working directory -WORKDIR /app - -# Copy over dependency files -COPY package.json ./ -COPY package-lock.json ./ - -# Install -RUN npm install - -# Copy over next.js config -COPY next.config.js ./next.config.js - -# Copy all files -COPY . . - -CMD ["npm", "run", "start:docker"] diff --git a/frontend/components/analytics/posthog.js b/frontend/components/analytics/posthog.js deleted file mode 100644 index 8b8e88a22..000000000 --- a/frontend/components/analytics/posthog.js +++ /dev/null @@ -1,16 +0,0 @@ -import posthog from 'posthog-js'; - -import { ENV, POSTHOG_API_KEY, POSTHOG_HOST } from '../utilities/config'; - -export const initPostHog = () => { - if (typeof window !== 'undefined') { - // eslint-disable-next-line - if (ENV == 'production' && TELEMETRY_CAPTURING_ENABLED) { - posthog.init(POSTHOG_API_KEY, { - api_host: POSTHOG_HOST - }); - } - } - - return posthog; -}; diff --git a/frontend/components/analytics/posthog.ts b/frontend/components/analytics/posthog.ts deleted file mode 100644 index e0d6e7c09..000000000 --- a/frontend/components/analytics/posthog.ts +++ /dev/null @@ -1,18 +0,0 @@ -/* eslint-disable @typescript-eslint/ban-ts-comment */ -/* eslint-disable no-undef */ -import posthog from 'posthog-js'; - -import { ENV, POSTHOG_API_KEY, POSTHOG_HOST } from '../utilities/config'; - -export const initPostHog = () => { - if (typeof window !== 'undefined') { - // @ts-ignore - if (ENV == 'production' && TELEMETRY_CAPTURING_ENABLED) { - posthog.init(POSTHOG_API_KEY, { - api_host: POSTHOG_HOST - }); - } - } - - return posthog; -}; diff --git a/frontend/components/basic/Error.tsx b/frontend/components/basic/Error.tsx deleted file mode 100644 index 79cc6e5f1..000000000 --- a/frontend/components/basic/Error.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import React from "react"; -import { faExclamationTriangle } from "@fortawesome/free-solid-svg-icons"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; - -export default function Error({ text }: { text: string }): JSX.Element { - return ( -
- - {text && ( -

{text}

- )} -
- ); -} diff --git a/frontend/components/basic/InputField.tsx b/frontend/components/basic/InputField.tsx deleted file mode 100644 index 46b42c15c..000000000 --- a/frontend/components/basic/InputField.tsx +++ /dev/null @@ -1,142 +0,0 @@ -import React, { useState } from 'react'; -import { faCircle, faEye, faEyeSlash } from '@fortawesome/free-solid-svg-icons'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; - -import guidGenerator from '../utilities/randomId'; - -interface InputFieldProps { - static?: boolean; - label: string; - type: string; - value: string; - placeholder?: string; - isRequired: boolean; - disabled?: boolean; - error?: boolean; - text?: string; - name?: string; - blurred?: boolean; - errorText?: string; - onChangeHandler: (value: string) => void; -} - -const InputField = ( - props: InputFieldProps & - Pick -) => { - const [passwordVisible, setPasswordVisible] = useState(false); - - if (props.static === true) { - return ( -
-

- {props.label} -

- {props.text && ( -

{props.text}

- )} - props.onChangeHandler(e.target.value)} - type={props.type} - placeholder={props.placeholder} - value={props.value} - required={props.isRequired} - className="bg-bunker-800 text-gray-400 border border-gray-600 rounded-md text-md p-2 w-full min-w-16 outline-none" - name={props.name} - readOnly - autoComplete={props.autoComplete} - id={props.id} - /> -
- ); - } else { - return ( -
-
-

{props.label}

- {/* {props.label == "Password" && router.asPath != "/login" && ( -
- - - The password should contain at least 8 - characters including at least 1 lowercase - character, uppercase character, number, and a - special character. - -
- )} */} -
-
- props.onChangeHandler(e.target.value)} - type={passwordVisible === false ? props.type : 'text'} - placeholder={props.placeholder} - value={props.value} - required={props.isRequired} - className={`${ - props.blurred - ? 'text-bunker-800 group-hover:text-gray-400 focus:text-gray-400 active:text-gray-400' - : '' - } ${ - props.error ? 'focus:ring-red/50' : 'focus:ring-primary/50' - } relative peer bg-bunker-800 rounded-md text-gray-400 text-md p-2 w-full min-w-16 outline-none focus:ring-4 duration-200`} - name={props.name} - spellCheck="false" - autoComplete={props.autoComplete} - id={props.id} - /> - {props.label?.includes('Password') && ( - - )} - {props.blurred && ( -
-

- {props.value - .split('') - .slice(0, 54) - .map(() => ( - - ))} -
- )} - {/* {props.error && ( -
- -
- )} */} -
- {props.error && ( -

- {props.errorText} -

- )} -
- ); - } -}; - -export default React.memo(InputField); diff --git a/frontend/components/basic/buttons/Button.tsx b/frontend/components/basic/buttons/Button.tsx deleted file mode 100644 index 9f8d481b4..000000000 --- a/frontend/components/basic/buttons/Button.tsx +++ /dev/null @@ -1,137 +0,0 @@ -import React from "react"; -import Image from "next/image"; -import { IconProp } from "@fortawesome/fontawesome-svg-core"; -import { - FontAwesomeIcon, - FontAwesomeIconProps, -} from "@fortawesome/react-fontawesome"; - -const classNames = require("classnames"); - -type ButtonProps = { - text: string; - onButtonPressed: () => void; - loading?: boolean; - color?: string; - size: string; - icon?: IconProp; - active?: boolean; - iconDisabled?: string; - textDisabled?: string; -}; - -/** - * This is the main butto component in the app. - * @param {object} props - * @param {string} props.text - text inside the button - * @param {function} props.onButtonPressed - the action that happens when the button is clicked - * @param {boolean} props.loading - if a button is currently in the laoding state - * @param {string} props.color - button color - * @param {string} props.size - button size - * @param {FontAwesomeIconProps} props.icon - the icon inside the button - * @param {boolean} props.active - if the button is active or disabled - * @param {FontAwesomeIconProps} props.text - the icon inside the button when it is disabled - * @param {string} props.textDisable - text inside the button when it is disabled - * @returns - */ -export default function Button(props: ButtonProps): JSX.Element { - // Check if the button show always be 'active' - then true; - // or if it should switch between 'active' and 'disabled' - then give the status - const activityStatus = - props.active || (props.text != "" && props.textDisabled == undefined); - - const styleButton = classNames( - "group m-auto md:m-0 inline-block rounded-md duration-200", - - // Setting background colors and hover modes - props.color == "mineshaft" && - activityStatus && - "bg-mineshaft-700 hover:bg-primary", - props.color == "mineshaft" && !activityStatus && "bg-mineshaft", - (props.color == "primary" || !props.color) && - activityStatus && - "bg-primary hover:opacity-80", - (props.color == "primary" || !props.color) && - !activityStatus && - "bg-primary", - props.color == "red" && "bg-red", - - // Changing the opacity when active vs when not - activityStatus ? "opacity-100 cursor-pointer" : "opacity-40", - - // Setting the button sizes - props.size == "md" && "h-10 w-full px-2 md:px-4", - props.size == "lg" && "h-12 w-full px-2 md:px-8", - !props.size && "md:py-1 px-3 md:px-8", - props.size == "icon-md" && "h-10 w-10 flex items-center justify-center", - props.size == "icon-sm" && "h-9 w-9 flex items-center justify-center" - ); - - const styleMainDiv = classNames( - "relative font-medium flex items-center", - - // Setting the text color for the text and icon - props.color == "mineshaft" && "text-gray-400", - props.color != "mineshaft" && props.color != "red" && "text-black", - props.color == "red" && "text-gray-200", - activityStatus && props.color != "red" ? "group-hover:text-black" : "", - - props.size == "icon" && "flex items-center justify-center" - ); - - const textStyle = classNames( - "relative duration-200", - - // Show the loading sign if the loading indicator is on - props.loading ? "opacity-0" : "opacity-100", - props.size == "md" && "text-sm", - props.size == "lg" && "text-lg" - ); - - const button = ( - - ); - - return button; -} diff --git a/frontend/components/basic/dialog/AddServiceTokenDialog.js b/frontend/components/basic/dialog/AddServiceTokenDialog.js deleted file mode 100644 index ab116cf4d..000000000 --- a/frontend/components/basic/dialog/AddServiceTokenDialog.js +++ /dev/null @@ -1,261 +0,0 @@ -import { Fragment, useState } from 'react'; -import { faCheck, faCopy } from '@fortawesome/free-solid-svg-icons'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { Dialog, Transition } from '@headlessui/react'; -import nacl from 'tweetnacl'; - -import addServiceToken from '~/pages/api/serviceToken/addServiceToken'; -import getLatestFileKey from '~/pages/api/workspace/getLatestFileKey'; - -import { envMapping } from '../../../public/data/frequentConstants'; -import { - decryptAssymmetric, - encryptAssymmetric -} from '../../utilities/cryptography/crypto'; -import Button from '../buttons/Button'; -import InputField from '../InputField'; -import ListBox from '../Listbox'; - -const expiryMapping = { - '1 day': 86400, - '7 days': 604800, - '1 month': 2592000, - '6 months': 15552000, - '12 months': 31104000 -}; - -const AddServiceTokenDialog = ({ - isOpen, - closeModal, - workspaceId, - workspaceName -}) => { - const [serviceToken, setServiceToken] = useState(''); - const [serviceTokenName, setServiceTokenName] = useState(''); - const [serviceTokenEnv, setServiceTokenEnv] = useState('Development'); - const [serviceTokenExpiresIn, setServiceTokenExpiresIn] = useState('1 day'); - const [serviceTokenCopied, setServiceTokenCopied] = useState(false); - - const generateServiceToken = async () => { - const latestFileKey = await getLatestFileKey({ workspaceId }); - - const key = decryptAssymmetric({ - ciphertext: latestFileKey.latestKey.encryptedKey, - nonce: latestFileKey.latestKey.nonce, - publicKey: latestFileKey.latestKey.sender.publicKey, - privateKey: localStorage.getItem('PRIVATE_KEY') - }); - - // generate new public/private key pair - const pair = nacl.box.keyPair(); - const publicKey = nacl.util.encodeBase64(pair.publicKey); - const privateKey = nacl.util.encodeBase64(pair.secretKey); - - // encrypt workspace key under newly-generated public key - const { ciphertext: encryptedKey, nonce } = encryptAssymmetric({ - plaintext: key, - publicKey, - privateKey - }); - - let newServiceToken = await addServiceToken({ - name: serviceTokenName, - workspaceId, - environment: envMapping[serviceTokenEnv], - expiresIn: expiryMapping[serviceTokenExpiresIn], - publicKey, - encryptedKey, - nonce - }); - - const serviceToken = newServiceToken + ',' + privateKey; - setServiceToken(serviceToken); - }; - - function copyToClipboard() { - // Get the text field - var copyText = document.getElementById('serviceToken'); - - // Select the text field - copyText.select(); - copyText.setSelectionRange(0, 99999); // For mobile devices - - // Copy the text inside the text field - navigator.clipboard.writeText(copyText.value); - - setServiceTokenCopied(true); - setTimeout(() => setServiceTokenCopied(false), 2000); - // Alert the copied text - // alert("Copied the text: " + copyText.value); - } - - const closeAddServiceTokenModal = () => { - closeModal(); - setServiceTokenName(''); - setServiceToken(''); - }; - - return ( -
- - - -
- - -
-
- - {serviceToken == '' ? ( - - - Add a service token for {workspaceName} - -
-
-

- Specify the name, environment, and expiry period. When - a token is generated, you will only be able to see it - once before it disappears. Make sure to save it - somewhere. -

-
-
-
- -
-
- -
-
- -
-
-
-
-
-
- ) : ( - - - Copy your service token - -
-
-

- Once you close this popup, you will never see your - service token again -

-
-
-
-
- -
- {serviceToken} -
-
- - - Click to Copy - -
-
-
-
-
-
- )} -
-
-
-
-
-
- ); -}; - -export default AddServiceTokenDialog; diff --git a/frontend/components/basic/table/Checkbox.js b/frontend/components/basic/table/Checkbox.js deleted file mode 100644 index 2ef6c2de8..000000000 --- a/frontend/components/basic/table/Checkbox.js +++ /dev/null @@ -1,28 +0,0 @@ -import React from "react"; - -export const Checkbox = ({ addAllUsers, setAddAllUsers }) => { - return ( - <> -
- {addAllUsers == true ? ( - setAddAllUsers(!addAllUsers)} - /> - ) : ( -
setAddAllUsers(!addAllUsers)} - >
- )} - - -
- - ); -}; diff --git a/frontend/components/basic/table/ServiceTokenTable.js b/frontend/components/basic/table/ServiceTokenTable.js deleted file mode 100644 index fda94e477..000000000 --- a/frontend/components/basic/table/ServiceTokenTable.js +++ /dev/null @@ -1,77 +0,0 @@ -import React, { useEffect, useState } from 'react'; -import { useRouter } from 'next/router'; -import { faX } from '@fortawesome/free-solid-svg-icons'; - -import { reverseEnvMapping } from '../../../public/data/frequentConstants'; -import guidGenerator from '../../utilities/randomId'; -import Button from '../buttons/Button'; - -/** - * This is the component that we utilize for the user table - in future, can reuse it for some other purposes too. - * #TODO: add the possibility of choosing and doing operations on multiple users. - * @param {*} props - * @returns - */ -const ServiceTokenTable = ({ data, workspaceName }) => { - const router = useRouter(); - - return ( -
-
- - - - - - - - - - - - {data?.length > 0 ? ( - data.map((row, index) => { - return ( - - - - - - - - ); - }) - ) : ( - - - - )} - -
Token nameProjectEnvironmentValid until
- {row.name} - - {workspaceName} - - {reverseEnvMapping[row.environment]} - - {new Date(row.expiresAt).toUTCString()} - -
-
-
- No service tokens yet -
-
- ); -}; - -export default ServiceTokenTable; diff --git a/frontend/components/basic/table/UserTable.js b/frontend/components/basic/table/UserTable.js deleted file mode 100644 index 99ec0ee75..000000000 --- a/frontend/components/basic/table/UserTable.js +++ /dev/null @@ -1,241 +0,0 @@ -import React, { useEffect, useMemo, useState } from 'react'; -import { useRouter } from 'next/router'; -import { faX } from '@fortawesome/free-solid-svg-icons'; - -import deleteUserFromOrganization from '~/pages/api/organization/deleteUserFromOrganization'; -import changeUserRoleInWorkspace from '~/pages/api/workspace/changeUserRoleInWorkspace'; -import deleteUserFromWorkspace from '~/pages/api/workspace/deleteUserFromWorkspace'; -import getLatestFileKey from '~/pages/api/workspace/getLatestFileKey'; -import uploadKeys from '~/pages/api/workspace/uploadKeys'; - -import guidGenerator from '../../utilities/randomId'; -import Button from '../buttons/Button'; -import Listbox from '../Listbox'; - -const { - decryptAssymmetric, - encryptAssymmetric -} = require('../../utilities/cryptography/crypto'); -const nacl = require('tweetnacl'); -nacl.util = require('tweetnacl-util'); - -const roles = ['admin', 'user']; - -/** - * This is the component that we utilize for the user table - in future, can reuse it for some other purposes too. - * #TODO: add the possibility of choosing and doing operations on multiple users. - * @param {*} props - * @returns - */ -const UserTable = ({ - userData, - changeData, - myUser, - filter, - resendInvite, - isOrg, - onClick, - deleteUser, - setUserIdToBeDeleted -}) => { - const [roleSelected, setRoleSelected] = useState( - Array(userData?.length).fill(userData.map((user) => user.role)) - ); - const router = useRouter(); - const [myRole, setMyRole] = useState('member'); - - // Delete the row in the table (e.g. a user) - // #TODO: Add a pop-up that warns you that the user is going to be deleted. - const handleDelete = (membershipId, index, e) => { - // setUserIdToBeDeleted(userId); - // onClick(); - if (isOrg) { - deleteUserFromOrganization(membershipId); - } else { - deleteUserFromWorkspace(membershipId); - } - changeData(userData.filter((v, i) => i !== index)); - setRoleSelected([ - ...roleSelected.slice(0, index), - ...roleSelected.slice(index + 1, userData?.length) - ]); - }; - - // Update the rold of a certain user - const handleRoleUpdate = (index, e) => { - changeUserRoleInWorkspace(userData[index].membershipId, e); - changeData([ - ...userData.slice(0, index), - ...[ - { - key: userData[index].key, - firstName: userData[index].firstName, - lastName: userData[index].lastName, - email: userData[index].email, - role: e, - status: userData[index].status, - userId: userData[index].userId, - membershipId: userData[index].membershipId, - publicKey: userData[index].publicKey - } - ], - ...userData.slice(index + 1, userData?.length) - ]); - }; - - useEffect(() => { - setMyRole(userData.filter((user) => user.email == myUser)[0]?.role); - }, [userData, myUser]); - - const grantAccess = async (id, publicKey) => { - let result = await getLatestFileKey({ workspaceId: router.query.id }); - - const PRIVATE_KEY = localStorage.getItem('PRIVATE_KEY'); - - // assymmetrically decrypt symmetric key with local private key - const key = decryptAssymmetric({ - ciphertext: result.latestKey.encryptedKey, - nonce: result.latestKey.nonce, - publicKey: result.latestKey.sender.publicKey, - privateKey: PRIVATE_KEY - }); - - const { ciphertext, nonce } = encryptAssymmetric({ - plaintext: key, - publicKey: publicKey, - privateKey: PRIVATE_KEY - }); - - uploadKeys(router.query.id, id, ciphertext, nonce); - router.reload(); - }; - - const deleteMembershipAndResendInvite = (email, membershipId) => { - // deleteUserFromWorkspace(membershipId); - resendInvite(email); - }; - - return ( -
-
- - - - - - - - - - - {userData?.filter( - (user) => - user.firstName?.toLowerCase().includes(filter) || - user.lastName?.toLowerCase().includes(filter) || - user.email?.toLowerCase().includes(filter) - ).length > 0 && - userData - ?.filter( - (user) => - user.firstName?.toLowerCase().includes(filter) || - user.lastName?.toLowerCase().includes(filter) || - user.email?.toLowerCase().includes(filter) - ) - .map((row, index) => { - return ( - - - - - - - ); - })} - -
First NameLast NameEmail
- {row.firstName} - - {row.lastName} - - {row.email} - -
- {row.status == 'granted' && - ((myRole == 'admin' && row.role != 'owner') || - myRole == 'owner') && - myUser !== row.email ? ( - handleRoleUpdate(index, e)} - data={ - myRole == 'owner' - ? ['owner', 'admin', 'member'] - : ['admin', 'member'] - } - text="Role: " - membershipId={row.membershipId} - /> - ) : ( - row.status != 'invited' && - row.status != 'verified' && ( - - ) - )} - {(row.status == 'invited' || - row.status == 'verified') && ( -
-
- )} - {row.status == 'completed' && myUser !== row.email && ( -
-
- )} -
- {myUser !== row.email && - // row.role != "admin" && - myRole != 'member' ? ( -
-
- ) : ( -
- )} -
-
- ); -}; - -export default UserTable; diff --git a/frontend/components/context/Notifications/NotificationProvider.tsx b/frontend/components/context/Notifications/NotificationProvider.tsx deleted file mode 100644 index 05f9eee19..000000000 --- a/frontend/components/context/Notifications/NotificationProvider.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import { createContext, ReactNode, useContext, useState } from 'react'; - -import Notifications from './Notifications'; - -type NotificationType = 'success' | 'error' | 'info'; - -export type Notification = { - text: string; - type?: NotificationType; - timeoutMs?: number; -}; - -type NotificationContextState = { - createNotification: (newNotification: Notification) => void; -}; - -const NotificationContext = createContext({ - createNotification: () => console.log('createNotification not set!') -}); - -export const useNotificationContext = () => useContext(NotificationContext); - -interface NotificationProviderProps { - children: ReactNode; -} - -const NotificationProvider = ({ children }: NotificationProviderProps) => { - const [notifications, setNotifications] = useState[]>( - [] - ); - - const clearNotification = (text: string) => { - return setNotifications((state) => - state.filter((notif) => notif.text !== text) - ); - }; - - const createNotification = ({ - text, - type = 'success', - timeoutMs = 5000 - }: Notification) => { - const doesNotifExist = notifications.some((notif) => notif.text === text); - - if (doesNotifExist) { - return; - } - - const newNotification: Required = { text, type, timeoutMs }; - - return setNotifications((state) => [...state, newNotification]); - }; - - return ( - - - {children} - - ); -}; - -export default NotificationProvider; diff --git a/frontend/components/context/Notifications/Notifications.tsx b/frontend/components/context/Notifications/Notifications.tsx deleted file mode 100644 index 2baba521b..000000000 --- a/frontend/components/context/Notifications/Notifications.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import Notification from './Notification'; -import { Notification as NotificationType } from './NotificationProvider'; - -interface NoticationsProps { - notifications: Required[]; - clearNotification: (text: string) => void; -} - -const Notifications = ({ - notifications, - clearNotification -}: NoticationsProps) => { - if (!notifications.length) { - return null; - } - - return ( -
- {notifications.map((notif) => ( - - ))} -
- ); -}; - -export default Notifications; diff --git a/frontend/components/navigation/NavHeader.tsx b/frontend/components/navigation/NavHeader.tsx deleted file mode 100644 index 3d64c2eda..000000000 --- a/frontend/components/navigation/NavHeader.tsx +++ /dev/null @@ -1,65 +0,0 @@ -import React, { useEffect, useState } from "react"; -import { useRouter } from "next/router"; -import { - faAngleRight, -} from "@fortawesome/free-solid-svg-icons"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; - -import getOrganization from "~/pages/api/organization/GetOrg"; -import getProjectInfo from "~/pages/api/workspace/getProjectInfo"; - -/** - * This is the component at the top of almost every page. - * It shows how to navigate to a certain page. - * It future these links should also be clickable and hoverable - * @param obj - * @param obj.pageName - Name of the page - * @param obj.isProjectRelated - whether this page is related to project or now (determine if it's 2 or 3 navigation steps) - * @returns - */ -export default function NavHeader({ pageName, isProjectRelated } : { pageName: string; isProjectRelated: boolean; }): JSX.Element { - const [orgName, setOrgName] = useState(""); - const [workspaceName, setWorkspaceName] = useState(""); - const router = useRouter(); - - useEffect(() => { - (async () => { - const orgId = localStorage.getItem("orgData.id") - const org = await getOrganization({ - orgId: orgId ? orgId : "", - }); - setOrgName(org.name); - - const workspace = await getProjectInfo({ - projectId: String(router.query.id), - }); - setWorkspaceName(workspace.name); - })(); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - - return ( -
-
- {orgName?.charAt(0)} -
-
{orgName}
- {isProjectRelated && ( - <> - -
- {workspaceName} -
- - )} - -
{pageName}
-
- ); -} diff --git a/frontend/components/utilities/SecurityClient.ts b/frontend/components/utilities/SecurityClient.ts deleted file mode 100644 index ea2664c70..000000000 --- a/frontend/components/utilities/SecurityClient.ts +++ /dev/null @@ -1,27 +0,0 @@ -import token from '~/pages/api/auth/Token'; - -export default class SecurityClient { - static #token = ''; - - constructor() {} - - static setToken(token: string) { - this.#token = token; - } - - static async fetchCall( - resource: RequestInfo, - options?: RequestInit | undefined - ) { - const req = new Request(resource, options); - - if (this.#token == '') { - this.setToken(await token()); - } - - if (this.#token) { - req.headers.set('Authorization', 'Bearer ' + this.#token); - return fetch(req); - } - } -} diff --git a/frontend/components/utilities/attemptLogin.js b/frontend/components/utilities/attemptLogin.js deleted file mode 100644 index 228f58727..000000000 --- a/frontend/components/utilities/attemptLogin.js +++ /dev/null @@ -1,145 +0,0 @@ -import Aes256Gcm from '~/components/utilities/cryptography/aes-256-gcm'; -import login1 from '~/pages/api/auth/Login1'; -import login2 from '~/pages/api/auth/Login2'; -import getOrganizations from '~/pages/api/organization/getOrgs'; -import getOrganizationUserProjects from '~/pages/api/organization/GetOrgUserProjects'; - -import pushKeys from './secrets/pushKeys'; -import Telemetry from './telemetry/Telemetry'; -import { saveTokenToLocalStorage } from './saveTokenToLocalStorage'; -import SecurityClient from './SecurityClient'; - -const nacl = require('tweetnacl'); -nacl.util = require('tweetnacl-util'); -const jsrp = require('jsrp'); -const client = new jsrp.client(); - -/** - * This function loggs in the user (whether it's right after signup, or a normal login) - * @param {*} email - * @param {*} password - * @param {*} setErrorLogin - * @param {*} router - * @param {*} isSignUp - * @returns - */ -const attemptLogin = async ( - email, - password, - setErrorLogin, - router, - isSignUp, - isLogin -) => { - try { - const telemetry = new Telemetry().getInstance(); - - client.init( - { - username: email, - password: password - }, - async () => { - const clientPublicKey = client.getPublicKey(); - - const { serverPublicKey, salt } = await login1(email, clientPublicKey); - - try { - client.setSalt(salt); - client.setServerPublicKey(serverPublicKey); - const clientProof = client.getProof(); // called M1 - - // if everything works, go the main dashboard page. - const { token, publicKey, encryptedPrivateKey, iv, tag } = - await login2(email, clientProof); - SecurityClient.setToken(token); - - const privateKey = Aes256Gcm.decrypt({ - ciphertext: encryptedPrivateKey, - iv, - tag, - secret: password - .slice(0, 32) - .padStart( - 32 + (password.slice(0, 32).length - new Blob([password]).size), - '0' - ) - }); - - saveTokenToLocalStorage({ - publicKey, - encryptedPrivateKey, - iv, - tag, - privateKey - }); - - const userOrgs = await getOrganizations(); - const userOrgsData = userOrgs.map((org) => org._id); - - let orgToLogin; - if (userOrgsData.includes(localStorage.getItem('orgData.id'))) { - orgToLogin = localStorage.getItem('orgData.id'); - } else { - orgToLogin = userOrgsData[0]; - localStorage.setItem('orgData.id', orgToLogin); - } - - let orgUserProjects = await getOrganizationUserProjects({ - orgId: orgToLogin - }); - - orgUserProjects = orgUserProjects?.map((project) => project._id); - let projectToLogin; - if ( - orgUserProjects.includes(localStorage.getItem('projectData.id')) - ) { - projectToLogin = localStorage.getItem('projectData.id'); - } else { - try { - projectToLogin = orgUserProjects[0]; - localStorage.setItem('projectData.id', projectToLogin); - } catch (error) { - console.log('ERROR: User likely has no projects. ', error); - } - } - - // If user is logging in for the first time, add the example keys - if (isSignUp) { - await pushKeys({ - obj: { - DATABASE_URL: [ - 'mongodb+srv://${DB_USERNAME}:${DB_PASSWORD}@mongodb.net', - 'personal' - ], - DB_USERNAME: ['user1234', 'personal'], - DB_PASSWORD: ['example_password', 'personal'], - TWILIO_AUTH_TOKEN: ['example_twillion_token', 'shared'], - WEBSITE_URL: ['http://localhost:3000', 'shared'], - STRIPE_SECRET_KEY: ['sk_test_7348oyho4hfq398HIUOH78', 'shared'] - }, - workspaceId: projectToLogin, - env: 'Development' - }); - } - if (email) { - telemetry.identify(email); - telemetry.capture('User Logged In'); - } - - if (isLogin) { - router.push('/dashboard/'); - } - } catch (error) { - setErrorLogin(true); - console.log('Login response not available'); - } - } - ); - } catch (error) { - console.log('Something went wrong during authentication'); - } - return true; -}; - -export default attemptLogin; diff --git a/frontend/components/utilities/file.ts b/frontend/components/utilities/file.ts deleted file mode 100644 index 3784405f9..000000000 --- a/frontend/components/utilities/file.ts +++ /dev/null @@ -1,47 +0,0 @@ -const LINE = - /(?:^|^)\s*(?:export\s+)?([\w.-]+)(?:\s*=\s*?|:\s+?)(\s*'(?:\\'|[^'])*'|\s*"(?:\\"|[^"])*"|\s*`(?:\\`|[^`])*`|[^#\r\n]+)?\s*(?:#.*)?(?:$|$)/gm; - -/** - * Return text that is the buffer parsed - * @param {Buffer} src - source buffer - * @returns {String} text - text of buffer - */ -function parse(src: Buffer) { - const obj: Record = {}; - - // Convert buffer to string - let lines = src.toString(); - - // Convert line breaks to same format - lines = lines.replace(/\r\n?/gm, '\n'); - - let match; - while ((match = LINE.exec(lines)) != null) { - const key = match[1]; - - // Default undefined or null to empty string - let value = match[2] || ''; - - // Remove whitespace - value = value.trim(); - - // Check if double quoted - const maybeQuote = value[0]; - - // Remove surrounding quotes - value = value.replace(/^(['"`])([\s\S]*)\1$/gm, '$2'); - - // Expand newlines if double quoted - if (maybeQuote === '"') { - value = value.replace(/\\n/g, '\n'); - value = value.replace(/\\r/g, '\r'); - } - - // Add to object - obj[key] = value; - } - - return obj; -} - -export default parse; diff --git a/frontend/components/utilities/secrets/getSecretsForProject.ts b/frontend/components/utilities/secrets/getSecretsForProject.ts deleted file mode 100644 index 3b63f9177..000000000 --- a/frontend/components/utilities/secrets/getSecretsForProject.ts +++ /dev/null @@ -1,103 +0,0 @@ -import getSecrets from '~/pages/api/files/GetSecrets'; - -import { envMapping } from '../../../public/data/frequentConstants'; -import guidGenerator from '../randomId'; - -const { - decryptAssymmetric, - decryptSymmetric -} = require('../cryptography/crypto'); -const nacl = require('tweetnacl'); -nacl.util = require('tweetnacl-util'); - -interface Props { - env: keyof typeof envMapping; - setFileState: any; - setIsKeyAvailable: any; - setData: any; - workspaceId: string; -} - -const getSecretsForProject = async ({ - env, - setFileState, - setIsKeyAvailable, - setData, - workspaceId -}: Props) => { - try { - let file; - try { - file = await getSecrets(workspaceId, envMapping[env]); - - setFileState(file); - } catch (error) { - console.log('ERROR: Not able to access the latest file'); - } - // This is called isKeyAvilable but what it really means is if a person is able to create new key pairs - setIsKeyAvailable(!file.key ? file.secrets.length == 0 : true); - - const PRIVATE_KEY = localStorage.getItem('PRIVATE_KEY'); - - const tempFileState: { key: string; value: string; type: string }[] = []; - if (file.key) { - // assymmetrically decrypt symmetric key with local private key - const key = decryptAssymmetric({ - ciphertext: file.key.encryptedKey, - nonce: file.key.nonce, - publicKey: file.key.sender.publicKey, - privateKey: PRIVATE_KEY - }); - - file.secrets.map((secretPair: any) => { - // decrypt .env file with symmetric key - const plainTextKey = decryptSymmetric({ - ciphertext: secretPair.secretKey.ciphertext, - iv: secretPair.secretKey.iv, - tag: secretPair.secretKey.tag, - key - }); - - const plainTextValue = decryptSymmetric({ - ciphertext: secretPair.secretValue.ciphertext, - iv: secretPair.secretValue.iv, - tag: secretPair.secretValue.tag, - key - }); - tempFileState.push({ - key: plainTextKey, - value: plainTextValue, - type: secretPair.type - }); - }); - } - setFileState(tempFileState); - - setData( - tempFileState.map((line, index) => { - return { - id: guidGenerator(), - pos: index, - key: line['key'], - value: line['value'], - type: line['type'] - }; - }) - ); - - return tempFileState.map((line, index) => { - return { - id: guidGenerator(), - pos: index, - key: line['key'], - value: line['value'], - type: line['type'] - }; - }); - } catch (error) { - console.log('Something went wrong during accessing or decripting secrets.'); - } - return true; -}; - -export default getSecretsForProject; diff --git a/frontend/components/utilities/secrets/pushKeys.ts b/frontend/components/utilities/secrets/pushKeys.ts deleted file mode 100644 index 0d570f273..000000000 --- a/frontend/components/utilities/secrets/pushKeys.ts +++ /dev/null @@ -1,112 +0,0 @@ -import uploadSecrets from "~/pages/api/files/UploadSecrets"; -import getLatestFileKey from "~/pages/api/workspace/getLatestFileKey"; -import getWorkspaceKeys from "~/pages/api/workspace/getWorkspaceKeys"; - -import { envMapping } from "../../../public/data/frequentConstants"; - -const crypto = require("crypto"); -const { - decryptAssymmetric, - encryptSymmetric, - encryptAssymmetric, -} = require("../cryptography/crypto"); -const nacl = require("tweetnacl"); -nacl.util = require("tweetnacl-util"); - -export interface IK { - publicKey: string; - userId: string; -} - -/** - * This function pushes the keys to the database after decrypting them end-to-end - * @param {object} obj - * @param {object} obj.obj - object with all the key pairs - * @param {object} obj.workspaceId - the id of a project to which a user is pushing - * @param {object} obj.env - which environment a user is pushing to - */ -const pushKeys = async({ obj, workspaceId, env }: { obj: object; workspaceId: string; env: string; }) => { - const sharedKey = await getLatestFileKey({ workspaceId }); - - const PRIVATE_KEY = localStorage.getItem("PRIVATE_KEY"); - - let randomBytes: string; - if (Object.keys(sharedKey).length > 0) { - // case: a (shared) key exists for the workspace - randomBytes = decryptAssymmetric({ - ciphertext: sharedKey.latestKey.encryptedKey, - nonce: sharedKey.latestKey.nonce, - publicKey: sharedKey.latestKey.sender.publicKey, - privateKey: PRIVATE_KEY, - }); - } else { - // case: a (shared) key does not exist for the workspace - randomBytes = crypto.randomBytes(16).toString("hex"); - } - - const secrets = Object.keys(obj).map((key) => { - // encrypt key - const { - ciphertext: ciphertextKey, - iv: ivKey, - tag: tagKey, - } = encryptSymmetric({ - plaintext: key, - key: randomBytes, - }); - - // encrypt value - const { - ciphertext: ciphertextValue, - iv: ivValue, - tag: tagValue, - } = encryptSymmetric({ - plaintext: obj[key as keyof typeof obj][0], - key: randomBytes, - }); - - const visibility = obj[key as keyof typeof obj][1] != null ? obj[key as keyof typeof obj][1] : "personal"; - - return { - ciphertextKey, - ivKey, - tagKey, - hashKey: crypto.createHash("sha256").update(key).digest("hex"), - ciphertextValue, - ivValue, - tagValue, - hashValue: crypto.createHash("sha256").update(obj[key as keyof typeof obj][0]).digest("hex"), - type: visibility, - }; - }); - - // obtain public keys of all receivers (i.e. members in workspace) - const publicKeys = await getWorkspaceKeys({ - workspaceId, - }); - - // assymmetrically encrypt key with each receiver public keys - const keys = publicKeys.map((k: IK) => { - const { ciphertext, nonce } = encryptAssymmetric({ - plaintext: randomBytes, - publicKey: k.publicKey, - privateKey: PRIVATE_KEY, - }); - - return { - encryptedKey: ciphertext, - nonce, - userId: k.userId, - }; - }); - - // send payload - await uploadSecrets({ - workspaceId, - secrets, - keys, - environment: envMapping[env as keyof typeof envMapping], - }); -}; - -export default pushKeys; diff --git a/frontend/components/utilities/secrets/pushKeysIntegration.ts b/frontend/components/utilities/secrets/pushKeysIntegration.ts deleted file mode 100644 index 949778927..000000000 --- a/frontend/components/utilities/secrets/pushKeysIntegration.ts +++ /dev/null @@ -1,79 +0,0 @@ -import publicKeyInfical from '~/pages/api/auth/publicKeyInfisical'; -import changeHerokuConfigVars from '~/pages/api/integrations/ChangeHerokuConfigVars'; - -const crypto = require('crypto'); -const { - encryptSymmetric, - encryptAssymmetric -} = require('../cryptography/crypto'); -const nacl = require('tweetnacl'); -nacl.util = require('tweetnacl-util'); - -interface Props { - obj: Record; - integrationId: string; -} - -const pushKeysIntegration = async ({ obj, integrationId }: Props) => { - const PRIVATE_KEY = localStorage.getItem('PRIVATE_KEY'); - - const randomBytes = crypto.randomBytes(16).toString('hex'); - - const secrets = Object.keys(obj).map((key) => { - // encrypt key - const { - ciphertext: ciphertextKey, - iv: ivKey, - tag: tagKey - } = encryptSymmetric({ - plaintext: key, - key: randomBytes - }); - - // encrypt value - const { - ciphertext: ciphertextValue, - iv: ivValue, - tag: tagValue - } = encryptSymmetric({ - plaintext: obj[key], - key: randomBytes - }); - - const visibility = 'shared'; - - return { - ciphertextKey, - ivKey, - tagKey, - hashKey: crypto.createHash('sha256').update(key).digest('hex'), - ciphertextValue, - ivValue, - tagValue, - hashValue: crypto.createHash('sha256').update(obj[key]).digest('hex'), - type: visibility - }; - }); - - // obtain public keys of all receivers (i.e. members in workspace) - const publicKeyInfisical = await publicKeyInfical(); - - const publicKey = (await publicKeyInfisical.json()).publicKey; - - // assymmetrically encrypt key with each receiver public keys - - const { ciphertext, nonce } = encryptAssymmetric({ - plaintext: randomBytes, - publicKey, - privateKey: PRIVATE_KEY - }); - - const key = { - encryptedKey: ciphertext, - nonce - }; - - changeHerokuConfigVars({ integrationId, key, secrets }); -}; - -export default pushKeysIntegration; diff --git a/frontend/components/utilities/telemetry/Telemetry.js b/frontend/components/utilities/telemetry/Telemetry.js deleted file mode 100644 index 92bdc078e..000000000 --- a/frontend/components/utilities/telemetry/Telemetry.js +++ /dev/null @@ -1,44 +0,0 @@ -/* eslint-disable */ -import { initPostHog } from "~/components/analytics/posthog"; -import { ENV } from "~/components/utilities/config"; - -class Capturer { - constructor() { - this.api = initPostHog(); - } - - capture(item) { - if (ENV == "production" && TELEMETRY_CAPTURING_ENABLED) { - try { - api.capture(item); - } catch (error) { - console.error("PostHog", error); - } - } - } - - identify(id) { - if (ENV == "production" && TELEMETRY_CAPTURING_ENABLED) { - try { - api.identify(id); - } catch (error) { - console.error("PostHog", error); - } - } - } - -} - -class Telemetry { - constructor() { - if (!Telemetry.instance) { - Telemetry.instance = new Capturer(); - } - } - - getInstance() { - return Telemetry.instance; - } -} - -module.exports = Telemetry; diff --git a/frontend/next-i18next.config.js b/frontend/next-i18next.config.js new file mode 100644 index 000000000..ea9fa3463 --- /dev/null +++ b/frontend/next-i18next.config.js @@ -0,0 +1,26 @@ +// @ts-check + +/** + * @type {import('next-i18next').UserConfig} + */ +module.exports = { + // https://www.i18next.com/overview/configuration-options#logging + debug: false, + i18n: { + defaultLocale: "en", + locales: ["en", "ko", "fr", "pt-BR"], + }, + fallbackLng: { + default: ["en"], + }, + + reloadOnPrerender: process.env.NODE_ENV === "development", + + /** + * @link https://github.com/i18next/next-i18next#6-advanced-configuration + */ + // saveMissing: false, + // strictMode: true, + // serializeConfig: false, + // react: { useSuspense: false } +}; diff --git a/frontend/next.config.js b/frontend/next.config.js index 2ae4b7641..06c56dd78 100644 --- a/frontend/next.config.js +++ b/frontend/next.config.js @@ -1,4 +1,9 @@ -// next.config.js +// @ts-check + +/** + * @type {import('next').NextConfig} + **/ +const { i18n } = require("./next-i18next.config.js"); const ContentSecurityPolicy = ` default-src 'self'; @@ -60,4 +65,8 @@ module.exports = { }, ]; }, + webpack: (config, { isServer, webpack }) => { + return config; + }, + i18n, }; diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 5e3bb010b..f5bb934fe 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -7,35 +7,51 @@ "dependencies": { "@emotion/css": "^11.10.0", "@emotion/server": "^11.10.0", + "@fontsource/inter": "^4.5.15", "@fortawesome/fontawesome-svg-core": "^6.1.2", "@fortawesome/free-brands-svg-icons": "^6.1.2", "@fortawesome/free-regular-svg-icons": "^6.1.1", "@fortawesome/free-solid-svg-icons": "^6.1.2", "@fortawesome/react-fontawesome": "^0.1.19", "@headlessui/react": "^1.6.6", + "@radix-ui/react-accordion": "^1.1.0", + "@radix-ui/react-alert-dialog": "^1.0.2", + "@radix-ui/react-checkbox": "^1.0.1", + "@radix-ui/react-dialog": "^1.0.2", + "@radix-ui/react-dropdown-menu": "^2.0.2", + "@radix-ui/react-label": "^2.0.0", + "@radix-ui/react-popover": "^1.0.3", + "@radix-ui/react-progress": "^1.0.1", + "@radix-ui/react-select": "^1.2.0", + "@radix-ui/react-switch": "^1.0.1", + "@radix-ui/react-toast": "^1.1.2", "@reduxjs/toolkit": "^1.8.3", "@stripe/react-stripe-js": "^1.10.0", - "@stripe/stripe-js": "^1.35.0", + "@stripe/stripe-js": "^1.46.0", + "@tanstack/react-query": "^4.23.0", "add": "^2.0.6", "axios": "^0.27.2", "axios-auth-refresh": "^3.3.3", "classnames": "^2.3.1", "cookies": "^0.8.0", + "cva": "npm:class-variance-authority@^0.4.0", "fs": "^0.0.1-security", "gray-matter": "^4.0.3", "http-proxy": "^1.18.1", + "i18next": "^22.4.6", "jspdf": "^2.5.1", "jsrp": "^0.2.4", "markdown-it": "^13.0.1", - "next": "^12.2.5", + "next": "^12.3.4", + "next-i18next": "^13.0.2", "posthog-js": "^1.34.0", "query-string": "^7.1.3", "react": "^17.0.2", "react-beautiful-dnd": "^13.1.1", "react-code-input": "^3.10.1", "react-dom": "^17.0.2", - "react-github-btn": "^1.4.0", "react-grid-layout": "^1.3.4", + "react-i18next": "^12.1.1", "react-mailchimp-subscribe": "^2.1.3", "react-markdown": "^8.0.3", "react-redux": "^8.0.2", @@ -43,25 +59,48 @@ "set-cookie-parser": "^2.5.1", "sharp": "^0.31.2", "styled-components": "^5.3.5", + "tailwind-merge": "^1.8.1", "tweetnacl": "^1.0.3", "tweetnacl-util": "^0.15.1", "uuid": "^8.3.2", - "uuidv4": "^6.2.13" + "uuidv4": "^6.2.13", + "yaml": "^2.2.0" }, "devDependencies": { + "@storybook/addon-essentials": "^7.0.0-beta.30", + "@storybook/addon-interactions": "^7.0.0-beta.30", + "@storybook/addon-links": "^7.0.0-beta.30", + "@storybook/addon-postcss": "^2.0.0", + "@storybook/blocks": "^7.0.0-beta.30", + "@storybook/nextjs": "^7.0.0-beta.30", + "@storybook/react": "^7.0.0-beta.30", + "@storybook/testing-library": "^0.0.13", "@tailwindcss/typography": "^0.5.4", + "@types/jsrp": "^0.2.4", "@types/node": "18.11.9", "@types/react": "^18.0.26", - "@typescript-eslint/eslint-plugin": "^5.45.0", + "@typescript-eslint/eslint-plugin": "^5.48.1", "@typescript-eslint/parser": "^5.45.0", "autoprefixer": "^10.4.7", - "eslint": "^8.29.0", + "eslint": "^8.32.0", + "eslint-config-airbnb": "^19.0.4", + "eslint-config-airbnb-typescript": "^17.0.0", "eslint-config-next": "^13.0.5", + "eslint-config-prettier": "^8.6.0", "eslint-import-resolver-typescript": "^3.5.2", + "eslint-plugin-import": "^2.27.4", + "eslint-plugin-jsx-a11y": "^6.7.1", + "eslint-plugin-prettier": "^4.2.1", + "eslint-plugin-react": "^7.32.0", + "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-simple-import-sort": "^8.0.0", + "eslint-plugin-storybook": "^0.6.10", "postcss": "^8.4.14", - "prettier": "2.7.1", - "tailwindcss": "^3.1.4", + "prettier": "^2.8.3", + "prettier-plugin-tailwindcss": "^0.2.2", + "storybook": "^7.0.0-beta.30", + "storybook-dark-mode": "^2.0.5", + "tailwindcss": "3.2", "typescript": "^4.9.3" } }, @@ -69,7 +108,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", - "peer": true, + "dev": true, "dependencies": { "@jridgewell/gen-mapping": "^0.1.0", "@jridgewell/trace-mapping": "^0.3.9" @@ -82,7 +121,7 @@ "version": "0.1.1", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", - "peer": true, + "dev": true, "dependencies": { "@jridgewell/set-array": "^1.0.0", "@jridgewell/sourcemap-codec": "^1.4.10" @@ -91,6 +130,18 @@ "node": ">=6.0.0" } }, + "node_modules/@aw-web-design/x-default-browser": { + "version": "1.4.88", + "resolved": "https://registry.npmjs.org/@aw-web-design/x-default-browser/-/x-default-browser-1.4.88.tgz", + "integrity": "sha512-AkEmF0wcwYC2QkhK703Y83fxWARttIWXDmQN8+cof8FmFZ5BRhnNXGymeb1S73bOCLfWjYELxtujL56idCN/XA==", + "dev": true, + "dependencies": { + "default-browser-id": "3.0.0" + }, + "bin": { + "x-default-browser": "bin/x-default-browser.js" + } + }, "node_modules/@babel/code-frame": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", @@ -106,7 +157,7 @@ "version": "7.20.5", "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.5.tgz", "integrity": "sha512-KZXo2t10+/jxmkhNXc7pZTqRvSOIvVv/+lJwHS+B2rErwOyjuVRh60yVpb7liQ1U5t7lLJ1bz+t8tSypUZdm0g==", - "peer": true, + "dev": true, "engines": { "node": ">=6.9.0" } @@ -115,7 +166,7 @@ "version": "7.20.5", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.5.tgz", "integrity": "sha512-UdOWmk4pNWTm/4DlPUl/Pt4Gz4rcEMb7CY0Y3eJl5Yz1vI8ZJGmHWaVE55LoxRjdpx0z259GE9U5STA9atUinQ==", - "peer": true, + "dev": true, "dependencies": { "@ampproject/remapping": "^2.1.0", "@babel/code-frame": "^7.18.6", @@ -145,7 +196,7 @@ "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "peer": true, + "dev": true, "dependencies": { "ms": "2.1.2" }, @@ -162,23 +213,23 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "peer": true + "dev": true }, "node_modules/@babel/core/node_modules/semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "peer": true, + "dev": true, "bin": { "semver": "bin/semver.js" } }, "node_modules/@babel/generator": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.5.tgz", - "integrity": "sha512-jl7JY2Ykn9S0yj4DQP82sYvPU+T3g0HFcWTqDLqiuA9tGRNIj9VfbtXGAYTTkyNEnQk1jkMGOdYka8aG/lulCA==", + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.7.tgz", + "integrity": "sha512-7wqMOJq8doJMZmP4ApXTzLxSr7+oO2jroJURrVEp6XShrQUObV8Tq/D0NCcoYg2uHqUrjzO0zwBjoYzelxK+sw==", "dependencies": { - "@babel/types": "^7.20.5", + "@babel/types": "^7.20.7", "@jridgewell/gen-mapping": "^0.3.2", "jsesc": "^2.5.1" }, @@ -197,15 +248,29 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.0.tgz", - "integrity": "sha512-0jp//vDGp9e8hZzBc6N/KwA5ZK3Wsm/pfm4CrY7vzegkVxc65SgSn6wYOnwHe9Js9HRQ1YTCKLGPzDtaS3RoLQ==", - "peer": true, + "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.18.9.tgz", + "integrity": "sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw==", + "dev": true, "dependencies": { - "@babel/compat-data": "^7.20.0", + "@babel/helper-explode-assignable-expression": "^7.18.6", + "@babel/types": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "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==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.20.5", "@babel/helper-validator-option": "^7.18.6", "browserslist": "^4.21.3", + "lru-cache": "^5.1.1", "semver": "^6.3.0" }, "engines": { @@ -215,11 +280,113 @@ "@babel/core": "^7.0.0" } }, + "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, "node_modules/@babel/helper-compilation-targets/node_modules/semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "peer": true, + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.20.12", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.20.12.tgz", + "integrity": "sha512-9OunRkbT0JQcednL0UFvbfXpAsUXiGjUk0a7sN8fUXX7Mue79cUSMjHGDRRi/Vz9vYlpIhLV5fMD5dKoMhhsNQ==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-member-expression-to-functions": "^7.20.7", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/helper-replace-supers": "^7.20.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", + "@babel/helper-split-export-declaration": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.20.5.tgz", + "integrity": "sha512-m68B1lkg3XDGX5yCvGO0kPx3v9WIYLnzjKfPcQiwntEQa5ZeRkPmo2X/ISJc8qxWGfwUr+kvZAeEzAwLec2r2w==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "regexpu-core": "^5.2.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz", + "integrity": "sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.17.7", + "@babel/helper-plugin-utils": "^7.16.7", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2", + "semver": "^6.1.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0-0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@babel/helper-define-polyfill-provider/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@babel/helper-define-polyfill-provider/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, "bin": { "semver": "bin/semver.js" } @@ -232,6 +399,18 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/helper-explode-assignable-expression": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz", + "integrity": "sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-function-name": { "version": "7.19.0", "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", @@ -255,6 +434,18 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.20.7.tgz", + "integrity": "sha512-9J0CxJLq315fEdi4s7xK5TQaNYjZw+nDVpVqr1axNGKzdrdwYBD5b4uKv3n75aABG0rCCTK8Im8Ww7eYfMrZgw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.20.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-module-imports": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", @@ -267,28 +458,75 @@ } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.2.tgz", - "integrity": "sha512-zvBKyJXRbmK07XhMuujYoJ48B5yvvmM6+wcpv6Ivj4Yg6qO7NOZOSnvZN9CRl1zz1Z4cKf8YejmCMh8clOoOeA==", - "peer": true, + "version": "7.20.11", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.11.tgz", + "integrity": "sha512-uRy78kN4psmji1s2QtbtcCSaj/LILFDp0f/ymhpQH5QY3nljUZCaNWz9X1dEj/8MBdBEFECs7yRhKn8i7NjZgg==", + "dev": true, "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.18.10", - "@babel/traverse": "^7.20.1", - "@babel/types": "^7.20.2" + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.20.10", + "@babel/types": "^7.20.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz", + "integrity": "sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", - "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==", + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz", + "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz", + "integrity": "sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-wrap-function": "^7.18.9", + "@babel/types": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.20.7.tgz", + "integrity": "sha512-vujDMtB6LVfNW13jhlCrp48QNslK6JXi7lQG736HVbHz/mbf4Dc7tIRh1Xf5C0rF7BP8iiSxGMCmY6Ci1ven3A==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-member-expression-to-functions": "^7.20.7", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.20.7", + "@babel/types": "^7.20.7" + }, "engines": { "node": ">=6.9.0" } @@ -297,7 +535,7 @@ "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==", - "peer": true, + "dev": true, "dependencies": { "@babel/types": "^7.20.2" }, @@ -305,6 +543,18 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.20.0.tgz", + "integrity": "sha512-5y1JYeNKfvnT8sZcK9DVRtpTbGiomYIHviSP3OQWmDPU3DeH4a1ZlT/N2lyQ5P8egjcRaT/Y9aNqUxK0WsnIIg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.20.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-split-export-declaration": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", @@ -336,7 +586,22 @@ "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", - "peer": true, + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.20.5.tgz", + "integrity": "sha512-bYMxIWK5mh+TgXGVqAtnu5Yn1un+v8DDZtqyzKRLUzrh70Eal2O3aZ7aPYiMADO4uKlkzOiRiZ6GX5q3qxvW9Q==", + "dev": true, + "dependencies": { + "@babel/helper-function-name": "^7.19.0", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.20.5", + "@babel/types": "^7.20.5" + }, "engines": { "node": ">=6.9.0" } @@ -345,7 +610,7 @@ "version": "7.20.6", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.6.tgz", "integrity": "sha512-Pf/OjgfgFRW5bApskEz5pvidpim7tEDPlFtKcNRXWmfHGn9IEI2W2flqRQXTFb7gIPTyK++N6rVHuwKut4XK6w==", - "peer": true, + "dev": true, "dependencies": { "@babel/template": "^7.18.10", "@babel/traverse": "^7.20.5", @@ -369,9 +634,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.5.tgz", - "integrity": "sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA==", + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.7.tgz", + "integrity": "sha512-T3Z9oHybU+0vZlY9CiDSJQTD5ZapcW18ZctFMi0MOAl/4BjFF4ul7NVSARLdbGO5vDqy9eQiGTV0LtKfvCYvcg==", "bin": { "parser": "bin/babel-parser.js" }, @@ -379,6 +644,392 @@ "node": ">=6.0.0" } }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz", + "integrity": "sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.20.7.tgz", + "integrity": "sha512-sbr9+wNE5aXMBBFBICk01tt7sBf2Oc9ikRFEcem/ZORup9IMUdNhW7/wVLEbbtlWOsEubJet46mHAL2C8+2jKQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", + "@babel/plugin-proposal-optional-chaining": "^7.20.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-proposal-async-generator-functions": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.20.7.tgz", + "integrity": "sha512-xMbiLsn/8RK7Wq7VeVytytS2L6qE69bXPB10YCmMdDZbKF4okCqY74pI/jJQ/8U0b/F6NrT2+14b8/P9/3AMGA==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-remap-async-to-generator": "^7.18.9", + "@babel/plugin-syntax-async-generators": "^7.8.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-class-properties": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz", + "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-class-static-block": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.20.7.tgz", + "integrity": "sha512-AveGOoi9DAjUYYuUAG//Ig69GlazLnoyzMw68VCDux+c1tsnnH/OkYcpz/5xzMkEFC6UxjR5Gw1c+iY2wOGVeQ==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.20.7", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-proposal-dynamic-import": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.18.6.tgz", + "integrity": "sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-export-namespace-from": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz", + "integrity": "sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-json-strings": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.18.6.tgz", + "integrity": "sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-json-strings": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-logical-assignment-operators": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.20.7.tgz", + "integrity": "sha512-y7C7cZgpMIjWlKE5T7eJwp+tnRYM89HmRvWM5EQuB5BoHEONjmQ8lSNmBUwOyy/GFRsohJED51YBF79hE1djug==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-nullish-coalescing-operator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz", + "integrity": "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-numeric-separator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz", + "integrity": "sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-object-rest-spread": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.20.7.tgz", + "integrity": "sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.20.5", + "@babel/helper-compilation-targets": "^7.20.7", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.20.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-optional-catch-binding": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz", + "integrity": "sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-optional-chaining": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.20.7.tgz", + "integrity": "sha512-T+A7b1kfjtRM51ssoOfS1+wbyCVqorfyZhT99TvxxLMirPShD8CzKMRepMlCBGM5RpHMbn8s+5MMHnPstJH6mQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-private-methods": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz", + "integrity": "sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.20.5.tgz", + "integrity": "sha512-Vq7b9dUA12ByzB4EjQTPo25sFhY+08pQDBSZRtUAkj7lb7jahaHR5igera16QZ+3my1nYR4dKsNdYj5IjPHilQ==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-create-class-features-plugin": "^7.20.5", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-unicode-property-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz", + "integrity": "sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-flow": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.18.6.tgz", + "integrity": "sha512-LUbR+KNTBWCUAqRG9ex5Gnzu2IOkt8jRJbHHXFT9q+L9zm7M/QQbEqXyw1n1pohYvOyWC8CjeyjrSaIwiYjK7A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.20.0.tgz", + "integrity": "sha512-IUh1vakzNoWalR8ch/areW7qFopR2AEw03JlG7BbrDqmQ4X3q9uuipQwSGrUn7oGiemKjtSLDhNtQHzMHr1JdQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/plugin-syntax-jsx": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz", @@ -393,56 +1044,1070 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/runtime": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.9.tgz", - "integrity": "sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw==", + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, "dependencies": { - "regenerator-runtime": "^0.13.4" + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/runtime-corejs3": { - "version": "7.20.1", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.20.1.tgz", - "integrity": "sha512-CGulbEDcg/ND1Im7fUNRZdGXmX2MTWVVZacQi/6DiKE5HNwZ3aVTm5PV4lO8HHz0B2h8WQyvKKjbX5XgTtydsg==", + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", "dev": true, "dependencies": { - "core-js-pure": "^3.25.1", - "regenerator-runtime": "^0.13.10" + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.20.0.tgz", + "integrity": "sha512-rd9TkG+u1CExzS4SM1BlMEhMXwFLKVjOAFFCDx9PbX5ycJWDoWMcwdJH9RhkPu1dOgn5TrxLot/Gx6lWFuAUNQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.20.7.tgz", + "integrity": "sha512-3poA5E7dzDomxj9WXWwuD6A5F3kc7VXwIJO+E+J8qtDtS+pXPAhrgEyh+9GBwBgPq1Z+bB+/JD60lp5jsN7JPQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.20.7.tgz", + "integrity": "sha512-Uo5gwHPT9vgnSXQxqGtpdufUiWp96gk7yiP4Mp5bm1QMkEmLXBO7PAGYbKoJ6DhAwiNkcHFBol/x5zZZkL/t0Q==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-remap-async-to-generator": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.18.6.tgz", + "integrity": "sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.20.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.20.11.tgz", + "integrity": "sha512-tA4N427a7fjf1P0/2I4ScsHGc5jcHPbb30xMbaTke2gxDuWpUfXDuX1FEymJwKk4tuGUvGcejAR6HdZVqmmPyw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.20.7.tgz", + "integrity": "sha512-LWYbsiXTPKl+oBlXUGlwNlJZetXD5Am+CyBdqhPsDVjM9Jc8jwBJFrKhHf900Kfk2eZG1y9MAG3UNajol7A4VQ==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-compilation-targets": "^7.20.7", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-replace-supers": "^7.20.7", + "@babel/helper-split-export-declaration": "^7.18.6", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.20.7.tgz", + "integrity": "sha512-Lz7MvBK6DTjElHAmfu6bfANzKcxpyNPeYBGEafyA6E5HtRpjpZwU+u7Qrgz/2OR0z+5TvKYbPdphfSaAcZBrYQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/template": "^7.20.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.20.7.tgz", + "integrity": "sha512-Xwg403sRrZb81IVB79ZPqNQME23yhugYVqgTxAhT99h485F4f+GMELFhhOsscDUB7HCswepKeCKLn/GZvUKoBA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.18.6.tgz", + "integrity": "sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.9.tgz", + "integrity": "sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.18.6.tgz", + "integrity": "sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw==", + "dev": true, + "dependencies": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-flow-strip-types": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.19.0.tgz", + "integrity": "sha512-sgeMlNaQVbCSpgLSKP4ZZKfsJVnFnNQlUSk6gPYzR/q7tzCgQF2t8RBKAP6cKJeZdveei7Q7Jm527xepI8lNLg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/plugin-syntax-flow": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.18.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.8.tgz", + "integrity": "sha512-yEfTRnjuskWYo0k1mHUqrVWaZwrdq8AYbfrpqULOJOaucGSp4mNMVps+YtA8byoevxS/urwU75vyhQIxcCgiBQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.9.tgz", + "integrity": "sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-function-name": "^7.18.9", + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.9.tgz", + "integrity": "sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.18.6.tgz", + "integrity": "sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.20.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.20.11.tgz", + "integrity": "sha512-NuzCt5IIYOW0O30UvqktzHYR2ud5bOWbY0yaxWZ6G+aFzOMJvrs5YHNikrbdaT15+KNO31nPOy5Fim3ku6Zb5g==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.20.11", + "@babel/helper-plugin-utils": "^7.20.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.20.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.20.11.tgz", + "integrity": "sha512-S8e1f7WQ7cimJQ51JkAaDrEtohVEitXjgCGAS2N8S31Y42E+kWwfSz83LYz57QdBm7q9diARVqanIaH2oVgQnw==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.20.11", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-simple-access": "^7.20.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.20.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.20.11.tgz", + "integrity": "sha512-vVu5g9BPQKSFEmvt2TA4Da5N+QVS66EX21d8uoOihC+OCpUoGvzVsXeqFdtAEfVa5BILAeFt+U7yVmLbQnAJmw==", + "dev": true, + "dependencies": { + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-module-transforms": "^7.20.11", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-validator-identifier": "^7.19.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.6.tgz", + "integrity": "sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.20.5.tgz", + "integrity": "sha512-mOW4tTzi5iTLnw+78iEq3gr8Aoq4WNRGpmSlrogqaiCBoR1HFhpU4JkpQFOHfeYx3ReVIFWOQJS4aZBRvuZ6mA==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.20.5", + "@babel/helper-plugin-utils": "^7.20.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.18.6.tgz", + "integrity": "sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.18.6.tgz", + "integrity": "sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-replace-supers": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.20.7.tgz", + "integrity": "sha512-WiWBIkeHKVOSYPO0pWkxGPfKeWrCJyD3NJ53+Lrp/QMSZbsVPovrVl2aWZ19D/LTVnaDv5Ap7GJ/B2CTOZdrfA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.18.6.tgz", + "integrity": "sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-display-name": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.18.6.tgz", + "integrity": "sha512-TV4sQ+T013n61uMoygyMRm+xf04Bd5oqFpv2jAEQwSZ8NwQA7zeRPg1LMVg2PWi3zWBz+CLKD+v5bcpZ/BS0aA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.20.7.tgz", + "integrity": "sha512-Tfq7qqD+tRj3EoDhY00nn2uP2hsRxgYGi5mLQ5TimKav0a9Lrpd4deE+fcLXU8zFYRjlKPHZhpCvfEA6qnBxqQ==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-jsx": "^7.18.6", + "@babel/types": "^7.20.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-development": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.18.6.tgz", + "integrity": "sha512-SA6HEjwYFKF7WDjWcMcMGUimmw/nhNRDWxr+KaLSCrkD/LMDBvWRmHAYgE1HDeF8KUuI8OAu+RT6EOtKxSW2qA==", + "dev": true, + "dependencies": { + "@babel/plugin-transform-react-jsx": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-pure-annotations": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.18.6.tgz", + "integrity": "sha512-I8VfEPg9r2TRDdvnHgPepTKvuRomzA8+u+nhY7qSI1fR2hRNebasZEETLyM5mAUr0Ku56OkXJ0I7NHJnO6cJiQ==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.20.5.tgz", + "integrity": "sha512-kW/oO7HPBtntbsahzQ0qSE3tFvkFwnbozz3NWFhLGqH75vLEg+sCGngLlhVkePlCs3Jv0dBBHDzCHxNiFAQKCQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2", + "regenerator-transform": "^0.15.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.18.6.tgz", + "integrity": "sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz", + "integrity": "sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.20.7.tgz", + "integrity": "sha512-ewBbHQ+1U/VnH1fxltbJqDeWBU1oNLG8Dj11uIv3xVf7nrQu0bPGe5Rf716r7K5Qz+SqtAOVswoVunoiBtGhxw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.18.6.tgz", + "integrity": "sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.9.tgz", + "integrity": "sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.9.tgz", + "integrity": "sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.20.7.tgz", + "integrity": "sha512-m3wVKEvf6SoszD8pu4NZz3PvfKRCMgk6D6d0Qi9hNnlM5M6CFS92EgF4EiHVLKbU0r/r7ty1hg7NPZwE7WRbYw==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.20.7", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-typescript": "^7.20.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.10.tgz", + "integrity": "sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.18.6.tgz", + "integrity": "sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.20.2.tgz", + "integrity": "sha512-1G0efQEWR1EHkKvKHqbG+IN/QdgwfByUpM5V5QroDzGV2t3S/WXNQd693cHiHTlCFMpr9B6FkPFXDA2lQcKoDg==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.20.1", + "@babel/helper-compilation-targets": "^7.20.0", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-validator-option": "^7.18.6", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.18.6", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.18.9", + "@babel/plugin-proposal-async-generator-functions": "^7.20.1", + "@babel/plugin-proposal-class-properties": "^7.18.6", + "@babel/plugin-proposal-class-static-block": "^7.18.6", + "@babel/plugin-proposal-dynamic-import": "^7.18.6", + "@babel/plugin-proposal-export-namespace-from": "^7.18.9", + "@babel/plugin-proposal-json-strings": "^7.18.6", + "@babel/plugin-proposal-logical-assignment-operators": "^7.18.9", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6", + "@babel/plugin-proposal-numeric-separator": "^7.18.6", + "@babel/plugin-proposal-object-rest-spread": "^7.20.2", + "@babel/plugin-proposal-optional-catch-binding": "^7.18.6", + "@babel/plugin-proposal-optional-chaining": "^7.18.9", + "@babel/plugin-proposal-private-methods": "^7.18.6", + "@babel/plugin-proposal-private-property-in-object": "^7.18.6", + "@babel/plugin-proposal-unicode-property-regex": "^7.18.6", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.20.0", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-transform-arrow-functions": "^7.18.6", + "@babel/plugin-transform-async-to-generator": "^7.18.6", + "@babel/plugin-transform-block-scoped-functions": "^7.18.6", + "@babel/plugin-transform-block-scoping": "^7.20.2", + "@babel/plugin-transform-classes": "^7.20.2", + "@babel/plugin-transform-computed-properties": "^7.18.9", + "@babel/plugin-transform-destructuring": "^7.20.2", + "@babel/plugin-transform-dotall-regex": "^7.18.6", + "@babel/plugin-transform-duplicate-keys": "^7.18.9", + "@babel/plugin-transform-exponentiation-operator": "^7.18.6", + "@babel/plugin-transform-for-of": "^7.18.8", + "@babel/plugin-transform-function-name": "^7.18.9", + "@babel/plugin-transform-literals": "^7.18.9", + "@babel/plugin-transform-member-expression-literals": "^7.18.6", + "@babel/plugin-transform-modules-amd": "^7.19.6", + "@babel/plugin-transform-modules-commonjs": "^7.19.6", + "@babel/plugin-transform-modules-systemjs": "^7.19.6", + "@babel/plugin-transform-modules-umd": "^7.18.6", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.19.1", + "@babel/plugin-transform-new-target": "^7.18.6", + "@babel/plugin-transform-object-super": "^7.18.6", + "@babel/plugin-transform-parameters": "^7.20.1", + "@babel/plugin-transform-property-literals": "^7.18.6", + "@babel/plugin-transform-regenerator": "^7.18.6", + "@babel/plugin-transform-reserved-words": "^7.18.6", + "@babel/plugin-transform-shorthand-properties": "^7.18.6", + "@babel/plugin-transform-spread": "^7.19.0", + "@babel/plugin-transform-sticky-regex": "^7.18.6", + "@babel/plugin-transform-template-literals": "^7.18.9", + "@babel/plugin-transform-typeof-symbol": "^7.18.9", + "@babel/plugin-transform-unicode-escapes": "^7.18.10", + "@babel/plugin-transform-unicode-regex": "^7.18.6", + "@babel/preset-modules": "^0.1.5", + "@babel/types": "^7.20.2", + "babel-plugin-polyfill-corejs2": "^0.3.3", + "babel-plugin-polyfill-corejs3": "^0.6.0", + "babel-plugin-polyfill-regenerator": "^0.4.1", + "core-js-compat": "^3.25.1", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/preset-flow": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/preset-flow/-/preset-flow-7.18.6.tgz", + "integrity": "sha512-E7BDhL64W6OUqpuyHnSroLnqyRTcG6ZdOBl1OKI/QK/HJfplqK/S3sq1Cckx7oTodJ5yOXyfw7rEADJ6UjoQDQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-validator-option": "^7.18.6", + "@babel/plugin-transform-flow-strip-types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz", + "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", + "@babel/plugin-transform-dotall-regex": "^7.4.4", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-react": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.18.6.tgz", + "integrity": "sha512-zXr6atUmyYdiWRVLOZahakYmOBHtWc2WGCkP8PYTgZi0iJXDY2CN180TdrIW4OGOAdLc7TifzDIvtx6izaRIzg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-validator-option": "^7.18.6", + "@babel/plugin-transform-react-display-name": "^7.18.6", + "@babel/plugin-transform-react-jsx": "^7.18.6", + "@babel/plugin-transform-react-jsx-development": "^7.18.6", + "@babel/plugin-transform-react-pure-annotations": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-typescript": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.18.6.tgz", + "integrity": "sha512-s9ik86kXBAnD760aybBucdpnLsAt0jK1xqJn2juOn9lkOvSHV60os5hxoVJsPzMQxvnUJFAlkont2DvvaYEBtQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-validator-option": "^7.18.6", + "@babel/plugin-transform-typescript": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/register": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.18.9.tgz", + "integrity": "sha512-ZlbnXDcNYHMR25ITwwNKT88JiaukkdVj/nG7r3wnuXkOTHc60Uy05PwMCPre0hSkY68E6zK3xz+vUJSP2jWmcw==", + "dev": true, + "dependencies": { + "clone-deep": "^4.0.1", + "find-cache-dir": "^2.0.0", + "make-dir": "^2.1.0", + "pirates": "^4.0.5", + "source-map-support": "^0.5.16" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/register/node_modules/find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "dev": true, + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@babel/register/node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@babel/register/node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@babel/register/node_modules/make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "dependencies": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@babel/register/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@babel/register/node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@babel/register/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/register/node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/@babel/register/node_modules/pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dev": true, + "dependencies": { + "find-up": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@babel/register/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/@babel/runtime": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.7.tgz", + "integrity": "sha512-UF0tvkUtxwAgZ5W/KrkHf0Rn0fdnLDU9ScxBrEVNUprE/MzirjK4MJUX1/BVDv00Sv8cljtukVK1aky++X1SjQ==", + "dependencies": { + "regenerator-runtime": "^0.13.11" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/template": { - "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", - "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", + "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.18.10", - "@babel/types": "^7.18.10" + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.5.tgz", - "integrity": "sha512-WM5ZNN3JITQIq9tFZaw1ojLU3WgWdtkxnhM1AegMS+PvHjkM5IXjmYEGY7yukz5XS4sJyEf2VzWjI8uAavhxBQ==", + "version": "7.20.12", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.12.tgz", + "integrity": "sha512-MsIbFN0u+raeja38qboyF8TIT7K0BFzz/Yd/77ta4MsUsmP2RAnidIlwq7d5HFQrH/OZJecGV6B71C4zAgpoSQ==", "dependencies": { "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.20.5", + "@babel/generator": "^7.20.7", "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-function-name": "^7.19.0", "@babel/helper-hoist-variables": "^7.18.6", "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.20.5", - "@babel/types": "^7.20.5", + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -472,9 +2137,9 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/@babel/types": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.5.tgz", - "integrity": "sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==", + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", + "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", "dependencies": { "@babel/helper-string-parser": "^7.19.4", "@babel/helper-validator-identifier": "^7.19.1", @@ -484,6 +2149,37 @@ "node": ">=6.9.0" } }, + "node_modules/@base2/pretty-print-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@base2/pretty-print-object/-/pretty-print-object-1.0.1.tgz", + "integrity": "sha512-4iri8i1AqYHJE2DstZYkyEprg6Pq6sKx3xn5FpySk9sNhH7qN2LLlHJCfDTZRILNwQNPD7mATWM0TBui7uC1pA==", + "dev": true + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true + }, + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "dev": true, + "optional": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/@emotion/babel-plugin": { "version": "11.10.2", "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.10.2.tgz", @@ -633,6 +2329,15 @@ "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz", "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==" }, + "node_modules/@emotion/use-insertion-effect-with-fallbacks": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.0.tgz", + "integrity": "sha512-1eEgUGmkaljiBnRMTdksDV1W4kUnmwgp7X9G8B++9GYwl1lUdqSndSriIrTJ0N7LQaoauY9JJ2yhiOYK5+NI4A==", + "dev": true, + "peerDependencies": { + "react": ">=16.8.0" + } + }, "node_modules/@emotion/utils": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.0.tgz", @@ -643,16 +2348,368 @@ "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.0.tgz", "integrity": "sha512-AHPmaAx+RYfZz0eYu6Gviiagpmiyw98ySSlQvCUhVGDRtDFe4DBS0x1bSjdF3gqUDYOczB+yYvBTtEylYSdRhg==" }, + "node_modules/@esbuild/android-arm": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.16.17.tgz", + "integrity": "sha512-N9x1CMXVhtWEAMS7pNNONyA14f71VPQN9Cnavj1XQh6T7bskqiLLrSca4O0Vr8Wdcga943eThxnVp3JLnBMYtw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.16.17.tgz", + "integrity": "sha512-MIGl6p5sc3RDTLLkYL1MyL8BMRN4tLMRCn+yRJJmEDvYZ2M7tmAf80hx1kbNEUX2KJ50RRtxZ4JHLvCfuB6kBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.16.17.tgz", + "integrity": "sha512-a3kTv3m0Ghh4z1DaFEuEDfz3OLONKuFvI4Xqczqx4BqLyuFaFkuaG4j2MtA6fuWEFeC5x9IvqnX7drmRq/fyAQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.16.17.tgz", + "integrity": "sha512-/2agbUEfmxWHi9ARTX6OQ/KgXnOWfsNlTeLcoV7HSuSTv63E4DqtAc+2XqGw1KHxKMHGZgbVCZge7HXWX9Vn+w==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.16.17.tgz", + "integrity": "sha512-2By45OBHulkd9Svy5IOCZt376Aa2oOkiE9QWUK9fe6Tb+WDr8hXL3dpqi+DeLiMed8tVXspzsTAvd0jUl96wmg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.16.17.tgz", + "integrity": "sha512-mt+cxZe1tVx489VTb4mBAOo2aKSnJ33L9fr25JXpqQqzbUIw/yzIzi+NHwAXK2qYV1lEFp4OoVeThGjUbmWmdw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.16.17.tgz", + "integrity": "sha512-8ScTdNJl5idAKjH8zGAsN7RuWcyHG3BAvMNpKOBaqqR7EbUhhVHOqXRdL7oZvz8WNHL2pr5+eIT5c65kA6NHug==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.16.17.tgz", + "integrity": "sha512-iihzrWbD4gIT7j3caMzKb/RsFFHCwqqbrbH9SqUSRrdXkXaygSZCZg1FybsZz57Ju7N/SHEgPyaR0LZ8Zbe9gQ==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.16.17.tgz", + "integrity": "sha512-7S8gJnSlqKGVJunnMCrXHU9Q8Q/tQIxk/xL8BqAP64wchPCTzuM6W3Ra8cIa1HIflAvDnNOt2jaL17vaW+1V0g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.16.17.tgz", + "integrity": "sha512-kiX69+wcPAdgl3Lonh1VI7MBr16nktEvOfViszBSxygRQqSpzv7BffMKRPMFwzeJGPxcio0pdD3kYQGpqQ2SSg==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.16.17.tgz", + "integrity": "sha512-dTzNnQwembNDhd654cA4QhbS9uDdXC3TKqMJjgOWsC0yNCbpzfWoXdZvp0mY7HU6nzk5E0zpRGGx3qoQg8T2DQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.16.17.tgz", + "integrity": "sha512-ezbDkp2nDl0PfIUn0CsQ30kxfcLTlcx4Foz2kYv8qdC6ia2oX5Q3E/8m6lq84Dj/6b0FrkgD582fJMIfHhJfSw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.16.17.tgz", + "integrity": "sha512-dzS678gYD1lJsW73zrFhDApLVdM3cUF2MvAa1D8K8KtcSKdLBPP4zZSLy6LFZ0jYqQdQ29bjAHJDgz0rVbLB3g==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.16.17.tgz", + "integrity": "sha512-ylNlVsxuFjZK8DQtNUwiMskh6nT0vI7kYl/4fZgV1llP5d6+HIeL/vmmm3jpuoo8+NuXjQVZxmKuhDApK0/cKw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.16.17.tgz", + "integrity": "sha512-gzy7nUTO4UA4oZ2wAMXPNBGTzZFP7mss3aKR2hH+/4UUkCOyqmjXiKpzGrY2TlEUhbbejzXVKKGazYcQTZWA/w==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.16.17.tgz", + "integrity": "sha512-mdPjPxfnmoqhgpiEArqi4egmBAMYvaObgn4poorpUaqmvzzbvqbowRllQ+ZgzGVMGKaPkqUmPDOOFQRUFDmeUw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.16.17.tgz", + "integrity": "sha512-/PzmzD/zyAeTUsduZa32bn0ORug+Jd1EGGAUJvqfeixoEISYpGnAezN6lnJoskauoai0Jrs+XSyvDhppCPoKOA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.16.17.tgz", + "integrity": "sha512-2yaWJhvxGEz2RiftSk0UObqJa/b+rIAjnODJgv2GbGGpRwAfpgzyrg1WLK8rqA24mfZa9GvpjLcBBg8JHkoodg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.16.17.tgz", + "integrity": "sha512-xtVUiev38tN0R3g8VhRfN7Zl42YCJvyBhRKw1RJjwE1d2emWTVToPLNEQj/5Qxc6lVFATDiy6LjVHYhIPrLxzw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.16.17.tgz", + "integrity": "sha512-ga8+JqBDHY4b6fQAmOgtJJue36scANy4l/rL97W+0wYmijhxKetzZdKOJI7olaBaMhWt8Pac2McJdZLxXWUEQw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.16.17.tgz", + "integrity": "sha512-WnsKaf46uSSF/sZhwnqE4L/F89AYNMiD4YtEcYekBt9Q7nj0DiId2XH2Ng2PHM54qi5oPrQ8luuzGszqi/veig==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.16.17.tgz", + "integrity": "sha512-y+EHuSchhL7FjHgvQL/0fnnFmO4T1bhvWANX6gcnqTjtnKWbTvUMCpGnv2+t+31d7RzyEAYAd4u2fnIhHL6N/Q==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, "node_modules/@eslint/eslintrc": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.3.tgz", - "integrity": "sha512-uj3pT6Mg+3t39fvLrj8iuCIJ38zKO9FpGtJ4BBJebJhEwjoT+KLVNCcHT5QC9NGRIEi7fZ0ZR8YRb884auB4Lg==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz", + "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==", "dev": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^9.4.0", - "globals": "^13.15.0", + "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", @@ -690,9 +2747,9 @@ } }, "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "13.18.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.18.0.tgz", - "integrity": "sha512-/mR4KI8Ps2spmoc0Ulu9L7agOF0du1CZNQ3dke8yItYlyKNmGrkONemBbd6V8UTc1Wgcqn21t3WYB7dbRmh6/A==", + "version": "13.19.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz", + "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -722,6 +2779,43 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, + "node_modules/@fal-works/esbuild-plugin-global-externals": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@fal-works/esbuild-plugin-global-externals/-/esbuild-plugin-global-externals-2.1.2.tgz", + "integrity": "sha512-cEee/Z+I12mZcFJshKcCqC8tuX5hG3s+d+9nZ3LabqKF1vKdF41B92pJVCBggjAGORAeOzyyDDKrZwIkLffeOQ==", + "dev": true + }, + "node_modules/@floating-ui/core": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-0.7.3.tgz", + "integrity": "sha512-buc8BXHmG9l82+OQXOFU3Kr2XQx9ys01U/Q9HMIrZ300iLc8HLMgh7dcCqgYzAzf4BkoQvDcXf5Y+CuEZ5JBYg==" + }, + "node_modules/@floating-ui/dom": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-0.5.4.tgz", + "integrity": "sha512-419BMceRLq0RrmTSDxn8hf9R3VCJv2K9PUfugh5JyEFmdjzDo+e8U5EdR8nzKq8Yj1htzLm3b6eQEEam3/rrtg==", + "dependencies": { + "@floating-ui/core": "^0.7.3" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-0.7.2.tgz", + "integrity": "sha512-1T0sJcpHgX/u4I1OzIEhlcrvkUN8ln39nz7fMoE/2HDHrPiMFoOGR7++GYyfUmIQHkkrTinaeQsO3XWubjSvGg==", + "dependencies": { + "@floating-ui/dom": "^0.5.3", + "use-isomorphic-layout-effect": "^1.1.1" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@fontsource/inter": { + "version": "4.5.15", + "resolved": "https://registry.npmjs.org/@fontsource/inter/-/inter-4.5.15.tgz", + "integrity": "sha512-FzleM9AxZQK2nqsTDtBiY0PMEVWvnKnuu2i09+p6DHvrHsuucoV2j0tmw+kAT3L4hvsLdAIDv6MdGehsPIdT+Q==" + }, "node_modules/@fortawesome/fontawesome-common-types": { "version": "6.1.2", "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.1.2.tgz", @@ -804,9 +2898,9 @@ } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.7", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.7.tgz", - "integrity": "sha512-kBbPWzN8oVMLb0hOUYXhmxggL/1cJE6ydvjDIGi9EnAGUyA7cLVKQg+d/Dsm+KZwx2czGHrCmMVLiyg8s5JPKw==", + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", + "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", "dev": true, "dependencies": { "@humanwhocodes/object-schema": "^1.2.1", @@ -859,6 +2953,257 @@ "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", "dev": true }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/schemas": { + "version": "29.0.0", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.0.0.tgz", + "integrity": "sha512-3Ab5HgYIIAnS0HjqJHQYZS+zXc4tUmTmBH3z83ajI6afXp8X3ZtdLX+nXx+I7LNkJD7uN9LAVhgnjDgZa2z0kA==", + "dev": true, + "dependencies": { + "@sinclair/typebox": "^0.24.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.3.1.tgz", + "integrity": "sha512-8wmCFBTVGYqFNLWfcOWoVuMuKYPUBTnTMDkdvFtAYELwDOl9RGwOsvQWGPFxDJ8AWY9xM/8xCXdqmPK3+Q5Lug==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.3.1", + "@jridgewell/trace-mapping": "^0.3.15", + "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.3.1", + "jest-regex-util": "^29.2.0", + "jest-util": "^29.3.1", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/transform/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/transform/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/transform/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "node_modules/@jest/transform/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/transform/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/types": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.3.1.tgz", + "integrity": "sha512-d0S0jmmTpjnhCmNpApgX3jrUZgZ22ivKJRvL2lli5hpCRoNnp1f85r2/wpKfXuYu8E7Jjh1hGfhPyup1NM5AmA==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.0.0", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/types/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/types/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/types/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", @@ -888,24 +3233,51 @@ "node": ">=6.0.0" } }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", + "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.4.14", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.14", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz", - "integrity": "sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==", + "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.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + } + }, + "node_modules/@mdx-js/react": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-2.2.1.tgz", + "integrity": "sha512-YdXcMcEnqZhzql98RNrqYo9cEhTTesBiCclEtoiQUbJwx87q9453GTapYU6kJ8ZZ2ek1Vp25SiAXEFy5O/eAPw==", + "dev": true, + "dependencies": { + "@types/mdx": "^2.0.0", + "@types/react": ">=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "react": ">=16" } }, "node_modules/@next/env": { - "version": "12.3.1", - "resolved": "https://registry.npmjs.org/@next/env/-/env-12.3.1.tgz", - "integrity": "sha512-9P9THmRFVKGKt9DYqeC2aKIxm8rlvkK38V1P1sRE7qyoPBIs8l9oo79QoSdPtOWfzkbDAVUqvbQGgTMsb8BtJg==" + "version": "12.3.4", + "resolved": "https://registry.npmjs.org/@next/env/-/env-12.3.4.tgz", + "integrity": "sha512-H/69Lc5Q02dq3o+dxxy5O/oNxFsZpdL6WREtOOtOM1B/weonIwDXkekr1KV5DPVPr12IHFPrMrcJQ6bgPMfn7A==" }, "node_modules/@next/eslint-plugin-next": { "version": "13.0.5", @@ -916,10 +3288,16 @@ "glob": "7.1.7" } }, + "node_modules/@next/font": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/@next/font/-/font-13.1.2.tgz", + "integrity": "sha512-NXGXGFGiOKEnvBIHq9cdFTKbHO2/4B3Zd9K27M7j1DioIQVar7oVRqZMYs0h3XMVEZLwjjkdAtqRPCzzd3RtXg==", + "dev": true + }, "node_modules/@next/swc-android-arm-eabi": { - "version": "12.3.1", - "resolved": "https://registry.npmjs.org/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-12.3.1.tgz", - "integrity": "sha512-i+BvKA8tB//srVPPQxIQN5lvfROcfv4OB23/L1nXznP+N/TyKL8lql3l7oo2LNhnH66zWhfoemg3Q4VJZSruzQ==", + "version": "12.3.4", + "resolved": "https://registry.npmjs.org/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-12.3.4.tgz", + "integrity": "sha512-cM42Cw6V4Bz/2+j/xIzO8nK/Q3Ly+VSlZJTa1vHzsocJRYz8KT6MrreXaci2++SIZCF1rVRCDgAg5PpqRibdIA==", "cpu": [ "arm" ], @@ -932,9 +3310,9 @@ } }, "node_modules/@next/swc-android-arm64": { - "version": "12.3.1", - "resolved": "https://registry.npmjs.org/@next/swc-android-arm64/-/swc-android-arm64-12.3.1.tgz", - "integrity": "sha512-CmgU2ZNyBP0rkugOOqLnjl3+eRpXBzB/I2sjwcGZ7/Z6RcUJXK5Evz+N0ucOxqE4cZ3gkTeXtSzRrMK2mGYV8Q==", + "version": "12.3.4", + "resolved": "https://registry.npmjs.org/@next/swc-android-arm64/-/swc-android-arm64-12.3.4.tgz", + "integrity": "sha512-5jf0dTBjL+rabWjGj3eghpLUxCukRhBcEJgwLedewEA/LJk2HyqCvGIwj5rH+iwmq1llCWbOky2dO3pVljrapg==", "cpu": [ "arm64" ], @@ -947,9 +3325,9 @@ } }, "node_modules/@next/swc-darwin-arm64": { - "version": "12.3.1", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.3.1.tgz", - "integrity": "sha512-hT/EBGNcu0ITiuWDYU9ur57Oa4LybD5DOQp4f22T6zLfpoBMfBibPtR8XktXmOyFHrL/6FC2p9ojdLZhWhvBHg==", + "version": "12.3.4", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.3.4.tgz", + "integrity": "sha512-DqsSTd3FRjQUR6ao0E1e2OlOcrF5br+uegcEGPVonKYJpcr0MJrtYmPxd4v5T6UCJZ+XzydF7eQo5wdGvSZAyA==", "cpu": [ "arm64" ], @@ -962,9 +3340,9 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "12.3.1", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-12.3.1.tgz", - "integrity": "sha512-9S6EVueCVCyGf2vuiLiGEHZCJcPAxglyckTZcEwLdJwozLqN0gtS0Eq0bQlGS3dH49Py/rQYpZ3KVWZ9BUf/WA==", + "version": "12.3.4", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-12.3.4.tgz", + "integrity": "sha512-PPF7tbWD4k0dJ2EcUSnOsaOJ5rhT3rlEt/3LhZUGiYNL8KvoqczFrETlUx0cUYaXe11dRA3F80Hpt727QIwByQ==", "cpu": [ "x64" ], @@ -977,9 +3355,9 @@ } }, "node_modules/@next/swc-freebsd-x64": { - "version": "12.3.1", - "resolved": "https://registry.npmjs.org/@next/swc-freebsd-x64/-/swc-freebsd-x64-12.3.1.tgz", - "integrity": "sha512-qcuUQkaBZWqzM0F1N4AkAh88lLzzpfE6ImOcI1P6YeyJSsBmpBIV8o70zV+Wxpc26yV9vpzb+e5gCyxNjKJg5Q==", + "version": "12.3.4", + "resolved": "https://registry.npmjs.org/@next/swc-freebsd-x64/-/swc-freebsd-x64-12.3.4.tgz", + "integrity": "sha512-KM9JXRXi/U2PUM928z7l4tnfQ9u8bTco/jb939pdFUHqc28V43Ohd31MmZD1QzEK4aFlMRaIBQOWQZh4D/E5lQ==", "cpu": [ "x64" ], @@ -992,9 +3370,9 @@ } }, "node_modules/@next/swc-linux-arm-gnueabihf": { - "version": "12.3.1", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.3.1.tgz", - "integrity": "sha512-diL9MSYrEI5nY2wc/h/DBewEDUzr/DqBjIgHJ3RUNtETAOB3spMNHvJk2XKUDjnQuluLmFMloet9tpEqU2TT9w==", + "version": "12.3.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.3.4.tgz", + "integrity": "sha512-3zqD3pO+z5CZyxtKDTnOJ2XgFFRUBciOox6EWkoZvJfc9zcidNAQxuwonUeNts6Xbm8Wtm5YGIRC0x+12YH7kw==", "cpu": [ "arm" ], @@ -1007,9 +3385,9 @@ } }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "12.3.1", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.3.1.tgz", - "integrity": "sha512-o/xB2nztoaC7jnXU3Q36vGgOolJpsGG8ETNjxM1VAPxRwM7FyGCPHOMk1XavG88QZSQf+1r+POBW0tLxQOJ9DQ==", + "version": "12.3.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.3.4.tgz", + "integrity": "sha512-kiX0vgJGMZVv+oo1QuObaYulXNvdH/IINmvdZnVzMO/jic/B8EEIGlZ8Bgvw8LCjH3zNVPO3mGrdMvnEEPEhKA==", "cpu": [ "arm64" ], @@ -1022,9 +3400,9 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "12.3.1", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.3.1.tgz", - "integrity": "sha512-2WEasRxJzgAmP43glFNhADpe8zB7kJofhEAVNbDJZANp+H4+wq+/cW1CdDi8DqjkShPEA6/ejJw+xnEyDID2jg==", + "version": "12.3.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.3.4.tgz", + "integrity": "sha512-EETZPa1juczrKLWk5okoW2hv7D7WvonU+Cf2CgsSoxgsYbUCZ1voOpL4JZTOb6IbKMDo6ja+SbY0vzXZBUMvkQ==", "cpu": [ "arm64" ], @@ -1037,9 +3415,9 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "12.3.1", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.3.1.tgz", - "integrity": "sha512-JWEaMyvNrXuM3dyy9Pp5cFPuSSvG82+yABqsWugjWlvfmnlnx9HOQZY23bFq3cNghy5V/t0iPb6cffzRWylgsA==", + "version": "12.3.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.3.4.tgz", + "integrity": "sha512-4csPbRbfZbuWOk3ATyWcvVFdD9/Rsdq5YHKvRuEni68OCLkfy4f+4I9OBpyK1SKJ00Cih16NJbHE+k+ljPPpag==", "cpu": [ "x64" ], @@ -1052,9 +3430,9 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "12.3.1", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.3.1.tgz", - "integrity": "sha512-xoEWQQ71waWc4BZcOjmatuvPUXKTv6MbIFzpm4LFeCHsg2iwai0ILmNXf81rJR+L1Wb9ifEke2sQpZSPNz1Iyg==", + "version": "12.3.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.3.4.tgz", + "integrity": "sha512-YeBmI+63Ro75SUiL/QXEVXQ19T++58aI/IINOyhpsRL1LKdyfK/35iilraZEFz9bLQrwy1LYAR5lK200A9Gjbg==", "cpu": [ "x64" ], @@ -1067,9 +3445,9 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "12.3.1", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.3.1.tgz", - "integrity": "sha512-hswVFYQYIeGHE2JYaBVtvqmBQ1CppplQbZJS/JgrVI3x2CurNhEkmds/yqvDONfwfbttTtH4+q9Dzf/WVl3Opw==", + "version": "12.3.4", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.3.4.tgz", + "integrity": "sha512-Sd0qFUJv8Tj0PukAYbCCDbmXcMkbIuhnTeHm9m4ZGjCf6kt7E/RMs55Pd3R5ePjOkN7dJEuxYBehawTR/aPDSQ==", "cpu": [ "arm64" ], @@ -1082,9 +3460,9 @@ } }, "node_modules/@next/swc-win32-ia32-msvc": { - "version": "12.3.1", - "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.3.1.tgz", - "integrity": "sha512-Kny5JBehkTbKPmqulr5i+iKntO5YMP+bVM8Hf8UAmjSMVo3wehyLVc9IZkNmcbxi+vwETnQvJaT5ynYBkJ9dWA==", + "version": "12.3.4", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.3.4.tgz", + "integrity": "sha512-rt/vv/vg/ZGGkrkKcuJ0LyliRdbskQU+91bje+PgoYmxTZf/tYs6IfbmgudBJk6gH3QnjHWbkphDdRQrseRefQ==", "cpu": [ "ia32" ], @@ -1097,9 +3475,9 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "12.3.1", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.3.1.tgz", - "integrity": "sha512-W1ijvzzg+kPEX6LAc+50EYYSEo0FVu7dmTE+t+DM4iOLqgGHoW9uYSz9wCVdkXOEEMP9xhXfGpcSxsfDucyPkA==", + "version": "12.3.4", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.3.4.tgz", + "integrity": "sha512-DQ20JEfTBZAgF8QCjYfJhv2/279M6onxFjdG/+5B0Cyj00/EdBxiWb2eGGFgQhrBbNv/lsvzFbbi0Ptf8Vw/bg==", "cpu": [ "x64" ], @@ -1166,6 +3544,693 @@ "url": "https://opencollective.com/unts" } }, + "node_modules/@pmmmwh/react-refresh-webpack-plugin": { + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.10.tgz", + "integrity": "sha512-j0Ya0hCFZPd4x40qLzbhGsh9TMtdb+CJQiso+WxLOPNasohq9cc5SNUcwsZaRH6++Xh91Xkm/xHCkuIiIu0LUA==", + "dev": true, + "dependencies": { + "ansi-html-community": "^0.0.8", + "common-path-prefix": "^3.0.0", + "core-js-pure": "^3.23.3", + "error-stack-parser": "^2.0.6", + "find-up": "^5.0.0", + "html-entities": "^2.1.0", + "loader-utils": "^2.0.4", + "schema-utils": "^3.0.0", + "source-map": "^0.7.3" + }, + "engines": { + "node": ">= 10.13" + }, + "peerDependencies": { + "@types/webpack": "4.x || 5.x", + "react-refresh": ">=0.10.0 <1.0.0", + "sockjs-client": "^1.4.0", + "type-fest": ">=0.17.0 <4.0.0", + "webpack": ">=4.43.0 <6.0.0", + "webpack-dev-server": "3.x || 4.x", + "webpack-hot-middleware": "2.x", + "webpack-plugin-serve": "0.x || 1.x" + }, + "peerDependenciesMeta": { + "@types/webpack": { + "optional": true + }, + "sockjs-client": { + "optional": true + }, + "type-fest": { + "optional": true + }, + "webpack-dev-server": { + "optional": true + }, + "webpack-hot-middleware": { + "optional": true + }, + "webpack-plugin-serve": { + "optional": true + } + } + }, + "node_modules/@pmmmwh/react-refresh-webpack-plugin/node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/@pmmmwh/react-refresh-webpack-plugin/node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@radix-ui/number": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.0.0.tgz", + "integrity": "sha512-Ofwh/1HX69ZfJRiRBMTy7rgjAzHmwe4kW9C9Y99HTRUcYLUuVT0KESFj15rPjRgKJs20GPq8Bm5aEDJ8DuA3vA==", + "dependencies": { + "@babel/runtime": "^7.13.10" + } + }, + "node_modules/@radix-ui/primitive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.0.0.tgz", + "integrity": "sha512-3e7rn8FDMin4CgeL7Z/49smCA3rFYY3Ha2rUQ7HRWFadS5iCRw08ZgVT1LaNTCNqgvrUiyczLflrVrF0SRQtNA==", + "dependencies": { + "@babel/runtime": "^7.13.10" + } + }, + "node_modules/@radix-ui/react-accordion": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-accordion/-/react-accordion-1.1.0.tgz", + "integrity": "sha512-CNN9ZBgCK4i4SX7gFk5s8095j55DUWi85vwRNfkfBLs0QdAG5Tb4ku6sBeugCAiLvsmxw481GyNl+C3stoJVBQ==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.0", + "@radix-ui/react-collapsible": "1.0.1", + "@radix-ui/react-collection": "1.0.1", + "@radix-ui/react-compose-refs": "1.0.0", + "@radix-ui/react-context": "1.0.0", + "@radix-ui/react-direction": "1.0.0", + "@radix-ui/react-id": "1.0.0", + "@radix-ui/react-primitive": "1.0.1", + "@radix-ui/react-use-controllable-state": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-alert-dialog": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-alert-dialog/-/react-alert-dialog-1.0.2.tgz", + "integrity": "sha512-0MtxV53FaEEBOKRgyLnEqHZKKDS5BldQ9oUBsKVXWI5FHbl2jp35qs+0aJET+K5hJDsc40kQUzP7g+wC7tqrqA==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.0", + "@radix-ui/react-compose-refs": "1.0.0", + "@radix-ui/react-context": "1.0.0", + "@radix-ui/react-dialog": "1.0.2", + "@radix-ui/react-primitive": "1.0.1", + "@radix-ui/react-slot": "1.0.1" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-arrow": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.0.1.tgz", + "integrity": "sha512-1yientwXqXcErDHEv8av9ZVNEBldH8L9scVR3is20lL+jOCfcJyMFZFEY5cgIrgexsq1qggSXqiEL/d/4f+QXA==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-primitive": "1.0.1" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-checkbox": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-checkbox/-/react-checkbox-1.0.1.tgz", + "integrity": "sha512-TisH0B8hWmYP3ONRduYCyN04rR9yLPIw/Rwyn1RoC1suSoGCa8Wn+YPdSSSarSszeIbcg3p2lBkDp2XXit4sZw==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.0", + "@radix-ui/react-compose-refs": "1.0.0", + "@radix-ui/react-context": "1.0.0", + "@radix-ui/react-presence": "1.0.0", + "@radix-ui/react-primitive": "1.0.1", + "@radix-ui/react-use-controllable-state": "1.0.0", + "@radix-ui/react-use-previous": "1.0.0", + "@radix-ui/react-use-size": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-collapsible": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.0.1.tgz", + "integrity": "sha512-0maX4q91iYa4gjt3PsNf7dq/yqSR+HGAE8I5p54dQ6gnveS+ETWlMoijxrhmgV1k8svxpm34mQAtqIrJt4XZmA==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.0", + "@radix-ui/react-compose-refs": "1.0.0", + "@radix-ui/react-context": "1.0.0", + "@radix-ui/react-id": "1.0.0", + "@radix-ui/react-presence": "1.0.0", + "@radix-ui/react-primitive": "1.0.1", + "@radix-ui/react-use-controllable-state": "1.0.0", + "@radix-ui/react-use-layout-effect": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-collection": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.0.1.tgz", + "integrity": "sha512-uuiFbs+YCKjn3X1DTSx9G7BHApu4GHbi3kgiwsnFUbOKCrwejAJv4eE4Vc8C0Oaxt9T0aV4ox0WCOdx+39Xo+g==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-compose-refs": "1.0.0", + "@radix-ui/react-context": "1.0.0", + "@radix-ui/react-primitive": "1.0.1", + "@radix-ui/react-slot": "1.0.1" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-compose-refs": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.0.0.tgz", + "integrity": "sha512-0KaSv6sx787/hK3eF53iOkiSLwAGlFMx5lotrqD2pTjB18KbybKoEIgkNZTKC60YECDQTKGTRcDBILwZVqVKvA==", + "dependencies": { + "@babel/runtime": "^7.13.10" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-context": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.0.0.tgz", + "integrity": "sha512-1pVM9RfOQ+n/N5PJK33kRSKsr1glNxomxONs5c49MliinBY6Yw2Q995qfBUUo0/Mbg05B/sGA0gkgPI7kmSHBg==", + "dependencies": { + "@babel/runtime": "^7.13.10" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-dialog": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.0.2.tgz", + "integrity": "sha512-EKxxp2WNSmUPkx4trtWNmZ4/vAYEg7JkAfa1HKBUnaubw9eHzf1Orr9B472lJYaYz327RHDrd4R95fsw7VR8DA==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.0", + "@radix-ui/react-compose-refs": "1.0.0", + "@radix-ui/react-context": "1.0.0", + "@radix-ui/react-dismissable-layer": "1.0.2", + "@radix-ui/react-focus-guards": "1.0.0", + "@radix-ui/react-focus-scope": "1.0.1", + "@radix-ui/react-id": "1.0.0", + "@radix-ui/react-portal": "1.0.1", + "@radix-ui/react-presence": "1.0.0", + "@radix-ui/react-primitive": "1.0.1", + "@radix-ui/react-slot": "1.0.1", + "@radix-ui/react-use-controllable-state": "1.0.0", + "aria-hidden": "^1.1.1", + "react-remove-scroll": "2.5.5" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-direction": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.0.0.tgz", + "integrity": "sha512-2HV05lGUgYcA6xgLQ4BKPDmtL+QbIZYH5fCOTAOOcJ5O0QbWS3i9lKaurLzliYUDhORI2Qr3pyjhJh44lKA3rQ==", + "dependencies": { + "@babel/runtime": "^7.13.10" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.0.2.tgz", + "integrity": "sha512-WjJzMrTWROozDqLB0uRWYvj4UuXsM/2L19EmQ3Au+IJWqwvwq9Bwd+P8ivo0Deg9JDPArR1I6MbWNi1CmXsskg==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.0", + "@radix-ui/react-compose-refs": "1.0.0", + "@radix-ui/react-primitive": "1.0.1", + "@radix-ui/react-use-callback-ref": "1.0.0", + "@radix-ui/react-use-escape-keydown": "1.0.2" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-dropdown-menu": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.0.2.tgz", + "integrity": "sha512-r0kN0fstrSi+uAdK2GkLxnnbhqVBy/9Q4o4PvGOYipW0BldQlYBMSmZprvCNj2i2mAATx16kvzIn12GnaGjbMw==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.0", + "@radix-ui/react-compose-refs": "1.0.0", + "@radix-ui/react-context": "1.0.0", + "@radix-ui/react-id": "1.0.0", + "@radix-ui/react-menu": "2.0.2", + "@radix-ui/react-primitive": "1.0.1", + "@radix-ui/react-use-controllable-state": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-focus-guards": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.0.0.tgz", + "integrity": "sha512-UagjDk4ijOAnGu4WMUPj9ahi7/zJJqNZ9ZAiGPp7waUWJO0O1aWXi/udPphI0IUjvrhBsZJGSN66dR2dsueLWQ==", + "dependencies": { + "@babel/runtime": "^7.13.10" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-focus-scope": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.0.1.tgz", + "integrity": "sha512-Ej2MQTit8IWJiS2uuujGUmxXjF/y5xZptIIQnyd2JHLwtV0R2j9NRVoRj/1j/gJ7e3REdaBw4Hjf4a1ImhkZcQ==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-compose-refs": "1.0.0", + "@radix-ui/react-primitive": "1.0.1", + "@radix-ui/react-use-callback-ref": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-id": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.0.0.tgz", + "integrity": "sha512-Q6iAB/U7Tq3NTolBBQbHTgclPmGWE3OlktGGqrClPozSw4vkQ1DfQAOtzgRPecKsMdJINE05iaoDUG8tRzCBjw==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-use-layout-effect": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-label": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.0.0.tgz", + "integrity": "sha512-7qCcZ3j2VQspWjy+gKR4W+V/z0XueQjeiZnlPOtsyiP9HaS8bfSU7ECoI3bvvdYntQj7NElW7OAYsYRW4MQvCg==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-primitive": "1.0.1" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-menu": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.0.2.tgz", + "integrity": "sha512-H5dtBi/k3tc45IMd2Pu+Q2PyONFlsYJ5sWUlflSs8BQRghh5GhJHLRuB1yb88VOywuzzvGkaR/HUJJ65Jf2POA==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.0", + "@radix-ui/react-collection": "1.0.1", + "@radix-ui/react-compose-refs": "1.0.0", + "@radix-ui/react-context": "1.0.0", + "@radix-ui/react-direction": "1.0.0", + "@radix-ui/react-dismissable-layer": "1.0.2", + "@radix-ui/react-focus-guards": "1.0.0", + "@radix-ui/react-focus-scope": "1.0.1", + "@radix-ui/react-id": "1.0.0", + "@radix-ui/react-popper": "1.1.0", + "@radix-ui/react-portal": "1.0.1", + "@radix-ui/react-presence": "1.0.0", + "@radix-ui/react-primitive": "1.0.1", + "@radix-ui/react-roving-focus": "1.0.2", + "@radix-ui/react-slot": "1.0.1", + "@radix-ui/react-use-callback-ref": "1.0.0", + "aria-hidden": "^1.1.1", + "react-remove-scroll": "2.5.5" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-popover": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.0.3.tgz", + "integrity": "sha512-YwedSukfWsyJs3/yP3yXUq44k4/JBe3jqU63Z8v2i19qZZ3dsx32oma17ztgclWPNuqp3A+Xa9UiDlZHyVX8Vg==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.0", + "@radix-ui/react-compose-refs": "1.0.0", + "@radix-ui/react-context": "1.0.0", + "@radix-ui/react-dismissable-layer": "1.0.2", + "@radix-ui/react-focus-guards": "1.0.0", + "@radix-ui/react-focus-scope": "1.0.1", + "@radix-ui/react-id": "1.0.0", + "@radix-ui/react-popper": "1.1.0", + "@radix-ui/react-portal": "1.0.1", + "@radix-ui/react-presence": "1.0.0", + "@radix-ui/react-primitive": "1.0.1", + "@radix-ui/react-slot": "1.0.1", + "@radix-ui/react-use-controllable-state": "1.0.0", + "aria-hidden": "^1.1.1", + "react-remove-scroll": "2.5.5" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-popper": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.1.0.tgz", + "integrity": "sha512-07U7jpI0dZcLRAxT7L9qs6HecSoPhDSJybF7mEGHJDBDv+ZoGCvIlva0s+WxMXwJEav+ckX3hAlXBtnHmuvlCQ==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@floating-ui/react-dom": "0.7.2", + "@radix-ui/react-arrow": "1.0.1", + "@radix-ui/react-compose-refs": "1.0.0", + "@radix-ui/react-context": "1.0.0", + "@radix-ui/react-primitive": "1.0.1", + "@radix-ui/react-use-callback-ref": "1.0.0", + "@radix-ui/react-use-layout-effect": "1.0.0", + "@radix-ui/react-use-rect": "1.0.0", + "@radix-ui/react-use-size": "1.0.0", + "@radix-ui/rect": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-portal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.0.1.tgz", + "integrity": "sha512-NY2vUWI5WENgAT1nfC6JS7RU5xRYBfjZVLq0HmgEN1Ezy3rk/UruMV4+Rd0F40PEaFC5SrLS1ixYvcYIQrb4Ig==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-primitive": "1.0.1" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-presence": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.0.0.tgz", + "integrity": "sha512-A+6XEvN01NfVWiKu38ybawfHsBjWum42MRPnEuqPsBZ4eV7e/7K321B5VgYMPv3Xx5An6o1/l9ZuDBgmcmWK3w==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-compose-refs": "1.0.0", + "@radix-ui/react-use-layout-effect": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-primitive": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-1.0.1.tgz", + "integrity": "sha512-fHbmislWVkZaIdeF6GZxF0A/NH/3BjrGIYj+Ae6eTmTCr7EB0RQAAVEiqsXK6p3/JcRqVSBQoceZroj30Jj3XA==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-slot": "1.0.1" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-progress": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-progress/-/react-progress-1.0.1.tgz", + "integrity": "sha512-QbDf9eguM5QtkvGcGHe/nUgloM9yfRGpJTB/Te5cn4WmVHvcbhHyHw39/rbCZxNX4E+GEPp5Vs6+mEoyIotUbg==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-context": "1.0.0", + "@radix-ui/react-primitive": "1.0.1" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-roving-focus": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.0.2.tgz", + "integrity": "sha512-HLK+CqD/8pN6GfJm3U+cqpqhSKYAWiOJDe+A+8MfxBnOue39QEeMa43csUn2CXCHQT0/mewh1LrrG4tfkM9DMA==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.0", + "@radix-ui/react-collection": "1.0.1", + "@radix-ui/react-compose-refs": "1.0.0", + "@radix-ui/react-context": "1.0.0", + "@radix-ui/react-direction": "1.0.0", + "@radix-ui/react-id": "1.0.0", + "@radix-ui/react-primitive": "1.0.1", + "@radix-ui/react-use-callback-ref": "1.0.0", + "@radix-ui/react-use-controllable-state": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-select": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-1.2.0.tgz", + "integrity": "sha512-MmXKsIBrG9GKxt8JKIn75LEPiX/zejBmj/Z36Hxtm9cdmCFzTo78QJ0Q3buLGzr0c3lzXdfgeKntmgCzaGxgkw==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/number": "1.0.0", + "@radix-ui/primitive": "1.0.0", + "@radix-ui/react-collection": "1.0.1", + "@radix-ui/react-compose-refs": "1.0.0", + "@radix-ui/react-context": "1.0.0", + "@radix-ui/react-direction": "1.0.0", + "@radix-ui/react-dismissable-layer": "1.0.2", + "@radix-ui/react-focus-guards": "1.0.0", + "@radix-ui/react-focus-scope": "1.0.1", + "@radix-ui/react-id": "1.0.0", + "@radix-ui/react-popper": "1.1.0", + "@radix-ui/react-portal": "1.0.1", + "@radix-ui/react-primitive": "1.0.1", + "@radix-ui/react-slot": "1.0.1", + "@radix-ui/react-use-callback-ref": "1.0.0", + "@radix-ui/react-use-controllable-state": "1.0.0", + "@radix-ui/react-use-layout-effect": "1.0.0", + "@radix-ui/react-use-previous": "1.0.0", + "@radix-ui/react-visually-hidden": "1.0.1", + "aria-hidden": "^1.1.1", + "react-remove-scroll": "2.5.5" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-slot": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.0.1.tgz", + "integrity": "sha512-avutXAFL1ehGvAXtPquu0YK5oz6ctS474iM3vNGQIkswrVhdrS52e3uoMQBzZhNRAIE0jBnUyXWNmSjGHhCFcw==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-compose-refs": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-switch": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-switch/-/react-switch-1.0.1.tgz", + "integrity": "sha512-tTxGluMtwrc5ffgAiOSMrYIx0r3vSTcgM4Vl8rqfpXcHt6ryB9B0OlFKUOiDpKASXlhvzfHf4Y0AYKJdpzjL8w==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.0", + "@radix-ui/react-compose-refs": "1.0.0", + "@radix-ui/react-context": "1.0.0", + "@radix-ui/react-primitive": "1.0.1", + "@radix-ui/react-use-controllable-state": "1.0.0", + "@radix-ui/react-use-previous": "1.0.0", + "@radix-ui/react-use-size": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-toast": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toast/-/react-toast-1.1.2.tgz", + "integrity": "sha512-Kpr4BBYoP0O5A1UeDBmao87UnCMNdAKGNioQH5JzEm6OYTUVGhuDRbOwoZxPwOZ6vsjJHeIpdUrwbiHEB65CCw==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.0", + "@radix-ui/react-collection": "1.0.1", + "@radix-ui/react-compose-refs": "1.0.0", + "@radix-ui/react-context": "1.0.0", + "@radix-ui/react-dismissable-layer": "1.0.2", + "@radix-ui/react-portal": "1.0.1", + "@radix-ui/react-presence": "1.0.0", + "@radix-ui/react-primitive": "1.0.1", + "@radix-ui/react-use-callback-ref": "1.0.0", + "@radix-ui/react-use-controllable-state": "1.0.0", + "@radix-ui/react-use-layout-effect": "1.0.0", + "@radix-ui/react-visually-hidden": "1.0.1" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.0.0.tgz", + "integrity": "sha512-GZtyzoHz95Rhs6S63D2t/eqvdFCm7I+yHMLVQheKM7nBD8mbZIt+ct1jz4536MDnaOGKIxynJ8eHTkVGVVkoTg==", + "dependencies": { + "@babel/runtime": "^7.13.10" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.0.0.tgz", + "integrity": "sha512-FohDoZvk3mEXh9AWAVyRTYR4Sq7/gavuofglmiXB2g1aKyboUD4YtgWxKj8O5n+Uak52gXQ4wKz5IFST4vtJHg==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-use-callback-ref": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-use-escape-keydown": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.0.2.tgz", + "integrity": "sha512-DXGim3x74WgUv+iMNCF+cAo8xUHHeqvjx8zs7trKf+FkQKPQXLk2sX7Gx1ysH7Q76xCpZuxIJE7HLPxRE+Q+GA==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-use-callback-ref": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.0.0.tgz", + "integrity": "sha512-6Tpkq+R6LOlmQb1R5NNETLG0B4YP0wc+klfXafpUCj6JGyaUc8il7/kUZ7m59rGbXGczE9Bs+iz2qloqsZBduQ==", + "dependencies": { + "@babel/runtime": "^7.13.10" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-use-previous": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.0.0.tgz", + "integrity": "sha512-RG2K8z/K7InnOKpq6YLDmT49HGjNmrK+fr82UCVKT2sW0GYfVnYp4wZWBooT/EYfQ5faA9uIjvsuMMhH61rheg==", + "dependencies": { + "@babel/runtime": "^7.13.10" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-use-rect": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.0.0.tgz", + "integrity": "sha512-TB7pID8NRMEHxb/qQJpvSt3hQU4sqNPM1VCTjTRjEOa7cEop/QMuq8S6fb/5Tsz64kqSvB9WnwsDHtjnrM9qew==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/rect": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-use-size": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.0.0.tgz", + "integrity": "sha512-imZ3aYcoYCKhhgNpkNDh/aTiU05qw9hX+HHI1QDBTyIlcFjgeFlKKySNGMwTp7nYFLQg/j0VA2FmCY4WPDDHMg==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-use-layout-effect": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-visually-hidden": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.0.1.tgz", + "integrity": "sha512-K1hJcCMfWfiYUibRqf3V8r5Drpyf7rh44jnrwAbdvI5iCCijilBBeyQv9SKidYNZIopMdCyR9FnIjkHxHN0FcQ==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-primitive": "1.0.1" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/rect": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.0.0.tgz", + "integrity": "sha512-d0O68AYy/9oeEy1DdC07bz1/ZXX+DqCskRd3i4JzLSTXwefzaepQrKjXC7aNM8lTHjFLDO0pDgaEiQ7jEk+HVg==", + "dependencies": { + "@babel/runtime": "^7.13.10" + } + }, "node_modules/@reduxjs/toolkit": { "version": "1.8.3", "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.8.3.tgz", @@ -1203,6 +4268,2344 @@ "node": ">=8" } }, + "node_modules/@sinclair/typebox": { + "version": "0.24.51", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", + "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==", + "dev": true + }, + "node_modules/@storybook/addon-actions": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/addon-actions/-/addon-actions-7.0.0-beta.30.tgz", + "integrity": "sha512-hk7e0B6kSPD/m5+pU6lKS3CzBBYf3n74m33cFjTRyhk8vO8x5QC5tni8nZdzmqREthoIOIf+1zHxYDO8SLE5zg==", + "dev": true, + "dependencies": { + "@storybook/client-logger": "7.0.0-beta.30", + "@storybook/components": "7.0.0-beta.30", + "@storybook/core-events": "7.0.0-beta.30", + "@storybook/global": "^5.0.0", + "@storybook/manager-api": "7.0.0-beta.30", + "@storybook/preview-api": "7.0.0-beta.30", + "@storybook/theming": "7.0.0-beta.30", + "@storybook/types": "7.0.0-beta.30", + "dequal": "^2.0.2", + "lodash": "^4.17.21", + "polished": "^4.2.2", + "prop-types": "^15.7.2", + "react-inspector": "^6.0.0", + "telejson": "^7.0.3", + "ts-dedent": "^2.0.0", + "uuid-browser": "^3.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/@storybook/addon-backgrounds": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/addon-backgrounds/-/addon-backgrounds-7.0.0-beta.30.tgz", + "integrity": "sha512-UDPWQEwreK1TXjBjAmZN40uu5+7hC5dobdZhZr+i/4W+xswFMgprT4PtvfcoVyFTdOjRIsIDd0doLurvB5c1ng==", + "dev": true, + "dependencies": { + "@storybook/client-logger": "7.0.0-beta.30", + "@storybook/components": "7.0.0-beta.30", + "@storybook/core-events": "7.0.0-beta.30", + "@storybook/global": "^5.0.0", + "@storybook/manager-api": "7.0.0-beta.30", + "@storybook/preview-api": "7.0.0-beta.30", + "@storybook/theming": "7.0.0-beta.30", + "@storybook/types": "7.0.0-beta.30", + "memoizerific": "^1.11.3", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/@storybook/addon-controls": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/addon-controls/-/addon-controls-7.0.0-beta.30.tgz", + "integrity": "sha512-5ybbmFH+gcrBRfJnRTdSgNbCYMJMHQY2QTNqukUHO0CjAPEZMpPCFkiQNdIBLslsju9+bunVo1S/MBfwH3Ku7Q==", + "dev": true, + "dependencies": { + "@storybook/blocks": "7.0.0-beta.30", + "@storybook/client-logger": "7.0.0-beta.30", + "@storybook/components": "7.0.0-beta.30", + "@storybook/core-common": "7.0.0-beta.30", + "@storybook/manager-api": "7.0.0-beta.30", + "@storybook/node-logger": "7.0.0-beta.30", + "@storybook/preview-api": "7.0.0-beta.30", + "@storybook/theming": "7.0.0-beta.30", + "@storybook/types": "7.0.0-beta.30", + "lodash": "^4.17.21", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/@storybook/addon-docs": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/addon-docs/-/addon-docs-7.0.0-beta.30.tgz", + "integrity": "sha512-++SN8wmtiKE+bKbhscO8656GPZOFIEv31a3qYgId3W8wg/9YmTKUmXrejjUi3SZmO3xKVZ0bskJUw16oBWddug==", + "dev": true, + "dependencies": { + "@babel/core": "^7.20.2", + "@babel/plugin-transform-react-jsx": "^7.19.0", + "@jest/transform": "^29.3.1", + "@mdx-js/react": "^2.1.5", + "@storybook/blocks": "7.0.0-beta.30", + "@storybook/client-logger": "7.0.0-beta.30", + "@storybook/components": "7.0.0-beta.30", + "@storybook/csf-plugin": "7.0.0-beta.30", + "@storybook/csf-tools": "7.0.0-beta.30", + "@storybook/global": "^5.0.0", + "@storybook/mdx2-csf": "next", + "@storybook/node-logger": "7.0.0-beta.30", + "@storybook/postinstall": "7.0.0-beta.30", + "@storybook/preview-api": "7.0.0-beta.30", + "@storybook/theming": "7.0.0-beta.30", + "@storybook/types": "7.0.0-beta.30", + "fs-extra": "^9.0.1", + "remark-external-links": "^8.0.0", + "remark-slug": "^6.0.0", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@storybook/addon-essentials": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/addon-essentials/-/addon-essentials-7.0.0-beta.30.tgz", + "integrity": "sha512-3X4WMrf4TCSN9iDrGAQlIM7bj8r+aov4O1Q/fM73n3B6puOG25uMzhT2V8MB4aJdGOXeYvvjAh5rMBdHxfQjPQ==", + "dev": true, + "dependencies": { + "@storybook/addon-actions": "7.0.0-beta.30", + "@storybook/addon-backgrounds": "7.0.0-beta.30", + "@storybook/addon-controls": "7.0.0-beta.30", + "@storybook/addon-docs": "7.0.0-beta.30", + "@storybook/addon-highlight": "7.0.0-beta.30", + "@storybook/addon-measure": "7.0.0-beta.30", + "@storybook/addon-outline": "7.0.0-beta.30", + "@storybook/addon-toolbars": "7.0.0-beta.30", + "@storybook/addon-viewport": "7.0.0-beta.30", + "@storybook/core-common": "7.0.0-beta.30", + "@storybook/manager-api": "7.0.0-beta.30", + "@storybook/node-logger": "7.0.0-beta.30", + "@storybook/preview-api": "7.0.0-beta.30", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@storybook/addon-highlight": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/addon-highlight/-/addon-highlight-7.0.0-beta.30.tgz", + "integrity": "sha512-wyOl7mHGBB6u9I4uqn8PMlAGbZEfa0LeeDLqzzxZWzGFrFUVqjthQ+BAIbb8C+wOs9eb0CTGEecJQhurbV+UuA==", + "dev": true, + "dependencies": { + "@storybook/core-events": "7.0.0-beta.30", + "@storybook/global": "^5.0.0", + "@storybook/preview-api": "7.0.0-beta.30" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/addon-interactions": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/addon-interactions/-/addon-interactions-7.0.0-beta.30.tgz", + "integrity": "sha512-mulmrEmDr9vynVVjmJ0OLiHd8NhGvrnTSrN6eMYLKp/VpOEOV0KgE28z+lqkeuAgRdcFG65ddV9AE8h1+rYxyg==", + "dev": true, + "dependencies": { + "@storybook/client-logger": "7.0.0-beta.30", + "@storybook/components": "7.0.0-beta.30", + "@storybook/core-common": "7.0.0-beta.30", + "@storybook/core-events": "7.0.0-beta.30", + "@storybook/global": "^5.0.0", + "@storybook/instrumenter": "7.0.0-beta.30", + "@storybook/manager-api": "7.0.0-beta.30", + "@storybook/preview-api": "7.0.0-beta.30", + "@storybook/theming": "7.0.0-beta.30", + "@storybook/types": "7.0.0-beta.30", + "jest-mock": "^27.0.6", + "polished": "^4.2.2", + "ts-dedent": "^2.2.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/@storybook/addon-links": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/addon-links/-/addon-links-7.0.0-beta.30.tgz", + "integrity": "sha512-Uyj/WwUOGOTmDvYygM24vP0Zfj28ebYxtd07CYAlhvJ6P7yOb6H9v2cM/a2cJc1h7VmH9eohPNuTFDbv1P+QMQ==", + "dev": true, + "dependencies": { + "@storybook/client-logger": "7.0.0-beta.30", + "@storybook/core-events": "7.0.0-beta.30", + "@storybook/csf": "next", + "@storybook/global": "^5.0.0", + "@storybook/manager-api": "7.0.0-beta.30", + "@storybook/preview-api": "7.0.0-beta.30", + "@storybook/router": "7.0.0-beta.30", + "@storybook/types": "7.0.0-beta.30", + "prop-types": "^15.7.2", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/@storybook/addon-measure": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/addon-measure/-/addon-measure-7.0.0-beta.30.tgz", + "integrity": "sha512-tlY+CcZleoxMV5F50LLY/GFcWU8X5g9Td5K/pYqVw25jZFeqBZCZs+k0eqct1HeWKY64uutAYmljzrrwgpsUmw==", + "dev": true, + "dependencies": { + "@storybook/client-logger": "7.0.0-beta.30", + "@storybook/components": "7.0.0-beta.30", + "@storybook/core-events": "7.0.0-beta.30", + "@storybook/global": "^5.0.0", + "@storybook/manager-api": "7.0.0-beta.30", + "@storybook/preview-api": "7.0.0-beta.30", + "@storybook/types": "7.0.0-beta.30" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/@storybook/addon-outline": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/addon-outline/-/addon-outline-7.0.0-beta.30.tgz", + "integrity": "sha512-qvJh05sc40NfF9RZ5KCVRHh3hRb0XCdxXP95qg7P0QF/BCRIrLTP8/94rT56IwhaMKDTttoU1x2PST0FDxQZaQ==", + "dev": true, + "dependencies": { + "@storybook/client-logger": "7.0.0-beta.30", + "@storybook/components": "7.0.0-beta.30", + "@storybook/core-events": "7.0.0-beta.30", + "@storybook/global": "^5.0.0", + "@storybook/manager-api": "7.0.0-beta.30", + "@storybook/preview-api": "7.0.0-beta.30", + "@storybook/types": "7.0.0-beta.30", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/@storybook/addon-postcss": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@storybook/addon-postcss/-/addon-postcss-2.0.0.tgz", + "integrity": "sha512-Nt82A7e9zJH4+A+VzLKKswUfru+T6FJTakj4dccP0i8DSn7a0CkzRPrLuZBq8tg4voV6gD74bcDf3gViCVBGtA==", + "dev": true, + "dependencies": { + "@storybook/node-logger": "^6.1.14", + "css-loader": "^3.6.0", + "postcss": "^7.0.35", + "postcss-loader": "^4.2.0", + "style-loader": "^1.3.0" + }, + "engines": { + "node": ">=10", + "yarn": "^1.17.0" + } + }, + "node_modules/@storybook/addon-postcss/node_modules/@storybook/node-logger": { + "version": "6.5.15", + "resolved": "https://registry.npmjs.org/@storybook/node-logger/-/node-logger-6.5.15.tgz", + "integrity": "sha512-LQjjbfMuUXm7wZTBKb+iGeCNnej4r1Jb2NxG3Svu2bVhaoB6u33jHAcbmhXpXW1jghzW3kQwOU7BoLuJiRRFIw==", + "dev": true, + "dependencies": { + "@types/npmlog": "^4.1.2", + "chalk": "^4.1.0", + "core-js": "^3.8.2", + "npmlog": "^5.0.1", + "pretty-hrtime": "^1.0.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/addon-postcss/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@storybook/addon-postcss/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@storybook/addon-postcss/node_modules/css-loader": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-3.6.0.tgz", + "integrity": "sha512-M5lSukoWi1If8dhQAUCvj4H8vUt3vOnwbQBH9DdTm/s4Ym2B/3dPMtYZeJmq7Q3S3Pa+I94DcZ7pc9bP14cWIQ==", + "dev": true, + "dependencies": { + "camelcase": "^5.3.1", + "cssesc": "^3.0.0", + "icss-utils": "^4.1.1", + "loader-utils": "^1.2.3", + "normalize-path": "^3.0.0", + "postcss": "^7.0.32", + "postcss-modules-extract-imports": "^2.0.0", + "postcss-modules-local-by-default": "^3.0.2", + "postcss-modules-scope": "^2.2.0", + "postcss-modules-values": "^3.0.0", + "postcss-value-parser": "^4.1.0", + "schema-utils": "^2.7.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/@storybook/addon-postcss/node_modules/css-loader/node_modules/schema-utils": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", + "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.5", + "ajv": "^6.12.4", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/@storybook/addon-postcss/node_modules/css-loader/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@storybook/addon-postcss/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@storybook/addon-postcss/node_modules/icss-utils": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-4.1.1.tgz", + "integrity": "sha512-4aFq7wvWyMHKgxsH8QQtGpvbASCf+eM3wPRLI6R+MgAnTCZ6STYsRvttLvRWK0Nfif5piF394St3HeJDaljGPA==", + "dev": true, + "dependencies": { + "postcss": "^7.0.14" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@storybook/addon-postcss/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/@storybook/addon-postcss/node_modules/loader-utils": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz", + "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/@storybook/addon-postcss/node_modules/picocolors": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", + "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", + "dev": true + }, + "node_modules/@storybook/addon-postcss/node_modules/postcss": { + "version": "7.0.39", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", + "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", + "dev": true, + "dependencies": { + "picocolors": "^0.2.1", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/@storybook/addon-postcss/node_modules/postcss-loader": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-4.3.0.tgz", + "integrity": "sha512-M/dSoIiNDOo8Rk0mUqoj4kpGq91gcxCfb9PoyZVdZ76/AuhxylHDYZblNE8o+EQ9AMSASeMFEKxZf5aU6wlx1Q==", + "dev": true, + "dependencies": { + "cosmiconfig": "^7.0.0", + "klona": "^2.0.4", + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0", + "semver": "^7.3.4" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "postcss": "^7.0.0 || ^8.0.1", + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/@storybook/addon-postcss/node_modules/postcss-loader/node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@storybook/addon-postcss/node_modules/postcss-loader/node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/@storybook/addon-postcss/node_modules/postcss-modules-extract-imports": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-2.0.0.tgz", + "integrity": "sha512-LaYLDNS4SG8Q5WAWqIJgdHPJrDDr/Lv775rMBFUbgjTz6j34lUznACHcdRWroPvXANP2Vj7yNK57vp9eFqzLWQ==", + "dev": true, + "dependencies": { + "postcss": "^7.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@storybook/addon-postcss/node_modules/postcss-modules-local-by-default": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-3.0.3.tgz", + "integrity": "sha512-e3xDq+LotiGesympRlKNgaJ0PCzoUIdpH0dj47iWAui/kyTgh3CiAr1qP54uodmJhl6p9rN6BoNcdEDVJx9RDw==", + "dev": true, + "dependencies": { + "icss-utils": "^4.1.1", + "postcss": "^7.0.32", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@storybook/addon-postcss/node_modules/postcss-modules-scope": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-2.2.0.tgz", + "integrity": "sha512-YyEgsTMRpNd+HmyC7H/mh3y+MeFWevy7V1evVhJWewmMbjDHIbZbOXICC2y+m1xI1UVfIT1HMW/O04Hxyu9oXQ==", + "dev": true, + "dependencies": { + "postcss": "^7.0.6", + "postcss-selector-parser": "^6.0.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@storybook/addon-postcss/node_modules/postcss-modules-values": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-3.0.0.tgz", + "integrity": "sha512-1//E5jCBrZ9DmRX+zCtmQtRSV6PV42Ix7Bzj9GbwJceduuf7IqP8MgeTXuRDHOWj2m0VzZD5+roFWDuU8RQjcg==", + "dev": true, + "dependencies": { + "icss-utils": "^4.0.0", + "postcss": "^7.0.6" + } + }, + "node_modules/@storybook/addon-postcss/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@storybook/addon-postcss/node_modules/style-loader": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-1.3.0.tgz", + "integrity": "sha512-V7TCORko8rs9rIqkSrlMfkqA63DfoGBBJmK1kKGCcSi+BWb4cqz0SRsnp4l6rU5iwOEd0/2ePv68SV22VXon4Q==", + "dev": true, + "dependencies": { + "loader-utils": "^2.0.0", + "schema-utils": "^2.7.0" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/@storybook/addon-postcss/node_modules/style-loader/node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@storybook/addon-postcss/node_modules/style-loader/node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/@storybook/addon-postcss/node_modules/style-loader/node_modules/schema-utils": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", + "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.5", + "ajv": "^6.12.4", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/@storybook/addon-postcss/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@storybook/addon-toolbars": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/addon-toolbars/-/addon-toolbars-7.0.0-beta.30.tgz", + "integrity": "sha512-b+aOu6lT9OR8WhqXDJwzV/u3DFvB3/Cl31UD1W6BrnqkoMJ7WbZy74stsNx0Kb2g6WqGzqHuErRtS2YMpCMUZA==", + "dev": true, + "dependencies": { + "@storybook/client-logger": "7.0.0-beta.30", + "@storybook/components": "7.0.0-beta.30", + "@storybook/manager-api": "7.0.0-beta.30", + "@storybook/preview-api": "7.0.0-beta.30", + "@storybook/theming": "7.0.0-beta.30" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/@storybook/addon-viewport": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/addon-viewport/-/addon-viewport-7.0.0-beta.30.tgz", + "integrity": "sha512-ugk44rt07zyj4kUNt8aNHGxMFbrqjygGk+MznASrOd4F4G4LzM09O+a/YqGGKSJQlb90gadW7Xj1iy4HP28NtA==", + "dev": true, + "dependencies": { + "@storybook/client-logger": "7.0.0-beta.30", + "@storybook/components": "7.0.0-beta.30", + "@storybook/core-events": "7.0.0-beta.30", + "@storybook/global": "^5.0.0", + "@storybook/manager-api": "7.0.0-beta.30", + "@storybook/preview-api": "7.0.0-beta.30", + "@storybook/theming": "7.0.0-beta.30", + "memoizerific": "^1.11.3", + "prop-types": "^15.7.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/@storybook/addons": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/addons/-/addons-7.0.0-beta.30.tgz", + "integrity": "sha512-J0/tiaEPXNVbjUAgSNuLirfRfhUwQ5PC4LvNLYO//OKpRn/pvsh5jlFWKVoXG5Km711atS6P7aOt7vTTAH8Akg==", + "dev": true, + "dependencies": { + "@storybook/manager-api": "7.0.0-beta.30", + "@storybook/preview-api": "7.0.0-beta.30", + "@storybook/types": "7.0.0-beta.30" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@storybook/api": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/api/-/api-7.0.0-beta.30.tgz", + "integrity": "sha512-D7ggwRM6yDrHBDI8IXoRA6XVWrrqNL0E1m+M2uBK9RoKfgVJr9TMapFl3u46LTIC76EsFigJCFdNnlPmnIwlhQ==", + "dev": true, + "dependencies": { + "@storybook/client-logger": "7.0.0-beta.30", + "@storybook/manager-api": "7.0.0-beta.30" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/blocks": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/blocks/-/blocks-7.0.0-beta.30.tgz", + "integrity": "sha512-kwH9Xlr8GeGvJPjbuvlC4aGkZq/1Xz5S5Cnapfs3vnDSD76/30XvFj+QUV+clf3aPAbbKI1QJIXy2lCzUME46w==", + "dev": true, + "dependencies": { + "@storybook/channels": "7.0.0-beta.30", + "@storybook/client-logger": "7.0.0-beta.30", + "@storybook/components": "7.0.0-beta.30", + "@storybook/core-events": "7.0.0-beta.30", + "@storybook/csf": "next", + "@storybook/docs-tools": "7.0.0-beta.30", + "@storybook/global": "^5.0.0", + "@storybook/manager-api": "7.0.0-beta.30", + "@storybook/preview-api": "7.0.0-beta.30", + "@storybook/theming": "7.0.0-beta.30", + "@storybook/types": "7.0.0-beta.30", + "@types/lodash": "^4.14.167", + "color-convert": "^2.0.1", + "dequal": "^2.0.2", + "lodash": "^4.17.21", + "markdown-to-jsx": "^7.1.3", + "memoizerific": "^1.11.3", + "polished": "^4.2.2", + "react-colorful": "^5.1.2", + "ts-dedent": "^2.0.0", + "util-deprecate": "^1.0.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@storybook/builder-manager": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/builder-manager/-/builder-manager-7.0.0-beta.30.tgz", + "integrity": "sha512-hBiF7LE4Ojsgh7E9LRPgwHATQuV/izY8F/tFKCbWO3g5yzElEHcspEDJmbxh9HnAhNcYFvshCwFBBC1CTc8sTQ==", + "dev": true, + "dependencies": { + "@fal-works/esbuild-plugin-global-externals": "^2.1.2", + "@storybook/core-common": "7.0.0-beta.30", + "@storybook/manager": "7.0.0-beta.30", + "@storybook/node-logger": "7.0.0-beta.30", + "@types/ejs": "^3.1.1", + "@types/find-cache-dir": "^3.2.1", + "@yarnpkg/esbuild-plugin-pnp": "^3.0.0-rc.10", + "browser-assert": "^1.2.1", + "ejs": "^3.1.8", + "esbuild": "^0.16.4", + "esbuild-plugin-alias": "^0.2.1", + "express": "^4.17.3", + "find-cache-dir": "^3.0.0", + "fs-extra": "^9.0.1", + "process": "^0.11.10", + "slash": "^3.0.0", + "util": "^0.12.4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/builder-webpack5": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/builder-webpack5/-/builder-webpack5-7.0.0-beta.30.tgz", + "integrity": "sha512-7SS+F9tyIL9N2iUNapCFy0aSxrXRI2byXuKM/xCXgYnMq04z3MbPuG6ymaYUoRZQ2zMYoHkMA8iaLthHsIoRAQ==", + "dev": true, + "dependencies": { + "@babel/core": "^7.12.10", + "@storybook/addons": "7.0.0-beta.30", + "@storybook/api": "7.0.0-beta.30", + "@storybook/channel-postmessage": "7.0.0-beta.30", + "@storybook/channel-websocket": "7.0.0-beta.30", + "@storybook/channels": "7.0.0-beta.30", + "@storybook/client-api": "7.0.0-beta.30", + "@storybook/client-logger": "7.0.0-beta.30", + "@storybook/components": "7.0.0-beta.30", + "@storybook/core-common": "7.0.0-beta.30", + "@storybook/core-events": "7.0.0-beta.30", + "@storybook/core-webpack": "7.0.0-beta.30", + "@storybook/global": "^5.0.0", + "@storybook/manager-api": "7.0.0-beta.30", + "@storybook/node-logger": "7.0.0-beta.30", + "@storybook/preview": "7.0.0-beta.30", + "@storybook/preview-api": "7.0.0-beta.30", + "@storybook/router": "7.0.0-beta.30", + "@storybook/store": "7.0.0-beta.30", + "@storybook/theming": "7.0.0-beta.30", + "@types/node": "^16.0.0", + "@types/semver": "^7.3.4", + "babel-loader": "^9.0.0", + "babel-plugin-named-exports-order": "^0.0.2", + "browser-assert": "^1.2.1", + "case-sensitive-paths-webpack-plugin": "^2.4.0", + "css-loader": "^6.7.1", + "express": "^4.17.3", + "fork-ts-checker-webpack-plugin": "^7.2.8", + "fs-extra": "^9.0.1", + "html-webpack-plugin": "^5.5.0", + "path-browserify": "^1.0.1", + "process": "^0.11.10", + "semver": "^7.3.7", + "slash": "^3.0.0", + "style-loader": "^3.3.1", + "terser-webpack-plugin": "^5.3.1", + "ts-dedent": "^2.0.0", + "util": "^0.12.4", + "util-deprecate": "^1.0.2", + "webpack": "5", + "webpack-dev-middleware": "^5.3.1", + "webpack-hot-middleware": "^2.25.1", + "webpack-virtual-modules": "^0.4.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/@types/node": { + "version": "16.18.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.11.tgz", + "integrity": "sha512-3oJbGBUWuS6ahSnEq1eN2XrCyf4YsWI8OyCvo7c64zQJNplk3mO84t53o8lfTk+2ji59g5ycfc6qQ3fdHliHuA==", + "dev": true + }, + "node_modules/@storybook/channel-postmessage": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/channel-postmessage/-/channel-postmessage-7.0.0-beta.30.tgz", + "integrity": "sha512-szCRSlMZr0ii/j+kIHKim1kCpmVblhvLl8vW25sbUkW0lSJ7F0VQ1mQSNjXDWhZHEMb9/1ZYCbN7HOsXp9oCRg==", + "dev": true, + "dependencies": { + "@storybook/channels": "7.0.0-beta.30", + "@storybook/client-logger": "7.0.0-beta.30", + "@storybook/core-events": "7.0.0-beta.30", + "@storybook/global": "^5.0.0", + "qs": "^6.10.0", + "telejson": "^7.0.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/channel-websocket": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/channel-websocket/-/channel-websocket-7.0.0-beta.30.tgz", + "integrity": "sha512-Q+bShSf8ueKw5H3vN76lgAqzl+bG7rqjQhgG7ALYUPDgNGFf+7dFoe2/g5byjhZAZGomObhmIRjpPkCmUzx4Uw==", + "dev": true, + "dependencies": { + "@storybook/channels": "7.0.0-beta.30", + "@storybook/client-logger": "7.0.0-beta.30", + "@storybook/global": "^5.0.0", + "telejson": "^7.0.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/channels": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/channels/-/channels-7.0.0-beta.30.tgz", + "integrity": "sha512-XIlFxLKy0MGpWIGondLHf92Aku57SpIxZXmjLbM2iAeG0UljzdL+d8BoMp5Yo0CVMmMBGGZEoM7INrhf6p2WKw==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/cli": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/cli/-/cli-7.0.0-beta.30.tgz", + "integrity": "sha512-nwgHQysnL67VZ/fP99BR16E9WRH634pg2hbRqzC1DCzEWAfAcnlZPbnOUmbVhpL6MdJw6i5nyVdk4ugUcFI8pA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.20.2", + "@babel/preset-env": "^7.20.2", + "@storybook/codemod": "7.0.0-beta.30", + "@storybook/core-common": "7.0.0-beta.30", + "@storybook/core-server": "7.0.0-beta.30", + "@storybook/csf-tools": "7.0.0-beta.30", + "@storybook/node-logger": "7.0.0-beta.30", + "@storybook/telemetry": "7.0.0-beta.30", + "@storybook/types": "7.0.0-beta.30", + "@types/semver": "^7.3.4", + "boxen": "^5.1.2", + "chalk": "^4.1.0", + "commander": "^6.2.1", + "cross-spawn": "^7.0.3", + "detect-indent": "^6.1.0", + "envinfo": "^7.7.3", + "execa": "^5.0.0", + "express": "^4.17.3", + "find-up": "^5.0.0", + "fs-extra": "^9.0.1", + "get-port": "^5.1.1", + "giget": "^1.0.0", + "globby": "^11.0.2", + "jscodeshift": "^0.13.1", + "leven": "^3.1.0", + "prompts": "^2.4.0", + "puppeteer-core": "^2.1.1", + "read-pkg-up": "^7.0.1", + "semver": "^7.3.7", + "shelljs": "^0.8.5", + "simple-update-notifier": "^1.0.0", + "strip-json-comments": "^3.0.1", + "tempy": "^1.0.1", + "ts-dedent": "^2.0.0", + "util-deprecate": "^1.0.2" + }, + "bin": { + "getstorybook": "bin/index.js", + "sb": "bin/index.js" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/cli/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@storybook/cli/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@storybook/cli/node_modules/commander": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", + "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@storybook/cli/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@storybook/cli/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@storybook/client-api": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/client-api/-/client-api-7.0.0-beta.30.tgz", + "integrity": "sha512-FPRmBmRRzsA9ZNXBwoOVEMze8dp/U1DxA0OKw9y24v/ijgg+P6GAqpX3WFrx3eQWn3I3oMg/8kJwANvOv38ZDw==", + "dev": true, + "dependencies": { + "@storybook/client-logger": "7.0.0-beta.30", + "@storybook/preview-api": "7.0.0-beta.30" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/client-logger": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/client-logger/-/client-logger-7.0.0-beta.30.tgz", + "integrity": "sha512-50JKxy0E2jUfGcfHwBp+NnlVLqaELSTjB5CjxckUExLfsU/u3dzTPrMmxevBw3ojqaCtyGKZE0yY0ndn/QbeuA==", + "dev": true, + "dependencies": { + "@storybook/global": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/codemod": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/codemod/-/codemod-7.0.0-beta.30.tgz", + "integrity": "sha512-kJmzhLVavUB5wTkL1RfnZZml6uSMtwTExMAAoMl1q8ie1KVIXEjO7vrQYz8xRFsQJ/y36TeJWY8w45kjBie0Aw==", + "dev": true, + "dependencies": { + "@babel/core": "^7.20.2", + "@babel/preset-env": "^7.20.2", + "@babel/types": "^7.20.7", + "@storybook/csf": "next", + "@storybook/csf-tools": "7.0.0-beta.30", + "@storybook/node-logger": "7.0.0-beta.30", + "@storybook/types": "7.0.0-beta.30", + "cross-spawn": "^7.0.3", + "globby": "^11.0.2", + "jscodeshift": "^0.13.1", + "lodash": "^4.17.21", + "prettier": "^2.8.0", + "recast": "^0.23.1", + "util": "^0.12.4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/components": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/components/-/components-7.0.0-beta.30.tgz", + "integrity": "sha512-CrGZY97t0lcjM/kevTVUYrZ35Civnpyyn4Q5uPbHv9cilmSGxbGg3r1yH8s6+FfbSobb77ZiCCbZXCWrSCiwnQ==", + "dev": true, + "dependencies": { + "@storybook/client-logger": "7.0.0-beta.30", + "@storybook/csf": "next", + "@storybook/global": "^5.0.0", + "@storybook/theming": "7.0.0-beta.30", + "@storybook/types": "7.0.0-beta.30", + "memoizerific": "^1.11.3", + "util-deprecate": "^1.0.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@storybook/core-client": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/core-client/-/core-client-7.0.0-beta.30.tgz", + "integrity": "sha512-4F2TMNjV8YpEJoCUGa9yfD+3zv60/pG1xjt6NP5uoMKsvqjfDOXCXXQGcUd6lnidGu/xoYvhR8r0KsRmsIzRYQ==", + "dev": true, + "dependencies": { + "@storybook/client-logger": "7.0.0-beta.30", + "@storybook/preview-api": "7.0.0-beta.30" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/core-common": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/core-common/-/core-common-7.0.0-beta.30.tgz", + "integrity": "sha512-46U4cHOgKQBxFBZO19lx0eR7F/fJgzBr4Nhx4Ws6vhdW5492aa8NPjHM+59jXOMpU8ZM3zHvhObaL/VMwnTJWg==", + "dev": true, + "dependencies": { + "@babel/core": "^7.20.2", + "@storybook/node-logger": "7.0.0-beta.30", + "@storybook/types": "7.0.0-beta.30", + "@types/babel__core": "^7.1.20", + "@types/express": "^4.7.0", + "@types/node": "^16.0.0", + "@types/pretty-hrtime": "^1.0.0", + "chalk": "^4.1.0", + "esbuild": "^0.16.4", + "esbuild-register": "^3.3.3", + "express": "^4.17.3", + "file-system-cache": "^2.0.0", + "find-up": "^5.0.0", + "fs-extra": "^9.0.1", + "glob": "^7.1.6", + "handlebars": "^4.7.7", + "lazy-universal-dotenv": "^3.0.1", + "picomatch": "^2.3.0", + "pkg-dir": "^5.0.0", + "pretty-hrtime": "^1.0.3", + "resolve-from": "^5.0.0", + "slash": "^3.0.0", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/core-common/node_modules/@types/node": { + "version": "16.18.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.11.tgz", + "integrity": "sha512-3oJbGBUWuS6ahSnEq1eN2XrCyf4YsWI8OyCvo7c64zQJNplk3mO84t53o8lfTk+2ji59g5ycfc6qQ3fdHliHuA==", + "dev": true + }, + "node_modules/@storybook/core-common/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@storybook/core-common/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@storybook/core-common/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@storybook/core-common/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@storybook/core-common/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@storybook/core-events": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/core-events/-/core-events-7.0.0-beta.30.tgz", + "integrity": "sha512-Q+psogB1KJFU6m+Zz4QqJBDVsTsR9vceVaUDceGogGbZEjBXpIAKwAJzVVi62pJKeFHclcCI4JbquYoOu2vK9w==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/core-server": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/core-server/-/core-server-7.0.0-beta.30.tgz", + "integrity": "sha512-GfOg7P53OMR/Qa/DAz9IdRpu0sUJlZdrKv53otu4TnI8OxW+Wcom6Ef16aiwaONivQG78zKPzB5w+0+1f2N5uw==", + "dev": true, + "dependencies": { + "@aw-web-design/x-default-browser": "1.4.88", + "@discoveryjs/json-ext": "^0.5.3", + "@storybook/builder-manager": "7.0.0-beta.30", + "@storybook/core-common": "7.0.0-beta.30", + "@storybook/core-events": "7.0.0-beta.30", + "@storybook/csf": "next", + "@storybook/csf-tools": "7.0.0-beta.30", + "@storybook/docs-mdx": "next", + "@storybook/global": "^5.0.0", + "@storybook/node-logger": "7.0.0-beta.30", + "@storybook/preview-api": "7.0.0-beta.30", + "@storybook/telemetry": "7.0.0-beta.30", + "@storybook/types": "7.0.0-beta.30", + "@types/detect-port": "^1.3.0", + "@types/node": "^16.0.0", + "@types/node-fetch": "^2.5.7", + "@types/pretty-hrtime": "^1.0.0", + "@types/semver": "^7.3.4", + "better-opn": "^2.1.1", + "boxen": "^5.1.2", + "chalk": "^4.1.0", + "cli-table3": "^0.6.1", + "compression": "^1.7.4", + "detect-port": "^1.3.0", + "express": "^4.17.3", + "fs-extra": "^9.0.1", + "globby": "^11.0.2", + "ip": "^2.0.0", + "lodash": "^4.17.21", + "node-fetch": "^2.6.7", + "open": "^8.4.0", + "pretty-hrtime": "^1.0.3", + "prompts": "^2.4.0", + "read-pkg-up": "^7.0.1", + "semver": "^7.3.7", + "serve-favicon": "^2.5.0", + "slash": "^3.0.0", + "telejson": "^7.0.3", + "ts-dedent": "^2.0.0", + "util-deprecate": "^1.0.2", + "watchpack": "^2.2.0", + "ws": "^8.2.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/core-server/node_modules/@types/node": { + "version": "16.18.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.11.tgz", + "integrity": "sha512-3oJbGBUWuS6ahSnEq1eN2XrCyf4YsWI8OyCvo7c64zQJNplk3mO84t53o8lfTk+2ji59g5ycfc6qQ3fdHliHuA==", + "dev": true + }, + "node_modules/@storybook/core-server/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@storybook/core-server/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@storybook/core-server/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@storybook/core-server/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@storybook/core-webpack": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/core-webpack/-/core-webpack-7.0.0-beta.30.tgz", + "integrity": "sha512-zVlXka9WlJovzNmtAnuGMPBnQBvOdP2Qi62TXdqRh1ctrCX4obRtleyDJVnzdev9awn6Z+Rfbe/zqOvwISr2vw==", + "dev": true, + "dependencies": { + "@storybook/core-common": "7.0.0-beta.30", + "@storybook/node-logger": "7.0.0-beta.30", + "@storybook/types": "7.0.0-beta.30", + "@types/node": "^16.0.0", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/core-webpack/node_modules/@types/node": { + "version": "16.18.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.11.tgz", + "integrity": "sha512-3oJbGBUWuS6ahSnEq1eN2XrCyf4YsWI8OyCvo7c64zQJNplk3mO84t53o8lfTk+2ji59g5ycfc6qQ3fdHliHuA==", + "dev": true + }, + "node_modules/@storybook/csf": { + "version": "0.0.2-next.8", + "resolved": "https://registry.npmjs.org/@storybook/csf/-/csf-0.0.2-next.8.tgz", + "integrity": "sha512-3T6rflW7D9q1iXOR+bidwoNbd9rVUTyjYH/sqsnYjbXhb/aOXsQzGKwNeq9QqZIFVpKfg5BoOF5i7DCMtoGknQ==", + "dev": true, + "dependencies": { + "expect-type": "^0.14.2", + "lodash": "^4.17.15", + "type-fest": "^2.19.0" + } + }, + "node_modules/@storybook/csf-plugin": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/csf-plugin/-/csf-plugin-7.0.0-beta.30.tgz", + "integrity": "sha512-ny8NCrdJWjSxraCWAGdMjXP1EtHygABCjv6Qcv9OijBexmzET04YwY7HmQlW6B9tq2l86TlFLPyICVtv8wniyA==", + "dev": true, + "dependencies": { + "@storybook/csf-tools": "7.0.0-beta.30", + "unplugin": "^0.10.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/csf-tools": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/csf-tools/-/csf-tools-7.0.0-beta.30.tgz", + "integrity": "sha512-/CCizDLZSqm3lNO0w+oc1Xqid4/Ix7TikKZxxaOpGipXp4Ehw8iRMjnfHbE+ANq8ZtTdQzOXBxG4LG2noUpHBw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.20.2", + "@storybook/csf": "next", + "@storybook/types": "7.0.0-beta.30", + "fs-extra": "^9.0.1", + "recast": "^0.23.1", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/csf/node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "dev": true, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@storybook/docs-mdx": { + "version": "0.0.1-next.5", + "resolved": "https://registry.npmjs.org/@storybook/docs-mdx/-/docs-mdx-0.0.1-next.5.tgz", + "integrity": "sha512-EowXFPq4TBZQguKCdU8y7EzpuSv2vSu5gy7pgF/1P5mq7LG9h8YIrerOW9DL4zfp9E0GHIWlSXR5KuFIqqKc/Q==", + "dev": true + }, + "node_modules/@storybook/docs-tools": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/docs-tools/-/docs-tools-7.0.0-beta.30.tgz", + "integrity": "sha512-pPGI1K0YXWTmRLg8VDy7BiZvUPmRLfdVP05vFEMw+5LpwZNjTI1hn8eQgEIME9eESNOZFj/VhdewPNfyki9M5A==", + "dev": true, + "dependencies": { + "@babel/core": "^7.12.10", + "@storybook/core-common": "7.0.0-beta.30", + "@storybook/preview-api": "7.0.0-beta.30", + "@storybook/types": "7.0.0-beta.30", + "@types/doctrine": "^0.0.3", + "doctrine": "^3.0.0", + "lodash": "^4.17.21" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/global": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@storybook/global/-/global-5.0.0.tgz", + "integrity": "sha512-FcOqPAXACP0I3oJ/ws6/rrPT9WGhu915Cg8D02a9YxLo0DE9zI+a9A5gRGvmQ09fiWPukqI8ZAEoQEdWUKMQdQ==", + "dev": true + }, + "node_modules/@storybook/instrumenter": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/instrumenter/-/instrumenter-7.0.0-beta.30.tgz", + "integrity": "sha512-raP9Sq5QmAJ4nf4IRs5hKOBZ3dg5h/GiKtwIlJI6sA5zo3bHzvqApOD308yG4fp2hyeiaBbjFBsDi2Kchrv6uw==", + "dev": true, + "dependencies": { + "@storybook/channels": "7.0.0-beta.30", + "@storybook/client-logger": "7.0.0-beta.30", + "@storybook/core-events": "7.0.0-beta.30", + "@storybook/global": "^5.0.0", + "@storybook/preview-api": "7.0.0-beta.30", + "core-js": "^3.8.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/manager": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/manager/-/manager-7.0.0-beta.30.tgz", + "integrity": "sha512-yI9O27g/k/wYGH4/ct/59XytnAy5XU49UxLrOUI3Np1Z+lstOikslqk2g0h3Zp3IFNzXNYZkVgQ2dPWxHeLabA==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/manager-api": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/manager-api/-/manager-api-7.0.0-beta.30.tgz", + "integrity": "sha512-cxEn56WpzI6UMBIaD5rgTeTg67VzREUOLgXIy51W1u7NWSb2T5agHrLzXg3Oaxlh1tL4bronbTibx/qveahtgA==", + "dev": true, + "dependencies": { + "@storybook/channels": "7.0.0-beta.30", + "@storybook/client-logger": "7.0.0-beta.30", + "@storybook/core-events": "7.0.0-beta.30", + "@storybook/csf": "next", + "@storybook/global": "^5.0.0", + "@storybook/router": "7.0.0-beta.30", + "@storybook/theming": "7.0.0-beta.30", + "@storybook/types": "7.0.0-beta.30", + "dequal": "^2.0.2", + "lodash": "^4.17.21", + "memoizerific": "^1.11.3", + "semver": "^7.3.7", + "store2": "^2.14.2", + "telejson": "^7.0.3", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@storybook/mdx2-csf": { + "version": "1.0.0-next.4", + "resolved": "https://registry.npmjs.org/@storybook/mdx2-csf/-/mdx2-csf-1.0.0-next.4.tgz", + "integrity": "sha512-nvRgYdpYvXsvSgCzKc4LQA1JxtJzmv47IsFAsh1rTz5FoHyK8watLU2WqX9T4w52fpFXBHx7RwGEsCRt0XgZlQ==", + "dev": true + }, + "node_modules/@storybook/nextjs": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/nextjs/-/nextjs-7.0.0-beta.30.tgz", + "integrity": "sha512-f8lJ4SFJEc6cp6ktUekiehRd8L9u+WoJCX4QnH630K+4dj5ZoXi+mEP3bSwrW/szkwN9A+P5wobAhTiXi7KTQw==", + "dev": true, + "dependencies": { + "@next/font": "^13.0.7", + "@storybook/addon-actions": "7.0.0-beta.30", + "@storybook/builder-webpack5": "7.0.0-beta.30", + "@storybook/core-common": "7.0.0-beta.30", + "@storybook/node-logger": "7.0.0-beta.30", + "@storybook/preset-react-webpack": "7.0.0-beta.30", + "@storybook/preview-api": "7.0.0-beta.30", + "@storybook/react": "7.0.0-beta.30", + "@types/node": "^16.0.0", + "find-up": "^5.0.0", + "fs-extra": "^9.0.1", + "image-size": "^1.0.0", + "loader-utils": "^3.2.0", + "pnp-webpack-plugin": "^1.7.0", + "postcss-loader": "^6.2.1", + "resolve-url-loader": "^5.0.0", + "sass-loader": "^12.4.0", + "semver": "^7.3.5", + "ts-dedent": "^2.0.0", + "tsconfig-paths": "^4.0.0", + "tsconfig-paths-webpack-plugin": "^3.5.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "@babel/core": "^7.11.5", + "next": "^9.0.0 || ^10.0.0 || ^11.0.0 || ^12.0.0 || ^13.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "@storybook/addon-actions": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/@storybook/nextjs/node_modules/@types/node": { + "version": "16.18.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.11.tgz", + "integrity": "sha512-3oJbGBUWuS6ahSnEq1eN2XrCyf4YsWI8OyCvo7c64zQJNplk3mO84t53o8lfTk+2ji59g5ycfc6qQ3fdHliHuA==", + "dev": true + }, + "node_modules/@storybook/nextjs/node_modules/tsconfig-paths": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.1.2.tgz", + "integrity": "sha512-uhxiMgnXQp1IR622dUXI+9Ehnws7i/y6xvpZB9IbUVOPy0muvdvgXeZOn88UcGPiT98Vp3rJPTa8bFoalZ3Qhw==", + "dev": true, + "dependencies": { + "json5": "^2.2.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@storybook/node-logger": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/node-logger/-/node-logger-7.0.0-beta.30.tgz", + "integrity": "sha512-mAvPG4smFASwSmb1+nMvR10Zlg/zPmNFeh6IKMttOWS5O0qSVzXGv4/QH63tjBcS0w915W3TGcDLLpKDa0c+lA==", + "dev": true, + "dependencies": { + "@types/npmlog": "^4.1.2", + "chalk": "^4.1.0", + "npmlog": "^5.0.1", + "pretty-hrtime": "^1.0.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/node-logger/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@storybook/node-logger/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@storybook/node-logger/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@storybook/node-logger/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@storybook/postinstall": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/postinstall/-/postinstall-7.0.0-beta.30.tgz", + "integrity": "sha512-PoM6+UVLd589bM8kg2SNer8ORNMhC3SV894/dfhvgXm7id4weqZ5xnhfZ/T0ZYH2Ts7qSuR+TQmPVAAQNHsrag==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/preset-react-webpack": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/preset-react-webpack/-/preset-react-webpack-7.0.0-beta.30.tgz", + "integrity": "sha512-PF7CAXWv6nS6N5OXnEj3XZKJRIKIFRmIrWwBhdK1L30XCHmQ313/0lA9JV24UHU8EwkUOfyF1IKkikhkKBkTTg==", + "dev": true, + "dependencies": { + "@babel/preset-flow": "^7.18.6", + "@babel/preset-react": "^7.18.6", + "@pmmmwh/react-refresh-webpack-plugin": "^0.5.5", + "@storybook/core-webpack": "7.0.0-beta.30", + "@storybook/docs-tools": "7.0.0-beta.30", + "@storybook/node-logger": "7.0.0-beta.30", + "@storybook/react": "7.0.0-beta.30", + "@storybook/react-docgen-typescript-plugin": "1.0.2-canary.6.9d540b91e815f8fc2f8829189deb00553559ff63.0", + "@types/node": "^16.0.0", + "@types/semver": "^7.3.4", + "babel-plugin-add-react-displayname": "^0.0.5", + "babel-plugin-react-docgen": "^4.2.1", + "fs-extra": "^9.0.1", + "react-refresh": "^0.11.0", + "semver": "^7.3.7" + }, + "engines": { + "node": ">=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "@babel/core": "^7.11.5", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0", + "webpack": "5" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/@storybook/preset-react-webpack/node_modules/@types/node": { + "version": "16.18.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.11.tgz", + "integrity": "sha512-3oJbGBUWuS6ahSnEq1eN2XrCyf4YsWI8OyCvo7c64zQJNplk3mO84t53o8lfTk+2ji59g5ycfc6qQ3fdHliHuA==", + "dev": true + }, + "node_modules/@storybook/preview": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/preview/-/preview-7.0.0-beta.30.tgz", + "integrity": "sha512-mcqs1PB7i/oEx4viFMECA6tI14x29RMGVctPtipkDIo0myo1BAsHSsgALaHRfQCw9mXl5KUiOyiwHQMf0dEkwg==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/preview-api": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/preview-api/-/preview-api-7.0.0-beta.30.tgz", + "integrity": "sha512-3klBZJ3gC+B80vJvzvHDh4uHy8+SwNOttcKyOAJOt0IJTNYo2HiAn7rUhaMeHfKzoD/YGiFiRkTrPKJDZJAGUA==", + "dev": true, + "dependencies": { + "@storybook/channel-postmessage": "7.0.0-beta.30", + "@storybook/channels": "7.0.0-beta.30", + "@storybook/client-logger": "7.0.0-beta.30", + "@storybook/core-events": "7.0.0-beta.30", + "@storybook/csf": "next", + "@storybook/global": "^5.0.0", + "@storybook/types": "7.0.0-beta.30", + "@types/qs": "^6.9.5", + "dequal": "^2.0.2", + "lodash": "^4.17.21", + "memoizerific": "^1.11.3", + "qs": "^6.10.0", + "slash": "^3.0.0", + "synchronous-promise": "^2.0.15", + "ts-dedent": "^2.0.0", + "util-deprecate": "^1.0.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/react": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/react/-/react-7.0.0-beta.30.tgz", + "integrity": "sha512-tcG+7vkf8/C2Az/Ei23DEfCx7sBqBi/odBEFIKYlZZkDTlkYWdTpcsn1P4fE/QFetwyS6F85aG3Qmluyk7YBQA==", + "dev": true, + "dependencies": { + "@storybook/client-logger": "7.0.0-beta.30", + "@storybook/core-client": "7.0.0-beta.30", + "@storybook/docs-tools": "7.0.0-beta.30", + "@storybook/global": "^5.0.0", + "@storybook/preview-api": "7.0.0-beta.30", + "@storybook/types": "7.0.0-beta.30", + "@types/escodegen": "^0.0.6", + "@types/estree": "^0.0.51", + "@types/node": "^16.0.0", + "acorn": "^7.4.1", + "acorn-jsx": "^5.3.1", + "acorn-walk": "^7.2.0", + "escodegen": "^2.0.0", + "html-tags": "^3.1.0", + "lodash": "^4.17.21", + "prop-types": "^15.7.2", + "react-element-to-jsx-string": "^15.0.0", + "ts-dedent": "^2.0.0", + "type-fest": "^2.19.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@storybook/react-docgen-typescript-plugin": { + "version": "1.0.2-canary.6.9d540b91e815f8fc2f8829189deb00553559ff63.0", + "resolved": "https://registry.npmjs.org/@storybook/react-docgen-typescript-plugin/-/react-docgen-typescript-plugin-1.0.2-canary.6.9d540b91e815f8fc2f8829189deb00553559ff63.0.tgz", + "integrity": "sha512-eVg3BxlOm2P+chijHBTByr90IZVUtgRW56qEOLX7xlww2NBuKrcavBlcmn+HH7GIUktquWkMPtvy6e0W0NgA5w==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "endent": "^2.0.1", + "find-cache-dir": "^3.3.1", + "flat-cache": "^3.0.4", + "micromatch": "^4.0.2", + "react-docgen-typescript": "^2.1.1", + "tslib": "^2.0.0" + }, + "peerDependencies": { + "typescript": ">= 3.x", + "webpack": ">= 4" + } + }, + "node_modules/@storybook/react-docgen-typescript-plugin/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@storybook/react-docgen-typescript-plugin/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@storybook/react/node_modules/@types/node": { + "version": "16.18.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.11.tgz", + "integrity": "sha512-3oJbGBUWuS6ahSnEq1eN2XrCyf4YsWI8OyCvo7c64zQJNplk3mO84t53o8lfTk+2ji59g5ycfc6qQ3fdHliHuA==", + "dev": true + }, + "node_modules/@storybook/react/node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "dev": true, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@storybook/router": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/router/-/router-7.0.0-beta.30.tgz", + "integrity": "sha512-hSdVv/IlBA96rf6RpmSCeS2CgxfmvgQOWVR8JR+5M97MjRMtXcIKB3f2ea8JSEPWkOa7i2k8ARunlAAVVmOiPw==", + "dev": true, + "dependencies": { + "@storybook/client-logger": "7.0.0-beta.30", + "memoizerific": "^1.11.3", + "qs": "^6.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@storybook/semver": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/@storybook/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-SWeszlsiPsMI0Ps0jVNtH64cI5c0UF3f7KgjVKJoNP30crQ6wUSddY2hsdeczZXEKVJGEn50Q60flcGsQGIcrg==", + "dev": true, + "dependencies": { + "core-js": "^3.6.5", + "find-up": "^4.1.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@storybook/semver/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@storybook/semver/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@storybook/semver/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@storybook/semver/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@storybook/store": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/store/-/store-7.0.0-beta.30.tgz", + "integrity": "sha512-Uzni6jW4cUee2i92jgMshRJh7AcBD79gUJpLz2HmKm7xXypi3TCzpUQi++8OAbfPgRkvk3sGwhcyrfkujJ1KqQ==", + "dev": true, + "dependencies": { + "@storybook/client-logger": "7.0.0-beta.30", + "@storybook/preview-api": "7.0.0-beta.30" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/telemetry": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/telemetry/-/telemetry-7.0.0-beta.30.tgz", + "integrity": "sha512-ufmdVxZoAiaIP5VWjbTRrruNTm6OXSvhjCYCpqBJIgMbvEosE5njNJ4ySuyZSjMtLvJy0kdnx7ca+bQQ5ALFuQ==", + "dev": true, + "dependencies": { + "@storybook/client-logger": "7.0.0-beta.30", + "@storybook/core-common": "7.0.0-beta.30", + "chalk": "^4.1.0", + "detect-package-manager": "^2.0.1", + "fetch-retry": "^5.0.2", + "fs-extra": "^9.0.1", + "isomorphic-unfetch": "^3.1.0", + "nanoid": "^3.3.1", + "read-pkg-up": "^7.0.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/telemetry/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@storybook/telemetry/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@storybook/telemetry/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@storybook/telemetry/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@storybook/testing-library": { + "version": "0.0.13", + "resolved": "https://registry.npmjs.org/@storybook/testing-library/-/testing-library-0.0.13.tgz", + "integrity": "sha512-vRMeIGer4EjJkTgI8sQyK9W431ekPWYCWL//OmSDJ64IT3h7FnW7Xg6p+eqM3oII98/O5pcya5049GxnjaPtxw==", + "dev": true, + "dependencies": { + "@storybook/client-logger": "^6.4.0", + "@storybook/instrumenter": "^6.4.0", + "@testing-library/dom": "^8.3.0", + "@testing-library/user-event": "^13.2.1", + "ts-dedent": "^2.2.0" + } + }, + "node_modules/@storybook/testing-library/node_modules/@storybook/addons": { + "version": "6.5.15", + "resolved": "https://registry.npmjs.org/@storybook/addons/-/addons-6.5.15.tgz", + "integrity": "sha512-xT31SuSX+kYGyxCNK2nqL7WTxucs3rSmhiCLovJcUjYk+QquV3c2c53Ki7lwwdDbzfXFcNAe0HJ4hoTN4jhn0Q==", + "dev": true, + "dependencies": { + "@storybook/api": "6.5.15", + "@storybook/channels": "6.5.15", + "@storybook/client-logger": "6.5.15", + "@storybook/core-events": "6.5.15", + "@storybook/csf": "0.0.2--canary.4566f4d.1", + "@storybook/router": "6.5.15", + "@storybook/theming": "6.5.15", + "@types/webpack-env": "^1.16.0", + "core-js": "^3.8.2", + "global": "^4.4.0", + "regenerator-runtime": "^0.13.7" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@storybook/testing-library/node_modules/@storybook/api": { + "version": "6.5.15", + "resolved": "https://registry.npmjs.org/@storybook/api/-/api-6.5.15.tgz", + "integrity": "sha512-BBE0KXKvj1/3jTghbIoWfrcDM0t+xO7EYtWWAXD6XlhGsZVD2Dy82Z52ONyLulMDRpMWl0OYy3h6A1YnFUH25w==", + "dev": true, + "dependencies": { + "@storybook/channels": "6.5.15", + "@storybook/client-logger": "6.5.15", + "@storybook/core-events": "6.5.15", + "@storybook/csf": "0.0.2--canary.4566f4d.1", + "@storybook/router": "6.5.15", + "@storybook/semver": "^7.3.2", + "@storybook/theming": "6.5.15", + "core-js": "^3.8.2", + "fast-deep-equal": "^3.1.3", + "global": "^4.4.0", + "lodash": "^4.17.21", + "memoizerific": "^1.11.3", + "regenerator-runtime": "^0.13.7", + "store2": "^2.12.0", + "telejson": "^6.0.8", + "ts-dedent": "^2.0.0", + "util-deprecate": "^1.0.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@storybook/testing-library/node_modules/@storybook/channels": { + "version": "6.5.15", + "resolved": "https://registry.npmjs.org/@storybook/channels/-/channels-6.5.15.tgz", + "integrity": "sha512-gPpsBgirv2NCXbH4WbYqdkI0JLE96aiVuu7UEWfn9yu071pQ9CLHbhXGD9fSFNrfOkyBBY10ppSE7uCXw3Wexg==", + "dev": true, + "dependencies": { + "core-js": "^3.8.2", + "ts-dedent": "^2.0.0", + "util-deprecate": "^1.0.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/testing-library/node_modules/@storybook/client-logger": { + "version": "6.5.15", + "resolved": "https://registry.npmjs.org/@storybook/client-logger/-/client-logger-6.5.15.tgz", + "integrity": "sha512-0uyxKvodq+FycGv6aUwC1wUR6suXf2+7ywMFAOlYolI4UvNj8NyU/5AfgKT5XnxYAgPmoCiAjOE700TrfHrosw==", + "dev": true, + "dependencies": { + "core-js": "^3.8.2", + "global": "^4.4.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/testing-library/node_modules/@storybook/core-events": { + "version": "6.5.15", + "resolved": "https://registry.npmjs.org/@storybook/core-events/-/core-events-6.5.15.tgz", + "integrity": "sha512-B1Ba6l5W7MeNclclqMMTMHgYgfdpB5SIhNCQFnzIz8blynzRhNFMdxvbAl6Je5G0S4xydYYd7Lno2kXQebs7HA==", + "dev": true, + "dependencies": { + "core-js": "^3.8.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/testing-library/node_modules/@storybook/csf": { + "version": "0.0.2--canary.4566f4d.1", + "resolved": "https://registry.npmjs.org/@storybook/csf/-/csf-0.0.2--canary.4566f4d.1.tgz", + "integrity": "sha512-9OVvMVh3t9znYZwb0Svf/YQoxX2gVOeQTGe2bses2yj+a3+OJnCrUF3/hGv6Em7KujtOdL2LL+JnG49oMVGFgQ==", + "dev": true, + "dependencies": { + "lodash": "^4.17.15" + } + }, + "node_modules/@storybook/testing-library/node_modules/@storybook/instrumenter": { + "version": "6.5.15", + "resolved": "https://registry.npmjs.org/@storybook/instrumenter/-/instrumenter-6.5.15.tgz", + "integrity": "sha512-93WyH0s63RCv496eHjQ5dWFXoExXg9dlNMe7i4/FVVbWeDdb1pPVIHsLn28WxOiVQahQEAW2EA7Mao3BiBWg+A==", + "dev": true, + "dependencies": { + "@storybook/addons": "6.5.15", + "@storybook/client-logger": "6.5.15", + "@storybook/core-events": "6.5.15", + "core-js": "^3.8.2", + "global": "^4.4.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/@storybook/testing-library/node_modules/@storybook/router": { + "version": "6.5.15", + "resolved": "https://registry.npmjs.org/@storybook/router/-/router-6.5.15.tgz", + "integrity": "sha512-9t8rI8t7/Krolau29gsdjdbRQ66orONIyP0efp0EukVgv6reNFzb/U14ARrl0uHys6Tl5Xyece9FoakQUdn8Kg==", + "dev": true, + "dependencies": { + "@storybook/client-logger": "6.5.15", + "core-js": "^3.8.2", + "memoizerific": "^1.11.3", + "qs": "^6.10.0", + "regenerator-runtime": "^0.13.7" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@storybook/testing-library/node_modules/@storybook/theming": { + "version": "6.5.15", + "resolved": "https://registry.npmjs.org/@storybook/theming/-/theming-6.5.15.tgz", + "integrity": "sha512-pgdW0lVZKKXQ4VhIfLHycMmwFSVOY7vLTKnytag4Y8Yz+aXm0bwDN/QxPntFzDH47F1Rcy2ywNnvty8ooDTvuA==", + "dev": true, + "dependencies": { + "@storybook/client-logger": "6.5.15", + "core-js": "^3.8.2", + "memoizerific": "^1.11.3", + "regenerator-runtime": "^0.13.7" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@storybook/testing-library/node_modules/telejson": { + "version": "6.0.8", + "resolved": "https://registry.npmjs.org/telejson/-/telejson-6.0.8.tgz", + "integrity": "sha512-nerNXi+j8NK1QEfBHtZUN/aLdDcyupA//9kAboYLrtzZlPLpUfqbVGWb9zz91f/mIjRbAYhbgtnJHY8I1b5MBg==", + "dev": true, + "dependencies": { + "@types/is-function": "^1.0.0", + "global": "^4.4.0", + "is-function": "^1.0.2", + "is-regex": "^1.1.2", + "is-symbol": "^1.0.3", + "isobject": "^4.0.0", + "lodash": "^4.17.21", + "memoizerific": "^1.11.3" + } + }, + "node_modules/@storybook/theming": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/theming/-/theming-7.0.0-beta.30.tgz", + "integrity": "sha512-b3GM3vQfgAbmLvUaMPoAwYVynMAk7iH7H+ig9Dqv5/IJl8KIP7DTD5HAkP+PEzk+WrcOnw7mKDIk6Kt/lD0VWQ==", + "dev": true, + "dependencies": { + "@emotion/use-insertion-effect-with-fallbacks": "^1.0.0", + "@storybook/client-logger": "7.0.0-beta.30", + "@storybook/global": "^5.0.0", + "memoizerific": "^1.11.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@storybook/types": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/types/-/types-7.0.0-beta.30.tgz", + "integrity": "sha512-udjSzDh8GPxpb0ITZqvooDv+khtyy1z1iNy/5VLOBhWe/vDWXC/mLHKPYlWdNthE9Vm3tJs61n8fTJBuPs2VZg==", + "dev": true, + "dependencies": { + "@babel/core": "^7.12.10", + "@storybook/channels": "7.0.0-beta.30", + "@types/babel__core": "^7.0.0", + "@types/express": "^4.7.0", + "express": "^4.17.3", + "file-system-cache": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, "node_modules/@stripe/react-stripe-js": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/@stripe/react-stripe-js/-/react-stripe-js-1.10.0.tgz", @@ -1217,9 +6620,9 @@ } }, "node_modules/@stripe/stripe-js": { - "version": "1.36.0", - "resolved": "https://registry.npmjs.org/@stripe/stripe-js/-/stripe-js-1.36.0.tgz", - "integrity": "sha512-m45BD9JxOfIBT0Tz4MupiKzM8M58NX/We8wKlf+54TCZpW1RVAyFpJ58CbtyU/LxAM+opT6cewHRVfs7bTUtBA==" + "version": "1.46.0", + "resolved": "https://registry.npmjs.org/@stripe/stripe-js/-/stripe-js-1.46.0.tgz", + "integrity": "sha512-dkm0zCEoRLu5rTnsIgwDf/QG2DKcalOT2dk1IVgMySOHWTChLyOvQwMYhEduGgLvyYWTwNhAUV4WOLPQvjwLwA==" }, "node_modules/@swc/helpers": { "version": "0.4.11", @@ -1244,6 +6647,194 @@ "tailwindcss": ">=3.0.0 || insiders" } }, + "node_modules/@tanstack/query-core": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-4.22.4.tgz", + "integrity": "sha512-t79CMwlbBnj+yL82tEcmRN93bL4U3pae2ota4t5NN2z3cIeWw74pzdWrKRwOfTvLcd+b30tC+ciDlfYOKFPGUw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/react-query": { + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-4.23.0.tgz", + "integrity": "sha512-cfQsrecZQjYYueiow4WcK8ItokXJnv+b2OrK8Lf5kF7lM9uCo1ilyygFB8wo4MfxchUBVM6Cs8wq4Ed7fouwkA==", + "dependencies": { + "@tanstack/query-core": "4.22.4", + "use-sync-external-store": "^1.2.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-native": "*" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, + "node_modules/@testing-library/dom": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.20.0.tgz", + "integrity": "sha512-d9ULIT+a4EXLX3UU8FBjauG9NnsZHkHztXoIcTsOKoOw030fyjheN9svkTULjJxtYag9DZz5Jz5qkWZDPxTFwA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "^5.0.0", + "chalk": "^4.1.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.4.4", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@testing-library/dom/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@testing-library/dom/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@testing-library/dom/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@testing-library/dom/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@testing-library/user-event": { + "version": "13.5.0", + "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-13.5.0.tgz", + "integrity": "sha512-5Kwtbo3Y/NowpkbRuSepbyMFkZmHgD+vPzYB/RJ4oxt5Gj/avFFBYjhw27cqSVPVw/3a67NK1PbiIr9k4Gwmdg==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.12.5" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + }, + "peerDependencies": { + "@testing-library/dom": ">=7.21.4" + } + }, + "node_modules/@types/aria-query": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.1.tgz", + "integrity": "sha512-XTIieEY+gvJ39ChLcB4If5zHtPxt3Syj5rgZR+e1ctpmK8NjPf0zFqsz4JpLJT0xla9GFDKjy8Cpu331nrmE1Q==", + "dev": true + }, + "node_modules/@types/babel__core": { + "version": "7.1.20", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.20.tgz", + "integrity": "sha512-PVb6Bg2QuscZ30FvOU7z4guG6c926D9YRvOxEaelzndpMsvP+YM74Q/dAFASpg2l6+XLalxSGxcq/lrgYWZtyQ==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", + "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", + "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.3.tgz", + "integrity": "sha512-1kbcJ40lLB7MHsj39U4Sh1uTd2E7rLEa79kmDpI6cy+XiXsteB3POdQomoq4FxszMrO3ZYchkhYJw7A2862b3w==", + "dev": true, + "dependencies": { + "@babel/types": "^7.3.0" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", + "dev": true, + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.35", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", + "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/debug": { "version": "4.1.7", "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.7.tgz", @@ -1252,6 +6843,94 @@ "@types/ms": "*" } }, + "node_modules/@types/detect-port": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@types/detect-port/-/detect-port-1.3.2.tgz", + "integrity": "sha512-xxgAGA2SAU4111QefXPSp5eGbDm/hW6zhvYl9IeEPZEry9F4d66QAHm5qpUXjb6IsevZV/7emAEx5MhP6O192g==", + "dev": true + }, + "node_modules/@types/doctrine": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/@types/doctrine/-/doctrine-0.0.3.tgz", + "integrity": "sha512-w5jZ0ee+HaPOaX25X2/2oGR/7rgAQSYII7X7pp0m9KgBfMP7uKfMfTvcpl5Dj+eDBbpxKGiqE+flqDr6XTd2RA==", + "dev": true + }, + "node_modules/@types/ejs": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/ejs/-/ejs-3.1.1.tgz", + "integrity": "sha512-RQul5wEfY7BjWm0sYY86cmUN/pcXWGyVxWX93DFFJvcrxax5zKlieLwA3T77xJGwNcZW0YW6CYG70p1m8xPFmA==", + "dev": true + }, + "node_modules/@types/escodegen": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/@types/escodegen/-/escodegen-0.0.6.tgz", + "integrity": "sha512-AjwI4MvWx3HAOaZqYsjKWyEObT9lcVV0Y0V8nXo6cXzN8ZiMxVhf6F3d/UNvXVGKrEzL/Dluc5p+y9GkzlTWig==", + "dev": true + }, + "node_modules/@types/eslint": { + "version": "8.4.10", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.10.tgz", + "integrity": "sha512-Sl/HOqN8NKPmhWo2VBEPm0nvHnu2LL3v9vKo8MEq0EtbJ4eVzGPl41VNPvn5E1i5poMk4/XD8UriLHpJvEP/Nw==", + "dev": true, + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz", + "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==", + "dev": true, + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "0.0.51", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", + "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", + "dev": true + }, + "node_modules/@types/express": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.15.tgz", + "integrity": "sha512-Yv0k4bXGOH+8a+7bELd2PqHQsuiANB+A8a4gnQrkRWzrkKlb6KHaVvyXhqs04sVW/OWlbPyYxRgYlIXLfrufMQ==", + "dev": true, + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.31", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.17.32", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.32.tgz", + "integrity": "sha512-aI5h/VOkxOF2Z1saPy0Zsxs5avets/iaiAJYznQFm5By/pamU31xWKL//epiF4OfUA2qTOc9PV6tCUjhO8wlZA==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*" + } + }, + "node_modules/@types/find-cache-dir": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@types/find-cache-dir/-/find-cache-dir-3.2.1.tgz", + "integrity": "sha512-frsJrz2t/CeGifcu/6uRo4b+SzAwT4NYCVPu1GN8IB9XTzrpPkGuV0tmh9mN+/L0PklAlsC3u5Fxt0ju00LXIw==", + "dev": true + }, + "node_modules/@types/graceful-fs": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz", + "integrity": "sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/hast": { "version": "2.3.4", "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.4.tgz", @@ -1269,6 +6948,42 @@ "hoist-non-react-statics": "^3.3.0" } }, + "node_modules/@types/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==", + "dev": true + }, + "node_modules/@types/is-function": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@types/is-function/-/is-function-1.0.1.tgz", + "integrity": "sha512-A79HEEiwXTFtfY+Bcbo58M2GRYzCr9itHWzbzHVFNEYCcoU/MMGwYYf721gBrnhpj1s6RGVVha/IgNFnR0Iw/Q==", + "dev": true + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", + "dev": true + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, "node_modules/@types/json-schema": { "version": "7.0.11", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", @@ -1281,6 +6996,18 @@ "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "dev": true }, + "node_modules/@types/jsrp": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@types/jsrp/-/jsrp-0.2.4.tgz", + "integrity": "sha512-9RerZiVclCJNQrAaUH71s7tQpIlvyrM+1oWYwaRW+9xYYG0p2rnqSZMS0j+W+bL1tkBRUQUyXiSEUTnbv8HQjA==", + "dev": true + }, + "node_modules/@types/lodash": { + "version": "4.14.191", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.191.tgz", + "integrity": "sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ==", + "dev": true + }, "node_modules/@types/mdast": { "version": "3.0.10", "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.10.tgz", @@ -1294,6 +7021,24 @@ "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-1.0.2.tgz", "integrity": "sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA==" }, + "node_modules/@types/mdx": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/mdx/-/mdx-2.0.3.tgz", + "integrity": "sha512-IgHxcT3RC8LzFLhKwP3gbMPeaK7BM9eBH46OdapPA7yvuIUJ8H6zHZV53J8hGZcTSnt95jANt+rTBNUUc22ACQ==", + "dev": true + }, + "node_modules/@types/mime": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", + "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==", + "dev": true + }, + "node_modules/@types/mime-types": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@types/mime-types/-/mime-types-2.1.1.tgz", + "integrity": "sha512-vXOTGVSLR2jMw440moWTC7H19iUyLtP3Z1YTj7cSsubOICinjMxFeb/V57v9QdyyPGbbWolUFSSmSiRSn94tFw==", + "dev": true + }, "node_modules/@types/ms": { "version": "0.7.31", "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.31.tgz", @@ -1305,22 +7050,76 @@ "integrity": "sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==", "dev": true }, + "node_modules/@types/node-fetch": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.2.tgz", + "integrity": "sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A==", + "dev": true, + "dependencies": { + "@types/node": "*", + "form-data": "^3.0.0" + } + }, + "node_modules/@types/node-fetch/node_modules/form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@types/normalize-package-data": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz", + "integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==", + "dev": true + }, + "node_modules/@types/npmlog": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@types/npmlog/-/npmlog-4.1.4.tgz", + "integrity": "sha512-WKG4gTr8przEZBiJ5r3s8ZIAoMXNbOgQ+j/d5O4X3x6kZJRLNvyUJuUK/KoG3+8BaOHPhp2m7WC6JKKeovDSzQ==", + "dev": true + }, "node_modules/@types/parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==" }, + "node_modules/@types/pretty-hrtime": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@types/pretty-hrtime/-/pretty-hrtime-1.0.1.tgz", + "integrity": "sha512-VjID5MJb1eGKthz2qUerWT8+R4b9N+CHvGCzg9fn4kWZgaF9AhdYikQio3R7wV8YY1NsQKPaCwKz1Yff+aHNUQ==", + "dev": true + }, "node_modules/@types/prop-types": { "version": "15.7.5", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" }, + "node_modules/@types/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", + "dev": true + }, "node_modules/@types/raf": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/@types/raf/-/raf-3.4.0.tgz", "integrity": "sha512-taW5/WYqo36N7V39oYyHP9Ipfd5pNFvGTIQsNGj86xV88YQ7GnI30/yMfKDF7Zgin0m3e+ikX88FvImnK4RjGw==", "optional": true }, + "node_modules/@types/range-parser": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", + "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", + "dev": true + }, "node_modules/@types/react": { "version": "18.0.26", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.26.tgz", @@ -1353,6 +7152,16 @@ "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", "dev": true }, + "node_modules/@types/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg==", + "dev": true, + "dependencies": { + "@types/mime": "*", + "@types/node": "*" + } + }, "node_modules/@types/unist": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.6.tgz", @@ -1368,15 +7177,36 @@ "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==" }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.45.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.45.0.tgz", - "integrity": "sha512-CXXHNlf0oL+Yg021cxgOdMHNTXD17rHkq7iW6RFHoybdFgQBjU3yIXhhcPpGwr1CjZlo6ET8C6tzX5juQoXeGA==", + "node_modules/@types/webpack-env": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/@types/webpack-env/-/webpack-env-1.18.0.tgz", + "integrity": "sha512-56/MAlX5WMsPVbOg7tAxnYvNYMMWr/QJiIp6BxVSW3JJXUVzzOn64qW8TzQyMSqSUFM2+PVI4aUHcHOzIz/1tg==", + "dev": true + }, + "node_modules/@types/yargs": { + "version": "17.0.19", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.19.tgz", + "integrity": "sha512-cAx3qamwaYX9R0fzOIZAlFpo4A+1uBVCxqpKz9D26uTF4srRXaGTTsikQmaotCtNdbhzyUH7ft6p9ktz9s6UNQ==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.45.0", - "@typescript-eslint/type-utils": "5.45.0", - "@typescript-eslint/utils": "5.45.0", + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", + "dev": true + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.48.1.tgz", + "integrity": "sha512-9nY5K1Rp2ppmpb9s9S2aBiF3xo5uExCehMDmYmmFqqyxgenbHJ3qbarcLt4ITgaD6r/2ypdlcFRdcuVPnks+fQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.48.1", + "@typescript-eslint/type-utils": "5.48.1", + "@typescript-eslint/utils": "5.48.1", "debug": "^4.3.4", "ignore": "^5.2.0", "natural-compare-lite": "^1.4.0", @@ -1401,6 +7231,53 @@ } } }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/scope-manager": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.1.tgz", + "integrity": "sha512-S035ueRrbxRMKvSTv9vJKIWgr86BD8s3RqoRZmsSh/s8HhIs90g6UlK8ZabUSjUZQkhVxt7nmZ63VJ9dcZhtDQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/visitor-keys": "5.48.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/types": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.1.tgz", + "integrity": "sha512-xHyDLU6MSuEEdIlzrrAerCGS3T7AA/L8Hggd0RCYBi0w3JMvGYxlLlXHeg50JI9Tfg5MrtsfuNxbS/3zF1/ATg==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.1.tgz", + "integrity": "sha512-Ns0XBwmfuX7ZknznfXozgnydyR8F6ev/KEGePP4i74uL3ArsKbEhJ7raeKr1JSa997DBDwol/4a0Y+At82c9dA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.48.1", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -1492,13 +7369,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "5.45.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.45.0.tgz", - "integrity": "sha512-DY7BXVFSIGRGFZ574hTEyLPRiQIvI/9oGcN8t1A7f6zIs6ftbrU0nhyV26ZW//6f85avkwrLag424n+fkuoJ1Q==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.48.1.tgz", + "integrity": "sha512-Hyr8HU8Alcuva1ppmqSYtM/Gp0q4JOp1F+/JH5D1IZm/bUBrV0edoewQZiEc1r6I8L4JL21broddxK8HAcZiqQ==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "5.45.0", - "@typescript-eslint/utils": "5.45.0", + "@typescript-eslint/typescript-estree": "5.48.1", + "@typescript-eslint/utils": "5.48.1", "debug": "^4.3.4", "tsutils": "^3.21.0" }, @@ -1518,6 +7395,63 @@ } } }, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.1.tgz", + "integrity": "sha512-xHyDLU6MSuEEdIlzrrAerCGS3T7AA/L8Hggd0RCYBi0w3JMvGYxlLlXHeg50JI9Tfg5MrtsfuNxbS/3zF1/ATg==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.1.tgz", + "integrity": "sha512-Hut+Osk5FYr+sgFh8J/FHjqX6HFcDzTlWLrFqGoK5kVUN3VBHF/QzZmAsIXCQ8T/W9nQNBTqalxi1P3LSqWnRA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/visitor-keys": "5.48.1", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.1.tgz", + "integrity": "sha512-Ns0XBwmfuX7ZknznfXozgnydyR8F6ev/KEGePP4i74uL3ArsKbEhJ7raeKr1JSa997DBDwol/4a0Y+At82c9dA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.48.1", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/@typescript-eslint/type-utils/node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -1605,16 +7539,16 @@ "dev": true }, "node_modules/@typescript-eslint/utils": { - "version": "5.45.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.45.0.tgz", - "integrity": "sha512-OUg2JvsVI1oIee/SwiejTot2OxwU8a7UfTFMOdlhD2y+Hl6memUSL4s98bpUTo8EpVEr0lmwlU7JSu/p2QpSvA==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.48.1.tgz", + "integrity": "sha512-SmQuSrCGUOdmGMwivW14Z0Lj8dxG1mOFZ7soeJ0TQZEJcs3n5Ndgkg0A4bcMFzBELqLJ6GTHnEU+iIoaD6hFGA==", "dev": true, "dependencies": { "@types/json-schema": "^7.0.9", "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.45.0", - "@typescript-eslint/types": "5.45.0", - "@typescript-eslint/typescript-estree": "5.45.0", + "@typescript-eslint/scope-manager": "5.48.1", + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/typescript-estree": "5.48.1", "eslint-scope": "^5.1.1", "eslint-utils": "^3.0.0", "semver": "^7.3.7" @@ -1630,6 +7564,97 @@ "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/scope-manager": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.1.tgz", + "integrity": "sha512-S035ueRrbxRMKvSTv9vJKIWgr86BD8s3RqoRZmsSh/s8HhIs90g6UlK8ZabUSjUZQkhVxt7nmZ63VJ9dcZhtDQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/visitor-keys": "5.48.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/types": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.1.tgz", + "integrity": "sha512-xHyDLU6MSuEEdIlzrrAerCGS3T7AA/L8Hggd0RCYBi0w3JMvGYxlLlXHeg50JI9Tfg5MrtsfuNxbS/3zF1/ATg==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.1.tgz", + "integrity": "sha512-Hut+Osk5FYr+sgFh8J/FHjqX6HFcDzTlWLrFqGoK5kVUN3VBHF/QzZmAsIXCQ8T/W9nQNBTqalxi1P3LSqWnRA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/visitor-keys": "5.48.1", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/visitor-keys": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.1.tgz", + "integrity": "sha512-Ns0XBwmfuX7ZknznfXozgnydyR8F6ev/KEGePP4i74uL3ArsKbEhJ7raeKr1JSa997DBDwol/4a0Y+At82c9dA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.48.1", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, "node_modules/@typescript-eslint/utils/node_modules/eslint-scope": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", @@ -1652,6 +7677,12 @@ "node": ">=4.0" } }, + "node_modules/@typescript-eslint/utils/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, "node_modules/@typescript-eslint/visitor-keys": { "version": "5.45.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.45.0.tgz", @@ -1669,6 +7700,192 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@webassemblyjs/ast": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", + "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", + "dev": true, + "dependencies": { + "@webassemblyjs/helper-numbers": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", + "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", + "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", + "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", + "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", + "dev": true, + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", + "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", + "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", + "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", + "dev": true, + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", + "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", + "dev": true, + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", + "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==", + "dev": true + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", + "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/helper-wasm-section": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-opt": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "@webassemblyjs/wast-printer": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", + "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", + "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", + "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", + "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "node_modules/@yarnpkg/esbuild-plugin-pnp": { + "version": "3.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@yarnpkg/esbuild-plugin-pnp/-/esbuild-plugin-pnp-3.0.0-rc.15.tgz", + "integrity": "sha512-kYzDJO5CA9sy+on/s2aIW0411AklfCi8Ck/4QDivOqsMKpStZA2SsR+X27VTggGwpStWaLrjJcDcdDMowtG8MA==", + "dev": true, + "dependencies": { + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "esbuild": ">=0.10.0" + } + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dev": true, + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/acorn": { "version": "7.4.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", @@ -1715,6 +7932,90 @@ "resolved": "https://registry.npmjs.org/add/-/add-2.0.6.tgz", "integrity": "sha512-j5QzrmsokwWWp6kUcJQySpbG+xfOBqqKnup3OIk1pz+kB/80SLorZ9V8zHFLO92Lcd+hbvq8bT+zOGoPkmBV0Q==" }, + "node_modules/address": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/address/-/address-1.2.2.tgz", + "integrity": "sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/adjust-sourcemap-loader": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-4.0.0.tgz", + "integrity": "sha512-OXwN5b9pCUXNQHJpwwD2qP40byEmSgzj8B4ydSN0uMNYWiFmJ6x6KwUllMmfk8Rwu/HJDFR7U8ubsWBoN0Xp0A==", + "dev": true, + "dependencies": { + "loader-utils": "^2.0.0", + "regex-parser": "^2.2.11" + }, + "engines": { + "node": ">=8.9" + } + }, + "node_modules/adjust-sourcemap-loader/node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/agent-base/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/agent-base/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -1731,6 +8032,75 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-formats/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/ansi-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "dev": true, + "dependencies": { + "string-width": "^4.1.0" + } + }, + "node_modules/ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "dev": true, + "engines": [ + "node >= 0.8.0" + ], + "bin": { + "ansi-html": "bin/ansi-html" + } + }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -1777,6 +8147,31 @@ "node": ">= 8" } }, + "node_modules/app-root-dir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/app-root-dir/-/app-root-dir-1.0.2.tgz", + "integrity": "sha512-jlpIfsOoNoafl92Sz//64uQHGSyMrD2vYG5d8o2a4qGvyNCvXur7bzIsWtAC/6flI2RYAp3kv8rsfBtaLm7w0g==", + "dev": true + }, + "node_modules/aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", + "dev": true + }, + "node_modules/are-we-there-yet": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", + "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", + "dev": true, + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/arg": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", @@ -1791,19 +8186,68 @@ "sprintf-js": "~1.0.2" } }, - "node_modules/aria-query": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz", - "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==", - "dev": true, + "node_modules/aria-hidden": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.2.tgz", + "integrity": "sha512-6y/ogyDTk/7YAe91T3E2PR1ALVKyM2QbTio5HwM+N1Q6CMlCKhvClyIjkckBswa0f2xJhjsfzIGa1yVSe1UMVA==", "dependencies": { - "@babel/runtime": "^7.10.2", - "@babel/runtime-corejs3": "^7.10.2" + "tslib": "^2.0.0" }, "engines": { - "node": ">=6.0" + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "^16.9.0 || ^17.0.0 || ^18.0.0", + "react": "^16.9.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, + "node_modules/aria-query": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", + "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", + "dev": true, + "dependencies": { + "deep-equal": "^2.0.5" + } + }, + "node_modules/arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "dev": true + }, "node_modules/array-includes": { "version": "3.1.6", "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz", @@ -1832,6 +8276,15 @@ "node": ">=8" } }, + "node_modules/array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/array.prototype.flat": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz", @@ -1881,17 +8334,71 @@ "get-intrinsic": "^1.1.3" } }, + "node_modules/assert": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-2.0.0.tgz", + "integrity": "sha512-se5Cd+js9dXJnu6Ag2JFc00t+HmHOen+8Q+L7O9zI0PqQXr20uk2J0XQqMxZEeo5U50o8Nvmmx7dZrl+Ufr35A==", + "dev": true, + "dependencies": { + "es6-object-assign": "^1.1.0", + "is-nan": "^1.2.1", + "object-is": "^1.0.1", + "util": "^0.12.0" + } + }, + "node_modules/assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ast-types": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.14.2.tgz", + "integrity": "sha512-O0yuUDnZeQDL+ncNGlJ78BiO4jnYI3bvMsD5prT0/nsgijG/LpNBIr63gTjVTNsiGkgQhiyCShTgxt8oXOrklA==", + "dev": true, + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/ast-types-flow": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", "integrity": "sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==", "dev": true }, + "node_modules/async": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", + "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==", + "dev": true + }, + "node_modules/async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", + "dev": true + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, "node_modules/atob": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", @@ -1936,10 +8443,22 @@ "postcss": "^8.1.0" } }, + "node_modules/available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/axe-core": { - "version": "4.5.2", - "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.5.2.tgz", - "integrity": "sha512-u2MVsXfew5HBvjsczCv+xlwdNnB1oQR9HlAcsejZttNjKKSkeDNVwB1vMThIUIFI9GoT57Vtk8iQLwqOfAkboA==", + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.6.2.tgz", + "integrity": "sha512-b1WlTV8+XKLj9gZy2DZXgQiyDp9xkkoe2a6U6UbYccScq2wgH/YwCeI2/Jq2mgo0HzQxqJOjWZBLeA/mqsk5Mg==", "dev": true, "engines": { "node": ">=4" @@ -1963,11 +8482,115 @@ } }, "node_modules/axobject-query": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz", - "integrity": "sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.1.1.tgz", + "integrity": "sha512-goKlv8DZrK9hUh975fnHzhNIO4jUnFCfv/dszV5VwUGDFjI6vQ2VwoyjYjYNEbBE8AH87TduWP5uyDR1D+Iteg==", + "dev": true, + "dependencies": { + "deep-equal": "^2.0.5" + } + }, + "node_modules/babel-core": { + "version": "7.0.0-bridge.0", + "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-7.0.0-bridge.0.tgz", + "integrity": "sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg==", + "dev": true, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-loader": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.1.2.tgz", + "integrity": "sha512-mN14niXW43tddohGl8HPu5yfQq70iUThvFL/4QzESA7GcZoC0eVOhvWdQ8+3UlSjaDE9MVtsW9mxDY07W7VpVA==", + "dev": true, + "dependencies": { + "find-cache-dir": "^3.3.2", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0", + "webpack": ">=5" + } + }, + "node_modules/babel-loader/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/babel-loader/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/babel-loader/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "dev": true }, + "node_modules/babel-loader/node_modules/schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/babel-plugin-add-react-displayname": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/babel-plugin-add-react-displayname/-/babel-plugin-add-react-displayname-0.0.5.tgz", + "integrity": "sha512-LY3+Y0XVDYcShHHorshrDbt4KFWL4bSeniCtl4SYZbask+Syngk1uMPCeN9+nSiZo6zX5s0RTq/J9Pnaaf/KHw==", + "dev": true + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/babel-plugin-macros": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", @@ -1982,6 +8605,71 @@ "npm": ">=6" } }, + "node_modules/babel-plugin-named-exports-order": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/babel-plugin-named-exports-order/-/babel-plugin-named-exports-order-0.0.2.tgz", + "integrity": "sha512-OgOYHOLoRK+/mvXU9imKHlG6GkPLYrUCvFXG/CM93R/aNNO8pOOF4aS+S8CCHMDQoNSeiOYEZb/G6RwL95Jktw==", + "dev": true + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz", + "integrity": "sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.17.7", + "@babel/helper-define-polyfill-provider": "^0.3.3", + "semver": "^6.1.1" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.6.0.tgz", + "integrity": "sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.3.3", + "core-js-compat": "^3.25.1" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz", + "integrity": "sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.3.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-plugin-react-docgen": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/babel-plugin-react-docgen/-/babel-plugin-react-docgen-4.2.1.tgz", + "integrity": "sha512-UQ0NmGHj/HAqi5Bew8WvNfCk8wSsmdgNd8ZdMjBCICtyCJCq9LiqgqvjCYe570/Wg7AQArSq1VQ60Dd/CHN7mQ==", + "dev": true, + "dependencies": { + "ast-types": "^0.14.2", + "lodash": "^4.17.15", + "react-docgen": "^5.0.0" + } + }, "node_modules/babel-plugin-styled-components": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/babel-plugin-styled-components/-/babel-plugin-styled-components-2.0.7.tgz", @@ -2017,6 +8705,45 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "node_modules/base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dev": true, + "dependencies": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base/node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/base64-arraybuffer": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", @@ -2045,6 +8772,52 @@ } ] }, + "node_modules/better-opn": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/better-opn/-/better-opn-2.1.1.tgz", + "integrity": "sha512-kIPXZS5qwyKiX/HcRvDYfmBQUa8XP17I0mYZZ0y4UhpYOSvtsLHDYqmomS+Mj20aDvD3knEiQ0ecQy2nhio3yA==", + "dev": true, + "dependencies": { + "open": "^7.0.3" + }, + "engines": { + "node": ">8.0.0" + } + }, + "node_modules/better-opn/node_modules/open": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", + "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==", + "dev": true, + "dependencies": { + "is-docker": "^2.0.0", + "is-wsl": "^2.1.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/big-integer": { + "version": "1.6.51", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", + "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true, + "engines": { + "node": "*" + } + }, "node_modules/binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", @@ -2064,6 +8837,134 @@ "readable-stream": "^3.4.0" } }, + "node_modules/body-parser": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true + }, + "node_modules/boxen": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz", + "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==", + "dev": true, + "dependencies": { + "ansi-align": "^3.0.0", + "camelcase": "^6.2.0", + "chalk": "^4.1.0", + "cli-boxes": "^2.2.1", + "string-width": "^4.2.2", + "type-fest": "^0.20.2", + "widest-line": "^3.1.0", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/boxen/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/boxen/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/boxen/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/boxen/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/boxen/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/bplist-parser": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.2.0.tgz", + "integrity": "sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw==", + "dev": true, + "dependencies": { + "big-integer": "^1.6.44" + }, + "engines": { + "node": ">= 5.10.0" + } + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -2086,10 +8987,17 @@ "node": ">=8" } }, + "node_modules/browser-assert": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/browser-assert/-/browser-assert-1.2.1.tgz", + "integrity": "sha512-nfulgvOR6S4gt9UKCeGJOuSGBPGiFT6oQ/2UBnvTY/5aQ1PnksW72fhZkM30DzoRRv2WpwZf1vHHEr3mtuXIWQ==", + "dev": true + }, "node_modules/browserslist": { - "version": "4.21.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.3.tgz", - "integrity": "sha512-898rgRXLAyRkM1GryrrBHGkqA5hlpkV5MhtZwg9QXeiyLUYs2k00Un05aX5l2/yJIOObYKOpS2JNo8nJDE7fWQ==", + "version": "4.21.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", + "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", + "dev": true, "funding": [ { "type": "opencollective", @@ -2101,10 +9009,10 @@ } ], "dependencies": { - "caniuse-lite": "^1.0.30001370", - "electron-to-chromium": "^1.4.202", + "caniuse-lite": "^1.0.30001400", + "electron-to-chromium": "^1.4.251", "node-releases": "^2.0.6", - "update-browserslist-db": "^1.0.5" + "update-browserslist-db": "^1.0.9" }, "bin": { "browserslist": "cli.js" @@ -2113,6 +9021,15 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "dependencies": { + "node-int64": "^0.4.0" + } + }, "node_modules/btoa": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/btoa/-/btoa-1.2.1.tgz", @@ -2147,11 +9064,84 @@ "ieee754": "^1.1.13" } }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true, + "engines": { + "node": "*" + } + }, "node_modules/buffer-from": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-0.1.2.tgz", "integrity": "sha512-RiWIenusJsmI2KcvqQABB83tLxCByE3upSP8QU3rJDMVFGPWLvPQJt/O1Su9moRWeH7d+Q2HYb68f6+v+tw2vg==" }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/c8": { + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/c8/-/c8-7.12.0.tgz", + "integrity": "sha512-CtgQrHOkyxr5koX1wEUmN/5cfDa2ckbHRA4Gy5LAL0zaCFtVWJS5++n+w4/sr2GWGerBxgTjpKeDclk/Qk6W/A==", + "dev": true, + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@istanbuljs/schema": "^0.1.3", + "find-up": "^5.0.0", + "foreground-child": "^2.0.0", + "istanbul-lib-coverage": "^3.2.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-reports": "^3.1.4", + "rimraf": "^3.0.2", + "test-exclude": "^6.0.0", + "v8-to-istanbul": "^9.0.0", + "yargs": "^16.2.0", + "yargs-parser": "^20.2.9" + }, + "bin": { + "c8": "bin/c8.js" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dev": true, + "dependencies": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cache-base/node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/call-bind": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", @@ -2173,6 +9163,25 @@ "node": ">=6" } }, + "node_modules/camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "dev": true, + "dependencies": { + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/camelcase-css": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", @@ -2221,6 +9230,15 @@ "node": ">=10.0.0" } }, + "node_modules/case-sensitive-paths-webpack-plugin": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.4.0.tgz", + "integrity": "sha512-roIFONhcxog0JSSWbvVAh3OocukmSgpqOH6YpMkCvav/ySIV3JKg4Dc8vYtQjYi/UxpNE36r/9v+VqTQqgkYmw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -2287,6 +9305,30 @@ "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" }, + "node_modules/chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "dev": true, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/ci-info": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.7.1.tgz", + "integrity": "sha512-4jYS4MOAaCIStSRwiuxc4B8MYhIe676yO1sYGzARnjXkWpmzZMMYxY6zu8WYWDhSuth5zhrQ1rhNSibyyvv4/w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, "node_modules/cipher-base": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", @@ -2296,11 +9338,227 @@ "safe-buffer": "^5.0.1" } }, + "node_modules/class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dev": true, + "dependencies": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "dev": true, + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/is-accessor-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "node_modules/class-utils/node_modules/is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/is-data-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/classnames": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz", "integrity": "sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA==" }, + "node_modules/clean-css": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.1.tgz", + "integrity": "sha512-lCr8OHhiWCTw4v8POJovCoh4T7I9U11yVsPjMWWnnMmp9ZowCxyad1Pathle/9HjaDp+fdQKjO9fQydE6RHTZg==", + "dev": true, + "dependencies": { + "source-map": "~0.6.0" + }, + "engines": { + "node": ">= 10.0" + } + }, + "node_modules/clean-css/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-boxes": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", + "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-table3": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.3.tgz", + "integrity": "sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0" + }, + "engines": { + "node": "10.* || >= 12.*" + }, + "optionalDependencies": { + "@colors/colors": "1.5.0" + } + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/clone-deep/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/clone-deep/node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/clsx": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", @@ -2309,6 +9567,19 @@ "node": ">=6" } }, + "node_modules/collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==", + "dev": true, + "dependencies": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/color": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", @@ -2346,6 +9617,21 @@ "simple-swizzle": "^0.2.2" } }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "dev": true, + "bin": { + "color-support": "bin.js" + } + }, + "node_modules/colorette": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz", + "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==", + "dev": true + }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -2366,12 +9652,168 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "dev": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/common-path-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", + "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==", + "dev": true + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "dev": true + }, + "node_modules/component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", + "dev": true + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dev": true, + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dev": true, + "dependencies": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/compression/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, + "node_modules/concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, + "engines": [ + "node >= 0.8" + ], + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/concat-stream/node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/concat-stream/node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/concat-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/concat-stream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/confusing-browser-globals": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz", + "integrity": "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==", + "dev": true + }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", + "dev": true + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dev": true, + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/convert-source-map": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", @@ -2385,6 +9827,21 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, + "node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "dev": true + }, "node_modules/cookies": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/cookies/-/cookies-0.8.0.tgz", @@ -2397,21 +9854,42 @@ "node": ">= 0.8" } }, + "node_modules/copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/core-js": { "version": "3.26.0", "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.26.0.tgz", "integrity": "sha512-+DkDrhoR4Y0PxDz6rurahuB+I45OsEUv8E1maPTB6OuHRohMMcznBq9TMpdpDMm/hUPob/mJJS3PqgbHpMTQgw==", "hasInstallScript": true, - "optional": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-js-compat": { + "version": "3.27.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.27.1.tgz", + "integrity": "sha512-Dg91JFeCDA17FKnneN7oCMz4BkQ4TcffkgHP4OWwp9yx3pi7ubqMDXXSacfNak1PQqjc95skyt+YBLHQJnkJwA==", + "dev": true, + "dependencies": { + "browserslist": "^4.21.4" + }, "funding": { "type": "opencollective", "url": "https://opencollective.com/core-js" } }, "node_modules/core-js-pure": { - "version": "3.26.1", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.26.1.tgz", - "integrity": "sha512-VVXcDpp/xJ21KdULRq/lXdLzQAtX7+37LzpyfFM973il0tWSsDEoyzG38G14AjTpK9VTfiNM9jnFauq/CpaWGQ==", + "version": "3.27.1", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.27.1.tgz", + "integrity": "sha512-BS2NHgwwUppfeoqOXqi08mUqS5FiZpuRuJJpKsaME7kJz0xxuk0xkhDdfMIlP/zLa80krBqss1LtD7f889heAw==", "dev": true, "hasInstallScript": true, "funding": { @@ -2439,6 +9917,14 @@ "node": ">=10" } }, + "node_modules/cosmiconfig/node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "engines": { + "node": ">= 6" + } + }, "node_modules/create-hash": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", @@ -2465,6 +9951,15 @@ "node": ">= 8" } }, + "node_modules/crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/css-box-model": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/css-box-model/-/css-box-model-1.2.1.tgz", @@ -2490,6 +9985,72 @@ "utrie": "^1.0.2" } }, + "node_modules/css-loader": { + "version": "6.7.3", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.7.3.tgz", + "integrity": "sha512-qhOH1KlBMnZP8FzRO6YCH9UHXQhVMcEGLyNdb7Hv2cpcmJbW0YrddO+tG1ab5nT41KpHIYGsbeHqxB9xPu1pKQ==", + "dev": true, + "dependencies": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.19", + "postcss-modules-extract-imports": "^3.0.0", + "postcss-modules-local-by-default": "^4.0.0", + "postcss-modules-scope": "^3.0.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.3.8" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/css-loader/node_modules/postcss": { + "version": "8.4.21", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz", + "integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + } + ], + "dependencies": { + "nanoid": "^3.3.4", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, "node_modules/css-to-react-native": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.0.0.tgz", @@ -2500,6 +10061,18 @@ "postcss-value-parser": "^4.0.2" } }, + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "dev": true, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, "node_modules/cssesc": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", @@ -2517,6 +10090,23 @@ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.0.tgz", "integrity": "sha512-uX1KG+x9h5hIJsaKR9xHUeUraxf8IODOwq9JLNPq6BwB04a/xgpq3rcx47l5BZu5zBPlgD342tdke3Hom/nJRA==" }, + "node_modules/cva": { + "name": "class-variance-authority", + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.4.0.tgz", + "integrity": "sha512-74enNN8O9ZNieycac/y8FxqgyzZhZbxmCitAtAeUrLPlxjSd5zA7LfpprmxEcOmQBnaGs5hYhiSGnJ0mqrtBLQ==", + "funding": { + "url": "https://joebell.co.uk" + }, + "peerDependencies": { + "typescript": ">= 4.5.5 < 5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "node_modules/damerau-levenshtein": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", @@ -2565,6 +10155,55 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", + "dev": true + }, + "node_modules/deep-equal": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.0.tgz", + "integrity": "sha512-RdpzE0Hv4lhowpIUKKMJfeH6C1pXdtT1/it80ubgWqwI3qpuxUBpC1S4hnHg+zjnuOoDkzUtUCEEkG+XG5l3Mw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "es-get-iterator": "^1.1.2", + "get-intrinsic": "^1.1.3", + "is-arguments": "^1.1.1", + "is-array-buffer": "^3.0.1", + "is-date-object": "^1.0.5", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "isarray": "^2.0.5", + "object-is": "^1.1.5", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.4.3", + "side-channel": "^1.0.4", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.9" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/deep-equal/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, + "node_modules/deep-equal/node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/deep-extend": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", @@ -2579,6 +10218,31 @@ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, + "node_modules/deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/default-browser-id": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-3.0.0.tgz", + "integrity": "sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA==", + "dev": true, + "dependencies": { + "bplist-parser": "^0.2.0", + "untildify": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/define-lazy-prop": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", @@ -2613,12 +10277,62 @@ "node": ">= 0.4" } }, + "node_modules/define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/define-property/node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/defined": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", "integrity": "sha512-Y2caI5+ZwS5c3RiNDJ6u53VhQHv+hHKwhkI1iHvceKUHw9Df6EK2zRLfjejRgMuCuxK7PfSWIMwWecceVvThjQ==", "dev": true }, + "node_modules/defu": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.1.tgz", + "integrity": "sha512-aA964RUCsBt0FGoNIlA3uFgo2hO+WWC0fiC6DBps/0SFzkKcYoM/3CzVLIa5xSsrFjdioMdYgAIbwo80qp2MoA==", + "dev": true + }, + "node_modules/del": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/del/-/del-6.1.1.tgz", + "integrity": "sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg==", + "dev": true, + "dependencies": { + "globby": "^11.0.1", + "graceful-fs": "^4.2.4", + "is-glob": "^4.0.1", + "is-path-cwd": "^2.2.0", + "is-path-inside": "^3.0.2", + "p-map": "^4.0.0", + "rimraf": "^3.0.2", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -2627,6 +10341,12 @@ "node": ">=0.4.0" } }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "dev": true + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -2643,6 +10363,25 @@ "node": ">=6" } }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "dev": true, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-indent": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", + "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/detect-libc": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz", @@ -2651,6 +10390,60 @@ "node": ">=8" } }, + "node_modules/detect-node-es": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", + "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==" + }, + "node_modules/detect-package-manager": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/detect-package-manager/-/detect-package-manager-2.0.1.tgz", + "integrity": "sha512-j/lJHyoLlWi6G1LDdLgvUtz60Zo5GEj+sVYtTVXnYLDPuzgC3llMxonXym9zIwhhUII8vjdw0LXxavpLqTbl1A==", + "dev": true, + "dependencies": { + "execa": "^5.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/detect-port": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/detect-port/-/detect-port-1.5.1.tgz", + "integrity": "sha512-aBzdj76lueB6uUst5iAs7+0H/oOjqI5D16XUWxlWMIMROhcM0rfsNVk93zTngq1dDNpoXRr++Sus7ETAExppAQ==", + "dev": true, + "dependencies": { + "address": "^1.0.1", + "debug": "4" + }, + "bin": { + "detect": "bin/detect-port.js", + "detect-port": "bin/detect-port.js" + } + }, + "node_modules/detect-port/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/detect-port/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, "node_modules/detective": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/detective/-/detective-5.2.1.tgz", @@ -2712,12 +10505,122 @@ "node": ">=6.0.0" } }, + "node_modules/dom-accessibility-api": { + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.15.tgz", + "integrity": "sha512-8o+oVqLQZoruQPYy3uAAQtc6YbtSiRq5aPJBhJ82YTJRHvI6ofhYAkC81WmjFTnfUbqg6T3aCglIpU9p/5e7Cw==", + "dev": true + }, + "node_modules/dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", + "dev": true, + "dependencies": { + "utila": "~0.4" + } + }, + "node_modules/dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "dev": true, + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/dom-serializer/node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/dom-walk": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz", + "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==", + "dev": true + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dev": true, + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, "node_modules/dompurify": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.4.1.tgz", "integrity": "sha512-ewwFzHzrrneRjxzmK6oVz/rZn9VWspGFRDb4/rRtIsM1n36t9AKma/ye8syCpcw+XJ25kOK/hOG7t1j2I2yBqA==", "optional": true }, + "node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dev": true, + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "dev": true, + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/dotenv": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.6.0.tgz", + "integrity": "sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/dotenv-expand": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", + "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==", + "dev": true + }, "node_modules/duplexer2": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", @@ -2753,10 +10656,32 @@ "safe-buffer": "~5.1.0" } }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dev": true + }, + "node_modules/ejs": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.8.tgz", + "integrity": "sha512-/sXZeMlhS0ArkfX2Aw780gJzXSMPnKjtspYZv+f3NiKLlubezAHDU5+9xz6gd3/NhG3txQCo6xlglmTS+oTGEQ==", + "dev": true, + "dependencies": { + "jake": "^10.8.5" + }, + "bin": { + "ejs": "bin/cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/electron-to-chromium": { - "version": "1.4.206", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.206.tgz", - "integrity": "sha512-h+Fadt1gIaQ06JaIiyqPsBjJ08fV5Q7md+V8bUvQW/9OvXfL2LRICTz2EcnnCP7QzrFTS6/27MRV6Bl9Yn97zA==" + "version": "1.4.284", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz", + "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==", + "dev": true }, "node_modules/emoji-regex": { "version": "9.2.2", @@ -2764,6 +10689,24 @@ "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", "dev": true }, + "node_modules/emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/end-of-stream": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", @@ -2772,6 +10715,17 @@ "once": "^1.4.0" } }, + "node_modules/endent": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/endent/-/endent-2.1.0.tgz", + "integrity": "sha512-r8VyPX7XL8U01Xgnb1CjZ3XV+z90cXIJ9JPE/R9SEC9vpw2P6CfsRPJmp20DppC5N7ZAMCmjYkJIa744Iyg96w==", + "dev": true, + "dependencies": { + "dedent": "^0.7.0", + "fast-json-parse": "^1.0.3", + "objectorarray": "^1.0.5" + } + }, "node_modules/enhanced-resolve": { "version": "5.12.0", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz", @@ -2796,6 +10750,18 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, + "node_modules/envinfo": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz", + "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==", + "dev": true, + "bin": { + "envinfo": "dist/cli.js" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -2809,6 +10775,15 @@ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" }, + "node_modules/error-stack-parser": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz", + "integrity": "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==", + "dev": true, + "dependencies": { + "stackframe": "^1.3.4" + } + }, "node_modules/es-abstract": { "version": "1.20.4", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.4.tgz", @@ -2856,6 +10831,38 @@ "node": ">= 0.4" } }, + "node_modules/es-get-iterator": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", + "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "has-symbols": "^1.0.3", + "is-arguments": "^1.1.1", + "is-map": "^2.0.2", + "is-set": "^2.0.2", + "is-string": "^1.0.7", + "isarray": "^2.0.5", + "stop-iteration-iterator": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-get-iterator/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, + "node_modules/es-module-lexer": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", + "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", + "dev": true + }, "node_modules/es-shim-unscopables": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", @@ -2882,14 +10889,105 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/es6-object-assign": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es6-object-assign/-/es6-object-assign-1.1.0.tgz", + "integrity": "sha512-MEl9uirslVwqQU369iHNWZXsI8yaZYGg/D65aOgZkeyFJwHYSxilf7rQzXKI7DdDuBPrBXbfk3sl9hJhmd5AUw==", + "dev": true + }, + "node_modules/esbuild": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.16.17.tgz", + "integrity": "sha512-G8LEkV0XzDMNwXKgM0Jwu3nY3lSTwSGY6XbxM9cr9+s0T/qSV1q1JVPBGzm3dcjhCic9+emZDmMffkwgPeOeLg==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.16.17", + "@esbuild/android-arm64": "0.16.17", + "@esbuild/android-x64": "0.16.17", + "@esbuild/darwin-arm64": "0.16.17", + "@esbuild/darwin-x64": "0.16.17", + "@esbuild/freebsd-arm64": "0.16.17", + "@esbuild/freebsd-x64": "0.16.17", + "@esbuild/linux-arm": "0.16.17", + "@esbuild/linux-arm64": "0.16.17", + "@esbuild/linux-ia32": "0.16.17", + "@esbuild/linux-loong64": "0.16.17", + "@esbuild/linux-mips64el": "0.16.17", + "@esbuild/linux-ppc64": "0.16.17", + "@esbuild/linux-riscv64": "0.16.17", + "@esbuild/linux-s390x": "0.16.17", + "@esbuild/linux-x64": "0.16.17", + "@esbuild/netbsd-x64": "0.16.17", + "@esbuild/openbsd-x64": "0.16.17", + "@esbuild/sunos-x64": "0.16.17", + "@esbuild/win32-arm64": "0.16.17", + "@esbuild/win32-ia32": "0.16.17", + "@esbuild/win32-x64": "0.16.17" + } + }, + "node_modules/esbuild-plugin-alias": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/esbuild-plugin-alias/-/esbuild-plugin-alias-0.2.1.tgz", + "integrity": "sha512-jyfL/pwPqaFXyKnj8lP8iLk6Z0m099uXR45aSN8Av1XD4vhvQutxxPzgA2bTcAwQpa1zCXDcWOlhFgyP3GKqhQ==", + "dev": true + }, + "node_modules/esbuild-register": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/esbuild-register/-/esbuild-register-3.4.2.tgz", + "integrity": "sha512-kG/XyTDyz6+YDuyfB9ZoSIOOmgyFCH+xPRtsCa8W85HLRV5Csp+o3jWVbOSHgSLfyLc5DmP+KFDNwty4mEjC+Q==", + "dev": true, + "dependencies": { + "debug": "^4.3.4" + }, + "peerDependencies": { + "esbuild": ">=0.12 <1" + } + }, + "node_modules/esbuild-register/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/esbuild-register/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, "node_modules/escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, "engines": { "node": ">=6" } }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "dev": true + }, "node_modules/escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -2898,14 +10996,97 @@ "node": ">=0.8.0" } }, - "node_modules/eslint": { - "version": "8.29.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.29.0.tgz", - "integrity": "sha512-isQ4EEiyUjZFbEKvEGJKKGBwXtvXX+zJbkVKCgTuB9t/+jUBcy8avhkEwWJecI15BkRkOYmvIM5ynbhRjEkoeg==", + "node_modules/escodegen": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", + "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", "dev": true, "dependencies": { - "@eslint/eslintrc": "^1.3.3", - "@humanwhocodes/config-array": "^0.11.6", + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/escodegen/node_modules/levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "dev": true, + "dependencies": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/escodegen/node_modules/optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "dependencies": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/escodegen/node_modules/prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/escodegen/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/escodegen/node_modules/type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", + "dev": true, + "dependencies": { + "prelude-ls": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint": { + "version": "8.32.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.32.0.tgz", + "integrity": "sha512-nETVXpnthqKPFyuY2FNjz/bEd6nbosRgKbkgS/y1C7LJop96gYHWpiguLecMHQ2XCPxn77DS0P+68WzG6vkZSQ==", + "dev": true, + "dependencies": { + "@eslint/eslintrc": "^1.4.1", + "@humanwhocodes/config-array": "^0.11.8", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", "ajv": "^6.10.0", @@ -2924,7 +11105,7 @@ "file-entry-cache": "^6.0.1", "find-up": "^5.0.0", "glob-parent": "^6.0.2", - "globals": "^13.15.0", + "globals": "^13.19.0", "grapheme-splitter": "^1.0.4", "ignore": "^5.2.0", "import-fresh": "^3.0.0", @@ -2954,6 +11135,70 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint-config-airbnb": { + "version": "19.0.4", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb/-/eslint-config-airbnb-19.0.4.tgz", + "integrity": "sha512-T75QYQVQX57jiNgpF9r1KegMICE94VYwoFQyMGhrvc+lB8YF2E/M/PYDaQe1AJcWaEgqLE+ErXV1Og/+6Vyzew==", + "dev": true, + "dependencies": { + "eslint-config-airbnb-base": "^15.0.0", + "object.assign": "^4.1.2", + "object.entries": "^1.1.5" + }, + "engines": { + "node": "^10.12.0 || ^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^7.32.0 || ^8.2.0", + "eslint-plugin-import": "^2.25.3", + "eslint-plugin-jsx-a11y": "^6.5.1", + "eslint-plugin-react": "^7.28.0", + "eslint-plugin-react-hooks": "^4.3.0" + } + }, + "node_modules/eslint-config-airbnb-base": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-15.0.0.tgz", + "integrity": "sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig==", + "dev": true, + "dependencies": { + "confusing-browser-globals": "^1.0.10", + "object.assign": "^4.1.2", + "object.entries": "^1.1.5", + "semver": "^6.3.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "peerDependencies": { + "eslint": "^7.32.0 || ^8.2.0", + "eslint-plugin-import": "^2.25.2" + } + }, + "node_modules/eslint-config-airbnb-base/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-config-airbnb-typescript": { + "version": "17.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-typescript/-/eslint-config-airbnb-typescript-17.0.0.tgz", + "integrity": "sha512-elNiuzD0kPAPTXjFWg+lE24nMdHMtuxgYoD30OyMD6yrW1AhFZPAg27VX7d3tzOErw+dgJTNWfRSDqEcXb4V0g==", + "dev": true, + "dependencies": { + "eslint-config-airbnb-base": "^15.0.0" + }, + "peerDependencies": { + "@typescript-eslint/eslint-plugin": "^5.13.0", + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^7.32.0 || ^8.2.0", + "eslint-plugin-import": "^2.25.3" + } + }, "node_modules/eslint-config-next": { "version": "13.0.5", "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-13.0.5.tgz", @@ -2980,14 +11225,27 @@ } } }, + "node_modules/eslint-config-prettier": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.6.0.tgz", + "integrity": "sha512-bAF0eLpLVqP5oEVUFKpMA+NnRFICwn9X8B5jrR9FcqnYBuPbqWEjTEspPWMj5ye6czoSLDweCzSo3Ko7gGrZaA==", + "dev": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, "node_modules/eslint-import-resolver-node": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", - "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz", + "integrity": "sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==", "dev": true, "dependencies": { "debug": "^3.2.7", - "resolve": "^1.20.0" + "is-core-module": "^2.11.0", + "resolve": "^1.22.1" } }, "node_modules/eslint-import-resolver-node/node_modules/debug": { @@ -3117,23 +11375,25 @@ "dev": true }, "node_modules/eslint-plugin-import": { - "version": "2.26.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz", - "integrity": "sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==", + "version": "2.27.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.27.4.tgz", + "integrity": "sha512-Z1jVt1EGKia1X9CnBCkpAOhWy8FgQ7OmJ/IblEkT82yrFU/xJaxwujaTzLWqigewwynRQ9mmHfX9MtAfhxm0sA==", "dev": true, "dependencies": { - "array-includes": "^3.1.4", - "array.prototype.flat": "^1.2.5", - "debug": "^2.6.9", + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "array.prototype.flatmap": "^1.3.0", + "debug": "^3.2.7", "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.6", - "eslint-module-utils": "^2.7.3", + "eslint-import-resolver-node": "^0.3.7", + "eslint-module-utils": "^2.7.4", "has": "^1.0.3", - "is-core-module": "^2.8.1", + "is-core-module": "^2.11.0", "is-glob": "^4.0.3", "minimatch": "^3.1.2", - "object.values": "^1.1.5", - "resolve": "^1.22.0", + "object.values": "^1.1.6", + "resolve": "^1.22.1", + "semver": "^6.3.0", "tsconfig-paths": "^3.14.1" }, "engines": { @@ -3143,6 +11403,15 @@ "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" } }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, "node_modules/eslint-plugin-import/node_modules/doctrine": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", @@ -3155,24 +11424,42 @@ "node": ">=0.10.0" } }, + "node_modules/eslint-plugin-import/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/eslint-plugin-import/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/eslint-plugin-jsx-a11y": { - "version": "6.6.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.6.1.tgz", - "integrity": "sha512-sXgFVNHiWffBq23uiS/JaP6eVR622DqwB4yTzKvGZGcPq6/yZ3WmOZfuBks/vHWo9GaFOqC2ZK4i6+C35knx7Q==", + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.7.1.tgz", + "integrity": "sha512-63Bog4iIethyo8smBklORknVjB0T2dwB8Mr/hIC+fBS0uyHdYYpzM/Ed+YC8VxTjlXHEWFOdmgwcDn1U2L9VCA==", "dev": true, "dependencies": { - "@babel/runtime": "^7.18.9", - "aria-query": "^4.2.2", - "array-includes": "^3.1.5", + "@babel/runtime": "^7.20.7", + "aria-query": "^5.1.3", + "array-includes": "^3.1.6", + "array.prototype.flatmap": "^1.3.1", "ast-types-flow": "^0.0.7", - "axe-core": "^4.4.3", - "axobject-query": "^2.2.0", + "axe-core": "^4.6.2", + "axobject-query": "^3.1.1", "damerau-levenshtein": "^1.0.8", "emoji-regex": "^9.2.2", "has": "^1.0.3", - "jsx-ast-utils": "^3.3.2", - "language-tags": "^1.0.5", + "jsx-ast-utils": "^3.3.3", + "language-tags": "=1.0.5", "minimatch": "^3.1.2", + "object.entries": "^1.1.6", + "object.fromentries": "^2.0.6", "semver": "^6.3.0" }, "engines": { @@ -3191,10 +11478,31 @@ "semver": "bin/semver.js" } }, + "node_modules/eslint-plugin-prettier": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz", + "integrity": "sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==", + "dev": true, + "dependencies": { + "prettier-linter-helpers": "^1.0.0" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "eslint": ">=7.28.0", + "prettier": ">=2.0.0" + }, + "peerDependenciesMeta": { + "eslint-config-prettier": { + "optional": true + } + } + }, "node_modules/eslint-plugin-react": { - "version": "7.31.11", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.31.11.tgz", - "integrity": "sha512-TTvq5JsT5v56wPa9OYHzsrOlHzKZKjV+aLgS+55NJP/cuzdiQPC7PfYoUjMoxlffKtvijpk7vA/jmuqRb9nohw==", + "version": "7.32.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.32.0.tgz", + "integrity": "sha512-vSBi1+SrPiLZCGvxpiZIa28fMEUaMjXtCplrvxcIxGzmFiYdsXQDwInEjuv5/i/2CTTxbkS87tE8lsQ0Qxinbw==", "dev": true, "dependencies": { "array-includes": "^3.1.6", @@ -3209,7 +11517,7 @@ "object.hasown": "^1.1.2", "object.values": "^1.1.6", "prop-types": "^15.8.1", - "resolve": "^2.0.0-next.3", + "resolve": "^2.0.0-next.4", "semver": "^6.3.0", "string.prototype.matchall": "^4.0.8" }, @@ -3279,6 +11587,33 @@ "eslint": ">=5.0.0" } }, + "node_modules/eslint-plugin-storybook": { + "version": "0.6.10", + "resolved": "https://registry.npmjs.org/eslint-plugin-storybook/-/eslint-plugin-storybook-0.6.10.tgz", + "integrity": "sha512-3DKXRey06EhwnTKaG6fgMqGTy4C3z6Ikyv6VVixO5BvaExWQe3yGWIAufrC2Et0OaAMIaMwx9KWjqb/Wq+JxPg==", + "dev": true, + "dependencies": { + "@storybook/csf": "^0.0.1", + "@typescript-eslint/utils": "^5.45.0", + "requireindex": "^1.1.0", + "ts-dedent": "^2.2.0" + }, + "engines": { + "node": "12.x || 14.x || >= 16" + }, + "peerDependencies": { + "eslint": ">=6" + } + }, + "node_modules/eslint-plugin-storybook/node_modules/@storybook/csf": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/@storybook/csf/-/csf-0.0.1.tgz", + "integrity": "sha512-USTLkZze5gkel8MYCujSRBVIrUQ3YPBrLOx7GNk/0wttvVtlzWXAq9eLbQ4p/NicGxP+3T7KPEMVV//g+yubpw==", + "dev": true, + "dependencies": { + "lodash": "^4.17.15" + } + }, "node_modules/eslint-scope": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", @@ -3395,9 +11730,9 @@ } }, "node_modules/eslint/node_modules/globals": { - "version": "13.18.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.18.0.tgz", - "integrity": "sha512-/mR4KI8Ps2spmoc0Ulu9L7agOF0du1CZNQ3dke8yItYlyKNmGrkONemBbd6V8UTc1Wgcqn21t3WYB7dbRmh6/A==", + "version": "13.19.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz", + "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -3522,6 +11857,20 @@ "node": ">=4.0" } }, + "node_modules/estree-to-babel": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/estree-to-babel/-/estree-to-babel-3.2.1.tgz", + "integrity": "sha512-YNF+mZ/Wu2FU/gvmzuWtYc8rloubL7wfXCTgouFrnjGVXPA/EeYYA7pupXWrb3Iv1cTBeSSxxJIbK23l4MRNqg==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.1.6", + "@babel/types": "^7.2.0", + "c8": "^7.6.0" + }, + "engines": { + "node": ">=8.3.0" + } + }, "node_modules/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -3531,11 +11880,159 @@ "node": ">=0.10.0" } }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/eventemitter3": { "version": "4.0.7", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==", + "dev": true, + "dependencies": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "dev": true, + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/is-accessor-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "node_modules/expand-brackets/node_modules/is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/is-data-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/expand-template": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", @@ -3544,6 +12041,54 @@ "node": ">=6" } }, + "node_modules/expect-type": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-0.14.2.tgz", + "integrity": "sha512-ed3+tr5ujbIYXZ8Pl/VgIphwJQ0q5tBLGGdn7Zvwt1WyPBRX83xjT5pT77P/GkuQbctx0K2ZNSSan7eruJqTCQ==", + "dev": true + }, + "node_modules/express": { + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "dev": true, + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, "node_modules/extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -3560,16 +12105,68 @@ "node": ">=0.10.0" } }, + "node_modules/extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "dependencies": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extract-zip": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.7.0.tgz", + "integrity": "sha512-xoh5G1W/PB0/27lXgMQyIhP5DSY/LhoCsOyZgb+6iMmRtCwVBo55uKaMoEYrDCKQhWvqEip5ZPKAc6eFNyf/MA==", + "dev": true, + "dependencies": { + "concat-stream": "^1.6.2", + "debug": "^2.6.9", + "mkdirp": "^0.5.4", + "yauzl": "^2.10.0" + }, + "bin": { + "extract-zip": "cli.js" + } + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true }, + "node_modules/fast-diff": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", + "dev": true + }, "node_modules/fast-glob": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", - "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", "dev": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -3594,6 +12191,12 @@ "node": ">= 6" } }, + "node_modules/fast-json-parse": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/fast-json-parse/-/fast-json-parse-1.0.3.tgz", + "integrity": "sha512-FRWsaZRWEJ1ESVNbDWmsAlqDk96gPQezzLghafp5J4GUKjbCz3OkAHuZs5TuPEtkbVQERysLp9xv6c24fBm8Aw==", + "dev": true + }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -3615,6 +12218,30 @@ "reusify": "^1.0.4" } }, + "node_modules/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "dev": true, + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "dev": true, + "dependencies": { + "pend": "~1.2.0" + } + }, + "node_modules/fetch-retry": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/fetch-retry/-/fetch-retry-5.0.3.tgz", + "integrity": "sha512-uJQyMrX5IJZkhoEUBQ3EjxkeiZkppBd5jS/fMTJmfZxLSiaQjv2zD0kTvuvkSH89uFvgSlB6ueGpjD3HWN7Bxw==", + "dev": true + }, "node_modules/fflate": { "version": "0.4.8", "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.4.8.tgz", @@ -3632,6 +12259,60 @@ "node": "^10.12.0 || >=12.0.0" } }, + "node_modules/file-system-cache": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/file-system-cache/-/file-system-cache-2.0.2.tgz", + "integrity": "sha512-lp4BHO4CWqvRyx88Tt3quZic9ZMf4cJyquYq7UI8sH42Bm2ArlBBjKQAalZOo+UfaBassb7X123Lik5qZ/tSAA==", + "dev": true, + "dependencies": { + "fs-extra": "^11.1.0", + "ramda": "^0.28.0" + } + }, + "node_modules/file-system-cache/node_modules/fs-extra": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.0.tgz", + "integrity": "sha512-0rcTq621PD5jM/e0a3EJoGC/1TC5ZBCERW82LQuwfGnCa1V8w7dpYH1yNu+SLb6E5dkeCBzKEyLGlFrnr+dUyw==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/filelist": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", + "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", + "dev": true, + "dependencies": { + "minimatch": "^5.0.1" + } + }, + "node_modules/filelist/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/filelist/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -3652,6 +12333,105 @@ "node": ">=0.10.0" } }, + "node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "dev": true, + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + } + }, + "node_modules/find-cache-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-cache-dir/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-cache-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-cache-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-cache-dir/node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/find-root": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", @@ -3692,6 +12472,15 @@ "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "dev": true }, + "node_modules/flow-parser": { + "version": "0.197.0", + "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.197.0.tgz", + "integrity": "sha512-yhwkJPxH1JBg0aJunk/jVRy5p3UhVZBGkzL1hq/GK+GaBh6bKr2YKkv6gDuiufaw+i3pKWQgOLtD++1cvrgXLA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/follow-redirects": { "version": "1.15.1", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz", @@ -3711,6 +12500,137 @@ } } }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/foreground-child": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", + "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/fork-ts-checker-webpack-plugin": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-7.3.0.tgz", + "integrity": "sha512-IN+XTzusCjR5VgntYFgxbxVx3WraPRnKehBFrf00cMSrtUuW9MsG9dhL6MWpY6MkjC3wVwoujfCDgZZCQwbswA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.16.7", + "chalk": "^4.1.2", + "chokidar": "^3.5.3", + "cosmiconfig": "^7.0.1", + "deepmerge": "^4.2.2", + "fs-extra": "^10.0.0", + "memfs": "^3.4.1", + "minimatch": "^3.0.4", + "node-abort-controller": "^3.0.1", + "schema-utils": "^3.1.1", + "semver": "^7.3.5", + "tapable": "^2.2.1" + }, + "engines": { + "node": ">=12.13.0", + "yarn": ">=1.0.0" + }, + "peerDependencies": { + "typescript": ">3.6.0", + "vue-template-compiler": "*", + "webpack": "^5.11.0" + }, + "peerDependenciesMeta": { + "vue-template-compiler": { + "optional": true + } + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/form-data": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", @@ -3724,6 +12644,15 @@ "node": ">= 6" } }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/fraction.js": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz", @@ -3737,6 +12666,27 @@ "url": "https://www.patreon.com/infusion" } }, + "node_modules/fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==", + "dev": true, + "dependencies": { + "map-cache": "^0.2.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/fs": { "version": "0.0.1-security", "resolved": "https://registry.npmjs.org/fs/-/fs-0.0.1-security.tgz", @@ -3747,6 +12697,51 @@ "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" }, + "node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fs-monkey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.3.tgz", + "integrity": "sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q==", + "dev": true + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -3799,15 +12794,44 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/gauge": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", + "dev": true, + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "peer": true, + "dev": true, "engines": { "node": ">=6.9.0" } }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, "node_modules/get-intrinsic": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", @@ -3822,6 +12846,47 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-nonce": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", + "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", + "engines": { + "node": ">=6" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-port": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-5.1.1.tgz", + "integrity": "sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/get-symbol-description": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", @@ -3847,16 +12912,44 @@ "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" } }, - "node_modules/github-buttons": { - "version": "2.22.0", - "resolved": "https://registry.npmjs.org/github-buttons/-/github-buttons-2.22.0.tgz", - "integrity": "sha512-N5bk01s1WgK1FVtoeSUVkRkJpkaSu8yHMPcjye+PTa0jsRjMRNrYqVLgpUf2RA5Kvec05DfHYAT6/68fwkdqPw==" + "node_modules/get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/giget": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/giget/-/giget-1.0.0.tgz", + "integrity": "sha512-KWELZn3Nxq5+0So485poHrFriK9Bn3V/x9y+wgqrHkbmnGbjfLmZ685/SVA/ovW+ewoqW0gVI47pI4yW/VNobQ==", + "dev": true, + "dependencies": { + "colorette": "^2.0.19", + "defu": "^6.1.1", + "https-proxy-agent": "^5.0.1", + "mri": "^1.2.0", + "node-fetch-native": "^1.0.1", + "pathe": "^1.0.0", + "tar": "^6.1.12" + }, + "bin": { + "giget": "dist/cli.mjs" + } }, "node_modules/github-from-package": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==" }, + "node_modules/github-slugger": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-1.5.0.tgz", + "integrity": "sha512-wIh+gKBI9Nshz2o46B0B3f5k/W+WI9ZAv6y5Dn5WJ5SK1t0TnDimB4WE5rmTD05ZAIn8HALCZVmCsvj0w0v0lw==", + "dev": true + }, "node_modules/glob": { "version": "7.1.7", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", @@ -3889,6 +12982,22 @@ "node": ">=10.13.0" } }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, + "node_modules/global": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz", + "integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==", + "dev": true, + "dependencies": { + "min-document": "^2.19.0", + "process": "^0.11.10" + } + }, "node_modules/globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", @@ -3929,6 +13038,18 @@ "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==", "dev": true }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/graceful-fs": { "version": "4.2.10", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", @@ -3955,6 +13076,36 @@ "node": ">=6.0" } }, + "node_modules/handlebars": { + "version": "4.7.7", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", + "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.0", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/handlebars/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -4022,6 +13173,90 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "dev": true + }, + "node_modules/has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==", + "dev": true, + "dependencies": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-value/node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==", + "dev": true, + "dependencies": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values/node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "node_modules/has-values/node_modules/is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values/node_modules/is-number/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values/node_modules/kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/hash-base": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", @@ -4044,6 +13279,15 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, "node_modules/hoist-non-react-statics": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", @@ -4052,6 +13296,65 @@ "react-is": "^16.7.0" } }, + "node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "node_modules/html-entities": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.3.tgz", + "integrity": "sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==", + "dev": true + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "node_modules/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", + "dev": true, + "dependencies": { + "camel-case": "^4.1.2", + "clean-css": "^5.2.2", + "commander": "^8.3.0", + "he": "^1.2.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.10.0" + }, + "bin": { + "html-minifier-terser": "cli.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/html-parse-stringify": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz", + "integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==", + "dependencies": { + "void-elements": "3.1.0" + } + }, + "node_modules/html-tags": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.2.0.tgz", + "integrity": "sha512-vy7ClnArOZwCnqZgvv+ddgHgJiAFXe3Ge9ML5/mBctVJoUoYPCdxVucOywjDARn6CVoh3dRSFdPHy2sX80L0Wg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/html-tokenize": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/html-tokenize/-/html-tokenize-2.0.1.tgz", @@ -4088,6 +13391,29 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==" }, + "node_modules/html-webpack-plugin": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.5.0.tgz", + "integrity": "sha512-sy88PC2cRTVxvETRgUHFrL4No3UxvcH8G1NepGhqaTT+GXN2kTamqasot0inS5hXeg1cMbFDt27zzo9p35lZVw==", + "dev": true, + "dependencies": { + "@types/html-minifier-terser": "^6.0.0", + "html-minifier-terser": "^6.0.2", + "lodash": "^4.17.21", + "pretty-error": "^4.0.0", + "tapable": "^2.0.0" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/html-webpack-plugin" + }, + "peerDependencies": { + "webpack": "^5.20.0" + } + }, "node_modules/html2canvas": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz", @@ -4101,6 +13427,50 @@ "node": ">=8.0.0" } }, + "node_modules/htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "dev": true, + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + } + }, + "node_modules/htmlparser2/node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/http-proxy": { "version": "1.18.1", "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", @@ -4114,6 +13484,102 @@ "node": ">=8.0.0" } }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/https-proxy-agent/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/https-proxy-agent/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/i18next": { + "version": "22.4.6", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-22.4.6.tgz", + "integrity": "sha512-9Tm1ezxWyzV+306CIDMBbYBitC1jedQyYuuLtIv7oxjp2ohh8eyxP9xytIf+2bbQfhH784IQKPSYp+Zq9+YSbw==", + "funding": [ + { + "type": "individual", + "url": "https://locize.com" + }, + { + "type": "individual", + "url": "https://locize.com/i18next.html" + }, + { + "type": "individual", + "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project" + } + ], + "dependencies": { + "@babel/runtime": "^7.20.6" + } + }, + "node_modules/i18next-fs-backend": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/i18next-fs-backend/-/i18next-fs-backend-2.1.1.tgz", + "integrity": "sha512-FTnj+UmNgT3YRml5ruRv0jMZDG7odOL/OP5PF5mOqvXud2vHrPOOs68Zdk6iqzL47cnnM0ZVkK2BAvpFeDJToA==" + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, "node_modules/ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", @@ -4142,6 +13608,21 @@ "node": ">= 4" } }, + "node_modules/image-size": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.0.2.tgz", + "integrity": "sha512-xfOoWjceHntRb3qFCrh5ZFORYH8XCdYpASltMhZ/Q0KZiOwjdE/Yl2QCiWdwD+lygV5bMCvauzgu5PxBX/Yerg==", + "dev": true, + "dependencies": { + "queue": "6.0.2" + }, + "bin": { + "image-size": "bin/image-size.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/immer": { "version": "9.0.15", "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.15.tgz", @@ -4175,6 +13656,15 @@ "node": ">=0.8.19" } }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -4201,12 +13691,12 @@ "integrity": "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==" }, "node_modules/internal-slot": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.4.tgz", + "integrity": "sha512-tA8URYccNzMo94s5MQZgH8NB/XTa6HsOo0MLfXTKKEnHVVdegzaQoFZ7Jp44bdvLvY2waT5dc+j5ICEswhi7UQ==", "dev": true, "dependencies": { - "get-intrinsic": "^1.1.0", + "get-intrinsic": "^1.1.3", "has": "^1.0.3", "side-channel": "^1.0.4" }, @@ -4214,6 +13704,89 @@ "node": ">= 0.4" } }, + "node_modules/interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, + "node_modules/ip": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", + "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==", + "dev": true + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-absolute-url": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-3.0.3.tgz", + "integrity": "sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.1.tgz", + "integrity": "sha512-ASfLknmY8Xa2XtB4wmbz13Wu202baeA18cJBCeCy0wXUHZF0IPyVEXqKEcd+t2fNSLLL1vC6k7lxZEojNbISXQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-typed-array": "^1.1.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-arrayish": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", @@ -4304,6 +13877,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-date-object": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", @@ -4319,6 +13904,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-docker": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", @@ -4351,6 +13950,36 @@ "node": ">=0.10.0" } }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-function": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.2.tgz", + "integrity": "sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ==", + "dev": true + }, + "node_modules/is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -4363,6 +13992,31 @@ "node": ">=0.10.0" } }, + "node_modules/is-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", + "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-nan": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/is-nan/-/is-nan-1.3.2.tgz", + "integrity": "sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-negative-zero": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", @@ -4399,6 +14053,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-path-cwd": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", + "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/is-path-inside": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", @@ -4419,6 +14082,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -4435,6 +14107,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-set": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", + "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-shared-array-buffer": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", @@ -4447,6 +14128,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-string": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", @@ -4477,6 +14170,34 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-typed-array": { + "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==", + "dev": true, + "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" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakmap": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", + "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-weakref": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", @@ -4489,6 +14210,28 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-weakset": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", + "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-wsl": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", @@ -4512,6 +14255,409 @@ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, + "node_modules/isobject": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-4.0.0.tgz", + "integrity": "sha512-S/2fF5wH8SJA/kmwr6HYhK/RI/OkhD84k8ntalo0iJjZikgq1XFvR5M8NPT1x5F7fBwCG3qHfnzeP/Vh/ZxCUA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isomorphic-unfetch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/isomorphic-unfetch/-/isomorphic-unfetch-3.1.0.tgz", + "integrity": "sha512-geDJjpoZ8N0kWexiwkX8F9NkTsXhetLPVbZFQ+JTW239QNOwvB0gniuR1Wc6f0AMTn7/mFGyXvHTifrCp/GH8Q==", + "dev": true, + "dependencies": { + "node-fetch": "^2.6.1", + "unfetch": "^4.2.0" + } + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dev": true, + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-reports": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", + "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", + "dev": true, + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jake": { + "version": "10.8.5", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.5.tgz", + "integrity": "sha512-sVpxYeuAhWt0OTWITwT98oyV0GsXyMlXCF+3L1SuafBVUIr/uILGRB+NqwkzhgXKvoJpDIpQvqkUALgdmQsQxw==", + "dev": true, + "dependencies": { + "async": "^3.2.3", + "chalk": "^4.0.2", + "filelist": "^1.0.1", + "minimatch": "^3.0.4" + }, + "bin": { + "jake": "bin/cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jake/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jake/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jake/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jake/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-haste-map": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.3.1.tgz", + "integrity": "sha512-/FFtvoG1xjbbPXQLFef+WSU4yrc0fc0Dds6aRPBojUid7qlPqZvxdUBA03HW0fnVHXVCnCdkuoghYItKNzc/0A==", + "dev": true, + "dependencies": { + "@jest/types": "^29.3.1", + "@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.2.0", + "jest-util": "^29.3.1", + "jest-worker": "^29.3.1", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-mock": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz", + "integrity": "sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==", + "dev": true, + "dependencies": { + "@jest/types": "^27.5.1", + "@types/node": "*" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-mock/node_modules/@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-mock/node_modules/@types/yargs": { + "version": "16.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", + "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/jest-mock/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-mock/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-mock/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-mock/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-regex-util": { + "version": "29.2.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.2.0.tgz", + "integrity": "sha512-6yXn0kg2JXzH30cr2NlThF+70iuO/3irbaB4mh5WyqNIvLLP+B6sFdluO1/1RJmslyh/f9osnefECflHvTbwVA==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-util": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.3.1.tgz", + "integrity": "sha512-7YOVZaiX7RJLv76ZfHt4nbNEzzTRiMW/IiOG7ZOKmTXmoGBxUDefgMAxQubu6WPVqP5zSzAdZG0FfLcC7HOIFQ==", + "dev": true, + "dependencies": { + "@jest/types": "^29.3.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-util/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-util/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-util/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-util/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-worker": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.3.1.tgz", + "integrity": "sha512-lY4AnnmsEWeiXirAIA0c9SDPbuCBq8IYuDVL8PMm0MZ2PEs2yPvRA/J64QBXuZp7CYKrDM/rmNrc9/i3KJQncw==", + "dev": true, + "dependencies": { + "@types/node": "*", + "jest-util": "^29.3.1", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, "node_modules/js-sdsl": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.2.0.tgz", @@ -4544,6 +14690,275 @@ "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==" }, + "node_modules/jscodeshift": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/jscodeshift/-/jscodeshift-0.13.1.tgz", + "integrity": "sha512-lGyiEbGOvmMRKgWk4vf+lUrCWO/8YR8sUR3FKF1Cq5fovjZDlIcw3Hu5ppLHAnEXshVffvaM0eyuY/AbOeYpnQ==", + "dev": true, + "dependencies": { + "@babel/core": "^7.13.16", + "@babel/parser": "^7.13.16", + "@babel/plugin-proposal-class-properties": "^7.13.0", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.13.8", + "@babel/plugin-proposal-optional-chaining": "^7.13.12", + "@babel/plugin-transform-modules-commonjs": "^7.13.8", + "@babel/preset-flow": "^7.13.13", + "@babel/preset-typescript": "^7.13.0", + "@babel/register": "^7.13.16", + "babel-core": "^7.0.0-bridge.0", + "chalk": "^4.1.2", + "flow-parser": "0.*", + "graceful-fs": "^4.2.4", + "micromatch": "^3.1.10", + "neo-async": "^2.5.0", + "node-dir": "^0.1.17", + "recast": "^0.20.4", + "temp": "^0.8.4", + "write-file-atomic": "^2.3.0" + }, + "bin": { + "jscodeshift": "bin/jscodeshift.js" + }, + "peerDependencies": { + "@babel/preset-env": "^7.1.6" + } + }, + "node_modules/jscodeshift/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jscodeshift/node_modules/braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "dependencies": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jscodeshift/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jscodeshift/node_modules/fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==", + "dev": true, + "dependencies": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jscodeshift/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jscodeshift/node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "node_modules/jscodeshift/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jscodeshift/node_modules/is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jscodeshift/node_modules/is-number/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jscodeshift/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jscodeshift/node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jscodeshift/node_modules/micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "dependencies": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jscodeshift/node_modules/micromatch/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jscodeshift/node_modules/recast": { + "version": "0.20.5", + "resolved": "https://registry.npmjs.org/recast/-/recast-0.20.5.tgz", + "integrity": "sha512-E5qICoPoNL4yU0H0NoBDntNB0Q5oMSNh9usFctYniLBluTthi3RsQVBXIJNbApOlvSwW/RGxIuokPcAc59J5fQ==", + "dev": true, + "dependencies": { + "ast-types": "0.14.2", + "esprima": "~4.0.0", + "source-map": "~0.6.1", + "tslib": "^2.0.1" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/jscodeshift/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jscodeshift/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jscodeshift/node_modules/to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==", + "dev": true, + "dependencies": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jscodeshift/node_modules/write-file-atomic": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", + "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" + } + }, "node_modules/jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -4573,10 +14988,10 @@ "dev": true }, "node_modules/json5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", - "peer": true, + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, "bin": { "json5": "lib/cli.js" }, @@ -4584,6 +14999,18 @@ "node": ">=6" } }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, "node_modules/jsonp": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/jsonp/-/jsonp-0.2.1.tgz", @@ -4659,6 +15086,15 @@ "node": ">=6" } }, + "node_modules/klona": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz", + "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, "node_modules/language-subtag-registry": { "version": "0.3.22", "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz", @@ -4674,6 +15110,33 @@ "language-subtag-registry": "~0.3.2" } }, + "node_modules/lazy-universal-dotenv": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lazy-universal-dotenv/-/lazy-universal-dotenv-3.0.1.tgz", + "integrity": "sha512-prXSYk799h3GY3iOWnC6ZigYzMPjxN2svgjJ9shk7oMadSNX3wXy0B6F32PMJv7qtMnrIbUxoEHzbutvxR2LBQ==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.5.0", + "app-root-dir": "^1.0.2", + "core-js": "^3.0.4", + "dotenv": "^8.0.0", + "dotenv-expand": "^5.1.0" + }, + "engines": { + "node": ">=6.0.0", + "npm": ">=6.0.0", + "yarn": ">=1.0.0" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -4709,6 +15172,24 @@ "uc.micro": "^1.0.1" } }, + "node_modules/loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "dev": true, + "engines": { + "node": ">=6.11.5" + } + }, + "node_modules/loader-utils": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.1.tgz", + "integrity": "sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw==", + "dev": true, + "engines": { + "node": ">= 12.13.0" + } + }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -4735,6 +15216,12 @@ "integrity": "sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==", "dev": true }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "dev": true + }, "node_modules/lodash.isequal": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", @@ -4763,6 +15250,15 @@ "loose-envify": "cli.js" } }, + "node_modules/lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "dev": true, + "dependencies": { + "tslib": "^2.0.3" + } + }, "node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -4774,6 +15270,75 @@ "node": ">=10" } }, + "node_modules/lz-string": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.4.4.tgz", + "integrity": "sha512-0ckx7ZHRPqb0oUm8zNr+90mtf9DQB60H1wMCjBtfi62Kl3a7JbHob6gA2bC+xRvZoOL+1hzUK8jeuEIQE8svEQ==", + "dev": true, + "bin": { + "lz-string": "bin/bin.js" + } + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/map-or-similar": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/map-or-similar/-/map-or-similar-1.5.0.tgz", + "integrity": "sha512-0aF7ZmVon1igznGI4VS30yugpduQW3y3GkcgGJOp7d8x8QrizhigUxjI/m2UojsXXto+jLAH3KSz+xOJTiORjg==", + "dev": true + }, + "node_modules/map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==", + "dev": true, + "dependencies": { + "object-visit": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/markdown-it": { "version": "13.0.1", "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-13.0.1.tgz", @@ -4794,6 +15359,18 @@ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, + "node_modules/markdown-to-jsx": { + "version": "7.1.8", + "resolved": "https://registry.npmjs.org/markdown-to-jsx/-/markdown-to-jsx-7.1.8.tgz", + "integrity": "sha512-rRSa1aFmFnpDRFAhv5vIkWM4nPaoB9vnzIjuIKa1wGupfn2hdCNeaQHKpu4/muoc8n8J7yowjTP2oncA4/Rbgg==", + "dev": true, + "engines": { + "node": ">= 10" + }, + "peerDependencies": { + "react": ">= 0.14.0" + } + }, "node_modules/md5.js": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", @@ -4877,11 +15454,53 @@ "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==" }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memfs": { + "version": "3.4.13", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.4.13.tgz", + "integrity": "sha512-omTM41g3Skpvx5dSYeZIbXKcXoAVc/AoMNwn9TKx++L/gaen/+4TTttmu8ZSch5vfVJ8uJvGbroTsIlslRg6lg==", + "dev": true, + "dependencies": { + "fs-monkey": "^1.0.3" + }, + "engines": { + "node": ">= 4.0.0" + } + }, "node_modules/memoize-one": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz", "integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==" }, + "node_modules/memoizerific": { + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/memoizerific/-/memoizerific-1.11.3.tgz", + "integrity": "sha512-/EuHYwAPdLtXwAwSZkh/Gutery6pD2KYd44oQLhAvQp/50mpyduZh8Q7PYHXTCJ+wuXxt7oij2LXyIJOOYFPog==", + "dev": true, + "dependencies": { + "map-or-similar": "^1.5.0" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", + "dev": true + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -4891,6 +15510,15 @@ "node": ">= 8" } }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/micromark": { "version": "3.0.10", "resolved": "https://registry.npmjs.org/micromark/-/micromark-3.0.10.tgz", @@ -5347,6 +15975,18 @@ "node": ">=8.6" } }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", @@ -5366,6 +16006,15 @@ "node": ">= 0.6" } }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/mimic-response": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", @@ -5377,6 +16026,24 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/min-document": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz", + "integrity": "sha512-9Wy1B3m3f66bPPmU5hdA4DR4PB2OfDU/+GS3yAB7IQozE3tqXaVv2zOjgla7MEGSRv95+ILmOuvhLkOK6wJtCQ==", + "dev": true, + "dependencies": { + "dom-walk": "^0.1.0" + } + }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -5394,6 +16061,101 @@ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" }, + "node_modules/minipass": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.0.0.tgz", + "integrity": "sha512-g2Uuh2jEKoht+zvO6vJqXmYpflPqzRBT+Th2h01DKh5z7wbY/AZ2gCQ78cP70YoHPyFdY30YBV5WxgLOEwOykw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "dev": true, + "dependencies": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mixin-deep/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mixin-deep/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mixin-deep/node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, "node_modules/mkdirp-classic": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", @@ -5432,6 +16194,74 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "dev": true, + "dependencies": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nanomatch/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nanomatch/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nanomatch/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nanomatch/node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/napi-build-utils": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", @@ -5449,12 +16279,27 @@ "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", "dev": true }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, "node_modules/next": { - "version": "12.3.1", - "resolved": "https://registry.npmjs.org/next/-/next-12.3.1.tgz", - "integrity": "sha512-l7bvmSeIwX5lp07WtIiP9u2ytZMv7jIeB8iacR28PuUEFG5j0HGAPnMqyG5kbZNBG2H7tRsrQ4HCjuMOPnANZw==", + "version": "12.3.4", + "resolved": "https://registry.npmjs.org/next/-/next-12.3.4.tgz", + "integrity": "sha512-VcyMJUtLZBGzLKo3oMxrEF0stxh8HwuW976pAzlHhI3t8qJ4SROjCrSh1T24bhrbjw55wfZXAbXPGwPt5FLRfQ==", "dependencies": { - "@next/env": "12.3.1", + "@next/env": "12.3.4", "@swc/helpers": "0.4.11", "caniuse-lite": "^1.0.30001406", "postcss": "8.4.14", @@ -5468,19 +16313,19 @@ "node": ">=12.22.0" }, "optionalDependencies": { - "@next/swc-android-arm-eabi": "12.3.1", - "@next/swc-android-arm64": "12.3.1", - "@next/swc-darwin-arm64": "12.3.1", - "@next/swc-darwin-x64": "12.3.1", - "@next/swc-freebsd-x64": "12.3.1", - "@next/swc-linux-arm-gnueabihf": "12.3.1", - "@next/swc-linux-arm64-gnu": "12.3.1", - "@next/swc-linux-arm64-musl": "12.3.1", - "@next/swc-linux-x64-gnu": "12.3.1", - "@next/swc-linux-x64-musl": "12.3.1", - "@next/swc-win32-arm64-msvc": "12.3.1", - "@next/swc-win32-ia32-msvc": "12.3.1", - "@next/swc-win32-x64-msvc": "12.3.1" + "@next/swc-android-arm-eabi": "12.3.4", + "@next/swc-android-arm64": "12.3.4", + "@next/swc-darwin-arm64": "12.3.4", + "@next/swc-darwin-x64": "12.3.4", + "@next/swc-freebsd-x64": "12.3.4", + "@next/swc-linux-arm-gnueabihf": "12.3.4", + "@next/swc-linux-arm64-gnu": "12.3.4", + "@next/swc-linux-arm64-musl": "12.3.4", + "@next/swc-linux-x64-gnu": "12.3.4", + "@next/swc-linux-x64-musl": "12.3.4", + "@next/swc-win32-arm64-msvc": "12.3.4", + "@next/swc-win32-ia32-msvc": "12.3.4", + "@next/swc-win32-x64-msvc": "12.3.4" }, "peerDependencies": { "fibers": ">= 3.1.0", @@ -5501,6 +16346,55 @@ } } }, + "node_modules/next-i18next": { + "version": "13.0.2", + "resolved": "https://registry.npmjs.org/next-i18next/-/next-i18next-13.0.2.tgz", + "integrity": "sha512-aUHyKT2kztMgEP44zDB5KoW8XZUQawIdOYWXcrMH6lxAcS0kBsKX0uKMzGS5XlgLW88gvOVc3D7NdfCznLgyyg==", + "funding": [ + { + "type": "individual", + "url": "https://locize.com/i18next.html" + }, + { + "type": "individual", + "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project" + }, + { + "type": "individual", + "url": "https://locize.com" + }, + { + "type": "individual", + "url": "https://github.com/belgattitude" + } + ], + "dependencies": { + "@babel/runtime": "^7.20.6", + "@types/hoist-non-react-statics": "^3.3.1", + "core-js": "^3", + "hoist-non-react-statics": "^3.3.2", + "i18next-fs-backend": "^2.1.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "i18next": "^22.0.6", + "next": ">= 12.0.0", + "react": ">= 17.0.2", + "react-i18next": "^12.1.1" + } + }, + "node_modules/no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "dev": true, + "dependencies": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, "node_modules/node-abi": { "version": "3.30.0", "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.30.0.tgz", @@ -5512,15 +16406,87 @@ "node": ">=10" } }, + "node_modules/node-abort-controller": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.0.1.tgz", + "integrity": "sha512-/ujIVxthRs+7q6hsdjHMaj8hRG9NuWmwrz+JdRwZ14jdFoKSkm+vDsCbF9PLpnSqjaWQJuTmVtcWHNLr+vrOFw==", + "dev": true + }, "node_modules/node-addon-api": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.0.0.tgz", "integrity": "sha512-CvkDw2OEnme7ybCykJpVcKH+uAOLV2qLqiyla128dN9TkEWfrYmxG6C2boDe5KcNQqZF3orkqzGgOMvZ/JNekA==" }, + "node_modules/node-dir": { + "version": "0.1.17", + "resolved": "https://registry.npmjs.org/node-dir/-/node-dir-0.1.17.tgz", + "integrity": "sha512-tmPX422rYgofd4epzrNoOXiE8XFZYOcCq1vD7MAXCDO+O+zndlA2ztdKKMa+EeuBG5tHETpr4ml4RGgpqDCCAg==", + "dev": true, + "dependencies": { + "minimatch": "^3.0.2" + }, + "engines": { + "node": ">= 0.10.5" + } + }, + "node_modules/node-fetch": { + "version": "2.6.8", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.8.tgz", + "integrity": "sha512-RZ6dBYuj8dRSfxpUSu+NsdF1dpPpluJxwOp+6IoDp/sH2QNDSvurYsAa+F1WxY2RjA1iP93xhcsUoYbF2XBqVg==", + "dev": true, + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-fetch-native": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.0.1.tgz", + "integrity": "sha512-VzW+TAk2wE4X9maiKMlT+GsPU4OMmR1U9CrHSmd3DFLn2IcZ9VJ6M6BBugGfYUnPCLSYxXdZy17M0BEJyhUTwg==", + "dev": true + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true + }, "node_modules/node-releases": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", - "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==" + "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", + "dev": true + }, + "node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/normalize-package-data/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } }, "node_modules/normalize-path": { "version": "3.0.0", @@ -5540,6 +16506,42 @@ "node": ">=0.10.0" } }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npmlog": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", + "dev": true, + "dependencies": { + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -5548,6 +16550,97 @@ "node": ">=0.10.0" } }, + "node_modules/object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==", + "dev": true, + "dependencies": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "dev": true, + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "node_modules/object-copy/node_modules/is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/is-descriptor/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/object-hash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", @@ -5566,11 +16659,48 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/object-is": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", + "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/object-keys": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-0.4.0.tgz", "integrity": "sha512-ncrLw+X55z7bkl5PnUvHwFK9FcGuFYo9gtjws2XtSzL+aZ8tm830P60WJ0dSmFVaSalWieW5MD7kEdnXda9yJw==" }, + "node_modules/object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==", + "dev": true, + "dependencies": { + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-visit/node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/object.assign": { "version": "4.1.4", "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", @@ -5642,6 +16772,27 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.pick/node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/object.values": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz", @@ -5659,6 +16810,33 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/objectorarray": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/objectorarray/-/objectorarray-1.0.5.tgz", + "integrity": "sha512-eJJDYkhJFFbBBAxeh8xW+weHlkI28n2ZdQV/J/DNfWfSKlGEf2xcfAbZTv3riEXHAhL9SVOTs2pRmXiSTf78xg==", + "dev": true + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -5667,6 +16845,21 @@ "wrappy": "1" } }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/open": { "version": "8.4.0", "resolved": "https://registry.npmjs.org/open/-/open-8.4.0.tgz", @@ -5731,6 +16924,40 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/param-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "dev": true, + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -5759,6 +16986,40 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "dev": true, + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "dev": true + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -5791,6 +17052,12 @@ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", + "dev": true + }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -5799,6 +17066,18 @@ "node": ">=8" } }, + "node_modules/pathe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.0.0.tgz", + "integrity": "sha512-nPdMG0Pd09HuSsr7QOKUXO2Jr9eqaDiZvDwdyIhNG5SHYujkQHYKDfGQkulBxvbDHz8oHLsTgKN86LSwYzSHAg==", + "dev": true + }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "dev": true + }, "node_modules/performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", @@ -5830,6 +17109,60 @@ "node": ">=0.10.0" } }, + "node_modules/pirates": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", + "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-5.0.0.tgz", + "integrity": "sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA==", + "dev": true, + "dependencies": { + "find-up": "^5.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/pnp-webpack-plugin": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/pnp-webpack-plugin/-/pnp-webpack-plugin-1.7.0.tgz", + "integrity": "sha512-2Rb3vm+EXble/sMXNSu6eoBx8e79gKqhNq9F5ZWW6ERNCTE/Q0wQNne5541tE5vKjfM8hpNCYL+LGc1YTfI0dg==", + "dev": true, + "dependencies": { + "ts-pnp": "^1.1.6" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/polished": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/polished/-/polished-4.2.2.tgz", + "integrity": "sha512-Sz2Lkdxz6F2Pgnpi9U5Ng/WdWAUZxmHrNPoVlm3aAemxoy2Qy7LGjQg4uf8qKelDAUW94F4np3iH2YPf2qefcQ==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.17.8" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/postcss": { "version": "8.4.14", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", @@ -5918,13 +17251,103 @@ } } }, - "node_modules/postcss-nested": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-5.0.6.tgz", - "integrity": "sha512-rKqm2Fk0KbA8Vt3AdGN0FB9OBOMDVajMG6ZCf/GoHgdxUJ4sBFp0A/uMIRm+MJUdo33YXEtjqIz8u7DAp8B7DA==", + "node_modules/postcss-load-config/node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/postcss-loader": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-6.2.1.tgz", + "integrity": "sha512-WbbYpmAaKcux/P66bZ40bpWsBucjx/TTgVVzRZ9yUO8yQfVBlameJ0ZGVaPfH64hNSBh63a+ICP5nqOpBA0w+Q==", "dev": true, "dependencies": { - "postcss-selector-parser": "^6.0.6" + "cosmiconfig": "^7.0.0", + "klona": "^2.0.5", + "semver": "^7.3.5" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "postcss": "^7.0.0 || ^8.0.1", + "webpack": "^5.0.0" + } + }, + "node_modules/postcss-modules-extract-imports": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", + "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-local-by-default": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz", + "integrity": "sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ==", + "dev": true, + "dependencies": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-scope": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz", + "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.4" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "dev": true, + "dependencies": { + "icss-utils": "^5.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-nested": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.0.tgz", + "integrity": "sha512-0DkamqrPcmkBDsLn+vQDIrtkSbNkv5AD/M322ySo9kqFkCIYklym2xEmWkwo+Y3/qZo34tzEPNUw4y7yMCdv5w==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.10" }, "engines": { "node": ">=12.0" @@ -6000,9 +17423,9 @@ } }, "node_modules/prettier": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz", - "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==", + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.3.tgz", + "integrity": "sha512-tJ/oJ4amDihPoufT5sM0Z1SKEuKay8LfVAMlbbhnnkvt6BUserZylqo2PN+p9KeljLr0OHa2rXHU1T8reeoTrw==", "dev": true, "bin": { "prettier": "bin-prettier.js" @@ -6014,11 +17437,184 @@ "url": "https://github.com/prettier/prettier?sponsor=1" } }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/prettier-plugin-tailwindcss": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.2.2.tgz", + "integrity": "sha512-5RjUbWRe305pUpc48MosoIp6uxZvZxrM6GyOgsbGLTce+ehePKNm7ziW2dLG2air9aXbGuXlHVSQQw4Lbosq3w==", + "dev": true, + "engines": { + "node": ">=12.17.0" + }, + "peerDependencies": { + "@prettier/plugin-php": "*", + "@prettier/plugin-pug": "*", + "@shopify/prettier-plugin-liquid": "*", + "@shufo/prettier-plugin-blade": "*", + "@trivago/prettier-plugin-sort-imports": "*", + "prettier": ">=2.2.0", + "prettier-plugin-astro": "*", + "prettier-plugin-css-order": "*", + "prettier-plugin-import-sort": "*", + "prettier-plugin-jsdoc": "*", + "prettier-plugin-organize-attributes": "*", + "prettier-plugin-organize-imports": "*", + "prettier-plugin-style-order": "*", + "prettier-plugin-svelte": "*", + "prettier-plugin-twig-melody": "*" + }, + "peerDependenciesMeta": { + "@prettier/plugin-php": { + "optional": true + }, + "@prettier/plugin-pug": { + "optional": true + }, + "@shopify/prettier-plugin-liquid": { + "optional": true + }, + "@shufo/prettier-plugin-blade": { + "optional": true + }, + "@trivago/prettier-plugin-sort-imports": { + "optional": true + }, + "prettier-plugin-astro": { + "optional": true + }, + "prettier-plugin-css-order": { + "optional": true + }, + "prettier-plugin-import-sort": { + "optional": true + }, + "prettier-plugin-jsdoc": { + "optional": true + }, + "prettier-plugin-organize-attributes": { + "optional": true + }, + "prettier-plugin-organize-imports": { + "optional": true + }, + "prettier-plugin-style-order": { + "optional": true + }, + "prettier-plugin-svelte": { + "optional": true + }, + "prettier-plugin-twig-melody": { + "optional": true + } + } + }, + "node_modules/pretty-error": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", + "integrity": "sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==", + "dev": true, + "dependencies": { + "lodash": "^4.17.20", + "renderkid": "^3.0.0" + } + }, + "node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/pretty-format/node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true + }, + "node_modules/pretty-hrtime": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", + "integrity": "sha512-66hKPCr+72mlfiSjlEB1+45IjXSqvVAIy6mocupoww4tBFE9R9IhwwUGoI4G++Tc9Aq+2rxOt0RFU6gPcrte0A==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "dev": true, + "engines": { + "node": ">= 0.6.0" + } + }, "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/prompts/node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/prop-types": { "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", @@ -6038,6 +17634,25 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dev": true, + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "dev": true + }, "node_modules/pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", @@ -6048,14 +17663,128 @@ } }, "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.2.0.tgz", + "integrity": "sha512-LN6QV1IJ9ZhxWTNdktaPClrNfp8xdSAYS0Zk2ddX7XsXZAxckMHPCBcHRo0cTcEIgYPRiGEkmji3Idkh2yFtYw==", "dev": true, "engines": { "node": ">=6" } }, + "node_modules/puppeteer-core": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-2.1.1.tgz", + "integrity": "sha512-n13AWriBMPYxnpbb6bnaY5YoY6rGj8vPLrz6CZF3o0qJNEwlcfJVxBzYZ0NJsQ21UbdJoijPCDrM++SUVEz7+w==", + "dev": true, + "dependencies": { + "@types/mime-types": "^2.1.0", + "debug": "^4.1.0", + "extract-zip": "^1.6.6", + "https-proxy-agent": "^4.0.0", + "mime": "^2.0.3", + "mime-types": "^2.1.25", + "progress": "^2.0.1", + "proxy-from-env": "^1.0.0", + "rimraf": "^2.6.1", + "ws": "^6.1.0" + }, + "engines": { + "node": ">=8.16.0" + } + }, + "node_modules/puppeteer-core/node_modules/agent-base": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-5.1.1.tgz", + "integrity": "sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g==", + "dev": true, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/puppeteer-core/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/puppeteer-core/node_modules/https-proxy-agent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz", + "integrity": "sha512-zoDhWrkR3of1l9QAL8/scJZyLu8j/gBkcwcaQOZh7Gyh/+uJQzGVETdgT30akuwkpL8HTRfssqI3BZuV18teDg==", + "dev": true, + "dependencies": { + "agent-base": "5", + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/puppeteer-core/node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/puppeteer-core/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/puppeteer-core/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/puppeteer-core/node_modules/ws": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.2.tgz", + "integrity": "sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==", + "dev": true, + "dependencies": { + "async-limiter": "~1.0.0" + } + }, + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dev": true, + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/query-string": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/query-string/-/query-string-7.1.3.tgz", @@ -6073,6 +17802,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/queue": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz", + "integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==", + "dev": true, + "dependencies": { + "inherits": "~2.0.3" + } + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -6119,6 +17857,16 @@ "resolved": "https://registry.npmjs.org/raf-schd/-/raf-schd-4.0.3.tgz", "integrity": "sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ==" }, + "node_modules/ramda": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.28.0.tgz", + "integrity": "sha512-9QnLuG/kPVgWvMQ4aODhsBUFKOUmnbUnsSXACv+NCQZcHbeb+v8Lodp8OVxtRULN1/xOyYLLaL6npE6dMq5QTA==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/ramda" + } + }, "node_modules/randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -6127,6 +17875,30 @@ "safe-buffer": "^5.1.0" } }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/rc": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", @@ -6258,6 +18030,55 @@ "object-assign": "^4.1.1" } }, + "node_modules/react-colorful": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/react-colorful/-/react-colorful-5.6.1.tgz", + "integrity": "sha512-1exovf0uGTGyq5mXQT0zgQ80uvj2PCwvF8zY1RN9/vbJVSjSo3fsB/4L3ObbF7u70NduSiK4xu4Y6q1MHoUGEw==", + "dev": true, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/react-docgen": { + "version": "5.4.3", + "resolved": "https://registry.npmjs.org/react-docgen/-/react-docgen-5.4.3.tgz", + "integrity": "sha512-xlLJyOlnfr8lLEEeaDZ+X2J/KJoe6Nr9AzxnkdQWush5hz2ZSu66w6iLMOScMmxoSHWpWMn+k3v5ZiyCfcWsOA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.7.5", + "@babel/generator": "^7.12.11", + "@babel/runtime": "^7.7.6", + "ast-types": "^0.14.2", + "commander": "^2.19.0", + "doctrine": "^3.0.0", + "estree-to-babel": "^3.1.0", + "neo-async": "^2.6.1", + "node-dir": "^0.1.10", + "strip-indent": "^3.0.0" + }, + "bin": { + "react-docgen": "bin/react-docgen.js" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/react-docgen-typescript": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/react-docgen-typescript/-/react-docgen-typescript-2.2.2.tgz", + "integrity": "sha512-tvg2ZtOpOi6QDwsb3GZhOjDkkX0h8Z2gipvTg6OVMUyoYoURhEiRNePT8NZItTVCDh39JJHnLdfCOkzoLbFnTg==", + "dev": true, + "peerDependencies": { + "typescript": ">= 4.3.x" + } + }, + "node_modules/react-docgen/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, "node_modules/react-dom": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", @@ -6284,17 +18105,27 @@ "react-dom": ">= 16.3.0" } }, - "node_modules/react-github-btn": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/react-github-btn/-/react-github-btn-1.4.0.tgz", - "integrity": "sha512-lV4FYClAfjWnBfv0iNlJUGhamDgIq6TayD0kPZED6VzHWdpcHmPfsYOZ/CFwLfPv4Zp+F4m8QKTj0oy2HjiGXg==", + "node_modules/react-element-to-jsx-string": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/react-element-to-jsx-string/-/react-element-to-jsx-string-15.0.0.tgz", + "integrity": "sha512-UDg4lXB6BzlobN60P8fHWVPX3Kyw8ORrTeBtClmIlGdkOOE+GYQSFvmEU5iLLpwp/6v42DINwNcwOhOLfQ//FQ==", + "dev": true, "dependencies": { - "github-buttons": "^2.22.0" + "@base2/pretty-print-object": "1.0.1", + "is-plain-object": "5.0.0", + "react-is": "18.1.0" }, "peerDependencies": { - "react": ">=16.3.0" + "react": "^0.14.8 || ^15.0.1 || ^16.0.0 || ^17.0.1 || ^18.0.0", + "react-dom": "^0.14.8 || ^15.0.1 || ^16.0.0 || ^17.0.1 || ^18.0.0" } }, + "node_modules/react-element-to-jsx-string/node_modules/react-is": { + "version": "18.1.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", + "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", + "dev": true + }, "node_modules/react-grid-layout": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/react-grid-layout/-/react-grid-layout-1.3.4.tgz", @@ -6311,6 +18142,36 @@ "react-dom": ">= 16.3.0" } }, + "node_modules/react-i18next": { + "version": "12.1.1", + "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-12.1.1.tgz", + "integrity": "sha512-mFdieOI0LDy84q3JuZU6Aou1DoWW2fhapcTGeBS8+vWSJuViuoCLQAMYSb0QoHhXS8B0WKUOPpx4cffAP7r/aA==", + "dependencies": { + "@babel/runtime": "^7.14.5", + "html-parse-stringify": "^3.0.1" + }, + "peerDependencies": { + "i18next": ">= 19.0.0", + "react": ">= 16.8.0" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, + "node_modules/react-inspector": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/react-inspector/-/react-inspector-6.0.1.tgz", + "integrity": "sha512-cxKSeFTf7jpSSVddm66sKdolG90qURAX3g1roTeaN6x0YEbtWc8JpmFN9+yIqLNH2uEkYerWLtJZIXRIFuBKrg==", + "dev": true, + "peerDependencies": { + "react": "^16.8.4 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", @@ -6407,6 +18268,60 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" }, + "node_modules/react-refresh": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz", + "integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-remove-scroll": { + "version": "2.5.5", + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.5.5.tgz", + "integrity": "sha512-ImKhrzJJsyXJfBZ4bzu8Bwpka14c/fQt0k+cyFp/PBhTfyDnU5hjOtM4AG/0AMyy8oKzOTR0lDgJIM7pYXI0kw==", + "dependencies": { + "react-remove-scroll-bar": "^2.3.3", + "react-style-singleton": "^2.2.1", + "tslib": "^2.1.0", + "use-callback-ref": "^1.3.0", + "use-sidecar": "^1.1.2" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-remove-scroll-bar": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.4.tgz", + "integrity": "sha512-63C4YQBUt0m6ALadE9XV56hV8BgJWDmmTPY758iIJjfQKt2nYwoUrPk0LXRXcB/yIj82T1/Ixfdpdk68LwIB0A==", + "dependencies": { + "react-style-singleton": "^2.2.1", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/react-resizable": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/react-resizable/-/react-resizable-3.0.4.tgz", @@ -6419,6 +18334,28 @@ "react": ">= 16.3" } }, + "node_modules/react-style-singleton": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.1.tgz", + "integrity": "sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==", + "dependencies": { + "get-nonce": "^1.0.0", + "invariant": "^2.2.4", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/react-table": { "version": "7.8.0", "resolved": "https://registry.npmjs.org/react-table/-/react-table-7.8.0.tgz", @@ -6440,6 +18377,108 @@ "pify": "^2.3.0" } }, + "node_modules/read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "dev": true, + "dependencies": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "dev": true, + "dependencies": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg-up/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg-up/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg-up/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg-up/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg-up/node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg/node_modules/type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/readable-stream": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", @@ -6465,6 +18504,55 @@ "node": ">=8.10.0" } }, + "node_modules/recast": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/recast/-/recast-0.23.1.tgz", + "integrity": "sha512-RokaBcoxSjXUDzz1TXSZmZsSW6ZpLmlA3GGqJ8uuTrQ9hZhEz+4Tpsc+gRvYRJ2BU4H+ZyUlg91eSGDw7bwy7g==", + "dev": true, + "dependencies": { + "assert": "^2.0.0", + "ast-types": "^0.16.1", + "esprima": "~4.0.0", + "source-map": "~0.6.1", + "tslib": "^2.0.1" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/recast/node_modules/ast-types": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.16.1.tgz", + "integrity": "sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==", + "dev": true, + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/recast/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", + "dev": true, + "dependencies": { + "resolve": "^1.1.6" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/redux": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.0.tgz", @@ -6481,11 +18569,103 @@ "redux": "^4" } }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz", + "integrity": "sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==", + "dev": true, + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/regenerator-runtime": { "version": "0.13.11", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" }, + "node_modules/regenerator-transform": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.1.tgz", + "integrity": "sha512-knzmNAcuyxV+gQCufkYcvOqX/qIIfHLv0u5x79kRxuGojfYVky1f15TzZEu2Avte8QGepvUNTnLskf8E6X6Vyg==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.8.4" + } + }, + "node_modules/regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dev": true, + "dependencies": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/regex-not/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/regex-not/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/regex-not/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/regex-not/node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/regex-parser": { + "version": "2.2.11", + "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.2.11.tgz", + "integrity": "sha512-jbD/FT0+9MBU2XAZluI7w2OBs1RBi6p9M83nkoZayQXXU9e8Robt69FcZc7wU4eJD/YFTjn1JdCk3rbMJajz8Q==", + "dev": true + }, "node_modules/regexp.prototype.flags": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", @@ -6515,6 +18695,138 @@ "url": "https://github.com/sponsors/mysticatea" } }, + "node_modules/regexpu-core": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.2.2.tgz", + "integrity": "sha512-T0+1Zp2wjF/juXMrMxHxidqGYn8U4R+zleSJhX9tQ1PUsS8a9UtYfbsF9LdiVgNX3kiX8RNaKM42nfSgvFJjmw==", + "dev": true, + "dependencies": { + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsgen": "^0.7.1", + "regjsparser": "^0.9.1", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsgen": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.7.1.tgz", + "integrity": "sha512-RAt+8H2ZEzHeYWxZ3H2z6tF18zyyOnlcdaafLrm21Bguj7uZy6ULibiAFdXEtKQY4Sy7wDTwDiOazasMLc4KPA==", + "dev": true + }, + "node_modules/regjsparser": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "dev": true, + "dependencies": { + "jsesc": "~0.5.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/regjsparser/node_modules/jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + } + }, + "node_modules/relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/remark-external-links": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/remark-external-links/-/remark-external-links-8.0.0.tgz", + "integrity": "sha512-5vPSX0kHoSsqtdftSHhIYofVINC8qmp0nctkeU9YoJwV3YfiBRiI6cbFRJ0oI/1F9xS+bopXG0m2KS8VFscuKA==", + "dev": true, + "dependencies": { + "extend": "^3.0.0", + "is-absolute-url": "^3.0.0", + "mdast-util-definitions": "^4.0.0", + "space-separated-tokens": "^1.0.0", + "unist-util-visit": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-external-links/node_modules/mdast-util-definitions": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-4.0.0.tgz", + "integrity": "sha512-k8AJ6aNnUkB7IE+5azR9h81O5EQ/cTDXtWdMq9Kk5KcEW/8ritU5CeLg/9HhOC++nALHBlaogJ5jz0Ybk3kPMQ==", + "dev": true, + "dependencies": { + "unist-util-visit": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-external-links/node_modules/space-separated-tokens": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz", + "integrity": "sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/remark-external-links/node_modules/unist-util-is": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-4.1.0.tgz", + "integrity": "sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-external-links/node_modules/unist-util-visit": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-2.0.3.tgz", + "integrity": "sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q==", + "dev": true, + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^4.0.0", + "unist-util-visit-parents": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-external-links/node_modules/unist-util-visit-parents": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-3.1.1.tgz", + "integrity": "sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg==", + "dev": true, + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/remark-parse": { "version": "10.0.1", "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-10.0.1.tgz", @@ -6544,6 +18856,128 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/remark-slug": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/remark-slug/-/remark-slug-6.1.0.tgz", + "integrity": "sha512-oGCxDF9deA8phWvxFuyr3oSJsdyUAxMFbA0mZ7Y1Sas+emILtO+e5WutF9564gDsEN4IXaQXm5pFo6MLH+YmwQ==", + "dev": true, + "dependencies": { + "github-slugger": "^1.0.0", + "mdast-util-to-string": "^1.0.0", + "unist-util-visit": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-slug/node_modules/mdast-util-to-string": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-1.1.0.tgz", + "integrity": "sha512-jVU0Nr2B9X3MU4tSK7JP1CMkSvOj7X5l/GboG1tKRw52lLF1x2Ju92Ms9tNetCcbfX3hzlM73zYo2NKkWSfF/A==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-slug/node_modules/unist-util-is": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-4.1.0.tgz", + "integrity": "sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-slug/node_modules/unist-util-visit": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-2.0.3.tgz", + "integrity": "sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q==", + "dev": true, + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^4.0.0", + "unist-util-visit-parents": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-slug/node_modules/unist-util-visit-parents": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-3.1.1.tgz", + "integrity": "sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg==", + "dev": true, + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/renderkid": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", + "integrity": "sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==", + "dev": true, + "dependencies": { + "css-select": "^4.1.3", + "dom-converter": "^0.2.0", + "htmlparser2": "^6.1.0", + "lodash": "^4.17.21", + "strip-ansi": "^6.0.1" + } + }, + "node_modules/repeat-element": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", + "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", + "dev": true, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/requireindex": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/requireindex/-/requireindex-1.2.0.tgz", + "integrity": "sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww==", + "dev": true, + "engines": { + "node": ">=0.10.5" + } + }, "node_modules/requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", @@ -6578,6 +19012,61 @@ "node": ">=4" } }, + "node_modules/resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==", + "deprecated": "https://github.com/lydell/resolve-url#deprecated", + "dev": true + }, + "node_modules/resolve-url-loader": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-5.0.0.tgz", + "integrity": "sha512-uZtduh8/8srhBoMx//5bwqjQ+rfYOUq8zC9NrMUGtjBiGTtFJM42s58/36+hTqeqINcnYe08Nj3LkK9lW4N8Xg==", + "dev": true, + "dependencies": { + "adjust-sourcemap-loader": "^4.0.0", + "convert-source-map": "^1.7.0", + "loader-utils": "^2.0.0", + "postcss": "^8.2.14", + "source-map": "0.6.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/resolve-url-loader/node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/resolve-url-loader/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "dev": true, + "engines": { + "node": ">=0.12" + } + }, "node_modules/reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", @@ -6679,6 +19168,15 @@ } ] }, + "node_modules/safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==", + "dev": true, + "dependencies": { + "ret": "~0.1.10" + } + }, "node_modules/safe-regex-test": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", @@ -6693,6 +19191,50 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "node_modules/sass-loader": { + "version": "12.6.0", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-12.6.0.tgz", + "integrity": "sha512-oLTaH0YCtX4cfnJZxKSLAyglED0naiYfNG1iXfU5w1LNZ+ukoA5DtyDIN5zmKVZwYNJP4KRc5Y3hkWga+7tYfA==", + "dev": true, + "dependencies": { + "klona": "^2.0.4", + "neo-async": "^2.6.2" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "fibers": ">= 3.1.0", + "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0", + "sass": "^1.3.0", + "sass-embedded": "*", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "fibers": { + "optional": true + }, + "node-sass": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + } + } + }, "node_modules/scheduler": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", @@ -6702,6 +19244,24 @@ "object-assign": "^4.1.1" } }, + "node_modules/schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, "node_modules/section-matter": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz", @@ -6728,11 +19288,141 @@ "node": ">=10" } }, + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/serialize-javascript": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", + "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-favicon": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/serve-favicon/-/serve-favicon-2.5.0.tgz", + "integrity": "sha512-FMW2RvqNr03x+C0WxTyu6sOv21oOjkq5j8tjquWccwa6ScNyGFOGJVpuS1NmTVGBAHS07xnSKotgf2ehQmf9iA==", + "dev": true, + "dependencies": { + "etag": "~1.8.1", + "fresh": "0.5.2", + "ms": "2.1.1", + "parseurl": "~1.3.2", + "safe-buffer": "5.1.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/serve-favicon/node_modules/ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + }, + "node_modules/serve-favicon/node_modules/safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", + "dev": true + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dev": true, + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "dev": true + }, "node_modules/set-cookie-parser": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.5.1.tgz", "integrity": "sha512-1jeBGaKNGdEq4FgIrORu/N570dwoPYio8lSoYLWmX7sQ//0JY08Xh9o5pBcgmHQ/MbsYp/aZnOe1s1lIsbLprQ==" }, + "node_modules/set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "dev": true, + "dependencies": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/set-value/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/set-value/node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true + }, "node_modules/sha.js": { "version": "2.4.11", "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", @@ -6745,6 +19435,18 @@ "sha.js": "bin.js" } }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/shallowequal": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", @@ -6793,6 +19495,23 @@ "node": ">=8" } }, + "node_modules/shelljs": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", + "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", + "dev": true, + "dependencies": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + }, + "bin": { + "shjs": "bin/shjs" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/side-channel": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", @@ -6807,6 +19526,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, "node_modules/simple-concat": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", @@ -6858,6 +19583,33 @@ "is-arrayish": "^0.3.1" } }, + "node_modules/simple-update-notifier": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz", + "integrity": "sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==", + "dev": true, + "dependencies": { + "semver": "~7.0.0" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/simple-update-notifier/node_modules/semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true + }, "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -6867,6 +19619,179 @@ "node": ">=8" } }, + "node_modules/snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "dev": true, + "dependencies": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "dev": true, + "dependencies": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node/node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "dev": true, + "dependencies": { + "kind-of": "^3.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-util/node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "node_modules/snapdragon-util/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "dev": true, + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/is-accessor-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "node_modules/snapdragon/node_modules/is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/is-data-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", @@ -6883,6 +19808,52 @@ "node": ">=0.10.0" } }, + "node_modules/source-map-resolve": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", + "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "deprecated": "See https://github.com/lydell/source-map-resolve#deprecated", + "dev": true, + "dependencies": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-url": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", + "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", + "deprecated": "See https://github.com/lydell/source-map-url#deprecated", + "dev": true + }, "node_modules/space-separated-tokens": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.1.tgz", @@ -6892,6 +19863,38 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "dev": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "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==", + "dev": true + }, "node_modules/split-on-first": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz", @@ -6900,6 +19903,64 @@ "node": ">=6" } }, + "node_modules/split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dev": true, + "dependencies": { + "extend-shallow": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split-string/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split-string/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split-string/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split-string/node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -6914,6 +19975,378 @@ "node": ">=0.1.14" } }, + "node_modules/stackframe": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz", + "integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==", + "dev": true + }, + "node_modules/static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==", + "dev": true, + "dependencies": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "dev": true, + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/is-accessor-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "node_modules/static-extend/node_modules/is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/is-data-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/stop-iteration-iterator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", + "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==", + "dev": true, + "dependencies": { + "internal-slot": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/store2": { + "version": "2.14.2", + "resolved": "https://registry.npmjs.org/store2/-/store2-2.14.2.tgz", + "integrity": "sha512-siT1RiqlfQnGqgT/YzXVUNsom9S0H1OX+dpdGN1xkyYATo4I6sep5NmsRD/40s3IIOvlCq6akxkqG82urIZW1w==", + "dev": true + }, + "node_modules/storybook": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/storybook/-/storybook-7.0.0-beta.30.tgz", + "integrity": "sha512-hfOtpvNnQ/rXLfojznCs2WdOFbojKx0Gf1W1Ra6DzOBrmUdXzWwRL8X1RUkI6jwUfYuaE97D8gQpfNRlvoqv4A==", + "dev": true, + "dependencies": { + "@storybook/cli": "7.0.0-beta.30" + }, + "bin": { + "sb": "index.js", + "storybook": "index.js" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/storybook-dark-mode": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/storybook-dark-mode/-/storybook-dark-mode-2.0.5.tgz", + "integrity": "sha512-egOMu2tgGttGAMtFZcDLZobs1xc7LzFOh+pRVqaW59AVp05ABdQ3Hj6IX2Pz7tYGmF9AmaK+nBv0hDFxPe7Hfg==", + "dev": true, + "dependencies": { + "@storybook/addons": "^6.5.14", + "@storybook/api": "^6.5.14", + "@storybook/components": "^6.5.14", + "@storybook/core-events": "^6.5.14", + "@storybook/theming": "^6.5.14", + "fast-deep-equal": "^3.1.3", + "global": "^4.4.0", + "memoizerific": "^1.11.3" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/storybook-dark-mode/node_modules/@storybook/addons": { + "version": "6.5.15", + "resolved": "https://registry.npmjs.org/@storybook/addons/-/addons-6.5.15.tgz", + "integrity": "sha512-xT31SuSX+kYGyxCNK2nqL7WTxucs3rSmhiCLovJcUjYk+QquV3c2c53Ki7lwwdDbzfXFcNAe0HJ4hoTN4jhn0Q==", + "dev": true, + "dependencies": { + "@storybook/api": "6.5.15", + "@storybook/channels": "6.5.15", + "@storybook/client-logger": "6.5.15", + "@storybook/core-events": "6.5.15", + "@storybook/csf": "0.0.2--canary.4566f4d.1", + "@storybook/router": "6.5.15", + "@storybook/theming": "6.5.15", + "@types/webpack-env": "^1.16.0", + "core-js": "^3.8.2", + "global": "^4.4.0", + "regenerator-runtime": "^0.13.7" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/storybook-dark-mode/node_modules/@storybook/api": { + "version": "6.5.15", + "resolved": "https://registry.npmjs.org/@storybook/api/-/api-6.5.15.tgz", + "integrity": "sha512-BBE0KXKvj1/3jTghbIoWfrcDM0t+xO7EYtWWAXD6XlhGsZVD2Dy82Z52ONyLulMDRpMWl0OYy3h6A1YnFUH25w==", + "dev": true, + "dependencies": { + "@storybook/channels": "6.5.15", + "@storybook/client-logger": "6.5.15", + "@storybook/core-events": "6.5.15", + "@storybook/csf": "0.0.2--canary.4566f4d.1", + "@storybook/router": "6.5.15", + "@storybook/semver": "^7.3.2", + "@storybook/theming": "6.5.15", + "core-js": "^3.8.2", + "fast-deep-equal": "^3.1.3", + "global": "^4.4.0", + "lodash": "^4.17.21", + "memoizerific": "^1.11.3", + "regenerator-runtime": "^0.13.7", + "store2": "^2.12.0", + "telejson": "^6.0.8", + "ts-dedent": "^2.0.0", + "util-deprecate": "^1.0.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/storybook-dark-mode/node_modules/@storybook/channels": { + "version": "6.5.15", + "resolved": "https://registry.npmjs.org/@storybook/channels/-/channels-6.5.15.tgz", + "integrity": "sha512-gPpsBgirv2NCXbH4WbYqdkI0JLE96aiVuu7UEWfn9yu071pQ9CLHbhXGD9fSFNrfOkyBBY10ppSE7uCXw3Wexg==", + "dev": true, + "dependencies": { + "core-js": "^3.8.2", + "ts-dedent": "^2.0.0", + "util-deprecate": "^1.0.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/storybook-dark-mode/node_modules/@storybook/client-logger": { + "version": "6.5.15", + "resolved": "https://registry.npmjs.org/@storybook/client-logger/-/client-logger-6.5.15.tgz", + "integrity": "sha512-0uyxKvodq+FycGv6aUwC1wUR6suXf2+7ywMFAOlYolI4UvNj8NyU/5AfgKT5XnxYAgPmoCiAjOE700TrfHrosw==", + "dev": true, + "dependencies": { + "core-js": "^3.8.2", + "global": "^4.4.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/storybook-dark-mode/node_modules/@storybook/components": { + "version": "6.5.15", + "resolved": "https://registry.npmjs.org/@storybook/components/-/components-6.5.15.tgz", + "integrity": "sha512-bHTT0Oa3s4g+MBMaLBbX9ofMtb1AW59AzIUNGrfqW1XqJMGuUHMiJ7TSo+i5dRSFpbFygnwMEG9LfHxpR2Z0Dw==", + "dev": true, + "dependencies": { + "@storybook/client-logger": "6.5.15", + "@storybook/csf": "0.0.2--canary.4566f4d.1", + "@storybook/theming": "6.5.15", + "core-js": "^3.8.2", + "memoizerific": "^1.11.3", + "qs": "^6.10.0", + "regenerator-runtime": "^0.13.7", + "util-deprecate": "^1.0.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/storybook-dark-mode/node_modules/@storybook/core-events": { + "version": "6.5.15", + "resolved": "https://registry.npmjs.org/@storybook/core-events/-/core-events-6.5.15.tgz", + "integrity": "sha512-B1Ba6l5W7MeNclclqMMTMHgYgfdpB5SIhNCQFnzIz8blynzRhNFMdxvbAl6Je5G0S4xydYYd7Lno2kXQebs7HA==", + "dev": true, + "dependencies": { + "core-js": "^3.8.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "node_modules/storybook-dark-mode/node_modules/@storybook/csf": { + "version": "0.0.2--canary.4566f4d.1", + "resolved": "https://registry.npmjs.org/@storybook/csf/-/csf-0.0.2--canary.4566f4d.1.tgz", + "integrity": "sha512-9OVvMVh3t9znYZwb0Svf/YQoxX2gVOeQTGe2bses2yj+a3+OJnCrUF3/hGv6Em7KujtOdL2LL+JnG49oMVGFgQ==", + "dev": true, + "dependencies": { + "lodash": "^4.17.15" + } + }, + "node_modules/storybook-dark-mode/node_modules/@storybook/router": { + "version": "6.5.15", + "resolved": "https://registry.npmjs.org/@storybook/router/-/router-6.5.15.tgz", + "integrity": "sha512-9t8rI8t7/Krolau29gsdjdbRQ66orONIyP0efp0EukVgv6reNFzb/U14ARrl0uHys6Tl5Xyece9FoakQUdn8Kg==", + "dev": true, + "dependencies": { + "@storybook/client-logger": "6.5.15", + "core-js": "^3.8.2", + "memoizerific": "^1.11.3", + "qs": "^6.10.0", + "regenerator-runtime": "^0.13.7" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/storybook-dark-mode/node_modules/@storybook/theming": { + "version": "6.5.15", + "resolved": "https://registry.npmjs.org/@storybook/theming/-/theming-6.5.15.tgz", + "integrity": "sha512-pgdW0lVZKKXQ4VhIfLHycMmwFSVOY7vLTKnytag4Y8Yz+aXm0bwDN/QxPntFzDH47F1Rcy2ywNnvty8ooDTvuA==", + "dev": true, + "dependencies": { + "@storybook/client-logger": "6.5.15", + "core-js": "^3.8.2", + "memoizerific": "^1.11.3", + "regenerator-runtime": "^0.13.7" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/storybook-dark-mode/node_modules/telejson": { + "version": "6.0.8", + "resolved": "https://registry.npmjs.org/telejson/-/telejson-6.0.8.tgz", + "integrity": "sha512-nerNXi+j8NK1QEfBHtZUN/aLdDcyupA//9kAboYLrtzZlPLpUfqbVGWb9zz91f/mIjRbAYhbgtnJHY8I1b5MBg==", + "dev": true, + "dependencies": { + "@types/is-function": "^1.0.0", + "global": "^4.4.0", + "is-function": "^1.0.2", + "is-regex": "^1.1.2", + "is-symbol": "^1.0.3", + "isobject": "^4.0.0", + "lodash": "^4.17.21", + "memoizerific": "^1.11.3" + } + }, "node_modules/strict-uri-encode": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz", @@ -6930,6 +20363,26 @@ "safe-buffer": "~5.2.0" } }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, "node_modules/string.prototype.matchall": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.8.tgz", @@ -7006,6 +20459,27 @@ "node": ">=0.10.0" } }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -7018,6 +20492,22 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/style-loader": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.1.tgz", + "integrity": "sha512-GPcQ+LDJbrcxHORTRes6Jy2sfvK2kS6hpSfI/fXhPt+spVzxF6LJ1dHLN9zIGmVaaP044YKaIatFaufENRiDoQ==", + "dev": true, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, "node_modules/style-to-object": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-0.3.0.tgz", @@ -7111,6 +20601,12 @@ "node": ">=12.0.0" } }, + "node_modules/synchronous-promise": { + "version": "2.0.16", + "resolved": "https://registry.npmjs.org/synchronous-promise/-/synchronous-promise-2.0.16.tgz", + "integrity": "sha512-qImOD23aDfnIDNqlG1NOehdB9IYsn1V9oByPjKY1nakv2MQYCEMyX033/q+aEtYCpmYK1cv2+NTmlH+ra6GA5A==", + "dev": true + }, "node_modules/synckit": { "version": "0.8.4", "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.4.tgz", @@ -7127,10 +20623,15 @@ "url": "https://opencollective.com/unts" } }, + "node_modules/tailwind-merge": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-1.8.1.tgz", + "integrity": "sha512-+fflfPxvHFr81hTJpQ3MIwtqgvefHZFUHFiIHpVIRXvG/nX9+gu2P7JNlFu2bfDMJ+uHhi/pUgzaYacMoXv+Ww==" + }, "node_modules/tailwindcss": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.1.7.tgz", - "integrity": "sha512-r7mgumZ3k0InfVPpGWcX8X/Ut4xBfv+1O/+C73ar/m01LxGVzWvPxF/w6xIUPEztrCoz7axfx0SMdh8FH8ZvRQ==", + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.2.4.tgz", + "integrity": "sha512-AhwtHCKMtR71JgeYDaswmZXhPcW9iuI9Sp2LvZPo9upDZ7231ZJ7eA9RaURbhpXGVlrjX4cFNlB4ieTetEb7hQ==", "dev": true, "dependencies": { "arg": "^5.0.2", @@ -7139,18 +20640,19 @@ "detective": "^5.2.1", "didyoumean": "^1.2.2", "dlv": "^1.1.3", - "fast-glob": "^3.2.11", + "fast-glob": "^3.2.12", "glob-parent": "^6.0.2", "is-glob": "^4.0.3", "lilconfig": "^2.0.6", + "micromatch": "^4.0.5", "normalize-path": "^3.0.0", "object-hash": "^3.0.0", "picocolors": "^1.0.0", - "postcss": "^8.4.14", + "postcss": "^8.4.18", "postcss-import": "^14.1.0", "postcss-js": "^4.0.0", "postcss-load-config": "^3.1.4", - "postcss-nested": "5.0.6", + "postcss-nested": "6.0.0", "postcss-selector-parser": "^6.0.10", "postcss-value-parser": "^4.2.0", "quick-lru": "^5.1.1", @@ -7167,6 +20669,30 @@ "postcss": "^8.0.9" } }, + "node_modules/tailwindcss/node_modules/postcss": { + "version": "8.4.21", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz", + "integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + } + ], + "dependencies": { + "nanoid": "^3.3.4", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, "node_modules/tapable": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", @@ -7176,6 +20702,23 @@ "node": ">=6" } }, + "node_modules/tar": { + "version": "6.1.13", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.13.tgz", + "integrity": "sha512-jdIBIN6LTIe2jqzay/2vtYLlBHa3JF42ot3h1dW8Q0PaAG4v8rm0cvpVePtau5C6OKXGGcgO9q2AMNSWxiLqKw==", + "dev": true, + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^4.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/tar-fs": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", @@ -7202,6 +20745,222 @@ "node": ">=6" } }, + "node_modules/tar/node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/telejson": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/telejson/-/telejson-7.0.4.tgz", + "integrity": "sha512-J4QEuCnYGXAI9KSN7RXK0a0cOW2ONpjc4IQbInGZ6c3stvplLAYyZjTnScrRd8deXVjNCFV1wXcLC7SObDuQYA==", + "dev": true, + "dependencies": { + "memoizerific": "^1.11.3" + } + }, + "node_modules/temp": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/temp/-/temp-0.8.4.tgz", + "integrity": "sha512-s0ZZzd0BzYv5tLSptZooSjK8oj6C+c19p7Vqta9+6NPOf7r+fxq0cJe6/oN4LTC79sy5NY8ucOJNgwsKCSbfqg==", + "dev": true, + "dependencies": { + "rimraf": "~2.6.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/temp-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz", + "integrity": "sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/temp/node_modules/rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/tempy": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tempy/-/tempy-1.0.1.tgz", + "integrity": "sha512-biM9brNqxSc04Ee71hzFbryD11nX7VPhQQY32AdDmjFvodsRFz/3ufeoTZ6uYkRFfGo188tENcASNs3vTdsM0w==", + "dev": true, + "dependencies": { + "del": "^6.0.0", + "is-stream": "^2.0.0", + "temp-dir": "^2.0.0", + "type-fest": "^0.16.0", + "unique-string": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tempy/node_modules/type-fest": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.16.0.tgz", + "integrity": "sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/terser": { + "version": "5.16.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.16.1.tgz", + "integrity": "sha512-xvQfyfA1ayT0qdK47zskQgRZeWLoOQ8JQ6mIgRGVNwZKdQMU+5FkCBjmv4QjcrTzyZquRw2FVtlJSRUmMKQslw==", + "dev": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.6", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.6.tgz", + "integrity": "sha512-kfLFk+PoLUQIbLmB1+PZDMRSZS99Mp+/MHqDNmMA6tOItzRt+Npe3E+fsMs5mfcM0wCtrrdU387UnV+vnSffXQ==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.14", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.0", + "terser": "^5.14.1" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/terser-webpack-plugin/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/terser-webpack-plugin/node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/terser-webpack-plugin/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/terser/node_modules/acorn": { + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", + "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/text-segmentation": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz", @@ -7278,6 +21037,12 @@ "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.2.0.tgz", "integrity": "sha512-1Uhn/aqw5C6RI4KejVeTg6mIS7IqxnLJ8Mv2tV5rTc0qWobay7pDUz6Wi392Cnc8ak1H0F2cjoRzb2/AW4+Fvg==" }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true + }, "node_modules/to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", @@ -7286,11 +21051,56 @@ "node": ">=4" } }, + "node_modules/to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-object-path/node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "node_modules/to-object-path/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/to-querystring": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/to-querystring/-/to-querystring-1.1.1.tgz", "integrity": "sha512-ZgIacl9TXAoT7sGXUYjQiy0MW7Tf/7CJQLt757hYHfXXc8JBzOVBMx4DckqKUO4hi36J72/m8UcH/GCHK+n97g==" }, + "node_modules/to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dev": true, + "dependencies": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -7303,6 +21113,67 @@ "node": ">=8.0" } }, + "node_modules/to-regex/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-regex/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-regex/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-regex/node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true + }, "node_modules/trim-lines": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", @@ -7321,6 +21192,29 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/ts-dedent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ts-dedent/-/ts-dedent-2.2.0.tgz", + "integrity": "sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==", + "dev": true, + "engines": { + "node": ">=6.10" + } + }, + "node_modules/ts-pnp": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/ts-pnp/-/ts-pnp-1.2.0.tgz", + "integrity": "sha512-csd+vJOb/gkzvcCHgTGSChYpy5f1/XKNsmvBGO4JXS+z1v2HobugDz4s1IeFXM3wZB44uczs+eazB5Q/ccdhQw==", + "dev": true, + "engines": { + "node": ">=6" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "node_modules/tsconfig-paths": { "version": "3.14.1", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", @@ -7333,10 +21227,73 @@ "strip-bom": "^3.0.0" } }, + "node_modules/tsconfig-paths-webpack-plugin": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/tsconfig-paths-webpack-plugin/-/tsconfig-paths-webpack-plugin-3.5.2.tgz", + "integrity": "sha512-EhnfjHbzm5IYI9YPNVIxx1moxMI4bpHD2e0zTXeDNQcwjjRaGepP7IhTHJkyDBG0CAOoxRfe7jCG630Ou+C6Pw==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "enhanced-resolve": "^5.7.0", + "tsconfig-paths": "^3.9.0" + } + }, + "node_modules/tsconfig-paths-webpack-plugin/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/tsconfig-paths-webpack-plugin/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/tsconfig-paths-webpack-plugin/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/tsconfig-paths-webpack-plugin/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/tsconfig-paths/node_modules/json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, "dependencies": { "minimist": "^1.2.0" @@ -7424,6 +21381,25 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", + "dev": true + }, "node_modules/typescript": { "version": "4.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.3.tgz", @@ -7442,6 +21418,19 @@ "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==" }, + "node_modules/uglify-js": { + "version": "3.17.4", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", + "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", + "dev": true, + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/unbox-primitive": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", @@ -7457,6 +21446,52 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/unfetch": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/unfetch/-/unfetch-4.2.0.tgz", + "integrity": "sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA==", + "dev": true + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dev": true, + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", + "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/unified": { "version": "10.1.2", "resolved": "https://registry.npmjs.org/unified/-/unified-10.1.2.tgz", @@ -7475,6 +21510,33 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "dev": true, + "dependencies": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "dev": true, + "dependencies": { + "crypto-random-string": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/unist-builder": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/unist-builder/-/unist-builder-3.0.0.tgz", @@ -7556,10 +21618,119 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/unplugin": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-0.10.2.tgz", + "integrity": "sha512-6rk7GUa4ICYjae5PrAllvcDeuT8pA9+j5J5EkxbMFaV+SalHhxZ7X2dohMzu6C3XzsMT+6jwR/+pwPNR3uK9MA==", + "dev": true, + "dependencies": { + "acorn": "^8.8.0", + "chokidar": "^3.5.3", + "webpack-sources": "^3.2.3", + "webpack-virtual-modules": "^0.4.5" + } + }, + "node_modules/unplugin/node_modules/acorn": { + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", + "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==", + "dev": true, + "dependencies": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==", + "dev": true, + "dependencies": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-value/node_modules/isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==", + "dev": true, + "dependencies": { + "isarray": "1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/untildify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", + "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/update-browserslist-db": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.5.tgz", - "integrity": "sha512-dteFFpCyvuDdr9S/ff1ISkKt/9YZxKjI9WlRR99c180GaztJtRa/fn18FdxGVKVsnPY7/a/FDN68mcvUmP4U7Q==", + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", + "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", + "dev": true, "funding": [ { "type": "opencollective", @@ -7590,6 +21761,55 @@ "punycode": "^2.1.0" } }, + "node_modules/urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==", + "deprecated": "Please see https://github.com/lydell/urix#deprecated", + "dev": true + }, + "node_modules/use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/use-callback-ref": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.0.tgz", + "integrity": "sha512-3FT9PRuRdbB9HfXhEq35u4oZkvpJ5kuYbpqhCfmiZyReuRgpnhDlbr2ZEnnuS0RrJAPn6l23xjFg9kpDM+Ms7w==", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-isomorphic-layout-effect": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz", + "integrity": "sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/use-memo-one": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/use-memo-one/-/use-memo-one-1.1.3.tgz", @@ -7598,6 +21818,27 @@ "react": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, + "node_modules/use-sidecar": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.2.tgz", + "integrity": "sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw==", + "dependencies": { + "detect-node-es": "^1.1.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "^16.9.0 || ^17.0.0 || ^18.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/use-sync-external-store": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", @@ -7606,11 +21847,39 @@ "react": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, + "node_modules/util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, + "node_modules/utila": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "integrity": "sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==", + "dev": true + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/utrie": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz", @@ -7628,6 +21897,12 @@ "uuid": "dist/bin/uuid" } }, + "node_modules/uuid-browser": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/uuid-browser/-/uuid-browser-3.1.0.tgz", + "integrity": "sha512-dsNgbLaTrd6l3MMxTtouOCFw4CBFc/3a+GgYA2YyrJvyQ1u6q4pcu3ktLoUZ/VN/Aw9WsauazbgsgdfVWgAKQg==", + "dev": true + }, "node_modules/uuidv4": { "version": "6.2.13", "resolved": "https://registry.npmjs.org/uuidv4/-/uuidv4-6.2.13.tgz", @@ -7654,6 +21929,39 @@ "node": ">=8" } }, + "node_modules/v8-to-istanbul": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz", + "integrity": "sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^1.6.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/vfile": { "version": "5.3.5", "resolved": "https://registry.npmjs.org/vfile/-/vfile-5.3.5.tgz", @@ -7682,6 +21990,244 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/void-elements": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", + "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "dependencies": { + "makeerror": "1.0.12" + } + }, + "node_modules/watchpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "dev": true, + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true + }, + "node_modules/webpack": { + "version": "5.75.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.75.0.tgz", + "integrity": "sha512-piaIaoVJlqMsPtX/+3KTTO6jfvrSYgauFVdt8cr9LTHKmcq/AMd4mhzsiP7ZF/PGRNPGA8336jldh9l2Kt2ogQ==", + "dev": true, + "dependencies": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^0.0.51", + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/wasm-edit": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.7.6", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.10.0", + "es-module-lexer": "^0.9.0", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.1.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.1.3", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-dev-middleware": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz", + "integrity": "sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA==", + "dev": true, + "dependencies": { + "colorette": "^2.0.10", + "memfs": "^3.4.3", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/webpack-dev-middleware/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/webpack-dev-middleware/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/webpack-dev-middleware/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/webpack-dev-middleware/node_modules/schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/webpack-hot-middleware": { + "version": "2.25.3", + "resolved": "https://registry.npmjs.org/webpack-hot-middleware/-/webpack-hot-middleware-2.25.3.tgz", + "integrity": "sha512-IK/0WAHs7MTu1tzLTjio73LjS3Ov+VvBKQmE8WPlJutgG5zT6Urgq/BbAdRrHTRpyzK0dvAvFh1Qg98akxgZpA==", + "dev": true, + "dependencies": { + "ansi-html-community": "0.0.8", + "html-entities": "^2.1.0", + "strip-ansi": "^6.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack-virtual-modules": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.4.6.tgz", + "integrity": "sha512-5tyDlKLqPfMqjT3Q9TAqf2YqjwmnUleZwzJi1A5qXnlBCdj2AtOJ6wAWdglTIDOPgOiOrXeBeFcsQ8+aGQ6QbA==", + "dev": true + }, + "node_modules/webpack/node_modules/acorn": { + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", + "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/webpack/node_modules/acorn-import-assertions": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", + "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", + "dev": true, + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/webpack/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/webpack/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -7713,6 +22259,62 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/which-collection": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", + "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", + "dev": true, + "dependencies": { + "is-map": "^2.0.1", + "is-set": "^2.0.1", + "is-weakmap": "^2.0.1", + "is-weakset": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", + "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", + "dev": true, + "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" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "dev": true, + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "node_modules/widest-line": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", + "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", + "dev": true, + "dependencies": { + "string-width": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", @@ -7722,11 +22324,83 @@ "node": ">=0.10.0" } }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, + "node_modules/write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/ws": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.12.0.tgz", + "integrity": "sha512-kU62emKIdKVeEIOIKVegvqpXMSTAMLJozpHZaJNDYqBjzlSYXQGviYwN1osDLJ9av68qHd4a2oSjd7yD4pacig==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", @@ -7736,17 +22410,63 @@ "node": ">=0.4" } }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.2.1.tgz", + "integrity": "sha512-e0WHiYql7+9wr4cWMx3TVQrNwejKaEe7/rHNmQmqRjazfOP5W8PB6Jpebb5o6fIapbz9o9+2ipcaTM2ZwDI6lw==", "engines": { - "node": ">= 6" + "node": ">= 14" + } + }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "dev": true, + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" } }, "node_modules/yocto-queue": { @@ -7767,7 +22487,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", - "peer": true, + "dev": true, "requires": { "@jridgewell/gen-mapping": "^0.1.0", "@jridgewell/trace-mapping": "^0.3.9" @@ -7777,7 +22497,7 @@ "version": "0.1.1", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", - "peer": true, + "dev": true, "requires": { "@jridgewell/set-array": "^1.0.0", "@jridgewell/sourcemap-codec": "^1.4.10" @@ -7785,6 +22505,15 @@ } } }, + "@aw-web-design/x-default-browser": { + "version": "1.4.88", + "resolved": "https://registry.npmjs.org/@aw-web-design/x-default-browser/-/x-default-browser-1.4.88.tgz", + "integrity": "sha512-AkEmF0wcwYC2QkhK703Y83fxWARttIWXDmQN8+cof8FmFZ5BRhnNXGymeb1S73bOCLfWjYELxtujL56idCN/XA==", + "dev": true, + "requires": { + "default-browser-id": "3.0.0" + } + }, "@babel/code-frame": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", @@ -7797,13 +22526,13 @@ "version": "7.20.5", "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.5.tgz", "integrity": "sha512-KZXo2t10+/jxmkhNXc7pZTqRvSOIvVv/+lJwHS+B2rErwOyjuVRh60yVpb7liQ1U5t7lLJ1bz+t8tSypUZdm0g==", - "peer": true + "dev": true }, "@babel/core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.5.tgz", "integrity": "sha512-UdOWmk4pNWTm/4DlPUl/Pt4Gz4rcEMb7CY0Y3eJl5Yz1vI8ZJGmHWaVE55LoxRjdpx0z259GE9U5STA9atUinQ==", - "peer": true, + "dev": true, "requires": { "@ampproject/remapping": "^2.1.0", "@babel/code-frame": "^7.18.6", @@ -7826,7 +22555,7 @@ "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "peer": true, + "dev": true, "requires": { "ms": "2.1.2" } @@ -7835,22 +22564,22 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "peer": true + "dev": true }, "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "peer": true + "dev": true } } }, "@babel/generator": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.5.tgz", - "integrity": "sha512-jl7JY2Ykn9S0yj4DQP82sYvPU+T3g0HFcWTqDLqiuA9tGRNIj9VfbtXGAYTTkyNEnQk1jkMGOdYka8aG/lulCA==", + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.7.tgz", + "integrity": "sha512-7wqMOJq8doJMZmP4ApXTzLxSr7+oO2jroJURrVEp6XShrQUObV8Tq/D0NCcoYg2uHqUrjzO0zwBjoYzelxK+sw==", "requires": { - "@babel/types": "^7.20.5", + "@babel/types": "^7.20.7", "@jridgewell/gen-mapping": "^0.3.2", "jsesc": "^2.5.1" } @@ -7863,23 +22592,112 @@ "@babel/types": "^7.18.6" } }, - "@babel/helper-compilation-targets": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.0.tgz", - "integrity": "sha512-0jp//vDGp9e8hZzBc6N/KwA5ZK3Wsm/pfm4CrY7vzegkVxc65SgSn6wYOnwHe9Js9HRQ1YTCKLGPzDtaS3RoLQ==", - "peer": true, + "@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.18.9.tgz", + "integrity": "sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw==", + "dev": true, "requires": { - "@babel/compat-data": "^7.20.0", + "@babel/helper-explode-assignable-expression": "^7.18.6", + "@babel/types": "^7.18.9" + } + }, + "@babel/helper-compilation-targets": { + "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==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.20.5", "@babel/helper-validator-option": "^7.18.6", "browserslist": "^4.21.3", + "lru-cache": "^5.1.1", "semver": "^6.3.0" }, "dependencies": { + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + }, "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "peer": true + "dev": true + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + } + } + }, + "@babel/helper-create-class-features-plugin": { + "version": "7.20.12", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.20.12.tgz", + "integrity": "sha512-9OunRkbT0JQcednL0UFvbfXpAsUXiGjUk0a7sN8fUXX7Mue79cUSMjHGDRRi/Vz9vYlpIhLV5fMD5dKoMhhsNQ==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-member-expression-to-functions": "^7.20.7", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/helper-replace-supers": "^7.20.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", + "@babel/helper-split-export-declaration": "^7.18.6" + } + }, + "@babel/helper-create-regexp-features-plugin": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.20.5.tgz", + "integrity": "sha512-m68B1lkg3XDGX5yCvGO0kPx3v9WIYLnzjKfPcQiwntEQa5ZeRkPmo2X/ISJc8qxWGfwUr+kvZAeEzAwLec2r2w==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "regexpu-core": "^5.2.1" + } + }, + "@babel/helper-define-polyfill-provider": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz", + "integrity": "sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==", + "dev": true, + "requires": { + "@babel/helper-compilation-targets": "^7.17.7", + "@babel/helper-plugin-utils": "^7.16.7", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2", + "semver": "^6.1.2" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true } } }, @@ -7888,6 +22706,15 @@ "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-explode-assignable-expression": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz", + "integrity": "sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg==", + "dev": true, + "requires": { + "@babel/types": "^7.18.6" + } + }, "@babel/helper-function-name": { "version": "7.19.0", "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", @@ -7905,6 +22732,15 @@ "@babel/types": "^7.18.6" } }, + "@babel/helper-member-expression-to-functions": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.20.7.tgz", + "integrity": "sha512-9J0CxJLq315fEdi4s7xK5TQaNYjZw+nDVpVqr1axNGKzdrdwYBD5b4uKv3n75aABG0rCCTK8Im8Ww7eYfMrZgw==", + "dev": true, + "requires": { + "@babel/types": "^7.20.7" + } + }, "@babel/helper-module-imports": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", @@ -7914,35 +22750,79 @@ } }, "@babel/helper-module-transforms": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.2.tgz", - "integrity": "sha512-zvBKyJXRbmK07XhMuujYoJ48B5yvvmM6+wcpv6Ivj4Yg6qO7NOZOSnvZN9CRl1zz1Z4cKf8YejmCMh8clOoOeA==", - "peer": true, + "version": "7.20.11", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.11.tgz", + "integrity": "sha512-uRy78kN4psmji1s2QtbtcCSaj/LILFDp0f/ymhpQH5QY3nljUZCaNWz9X1dEj/8MBdBEFECs7yRhKn8i7NjZgg==", + "dev": true, "requires": { "@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.18.10", - "@babel/traverse": "^7.20.1", - "@babel/types": "^7.20.2" + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.20.10", + "@babel/types": "^7.20.7" + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz", + "integrity": "sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==", + "dev": true, + "requires": { + "@babel/types": "^7.18.6" } }, "@babel/helper-plugin-utils": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", - "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==" + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz", + "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==" + }, + "@babel/helper-remap-async-to-generator": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz", + "integrity": "sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-wrap-function": "^7.18.9", + "@babel/types": "^7.18.9" + } + }, + "@babel/helper-replace-supers": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.20.7.tgz", + "integrity": "sha512-vujDMtB6LVfNW13jhlCrp48QNslK6JXi7lQG736HVbHz/mbf4Dc7tIRh1Xf5C0rF7BP8iiSxGMCmY6Ci1ven3A==", + "dev": true, + "requires": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-member-expression-to-functions": "^7.20.7", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.20.7", + "@babel/types": "^7.20.7" + } }, "@babel/helper-simple-access": { "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==", - "peer": true, + "dev": true, "requires": { "@babel/types": "^7.20.2" } }, + "@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.20.0.tgz", + "integrity": "sha512-5y1JYeNKfvnT8sZcK9DVRtpTbGiomYIHviSP3OQWmDPU3DeH4a1ZlT/N2lyQ5P8egjcRaT/Y9aNqUxK0WsnIIg==", + "dev": true, + "requires": { + "@babel/types": "^7.20.0" + } + }, "@babel/helper-split-export-declaration": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", @@ -7965,13 +22845,25 @@ "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", - "peer": true + "dev": true + }, + "@babel/helper-wrap-function": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.20.5.tgz", + "integrity": "sha512-bYMxIWK5mh+TgXGVqAtnu5Yn1un+v8DDZtqyzKRLUzrh70Eal2O3aZ7aPYiMADO4uKlkzOiRiZ6GX5q3qxvW9Q==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.19.0", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.20.5", + "@babel/types": "^7.20.5" + } }, "@babel/helpers": { "version": "7.20.6", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.6.tgz", "integrity": "sha512-Pf/OjgfgFRW5bApskEz5pvidpim7tEDPlFtKcNRXWmfHGn9IEI2W2flqRQXTFb7gIPTyK++N6rVHuwKut4XK6w==", - "peer": true, + "dev": true, "requires": { "@babel/template": "^7.18.10", "@babel/traverse": "^7.20.5", @@ -7989,9 +22881,260 @@ } }, "@babel/parser": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.7.tgz", + "integrity": "sha512-T3Z9oHybU+0vZlY9CiDSJQTD5ZapcW18ZctFMi0MOAl/4BjFF4ul7NVSARLdbGO5vDqy9eQiGTV0LtKfvCYvcg==" + }, + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz", + "integrity": "sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.20.7.tgz", + "integrity": "sha512-sbr9+wNE5aXMBBFBICk01tt7sBf2Oc9ikRFEcem/ZORup9IMUdNhW7/wVLEbbtlWOsEubJet46mHAL2C8+2jKQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", + "@babel/plugin-proposal-optional-chaining": "^7.20.7" + } + }, + "@babel/plugin-proposal-async-generator-functions": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.20.7.tgz", + "integrity": "sha512-xMbiLsn/8RK7Wq7VeVytytS2L6qE69bXPB10YCmMdDZbKF4okCqY74pI/jJQ/8U0b/F6NrT2+14b8/P9/3AMGA==", + "dev": true, + "requires": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-remap-async-to-generator": "^7.18.9", + "@babel/plugin-syntax-async-generators": "^7.8.4" + } + }, + "@babel/plugin-proposal-class-properties": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz", + "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-proposal-class-static-block": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.20.7.tgz", + "integrity": "sha512-AveGOoi9DAjUYYuUAG//Ig69GlazLnoyzMw68VCDux+c1tsnnH/OkYcpz/5xzMkEFC6UxjR5Gw1c+iY2wOGVeQ==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.20.7", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + } + }, + "@babel/plugin-proposal-dynamic-import": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.18.6.tgz", + "integrity": "sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + } + }, + "@babel/plugin-proposal-export-namespace-from": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz", + "integrity": "sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + } + }, + "@babel/plugin-proposal-json-strings": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.18.6.tgz", + "integrity": "sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-json-strings": "^7.8.3" + } + }, + "@babel/plugin-proposal-logical-assignment-operators": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.20.7.tgz", + "integrity": "sha512-y7C7cZgpMIjWlKE5T7eJwp+tnRYM89HmRvWM5EQuB5BoHEONjmQ8lSNmBUwOyy/GFRsohJED51YBF79hE1djug==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + } + }, + "@babel/plugin-proposal-nullish-coalescing-operator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz", + "integrity": "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + } + }, + "@babel/plugin-proposal-numeric-separator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz", + "integrity": "sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + } + }, + "@babel/plugin-proposal-object-rest-spread": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.20.7.tgz", + "integrity": "sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.20.5", + "@babel/helper-compilation-targets": "^7.20.7", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.20.7" + } + }, + "@babel/plugin-proposal-optional-catch-binding": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz", + "integrity": "sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + } + }, + "@babel/plugin-proposal-optional-chaining": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.20.7.tgz", + "integrity": "sha512-T+A7b1kfjtRM51ssoOfS1+wbyCVqorfyZhT99TvxxLMirPShD8CzKMRepMlCBGM5RpHMbn8s+5MMHnPstJH6mQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + } + }, + "@babel/plugin-proposal-private-methods": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz", + "integrity": "sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-proposal-private-property-in-object": { "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.5.tgz", - "integrity": "sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA==" + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.20.5.tgz", + "integrity": "sha512-Vq7b9dUA12ByzB4EjQTPo25sFhY+08pQDBSZRtUAkj7lb7jahaHR5igera16QZ+3my1nYR4dKsNdYj5IjPHilQ==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-create-class-features-plugin": "^7.20.5", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + } + }, + "@babel/plugin-proposal-unicode-property-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz", + "integrity": "sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-syntax-flow": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.18.6.tgz", + "integrity": "sha512-LUbR+KNTBWCUAqRG9ex5Gnzu2IOkt8jRJbHHXFT9q+L9zm7M/QQbEqXyw1n1pohYvOyWC8CjeyjrSaIwiYjK7A==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-syntax-import-assertions": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.20.0.tgz", + "integrity": "sha512-IUh1vakzNoWalR8ch/areW7qFopR2AEw03JlG7BbrDqmQ4X3q9uuipQwSGrUn7oGiemKjtSLDhNtQHzMHr1JdQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.19.0" + } + }, + "@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } }, "@babel/plugin-syntax-jsx": { "version": "7.18.6", @@ -8001,47 +23144,735 @@ "@babel/helper-plugin-utils": "^7.18.6" } }, - "@babel/runtime": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.9.tgz", - "integrity": "sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw==", - "requires": { - "regenerator-runtime": "^0.13.4" - } - }, - "@babel/runtime-corejs3": { - "version": "7.20.1", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.20.1.tgz", - "integrity": "sha512-CGulbEDcg/ND1Im7fUNRZdGXmX2MTWVVZacQi/6DiKE5HNwZ3aVTm5PV4lO8HHz0B2h8WQyvKKjbX5XgTtydsg==", + "@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", "dev": true, "requires": { - "core-js-pure": "^3.25.1", - "regenerator-runtime": "^0.13.10" + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-typescript": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.20.0.tgz", + "integrity": "sha512-rd9TkG+u1CExzS4SM1BlMEhMXwFLKVjOAFFCDx9PbX5ycJWDoWMcwdJH9RhkPu1dOgn5TrxLot/Gx6lWFuAUNQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.19.0" + } + }, + "@babel/plugin-transform-arrow-functions": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.20.7.tgz", + "integrity": "sha512-3poA5E7dzDomxj9WXWwuD6A5F3kc7VXwIJO+E+J8qtDtS+pXPAhrgEyh+9GBwBgPq1Z+bB+/JD60lp5jsN7JPQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.20.2" + } + }, + "@babel/plugin-transform-async-to-generator": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.20.7.tgz", + "integrity": "sha512-Uo5gwHPT9vgnSXQxqGtpdufUiWp96gk7yiP4Mp5bm1QMkEmLXBO7PAGYbKoJ6DhAwiNkcHFBol/x5zZZkL/t0Q==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-remap-async-to-generator": "^7.18.9" + } + }, + "@babel/plugin-transform-block-scoped-functions": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.18.6.tgz", + "integrity": "sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-block-scoping": { + "version": "7.20.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.20.11.tgz", + "integrity": "sha512-tA4N427a7fjf1P0/2I4ScsHGc5jcHPbb30xMbaTke2gxDuWpUfXDuX1FEymJwKk4tuGUvGcejAR6HdZVqmmPyw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.20.2" + } + }, + "@babel/plugin-transform-classes": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.20.7.tgz", + "integrity": "sha512-LWYbsiXTPKl+oBlXUGlwNlJZetXD5Am+CyBdqhPsDVjM9Jc8jwBJFrKhHf900Kfk2eZG1y9MAG3UNajol7A4VQ==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-compilation-targets": "^7.20.7", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-replace-supers": "^7.20.7", + "@babel/helper-split-export-declaration": "^7.18.6", + "globals": "^11.1.0" + } + }, + "@babel/plugin-transform-computed-properties": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.20.7.tgz", + "integrity": "sha512-Lz7MvBK6DTjElHAmfu6bfANzKcxpyNPeYBGEafyA6E5HtRpjpZwU+u7Qrgz/2OR0z+5TvKYbPdphfSaAcZBrYQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/template": "^7.20.7" + } + }, + "@babel/plugin-transform-destructuring": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.20.7.tgz", + "integrity": "sha512-Xwg403sRrZb81IVB79ZPqNQME23yhugYVqgTxAhT99h485F4f+GMELFhhOsscDUB7HCswepKeCKLn/GZvUKoBA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.20.2" + } + }, + "@babel/plugin-transform-dotall-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.18.6.tgz", + "integrity": "sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-duplicate-keys": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.9.tgz", + "integrity": "sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9" + } + }, + "@babel/plugin-transform-exponentiation-operator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.18.6.tgz", + "integrity": "sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw==", + "dev": true, + "requires": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-flow-strip-types": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.19.0.tgz", + "integrity": "sha512-sgeMlNaQVbCSpgLSKP4ZZKfsJVnFnNQlUSk6gPYzR/q7tzCgQF2t8RBKAP6cKJeZdveei7Q7Jm527xepI8lNLg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/plugin-syntax-flow": "^7.18.6" + } + }, + "@babel/plugin-transform-for-of": { + "version": "7.18.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.8.tgz", + "integrity": "sha512-yEfTRnjuskWYo0k1mHUqrVWaZwrdq8AYbfrpqULOJOaucGSp4mNMVps+YtA8byoevxS/urwU75vyhQIxcCgiBQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-function-name": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.9.tgz", + "integrity": "sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ==", + "dev": true, + "requires": { + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-function-name": "^7.18.9", + "@babel/helper-plugin-utils": "^7.18.9" + } + }, + "@babel/plugin-transform-literals": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.9.tgz", + "integrity": "sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9" + } + }, + "@babel/plugin-transform-member-expression-literals": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.18.6.tgz", + "integrity": "sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-modules-amd": { + "version": "7.20.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.20.11.tgz", + "integrity": "sha512-NuzCt5IIYOW0O30UvqktzHYR2ud5bOWbY0yaxWZ6G+aFzOMJvrs5YHNikrbdaT15+KNO31nPOy5Fim3ku6Zb5g==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.20.11", + "@babel/helper-plugin-utils": "^7.20.2" + } + }, + "@babel/plugin-transform-modules-commonjs": { + "version": "7.20.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.20.11.tgz", + "integrity": "sha512-S8e1f7WQ7cimJQ51JkAaDrEtohVEitXjgCGAS2N8S31Y42E+kWwfSz83LYz57QdBm7q9diARVqanIaH2oVgQnw==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.20.11", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-simple-access": "^7.20.2" + } + }, + "@babel/plugin-transform-modules-systemjs": { + "version": "7.20.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.20.11.tgz", + "integrity": "sha512-vVu5g9BPQKSFEmvt2TA4Da5N+QVS66EX21d8uoOihC+OCpUoGvzVsXeqFdtAEfVa5BILAeFt+U7yVmLbQnAJmw==", + "dev": true, + "requires": { + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-module-transforms": "^7.20.11", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-validator-identifier": "^7.19.1" + } + }, + "@babel/plugin-transform-modules-umd": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.6.tgz", + "integrity": "sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.20.5.tgz", + "integrity": "sha512-mOW4tTzi5iTLnw+78iEq3gr8Aoq4WNRGpmSlrogqaiCBoR1HFhpU4JkpQFOHfeYx3ReVIFWOQJS4aZBRvuZ6mA==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.20.5", + "@babel/helper-plugin-utils": "^7.20.2" + } + }, + "@babel/plugin-transform-new-target": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.18.6.tgz", + "integrity": "sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-object-super": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.18.6.tgz", + "integrity": "sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-replace-supers": "^7.18.6" + } + }, + "@babel/plugin-transform-parameters": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.20.7.tgz", + "integrity": "sha512-WiWBIkeHKVOSYPO0pWkxGPfKeWrCJyD3NJ53+Lrp/QMSZbsVPovrVl2aWZ19D/LTVnaDv5Ap7GJ/B2CTOZdrfA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.20.2" + } + }, + "@babel/plugin-transform-property-literals": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.18.6.tgz", + "integrity": "sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-react-display-name": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.18.6.tgz", + "integrity": "sha512-TV4sQ+T013n61uMoygyMRm+xf04Bd5oqFpv2jAEQwSZ8NwQA7zeRPg1LMVg2PWi3zWBz+CLKD+v5bcpZ/BS0aA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-react-jsx": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.20.7.tgz", + "integrity": "sha512-Tfq7qqD+tRj3EoDhY00nn2uP2hsRxgYGi5mLQ5TimKav0a9Lrpd4deE+fcLXU8zFYRjlKPHZhpCvfEA6qnBxqQ==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-jsx": "^7.18.6", + "@babel/types": "^7.20.7" + } + }, + "@babel/plugin-transform-react-jsx-development": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.18.6.tgz", + "integrity": "sha512-SA6HEjwYFKF7WDjWcMcMGUimmw/nhNRDWxr+KaLSCrkD/LMDBvWRmHAYgE1HDeF8KUuI8OAu+RT6EOtKxSW2qA==", + "dev": true, + "requires": { + "@babel/plugin-transform-react-jsx": "^7.18.6" + } + }, + "@babel/plugin-transform-react-pure-annotations": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.18.6.tgz", + "integrity": "sha512-I8VfEPg9r2TRDdvnHgPepTKvuRomzA8+u+nhY7qSI1fR2hRNebasZEETLyM5mAUr0Ku56OkXJ0I7NHJnO6cJiQ==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-regenerator": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.20.5.tgz", + "integrity": "sha512-kW/oO7HPBtntbsahzQ0qSE3tFvkFwnbozz3NWFhLGqH75vLEg+sCGngLlhVkePlCs3Jv0dBBHDzCHxNiFAQKCQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.20.2", + "regenerator-transform": "^0.15.1" + } + }, + "@babel/plugin-transform-reserved-words": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.18.6.tgz", + "integrity": "sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-shorthand-properties": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz", + "integrity": "sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-spread": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.20.7.tgz", + "integrity": "sha512-ewBbHQ+1U/VnH1fxltbJqDeWBU1oNLG8Dj11uIv3xVf7nrQu0bPGe5Rf716r7K5Qz+SqtAOVswoVunoiBtGhxw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0" + } + }, + "@babel/plugin-transform-sticky-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.18.6.tgz", + "integrity": "sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-template-literals": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.9.tgz", + "integrity": "sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9" + } + }, + "@babel/plugin-transform-typeof-symbol": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.9.tgz", + "integrity": "sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9" + } + }, + "@babel/plugin-transform-typescript": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.20.7.tgz", + "integrity": "sha512-m3wVKEvf6SoszD8pu4NZz3PvfKRCMgk6D6d0Qi9hNnlM5M6CFS92EgF4EiHVLKbU0r/r7ty1hg7NPZwE7WRbYw==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.20.7", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-typescript": "^7.20.0" + } + }, + "@babel/plugin-transform-unicode-escapes": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.10.tgz", + "integrity": "sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9" + } + }, + "@babel/plugin-transform-unicode-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.18.6.tgz", + "integrity": "sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/preset-env": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.20.2.tgz", + "integrity": "sha512-1G0efQEWR1EHkKvKHqbG+IN/QdgwfByUpM5V5QroDzGV2t3S/WXNQd693cHiHTlCFMpr9B6FkPFXDA2lQcKoDg==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.20.1", + "@babel/helper-compilation-targets": "^7.20.0", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-validator-option": "^7.18.6", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.18.6", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.18.9", + "@babel/plugin-proposal-async-generator-functions": "^7.20.1", + "@babel/plugin-proposal-class-properties": "^7.18.6", + "@babel/plugin-proposal-class-static-block": "^7.18.6", + "@babel/plugin-proposal-dynamic-import": "^7.18.6", + "@babel/plugin-proposal-export-namespace-from": "^7.18.9", + "@babel/plugin-proposal-json-strings": "^7.18.6", + "@babel/plugin-proposal-logical-assignment-operators": "^7.18.9", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6", + "@babel/plugin-proposal-numeric-separator": "^7.18.6", + "@babel/plugin-proposal-object-rest-spread": "^7.20.2", + "@babel/plugin-proposal-optional-catch-binding": "^7.18.6", + "@babel/plugin-proposal-optional-chaining": "^7.18.9", + "@babel/plugin-proposal-private-methods": "^7.18.6", + "@babel/plugin-proposal-private-property-in-object": "^7.18.6", + "@babel/plugin-proposal-unicode-property-regex": "^7.18.6", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.20.0", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-transform-arrow-functions": "^7.18.6", + "@babel/plugin-transform-async-to-generator": "^7.18.6", + "@babel/plugin-transform-block-scoped-functions": "^7.18.6", + "@babel/plugin-transform-block-scoping": "^7.20.2", + "@babel/plugin-transform-classes": "^7.20.2", + "@babel/plugin-transform-computed-properties": "^7.18.9", + "@babel/plugin-transform-destructuring": "^7.20.2", + "@babel/plugin-transform-dotall-regex": "^7.18.6", + "@babel/plugin-transform-duplicate-keys": "^7.18.9", + "@babel/plugin-transform-exponentiation-operator": "^7.18.6", + "@babel/plugin-transform-for-of": "^7.18.8", + "@babel/plugin-transform-function-name": "^7.18.9", + "@babel/plugin-transform-literals": "^7.18.9", + "@babel/plugin-transform-member-expression-literals": "^7.18.6", + "@babel/plugin-transform-modules-amd": "^7.19.6", + "@babel/plugin-transform-modules-commonjs": "^7.19.6", + "@babel/plugin-transform-modules-systemjs": "^7.19.6", + "@babel/plugin-transform-modules-umd": "^7.18.6", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.19.1", + "@babel/plugin-transform-new-target": "^7.18.6", + "@babel/plugin-transform-object-super": "^7.18.6", + "@babel/plugin-transform-parameters": "^7.20.1", + "@babel/plugin-transform-property-literals": "^7.18.6", + "@babel/plugin-transform-regenerator": "^7.18.6", + "@babel/plugin-transform-reserved-words": "^7.18.6", + "@babel/plugin-transform-shorthand-properties": "^7.18.6", + "@babel/plugin-transform-spread": "^7.19.0", + "@babel/plugin-transform-sticky-regex": "^7.18.6", + "@babel/plugin-transform-template-literals": "^7.18.9", + "@babel/plugin-transform-typeof-symbol": "^7.18.9", + "@babel/plugin-transform-unicode-escapes": "^7.18.10", + "@babel/plugin-transform-unicode-regex": "^7.18.6", + "@babel/preset-modules": "^0.1.5", + "@babel/types": "^7.20.2", + "babel-plugin-polyfill-corejs2": "^0.3.3", + "babel-plugin-polyfill-corejs3": "^0.6.0", + "babel-plugin-polyfill-regenerator": "^0.4.1", + "core-js-compat": "^3.25.1", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "@babel/preset-flow": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/preset-flow/-/preset-flow-7.18.6.tgz", + "integrity": "sha512-E7BDhL64W6OUqpuyHnSroLnqyRTcG6ZdOBl1OKI/QK/HJfplqK/S3sq1Cckx7oTodJ5yOXyfw7rEADJ6UjoQDQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-validator-option": "^7.18.6", + "@babel/plugin-transform-flow-strip-types": "^7.18.6" + } + }, + "@babel/preset-modules": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz", + "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", + "@babel/plugin-transform-dotall-regex": "^7.4.4", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + } + }, + "@babel/preset-react": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.18.6.tgz", + "integrity": "sha512-zXr6atUmyYdiWRVLOZahakYmOBHtWc2WGCkP8PYTgZi0iJXDY2CN180TdrIW4OGOAdLc7TifzDIvtx6izaRIzg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-validator-option": "^7.18.6", + "@babel/plugin-transform-react-display-name": "^7.18.6", + "@babel/plugin-transform-react-jsx": "^7.18.6", + "@babel/plugin-transform-react-jsx-development": "^7.18.6", + "@babel/plugin-transform-react-pure-annotations": "^7.18.6" + } + }, + "@babel/preset-typescript": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.18.6.tgz", + "integrity": "sha512-s9ik86kXBAnD760aybBucdpnLsAt0jK1xqJn2juOn9lkOvSHV60os5hxoVJsPzMQxvnUJFAlkont2DvvaYEBtQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-validator-option": "^7.18.6", + "@babel/plugin-transform-typescript": "^7.18.6" + } + }, + "@babel/register": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.18.9.tgz", + "integrity": "sha512-ZlbnXDcNYHMR25ITwwNKT88JiaukkdVj/nG7r3wnuXkOTHc60Uy05PwMCPre0hSkY68E6zK3xz+vUJSP2jWmcw==", + "dev": true, + "requires": { + "clone-deep": "^4.0.1", + "find-cache-dir": "^2.0.0", + "make-dir": "^2.1.0", + "pirates": "^4.0.5", + "source-map-support": "^0.5.16" + }, + "dependencies": { + "find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "dev": true + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + }, + "pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dev": true, + "requires": { + "find-up": "^3.0.0" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "@babel/runtime": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.7.tgz", + "integrity": "sha512-UF0tvkUtxwAgZ5W/KrkHf0Rn0fdnLDU9ScxBrEVNUprE/MzirjK4MJUX1/BVDv00Sv8cljtukVK1aky++X1SjQ==", + "requires": { + "regenerator-runtime": "^0.13.11" } }, "@babel/template": { - "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", - "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz", + "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==", "requires": { "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.18.10", - "@babel/types": "^7.18.10" + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7" } }, "@babel/traverse": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.5.tgz", - "integrity": "sha512-WM5ZNN3JITQIq9tFZaw1ojLU3WgWdtkxnhM1AegMS+PvHjkM5IXjmYEGY7yukz5XS4sJyEf2VzWjI8uAavhxBQ==", + "version": "7.20.12", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.12.tgz", + "integrity": "sha512-MsIbFN0u+raeja38qboyF8TIT7K0BFzz/Yd/77ta4MsUsmP2RAnidIlwq7d5HFQrH/OZJecGV6B71C4zAgpoSQ==", "requires": { "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.20.5", + "@babel/generator": "^7.20.7", "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-function-name": "^7.19.0", "@babel/helper-hoist-variables": "^7.18.6", "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.20.5", - "@babel/types": "^7.20.5", + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -8062,15 +23893,40 @@ } }, "@babel/types": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.5.tgz", - "integrity": "sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==", + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", + "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", "requires": { "@babel/helper-string-parser": "^7.19.4", "@babel/helper-validator-identifier": "^7.19.1", "to-fast-properties": "^2.0.0" } }, + "@base2/pretty-print-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@base2/pretty-print-object/-/pretty-print-object-1.0.1.tgz", + "integrity": "sha512-4iri8i1AqYHJE2DstZYkyEprg6Pq6sKx3xn5FpySk9sNhH7qN2LLlHJCfDTZRILNwQNPD7mATWM0TBui7uC1pA==", + "dev": true + }, + "@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true + }, + "@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "dev": true, + "optional": true + }, + "@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "dev": true + }, "@emotion/babel-plugin": { "version": "11.10.2", "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.10.2.tgz", @@ -8201,6 +24057,12 @@ "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz", "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==" }, + "@emotion/use-insertion-effect-with-fallbacks": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.0.tgz", + "integrity": "sha512-1eEgUGmkaljiBnRMTdksDV1W4kUnmwgp7X9G8B++9GYwl1lUdqSndSriIrTJ0N7LQaoauY9JJ2yhiOYK5+NI4A==", + "dev": true + }, "@emotion/utils": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.0.tgz", @@ -8211,16 +24073,170 @@ "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.0.tgz", "integrity": "sha512-AHPmaAx+RYfZz0eYu6Gviiagpmiyw98ySSlQvCUhVGDRtDFe4DBS0x1bSjdF3gqUDYOczB+yYvBTtEylYSdRhg==" }, + "@esbuild/android-arm": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.16.17.tgz", + "integrity": "sha512-N9x1CMXVhtWEAMS7pNNONyA14f71VPQN9Cnavj1XQh6T7bskqiLLrSca4O0Vr8Wdcga943eThxnVp3JLnBMYtw==", + "dev": true, + "optional": true + }, + "@esbuild/android-arm64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.16.17.tgz", + "integrity": "sha512-MIGl6p5sc3RDTLLkYL1MyL8BMRN4tLMRCn+yRJJmEDvYZ2M7tmAf80hx1kbNEUX2KJ50RRtxZ4JHLvCfuB6kBg==", + "dev": true, + "optional": true + }, + "@esbuild/android-x64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.16.17.tgz", + "integrity": "sha512-a3kTv3m0Ghh4z1DaFEuEDfz3OLONKuFvI4Xqczqx4BqLyuFaFkuaG4j2MtA6fuWEFeC5x9IvqnX7drmRq/fyAQ==", + "dev": true, + "optional": true + }, + "@esbuild/darwin-arm64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.16.17.tgz", + "integrity": "sha512-/2agbUEfmxWHi9ARTX6OQ/KgXnOWfsNlTeLcoV7HSuSTv63E4DqtAc+2XqGw1KHxKMHGZgbVCZge7HXWX9Vn+w==", + "dev": true, + "optional": true + }, + "@esbuild/darwin-x64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.16.17.tgz", + "integrity": "sha512-2By45OBHulkd9Svy5IOCZt376Aa2oOkiE9QWUK9fe6Tb+WDr8hXL3dpqi+DeLiMed8tVXspzsTAvd0jUl96wmg==", + "dev": true, + "optional": true + }, + "@esbuild/freebsd-arm64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.16.17.tgz", + "integrity": "sha512-mt+cxZe1tVx489VTb4mBAOo2aKSnJ33L9fr25JXpqQqzbUIw/yzIzi+NHwAXK2qYV1lEFp4OoVeThGjUbmWmdw==", + "dev": true, + "optional": true + }, + "@esbuild/freebsd-x64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.16.17.tgz", + "integrity": "sha512-8ScTdNJl5idAKjH8zGAsN7RuWcyHG3BAvMNpKOBaqqR7EbUhhVHOqXRdL7oZvz8WNHL2pr5+eIT5c65kA6NHug==", + "dev": true, + "optional": true + }, + "@esbuild/linux-arm": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.16.17.tgz", + "integrity": "sha512-iihzrWbD4gIT7j3caMzKb/RsFFHCwqqbrbH9SqUSRrdXkXaygSZCZg1FybsZz57Ju7N/SHEgPyaR0LZ8Zbe9gQ==", + "dev": true, + "optional": true + }, + "@esbuild/linux-arm64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.16.17.tgz", + "integrity": "sha512-7S8gJnSlqKGVJunnMCrXHU9Q8Q/tQIxk/xL8BqAP64wchPCTzuM6W3Ra8cIa1HIflAvDnNOt2jaL17vaW+1V0g==", + "dev": true, + "optional": true + }, + "@esbuild/linux-ia32": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.16.17.tgz", + "integrity": "sha512-kiX69+wcPAdgl3Lonh1VI7MBr16nktEvOfViszBSxygRQqSpzv7BffMKRPMFwzeJGPxcio0pdD3kYQGpqQ2SSg==", + "dev": true, + "optional": true + }, + "@esbuild/linux-loong64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.16.17.tgz", + "integrity": "sha512-dTzNnQwembNDhd654cA4QhbS9uDdXC3TKqMJjgOWsC0yNCbpzfWoXdZvp0mY7HU6nzk5E0zpRGGx3qoQg8T2DQ==", + "dev": true, + "optional": true + }, + "@esbuild/linux-mips64el": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.16.17.tgz", + "integrity": "sha512-ezbDkp2nDl0PfIUn0CsQ30kxfcLTlcx4Foz2kYv8qdC6ia2oX5Q3E/8m6lq84Dj/6b0FrkgD582fJMIfHhJfSw==", + "dev": true, + "optional": true + }, + "@esbuild/linux-ppc64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.16.17.tgz", + "integrity": "sha512-dzS678gYD1lJsW73zrFhDApLVdM3cUF2MvAa1D8K8KtcSKdLBPP4zZSLy6LFZ0jYqQdQ29bjAHJDgz0rVbLB3g==", + "dev": true, + "optional": true + }, + "@esbuild/linux-riscv64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.16.17.tgz", + "integrity": "sha512-ylNlVsxuFjZK8DQtNUwiMskh6nT0vI7kYl/4fZgV1llP5d6+HIeL/vmmm3jpuoo8+NuXjQVZxmKuhDApK0/cKw==", + "dev": true, + "optional": true + }, + "@esbuild/linux-s390x": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.16.17.tgz", + "integrity": "sha512-gzy7nUTO4UA4oZ2wAMXPNBGTzZFP7mss3aKR2hH+/4UUkCOyqmjXiKpzGrY2TlEUhbbejzXVKKGazYcQTZWA/w==", + "dev": true, + "optional": true + }, + "@esbuild/linux-x64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.16.17.tgz", + "integrity": "sha512-mdPjPxfnmoqhgpiEArqi4egmBAMYvaObgn4poorpUaqmvzzbvqbowRllQ+ZgzGVMGKaPkqUmPDOOFQRUFDmeUw==", + "dev": true, + "optional": true + }, + "@esbuild/netbsd-x64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.16.17.tgz", + "integrity": "sha512-/PzmzD/zyAeTUsduZa32bn0ORug+Jd1EGGAUJvqfeixoEISYpGnAezN6lnJoskauoai0Jrs+XSyvDhppCPoKOA==", + "dev": true, + "optional": true + }, + "@esbuild/openbsd-x64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.16.17.tgz", + "integrity": "sha512-2yaWJhvxGEz2RiftSk0UObqJa/b+rIAjnODJgv2GbGGpRwAfpgzyrg1WLK8rqA24mfZa9GvpjLcBBg8JHkoodg==", + "dev": true, + "optional": true + }, + "@esbuild/sunos-x64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.16.17.tgz", + "integrity": "sha512-xtVUiev38tN0R3g8VhRfN7Zl42YCJvyBhRKw1RJjwE1d2emWTVToPLNEQj/5Qxc6lVFATDiy6LjVHYhIPrLxzw==", + "dev": true, + "optional": true + }, + "@esbuild/win32-arm64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.16.17.tgz", + "integrity": "sha512-ga8+JqBDHY4b6fQAmOgtJJue36scANy4l/rL97W+0wYmijhxKetzZdKOJI7olaBaMhWt8Pac2McJdZLxXWUEQw==", + "dev": true, + "optional": true + }, + "@esbuild/win32-ia32": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.16.17.tgz", + "integrity": "sha512-WnsKaf46uSSF/sZhwnqE4L/F89AYNMiD4YtEcYekBt9Q7nj0DiId2XH2Ng2PHM54qi5oPrQ8luuzGszqi/veig==", + "dev": true, + "optional": true + }, + "@esbuild/win32-x64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.16.17.tgz", + "integrity": "sha512-y+EHuSchhL7FjHgvQL/0fnnFmO4T1bhvWANX6gcnqTjtnKWbTvUMCpGnv2+t+31d7RzyEAYAd4u2fnIhHL6N/Q==", + "dev": true, + "optional": true + }, "@eslint/eslintrc": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.3.tgz", - "integrity": "sha512-uj3pT6Mg+3t39fvLrj8iuCIJ38zKO9FpGtJ4BBJebJhEwjoT+KLVNCcHT5QC9NGRIEi7fZ0ZR8YRb884auB4Lg==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz", + "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==", "dev": true, "requires": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^9.4.0", - "globals": "^13.15.0", + "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", @@ -8244,9 +24260,9 @@ } }, "globals": { - "version": "13.18.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.18.0.tgz", - "integrity": "sha512-/mR4KI8Ps2spmoc0Ulu9L7agOF0du1CZNQ3dke8yItYlyKNmGrkONemBbd6V8UTc1Wgcqn21t3WYB7dbRmh6/A==", + "version": "13.19.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz", + "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==", "dev": true, "requires": { "type-fest": "^0.20.2" @@ -8269,6 +24285,39 @@ } } }, + "@fal-works/esbuild-plugin-global-externals": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@fal-works/esbuild-plugin-global-externals/-/esbuild-plugin-global-externals-2.1.2.tgz", + "integrity": "sha512-cEee/Z+I12mZcFJshKcCqC8tuX5hG3s+d+9nZ3LabqKF1vKdF41B92pJVCBggjAGORAeOzyyDDKrZwIkLffeOQ==", + "dev": true + }, + "@floating-ui/core": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-0.7.3.tgz", + "integrity": "sha512-buc8BXHmG9l82+OQXOFU3Kr2XQx9ys01U/Q9HMIrZ300iLc8HLMgh7dcCqgYzAzf4BkoQvDcXf5Y+CuEZ5JBYg==" + }, + "@floating-ui/dom": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-0.5.4.tgz", + "integrity": "sha512-419BMceRLq0RrmTSDxn8hf9R3VCJv2K9PUfugh5JyEFmdjzDo+e8U5EdR8nzKq8Yj1htzLm3b6eQEEam3/rrtg==", + "requires": { + "@floating-ui/core": "^0.7.3" + } + }, + "@floating-ui/react-dom": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-0.7.2.tgz", + "integrity": "sha512-1T0sJcpHgX/u4I1OzIEhlcrvkUN8ln39nz7fMoE/2HDHrPiMFoOGR7++GYyfUmIQHkkrTinaeQsO3XWubjSvGg==", + "requires": { + "@floating-ui/dom": "^0.5.3", + "use-isomorphic-layout-effect": "^1.1.1" + } + }, + "@fontsource/inter": { + "version": "4.5.15", + "resolved": "https://registry.npmjs.org/@fontsource/inter/-/inter-4.5.15.tgz", + "integrity": "sha512-FzleM9AxZQK2nqsTDtBiY0PMEVWvnKnuu2i09+p6DHvrHsuucoV2j0tmw+kAT3L4hvsLdAIDv6MdGehsPIdT+Q==" + }, "@fortawesome/fontawesome-common-types": { "version": "6.1.2", "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.1.2.tgz", @@ -8317,13 +24366,12 @@ "@headlessui/react": { "version": "1.6.6", "resolved": "https://registry.npmjs.org/@headlessui/react/-/react-1.6.6.tgz", - "integrity": "sha512-MFJtmj9Xh/hhBMhLccGbBoSk+sk61BlP6sJe4uQcVMtXZhCgGqd2GyIQzzmsdPdTEWGSF434CBi8mnhR6um46Q==", - "requires": {} + "integrity": "sha512-MFJtmj9Xh/hhBMhLccGbBoSk+sk61BlP6sJe4uQcVMtXZhCgGqd2GyIQzzmsdPdTEWGSF434CBi8mnhR6um46Q==" }, "@humanwhocodes/config-array": { - "version": "0.11.7", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.7.tgz", - "integrity": "sha512-kBbPWzN8oVMLb0hOUYXhmxggL/1cJE6ydvjDIGi9EnAGUyA7cLVKQg+d/Dsm+KZwx2czGHrCmMVLiyg8s5JPKw==", + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", + "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", "dev": true, "requires": { "@humanwhocodes/object-schema": "^1.2.1", @@ -8360,6 +24408,194 @@ "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", "dev": true }, + "@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "requires": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "dependencies": { + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true + } + } + }, + "@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true + }, + "@jest/schemas": { + "version": "29.0.0", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.0.0.tgz", + "integrity": "sha512-3Ab5HgYIIAnS0HjqJHQYZS+zXc4tUmTmBH3z83ajI6afXp8X3ZtdLX+nXx+I7LNkJD7uN9LAVhgnjDgZa2z0kA==", + "dev": true, + "requires": { + "@sinclair/typebox": "^0.24.1" + } + }, + "@jest/transform": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.3.1.tgz", + "integrity": "sha512-8wmCFBTVGYqFNLWfcOWoVuMuKYPUBTnTMDkdvFtAYELwDOl9RGwOsvQWGPFxDJ8AWY9xM/8xCXdqmPK3+Q5Lug==", + "dev": true, + "requires": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.3.1", + "@jridgewell/trace-mapping": "^0.3.15", + "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.3.1", + "jest-regex-util": "^29.2.0", + "jest-util": "^29.3.1", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "@jest/types": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.3.1.tgz", + "integrity": "sha512-d0S0jmmTpjnhCmNpApgX3jrUZgZ22ivKJRvL2lli5hpCRoNnp1f85r2/wpKfXuYu8E7Jjh1hGfhPyup1NM5AmA==", + "dev": true, + "requires": { + "@jest/schemas": "^29.0.0", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, "@jridgewell/gen-mapping": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", @@ -8380,24 +24616,44 @@ "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==" }, + "@jridgewell/source-map": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", + "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, "@jridgewell/sourcemap-codec": { "version": "1.4.14", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" }, "@jridgewell/trace-mapping": { - "version": "0.3.14", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz", - "integrity": "sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==", + "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==", "requires": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + } + }, + "@mdx-js/react": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-2.2.1.tgz", + "integrity": "sha512-YdXcMcEnqZhzql98RNrqYo9cEhTTesBiCclEtoiQUbJwx87q9453GTapYU6kJ8ZZ2ek1Vp25SiAXEFy5O/eAPw==", + "dev": true, + "requires": { + "@types/mdx": "^2.0.0", + "@types/react": ">=16" } }, "@next/env": { - "version": "12.3.1", - "resolved": "https://registry.npmjs.org/@next/env/-/env-12.3.1.tgz", - "integrity": "sha512-9P9THmRFVKGKt9DYqeC2aKIxm8rlvkK38V1P1sRE7qyoPBIs8l9oo79QoSdPtOWfzkbDAVUqvbQGgTMsb8BtJg==" + "version": "12.3.4", + "resolved": "https://registry.npmjs.org/@next/env/-/env-12.3.4.tgz", + "integrity": "sha512-H/69Lc5Q02dq3o+dxxy5O/oNxFsZpdL6WREtOOtOM1B/weonIwDXkekr1KV5DPVPr12IHFPrMrcJQ6bgPMfn7A==" }, "@next/eslint-plugin-next": { "version": "13.0.5", @@ -8408,82 +24664,88 @@ "glob": "7.1.7" } }, + "@next/font": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/@next/font/-/font-13.1.2.tgz", + "integrity": "sha512-NXGXGFGiOKEnvBIHq9cdFTKbHO2/4B3Zd9K27M7j1DioIQVar7oVRqZMYs0h3XMVEZLwjjkdAtqRPCzzd3RtXg==", + "dev": true + }, "@next/swc-android-arm-eabi": { - "version": "12.3.1", - "resolved": "https://registry.npmjs.org/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-12.3.1.tgz", - "integrity": "sha512-i+BvKA8tB//srVPPQxIQN5lvfROcfv4OB23/L1nXznP+N/TyKL8lql3l7oo2LNhnH66zWhfoemg3Q4VJZSruzQ==", + "version": "12.3.4", + "resolved": "https://registry.npmjs.org/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-12.3.4.tgz", + "integrity": "sha512-cM42Cw6V4Bz/2+j/xIzO8nK/Q3Ly+VSlZJTa1vHzsocJRYz8KT6MrreXaci2++SIZCF1rVRCDgAg5PpqRibdIA==", "optional": true }, "@next/swc-android-arm64": { - "version": "12.3.1", - "resolved": "https://registry.npmjs.org/@next/swc-android-arm64/-/swc-android-arm64-12.3.1.tgz", - "integrity": "sha512-CmgU2ZNyBP0rkugOOqLnjl3+eRpXBzB/I2sjwcGZ7/Z6RcUJXK5Evz+N0ucOxqE4cZ3gkTeXtSzRrMK2mGYV8Q==", + "version": "12.3.4", + "resolved": "https://registry.npmjs.org/@next/swc-android-arm64/-/swc-android-arm64-12.3.4.tgz", + "integrity": "sha512-5jf0dTBjL+rabWjGj3eghpLUxCukRhBcEJgwLedewEA/LJk2HyqCvGIwj5rH+iwmq1llCWbOky2dO3pVljrapg==", "optional": true }, "@next/swc-darwin-arm64": { - "version": "12.3.1", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.3.1.tgz", - "integrity": "sha512-hT/EBGNcu0ITiuWDYU9ur57Oa4LybD5DOQp4f22T6zLfpoBMfBibPtR8XktXmOyFHrL/6FC2p9ojdLZhWhvBHg==", + "version": "12.3.4", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.3.4.tgz", + "integrity": "sha512-DqsSTd3FRjQUR6ao0E1e2OlOcrF5br+uegcEGPVonKYJpcr0MJrtYmPxd4v5T6UCJZ+XzydF7eQo5wdGvSZAyA==", "optional": true }, "@next/swc-darwin-x64": { - "version": "12.3.1", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-12.3.1.tgz", - "integrity": "sha512-9S6EVueCVCyGf2vuiLiGEHZCJcPAxglyckTZcEwLdJwozLqN0gtS0Eq0bQlGS3dH49Py/rQYpZ3KVWZ9BUf/WA==", + "version": "12.3.4", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-12.3.4.tgz", + "integrity": "sha512-PPF7tbWD4k0dJ2EcUSnOsaOJ5rhT3rlEt/3LhZUGiYNL8KvoqczFrETlUx0cUYaXe11dRA3F80Hpt727QIwByQ==", "optional": true }, "@next/swc-freebsd-x64": { - "version": "12.3.1", - "resolved": "https://registry.npmjs.org/@next/swc-freebsd-x64/-/swc-freebsd-x64-12.3.1.tgz", - "integrity": "sha512-qcuUQkaBZWqzM0F1N4AkAh88lLzzpfE6ImOcI1P6YeyJSsBmpBIV8o70zV+Wxpc26yV9vpzb+e5gCyxNjKJg5Q==", + "version": "12.3.4", + "resolved": "https://registry.npmjs.org/@next/swc-freebsd-x64/-/swc-freebsd-x64-12.3.4.tgz", + "integrity": "sha512-KM9JXRXi/U2PUM928z7l4tnfQ9u8bTco/jb939pdFUHqc28V43Ohd31MmZD1QzEK4aFlMRaIBQOWQZh4D/E5lQ==", "optional": true }, "@next/swc-linux-arm-gnueabihf": { - "version": "12.3.1", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.3.1.tgz", - "integrity": "sha512-diL9MSYrEI5nY2wc/h/DBewEDUzr/DqBjIgHJ3RUNtETAOB3spMNHvJk2XKUDjnQuluLmFMloet9tpEqU2TT9w==", + "version": "12.3.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.3.4.tgz", + "integrity": "sha512-3zqD3pO+z5CZyxtKDTnOJ2XgFFRUBciOox6EWkoZvJfc9zcidNAQxuwonUeNts6Xbm8Wtm5YGIRC0x+12YH7kw==", "optional": true }, "@next/swc-linux-arm64-gnu": { - "version": "12.3.1", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.3.1.tgz", - "integrity": "sha512-o/xB2nztoaC7jnXU3Q36vGgOolJpsGG8ETNjxM1VAPxRwM7FyGCPHOMk1XavG88QZSQf+1r+POBW0tLxQOJ9DQ==", + "version": "12.3.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.3.4.tgz", + "integrity": "sha512-kiX0vgJGMZVv+oo1QuObaYulXNvdH/IINmvdZnVzMO/jic/B8EEIGlZ8Bgvw8LCjH3zNVPO3mGrdMvnEEPEhKA==", "optional": true }, "@next/swc-linux-arm64-musl": { - "version": "12.3.1", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.3.1.tgz", - "integrity": "sha512-2WEasRxJzgAmP43glFNhADpe8zB7kJofhEAVNbDJZANp+H4+wq+/cW1CdDi8DqjkShPEA6/ejJw+xnEyDID2jg==", + "version": "12.3.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.3.4.tgz", + "integrity": "sha512-EETZPa1juczrKLWk5okoW2hv7D7WvonU+Cf2CgsSoxgsYbUCZ1voOpL4JZTOb6IbKMDo6ja+SbY0vzXZBUMvkQ==", "optional": true }, "@next/swc-linux-x64-gnu": { - "version": "12.3.1", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.3.1.tgz", - "integrity": "sha512-JWEaMyvNrXuM3dyy9Pp5cFPuSSvG82+yABqsWugjWlvfmnlnx9HOQZY23bFq3cNghy5V/t0iPb6cffzRWylgsA==", + "version": "12.3.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.3.4.tgz", + "integrity": "sha512-4csPbRbfZbuWOk3ATyWcvVFdD9/Rsdq5YHKvRuEni68OCLkfy4f+4I9OBpyK1SKJ00Cih16NJbHE+k+ljPPpag==", "optional": true }, "@next/swc-linux-x64-musl": { - "version": "12.3.1", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.3.1.tgz", - "integrity": "sha512-xoEWQQ71waWc4BZcOjmatuvPUXKTv6MbIFzpm4LFeCHsg2iwai0ILmNXf81rJR+L1Wb9ifEke2sQpZSPNz1Iyg==", + "version": "12.3.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.3.4.tgz", + "integrity": "sha512-YeBmI+63Ro75SUiL/QXEVXQ19T++58aI/IINOyhpsRL1LKdyfK/35iilraZEFz9bLQrwy1LYAR5lK200A9Gjbg==", "optional": true }, "@next/swc-win32-arm64-msvc": { - "version": "12.3.1", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.3.1.tgz", - "integrity": "sha512-hswVFYQYIeGHE2JYaBVtvqmBQ1CppplQbZJS/JgrVI3x2CurNhEkmds/yqvDONfwfbttTtH4+q9Dzf/WVl3Opw==", + "version": "12.3.4", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.3.4.tgz", + "integrity": "sha512-Sd0qFUJv8Tj0PukAYbCCDbmXcMkbIuhnTeHm9m4ZGjCf6kt7E/RMs55Pd3R5ePjOkN7dJEuxYBehawTR/aPDSQ==", "optional": true }, "@next/swc-win32-ia32-msvc": { - "version": "12.3.1", - "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.3.1.tgz", - "integrity": "sha512-Kny5JBehkTbKPmqulr5i+iKntO5YMP+bVM8Hf8UAmjSMVo3wehyLVc9IZkNmcbxi+vwETnQvJaT5ynYBkJ9dWA==", + "version": "12.3.4", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.3.4.tgz", + "integrity": "sha512-rt/vv/vg/ZGGkrkKcuJ0LyliRdbskQU+91bje+PgoYmxTZf/tYs6IfbmgudBJk6gH3QnjHWbkphDdRQrseRefQ==", "optional": true }, "@next/swc-win32-x64-msvc": { - "version": "12.3.1", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.3.1.tgz", - "integrity": "sha512-W1ijvzzg+kPEX6LAc+50EYYSEo0FVu7dmTE+t+DM4iOLqgGHoW9uYSz9wCVdkXOEEMP9xhXfGpcSxsfDucyPkA==", + "version": "12.3.4", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.3.4.tgz", + "integrity": "sha512-DQ20JEfTBZAgF8QCjYfJhv2/279M6onxFjdG/+5B0Cyj00/EdBxiWb2eGGFgQhrBbNv/lsvzFbbi0Ptf8Vw/bg==", "optional": true }, "@nodelib/fs.scandir": { @@ -8526,6 +24788,525 @@ "tslib": "^2.4.0" } }, + "@pmmmwh/react-refresh-webpack-plugin": { + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.10.tgz", + "integrity": "sha512-j0Ya0hCFZPd4x40qLzbhGsh9TMtdb+CJQiso+WxLOPNasohq9cc5SNUcwsZaRH6++Xh91Xkm/xHCkuIiIu0LUA==", + "dev": true, + "requires": { + "ansi-html-community": "^0.0.8", + "common-path-prefix": "^3.0.0", + "core-js-pure": "^3.23.3", + "error-stack-parser": "^2.0.6", + "find-up": "^5.0.0", + "html-entities": "^2.1.0", + "loader-utils": "^2.0.4", + "schema-utils": "^3.0.0", + "source-map": "^0.7.3" + }, + "dependencies": { + "loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + }, + "source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true + } + } + }, + "@radix-ui/number": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.0.0.tgz", + "integrity": "sha512-Ofwh/1HX69ZfJRiRBMTy7rgjAzHmwe4kW9C9Y99HTRUcYLUuVT0KESFj15rPjRgKJs20GPq8Bm5aEDJ8DuA3vA==", + "requires": { + "@babel/runtime": "^7.13.10" + } + }, + "@radix-ui/primitive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.0.0.tgz", + "integrity": "sha512-3e7rn8FDMin4CgeL7Z/49smCA3rFYY3Ha2rUQ7HRWFadS5iCRw08ZgVT1LaNTCNqgvrUiyczLflrVrF0SRQtNA==", + "requires": { + "@babel/runtime": "^7.13.10" + } + }, + "@radix-ui/react-accordion": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-accordion/-/react-accordion-1.1.0.tgz", + "integrity": "sha512-CNN9ZBgCK4i4SX7gFk5s8095j55DUWi85vwRNfkfBLs0QdAG5Tb4ku6sBeugCAiLvsmxw481GyNl+C3stoJVBQ==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.0", + "@radix-ui/react-collapsible": "1.0.1", + "@radix-ui/react-collection": "1.0.1", + "@radix-ui/react-compose-refs": "1.0.0", + "@radix-ui/react-context": "1.0.0", + "@radix-ui/react-direction": "1.0.0", + "@radix-ui/react-id": "1.0.0", + "@radix-ui/react-primitive": "1.0.1", + "@radix-ui/react-use-controllable-state": "1.0.0" + } + }, + "@radix-ui/react-alert-dialog": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-alert-dialog/-/react-alert-dialog-1.0.2.tgz", + "integrity": "sha512-0MtxV53FaEEBOKRgyLnEqHZKKDS5BldQ9oUBsKVXWI5FHbl2jp35qs+0aJET+K5hJDsc40kQUzP7g+wC7tqrqA==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.0", + "@radix-ui/react-compose-refs": "1.0.0", + "@radix-ui/react-context": "1.0.0", + "@radix-ui/react-dialog": "1.0.2", + "@radix-ui/react-primitive": "1.0.1", + "@radix-ui/react-slot": "1.0.1" + } + }, + "@radix-ui/react-arrow": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.0.1.tgz", + "integrity": "sha512-1yientwXqXcErDHEv8av9ZVNEBldH8L9scVR3is20lL+jOCfcJyMFZFEY5cgIrgexsq1qggSXqiEL/d/4f+QXA==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-primitive": "1.0.1" + } + }, + "@radix-ui/react-checkbox": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-checkbox/-/react-checkbox-1.0.1.tgz", + "integrity": "sha512-TisH0B8hWmYP3ONRduYCyN04rR9yLPIw/Rwyn1RoC1suSoGCa8Wn+YPdSSSarSszeIbcg3p2lBkDp2XXit4sZw==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.0", + "@radix-ui/react-compose-refs": "1.0.0", + "@radix-ui/react-context": "1.0.0", + "@radix-ui/react-presence": "1.0.0", + "@radix-ui/react-primitive": "1.0.1", + "@radix-ui/react-use-controllable-state": "1.0.0", + "@radix-ui/react-use-previous": "1.0.0", + "@radix-ui/react-use-size": "1.0.0" + } + }, + "@radix-ui/react-collapsible": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.0.1.tgz", + "integrity": "sha512-0maX4q91iYa4gjt3PsNf7dq/yqSR+HGAE8I5p54dQ6gnveS+ETWlMoijxrhmgV1k8svxpm34mQAtqIrJt4XZmA==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.0", + "@radix-ui/react-compose-refs": "1.0.0", + "@radix-ui/react-context": "1.0.0", + "@radix-ui/react-id": "1.0.0", + "@radix-ui/react-presence": "1.0.0", + "@radix-ui/react-primitive": "1.0.1", + "@radix-ui/react-use-controllable-state": "1.0.0", + "@radix-ui/react-use-layout-effect": "1.0.0" + } + }, + "@radix-ui/react-collection": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.0.1.tgz", + "integrity": "sha512-uuiFbs+YCKjn3X1DTSx9G7BHApu4GHbi3kgiwsnFUbOKCrwejAJv4eE4Vc8C0Oaxt9T0aV4ox0WCOdx+39Xo+g==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-compose-refs": "1.0.0", + "@radix-ui/react-context": "1.0.0", + "@radix-ui/react-primitive": "1.0.1", + "@radix-ui/react-slot": "1.0.1" + } + }, + "@radix-ui/react-compose-refs": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.0.0.tgz", + "integrity": "sha512-0KaSv6sx787/hK3eF53iOkiSLwAGlFMx5lotrqD2pTjB18KbybKoEIgkNZTKC60YECDQTKGTRcDBILwZVqVKvA==", + "requires": { + "@babel/runtime": "^7.13.10" + } + }, + "@radix-ui/react-context": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.0.0.tgz", + "integrity": "sha512-1pVM9RfOQ+n/N5PJK33kRSKsr1glNxomxONs5c49MliinBY6Yw2Q995qfBUUo0/Mbg05B/sGA0gkgPI7kmSHBg==", + "requires": { + "@babel/runtime": "^7.13.10" + } + }, + "@radix-ui/react-dialog": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.0.2.tgz", + "integrity": "sha512-EKxxp2WNSmUPkx4trtWNmZ4/vAYEg7JkAfa1HKBUnaubw9eHzf1Orr9B472lJYaYz327RHDrd4R95fsw7VR8DA==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.0", + "@radix-ui/react-compose-refs": "1.0.0", + "@radix-ui/react-context": "1.0.0", + "@radix-ui/react-dismissable-layer": "1.0.2", + "@radix-ui/react-focus-guards": "1.0.0", + "@radix-ui/react-focus-scope": "1.0.1", + "@radix-ui/react-id": "1.0.0", + "@radix-ui/react-portal": "1.0.1", + "@radix-ui/react-presence": "1.0.0", + "@radix-ui/react-primitive": "1.0.1", + "@radix-ui/react-slot": "1.0.1", + "@radix-ui/react-use-controllable-state": "1.0.0", + "aria-hidden": "^1.1.1", + "react-remove-scroll": "2.5.5" + } + }, + "@radix-ui/react-direction": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.0.0.tgz", + "integrity": "sha512-2HV05lGUgYcA6xgLQ4BKPDmtL+QbIZYH5fCOTAOOcJ5O0QbWS3i9lKaurLzliYUDhORI2Qr3pyjhJh44lKA3rQ==", + "requires": { + "@babel/runtime": "^7.13.10" + } + }, + "@radix-ui/react-dismissable-layer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.0.2.tgz", + "integrity": "sha512-WjJzMrTWROozDqLB0uRWYvj4UuXsM/2L19EmQ3Au+IJWqwvwq9Bwd+P8ivo0Deg9JDPArR1I6MbWNi1CmXsskg==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.0", + "@radix-ui/react-compose-refs": "1.0.0", + "@radix-ui/react-primitive": "1.0.1", + "@radix-ui/react-use-callback-ref": "1.0.0", + "@radix-ui/react-use-escape-keydown": "1.0.2" + } + }, + "@radix-ui/react-dropdown-menu": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.0.2.tgz", + "integrity": "sha512-r0kN0fstrSi+uAdK2GkLxnnbhqVBy/9Q4o4PvGOYipW0BldQlYBMSmZprvCNj2i2mAATx16kvzIn12GnaGjbMw==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.0", + "@radix-ui/react-compose-refs": "1.0.0", + "@radix-ui/react-context": "1.0.0", + "@radix-ui/react-id": "1.0.0", + "@radix-ui/react-menu": "2.0.2", + "@radix-ui/react-primitive": "1.0.1", + "@radix-ui/react-use-controllable-state": "1.0.0" + } + }, + "@radix-ui/react-focus-guards": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.0.0.tgz", + "integrity": "sha512-UagjDk4ijOAnGu4WMUPj9ahi7/zJJqNZ9ZAiGPp7waUWJO0O1aWXi/udPphI0IUjvrhBsZJGSN66dR2dsueLWQ==", + "requires": { + "@babel/runtime": "^7.13.10" + } + }, + "@radix-ui/react-focus-scope": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.0.1.tgz", + "integrity": "sha512-Ej2MQTit8IWJiS2uuujGUmxXjF/y5xZptIIQnyd2JHLwtV0R2j9NRVoRj/1j/gJ7e3REdaBw4Hjf4a1ImhkZcQ==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-compose-refs": "1.0.0", + "@radix-ui/react-primitive": "1.0.1", + "@radix-ui/react-use-callback-ref": "1.0.0" + } + }, + "@radix-ui/react-id": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.0.0.tgz", + "integrity": "sha512-Q6iAB/U7Tq3NTolBBQbHTgclPmGWE3OlktGGqrClPozSw4vkQ1DfQAOtzgRPecKsMdJINE05iaoDUG8tRzCBjw==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-use-layout-effect": "1.0.0" + } + }, + "@radix-ui/react-label": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.0.0.tgz", + "integrity": "sha512-7qCcZ3j2VQspWjy+gKR4W+V/z0XueQjeiZnlPOtsyiP9HaS8bfSU7ECoI3bvvdYntQj7NElW7OAYsYRW4MQvCg==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-primitive": "1.0.1" + } + }, + "@radix-ui/react-menu": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.0.2.tgz", + "integrity": "sha512-H5dtBi/k3tc45IMd2Pu+Q2PyONFlsYJ5sWUlflSs8BQRghh5GhJHLRuB1yb88VOywuzzvGkaR/HUJJ65Jf2POA==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.0", + "@radix-ui/react-collection": "1.0.1", + "@radix-ui/react-compose-refs": "1.0.0", + "@radix-ui/react-context": "1.0.0", + "@radix-ui/react-direction": "1.0.0", + "@radix-ui/react-dismissable-layer": "1.0.2", + "@radix-ui/react-focus-guards": "1.0.0", + "@radix-ui/react-focus-scope": "1.0.1", + "@radix-ui/react-id": "1.0.0", + "@radix-ui/react-popper": "1.1.0", + "@radix-ui/react-portal": "1.0.1", + "@radix-ui/react-presence": "1.0.0", + "@radix-ui/react-primitive": "1.0.1", + "@radix-ui/react-roving-focus": "1.0.2", + "@radix-ui/react-slot": "1.0.1", + "@radix-ui/react-use-callback-ref": "1.0.0", + "aria-hidden": "^1.1.1", + "react-remove-scroll": "2.5.5" + } + }, + "@radix-ui/react-popover": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.0.3.tgz", + "integrity": "sha512-YwedSukfWsyJs3/yP3yXUq44k4/JBe3jqU63Z8v2i19qZZ3dsx32oma17ztgclWPNuqp3A+Xa9UiDlZHyVX8Vg==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.0", + "@radix-ui/react-compose-refs": "1.0.0", + "@radix-ui/react-context": "1.0.0", + "@radix-ui/react-dismissable-layer": "1.0.2", + "@radix-ui/react-focus-guards": "1.0.0", + "@radix-ui/react-focus-scope": "1.0.1", + "@radix-ui/react-id": "1.0.0", + "@radix-ui/react-popper": "1.1.0", + "@radix-ui/react-portal": "1.0.1", + "@radix-ui/react-presence": "1.0.0", + "@radix-ui/react-primitive": "1.0.1", + "@radix-ui/react-slot": "1.0.1", + "@radix-ui/react-use-controllable-state": "1.0.0", + "aria-hidden": "^1.1.1", + "react-remove-scroll": "2.5.5" + } + }, + "@radix-ui/react-popper": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.1.0.tgz", + "integrity": "sha512-07U7jpI0dZcLRAxT7L9qs6HecSoPhDSJybF7mEGHJDBDv+ZoGCvIlva0s+WxMXwJEav+ckX3hAlXBtnHmuvlCQ==", + "requires": { + "@babel/runtime": "^7.13.10", + "@floating-ui/react-dom": "0.7.2", + "@radix-ui/react-arrow": "1.0.1", + "@radix-ui/react-compose-refs": "1.0.0", + "@radix-ui/react-context": "1.0.0", + "@radix-ui/react-primitive": "1.0.1", + "@radix-ui/react-use-callback-ref": "1.0.0", + "@radix-ui/react-use-layout-effect": "1.0.0", + "@radix-ui/react-use-rect": "1.0.0", + "@radix-ui/react-use-size": "1.0.0", + "@radix-ui/rect": "1.0.0" + } + }, + "@radix-ui/react-portal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.0.1.tgz", + "integrity": "sha512-NY2vUWI5WENgAT1nfC6JS7RU5xRYBfjZVLq0HmgEN1Ezy3rk/UruMV4+Rd0F40PEaFC5SrLS1ixYvcYIQrb4Ig==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-primitive": "1.0.1" + } + }, + "@radix-ui/react-presence": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.0.0.tgz", + "integrity": "sha512-A+6XEvN01NfVWiKu38ybawfHsBjWum42MRPnEuqPsBZ4eV7e/7K321B5VgYMPv3Xx5An6o1/l9ZuDBgmcmWK3w==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-compose-refs": "1.0.0", + "@radix-ui/react-use-layout-effect": "1.0.0" + } + }, + "@radix-ui/react-primitive": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-1.0.1.tgz", + "integrity": "sha512-fHbmislWVkZaIdeF6GZxF0A/NH/3BjrGIYj+Ae6eTmTCr7EB0RQAAVEiqsXK6p3/JcRqVSBQoceZroj30Jj3XA==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-slot": "1.0.1" + } + }, + "@radix-ui/react-progress": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-progress/-/react-progress-1.0.1.tgz", + "integrity": "sha512-QbDf9eguM5QtkvGcGHe/nUgloM9yfRGpJTB/Te5cn4WmVHvcbhHyHw39/rbCZxNX4E+GEPp5Vs6+mEoyIotUbg==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-context": "1.0.0", + "@radix-ui/react-primitive": "1.0.1" + } + }, + "@radix-ui/react-roving-focus": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.0.2.tgz", + "integrity": "sha512-HLK+CqD/8pN6GfJm3U+cqpqhSKYAWiOJDe+A+8MfxBnOue39QEeMa43csUn2CXCHQT0/mewh1LrrG4tfkM9DMA==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.0", + "@radix-ui/react-collection": "1.0.1", + "@radix-ui/react-compose-refs": "1.0.0", + "@radix-ui/react-context": "1.0.0", + "@radix-ui/react-direction": "1.0.0", + "@radix-ui/react-id": "1.0.0", + "@radix-ui/react-primitive": "1.0.1", + "@radix-ui/react-use-callback-ref": "1.0.0", + "@radix-ui/react-use-controllable-state": "1.0.0" + } + }, + "@radix-ui/react-select": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-1.2.0.tgz", + "integrity": "sha512-MmXKsIBrG9GKxt8JKIn75LEPiX/zejBmj/Z36Hxtm9cdmCFzTo78QJ0Q3buLGzr0c3lzXdfgeKntmgCzaGxgkw==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/number": "1.0.0", + "@radix-ui/primitive": "1.0.0", + "@radix-ui/react-collection": "1.0.1", + "@radix-ui/react-compose-refs": "1.0.0", + "@radix-ui/react-context": "1.0.0", + "@radix-ui/react-direction": "1.0.0", + "@radix-ui/react-dismissable-layer": "1.0.2", + "@radix-ui/react-focus-guards": "1.0.0", + "@radix-ui/react-focus-scope": "1.0.1", + "@radix-ui/react-id": "1.0.0", + "@radix-ui/react-popper": "1.1.0", + "@radix-ui/react-portal": "1.0.1", + "@radix-ui/react-primitive": "1.0.1", + "@radix-ui/react-slot": "1.0.1", + "@radix-ui/react-use-callback-ref": "1.0.0", + "@radix-ui/react-use-controllable-state": "1.0.0", + "@radix-ui/react-use-layout-effect": "1.0.0", + "@radix-ui/react-use-previous": "1.0.0", + "@radix-ui/react-visually-hidden": "1.0.1", + "aria-hidden": "^1.1.1", + "react-remove-scroll": "2.5.5" + } + }, + "@radix-ui/react-slot": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.0.1.tgz", + "integrity": "sha512-avutXAFL1ehGvAXtPquu0YK5oz6ctS474iM3vNGQIkswrVhdrS52e3uoMQBzZhNRAIE0jBnUyXWNmSjGHhCFcw==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-compose-refs": "1.0.0" + } + }, + "@radix-ui/react-switch": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-switch/-/react-switch-1.0.1.tgz", + "integrity": "sha512-tTxGluMtwrc5ffgAiOSMrYIx0r3vSTcgM4Vl8rqfpXcHt6ryB9B0OlFKUOiDpKASXlhvzfHf4Y0AYKJdpzjL8w==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.0", + "@radix-ui/react-compose-refs": "1.0.0", + "@radix-ui/react-context": "1.0.0", + "@radix-ui/react-primitive": "1.0.1", + "@radix-ui/react-use-controllable-state": "1.0.0", + "@radix-ui/react-use-previous": "1.0.0", + "@radix-ui/react-use-size": "1.0.0" + } + }, + "@radix-ui/react-toast": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toast/-/react-toast-1.1.2.tgz", + "integrity": "sha512-Kpr4BBYoP0O5A1UeDBmao87UnCMNdAKGNioQH5JzEm6OYTUVGhuDRbOwoZxPwOZ6vsjJHeIpdUrwbiHEB65CCw==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.0", + "@radix-ui/react-collection": "1.0.1", + "@radix-ui/react-compose-refs": "1.0.0", + "@radix-ui/react-context": "1.0.0", + "@radix-ui/react-dismissable-layer": "1.0.2", + "@radix-ui/react-portal": "1.0.1", + "@radix-ui/react-presence": "1.0.0", + "@radix-ui/react-primitive": "1.0.1", + "@radix-ui/react-use-callback-ref": "1.0.0", + "@radix-ui/react-use-controllable-state": "1.0.0", + "@radix-ui/react-use-layout-effect": "1.0.0", + "@radix-ui/react-visually-hidden": "1.0.1" + } + }, + "@radix-ui/react-use-callback-ref": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.0.0.tgz", + "integrity": "sha512-GZtyzoHz95Rhs6S63D2t/eqvdFCm7I+yHMLVQheKM7nBD8mbZIt+ct1jz4536MDnaOGKIxynJ8eHTkVGVVkoTg==", + "requires": { + "@babel/runtime": "^7.13.10" + } + }, + "@radix-ui/react-use-controllable-state": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.0.0.tgz", + "integrity": "sha512-FohDoZvk3mEXh9AWAVyRTYR4Sq7/gavuofglmiXB2g1aKyboUD4YtgWxKj8O5n+Uak52gXQ4wKz5IFST4vtJHg==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-use-callback-ref": "1.0.0" + } + }, + "@radix-ui/react-use-escape-keydown": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.0.2.tgz", + "integrity": "sha512-DXGim3x74WgUv+iMNCF+cAo8xUHHeqvjx8zs7trKf+FkQKPQXLk2sX7Gx1ysH7Q76xCpZuxIJE7HLPxRE+Q+GA==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-use-callback-ref": "1.0.0" + } + }, + "@radix-ui/react-use-layout-effect": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.0.0.tgz", + "integrity": "sha512-6Tpkq+R6LOlmQb1R5NNETLG0B4YP0wc+klfXafpUCj6JGyaUc8il7/kUZ7m59rGbXGczE9Bs+iz2qloqsZBduQ==", + "requires": { + "@babel/runtime": "^7.13.10" + } + }, + "@radix-ui/react-use-previous": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.0.0.tgz", + "integrity": "sha512-RG2K8z/K7InnOKpq6YLDmT49HGjNmrK+fr82UCVKT2sW0GYfVnYp4wZWBooT/EYfQ5faA9uIjvsuMMhH61rheg==", + "requires": { + "@babel/runtime": "^7.13.10" + } + }, + "@radix-ui/react-use-rect": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.0.0.tgz", + "integrity": "sha512-TB7pID8NRMEHxb/qQJpvSt3hQU4sqNPM1VCTjTRjEOa7cEop/QMuq8S6fb/5Tsz64kqSvB9WnwsDHtjnrM9qew==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/rect": "1.0.0" + } + }, + "@radix-ui/react-use-size": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.0.0.tgz", + "integrity": "sha512-imZ3aYcoYCKhhgNpkNDh/aTiU05qw9hX+HHI1QDBTyIlcFjgeFlKKySNGMwTp7nYFLQg/j0VA2FmCY4WPDDHMg==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-use-layout-effect": "1.0.0" + } + }, + "@radix-ui/react-visually-hidden": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.0.1.tgz", + "integrity": "sha512-K1hJcCMfWfiYUibRqf3V8r5Drpyf7rh44jnrwAbdvI5iCCijilBBeyQv9SKidYNZIopMdCyR9FnIjkHxHN0FcQ==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-primitive": "1.0.1" + } + }, + "@radix-ui/rect": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.0.0.tgz", + "integrity": "sha512-d0O68AYy/9oeEy1DdC07bz1/ZXX+DqCskRd3i4JzLSTXwefzaepQrKjXC7aNM8lTHjFLDO0pDgaEiQ7jEk+HVg==", + "requires": { + "@babel/runtime": "^7.13.10" + } + }, "@reduxjs/toolkit": { "version": "1.8.3", "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.8.3.tgz", @@ -8548,6 +25329,1673 @@ "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.15.0.tgz", "integrity": "sha512-MN9haDRh9ZOsTotoDTHu2BT3sT8Vs1F0alhizUpDyjN2YgBCqR6JV+AbAE1XNHwS2+5zbppch1PwJUVeE58URQ==" }, + "@sinclair/typebox": { + "version": "0.24.51", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", + "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==", + "dev": true + }, + "@storybook/addon-actions": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/addon-actions/-/addon-actions-7.0.0-beta.30.tgz", + "integrity": "sha512-hk7e0B6kSPD/m5+pU6lKS3CzBBYf3n74m33cFjTRyhk8vO8x5QC5tni8nZdzmqREthoIOIf+1zHxYDO8SLE5zg==", + "dev": true, + "requires": { + "@storybook/client-logger": "7.0.0-beta.30", + "@storybook/components": "7.0.0-beta.30", + "@storybook/core-events": "7.0.0-beta.30", + "@storybook/global": "^5.0.0", + "@storybook/manager-api": "7.0.0-beta.30", + "@storybook/preview-api": "7.0.0-beta.30", + "@storybook/theming": "7.0.0-beta.30", + "@storybook/types": "7.0.0-beta.30", + "dequal": "^2.0.2", + "lodash": "^4.17.21", + "polished": "^4.2.2", + "prop-types": "^15.7.2", + "react-inspector": "^6.0.0", + "telejson": "^7.0.3", + "ts-dedent": "^2.0.0", + "uuid-browser": "^3.1.0" + } + }, + "@storybook/addon-backgrounds": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/addon-backgrounds/-/addon-backgrounds-7.0.0-beta.30.tgz", + "integrity": "sha512-UDPWQEwreK1TXjBjAmZN40uu5+7hC5dobdZhZr+i/4W+xswFMgprT4PtvfcoVyFTdOjRIsIDd0doLurvB5c1ng==", + "dev": true, + "requires": { + "@storybook/client-logger": "7.0.0-beta.30", + "@storybook/components": "7.0.0-beta.30", + "@storybook/core-events": "7.0.0-beta.30", + "@storybook/global": "^5.0.0", + "@storybook/manager-api": "7.0.0-beta.30", + "@storybook/preview-api": "7.0.0-beta.30", + "@storybook/theming": "7.0.0-beta.30", + "@storybook/types": "7.0.0-beta.30", + "memoizerific": "^1.11.3", + "ts-dedent": "^2.0.0" + } + }, + "@storybook/addon-controls": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/addon-controls/-/addon-controls-7.0.0-beta.30.tgz", + "integrity": "sha512-5ybbmFH+gcrBRfJnRTdSgNbCYMJMHQY2QTNqukUHO0CjAPEZMpPCFkiQNdIBLslsju9+bunVo1S/MBfwH3Ku7Q==", + "dev": true, + "requires": { + "@storybook/blocks": "7.0.0-beta.30", + "@storybook/client-logger": "7.0.0-beta.30", + "@storybook/components": "7.0.0-beta.30", + "@storybook/core-common": "7.0.0-beta.30", + "@storybook/manager-api": "7.0.0-beta.30", + "@storybook/node-logger": "7.0.0-beta.30", + "@storybook/preview-api": "7.0.0-beta.30", + "@storybook/theming": "7.0.0-beta.30", + "@storybook/types": "7.0.0-beta.30", + "lodash": "^4.17.21", + "ts-dedent": "^2.0.0" + } + }, + "@storybook/addon-docs": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/addon-docs/-/addon-docs-7.0.0-beta.30.tgz", + "integrity": "sha512-++SN8wmtiKE+bKbhscO8656GPZOFIEv31a3qYgId3W8wg/9YmTKUmXrejjUi3SZmO3xKVZ0bskJUw16oBWddug==", + "dev": true, + "requires": { + "@babel/core": "^7.20.2", + "@babel/plugin-transform-react-jsx": "^7.19.0", + "@jest/transform": "^29.3.1", + "@mdx-js/react": "^2.1.5", + "@storybook/blocks": "7.0.0-beta.30", + "@storybook/client-logger": "7.0.0-beta.30", + "@storybook/components": "7.0.0-beta.30", + "@storybook/csf-plugin": "7.0.0-beta.30", + "@storybook/csf-tools": "7.0.0-beta.30", + "@storybook/global": "^5.0.0", + "@storybook/mdx2-csf": "next", + "@storybook/node-logger": "7.0.0-beta.30", + "@storybook/postinstall": "7.0.0-beta.30", + "@storybook/preview-api": "7.0.0-beta.30", + "@storybook/theming": "7.0.0-beta.30", + "@storybook/types": "7.0.0-beta.30", + "fs-extra": "^9.0.1", + "remark-external-links": "^8.0.0", + "remark-slug": "^6.0.0", + "ts-dedent": "^2.0.0" + } + }, + "@storybook/addon-essentials": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/addon-essentials/-/addon-essentials-7.0.0-beta.30.tgz", + "integrity": "sha512-3X4WMrf4TCSN9iDrGAQlIM7bj8r+aov4O1Q/fM73n3B6puOG25uMzhT2V8MB4aJdGOXeYvvjAh5rMBdHxfQjPQ==", + "dev": true, + "requires": { + "@storybook/addon-actions": "7.0.0-beta.30", + "@storybook/addon-backgrounds": "7.0.0-beta.30", + "@storybook/addon-controls": "7.0.0-beta.30", + "@storybook/addon-docs": "7.0.0-beta.30", + "@storybook/addon-highlight": "7.0.0-beta.30", + "@storybook/addon-measure": "7.0.0-beta.30", + "@storybook/addon-outline": "7.0.0-beta.30", + "@storybook/addon-toolbars": "7.0.0-beta.30", + "@storybook/addon-viewport": "7.0.0-beta.30", + "@storybook/core-common": "7.0.0-beta.30", + "@storybook/manager-api": "7.0.0-beta.30", + "@storybook/node-logger": "7.0.0-beta.30", + "@storybook/preview-api": "7.0.0-beta.30", + "ts-dedent": "^2.0.0" + } + }, + "@storybook/addon-highlight": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/addon-highlight/-/addon-highlight-7.0.0-beta.30.tgz", + "integrity": "sha512-wyOl7mHGBB6u9I4uqn8PMlAGbZEfa0LeeDLqzzxZWzGFrFUVqjthQ+BAIbb8C+wOs9eb0CTGEecJQhurbV+UuA==", + "dev": true, + "requires": { + "@storybook/core-events": "7.0.0-beta.30", + "@storybook/global": "^5.0.0", + "@storybook/preview-api": "7.0.0-beta.30" + } + }, + "@storybook/addon-interactions": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/addon-interactions/-/addon-interactions-7.0.0-beta.30.tgz", + "integrity": "sha512-mulmrEmDr9vynVVjmJ0OLiHd8NhGvrnTSrN6eMYLKp/VpOEOV0KgE28z+lqkeuAgRdcFG65ddV9AE8h1+rYxyg==", + "dev": true, + "requires": { + "@storybook/client-logger": "7.0.0-beta.30", + "@storybook/components": "7.0.0-beta.30", + "@storybook/core-common": "7.0.0-beta.30", + "@storybook/core-events": "7.0.0-beta.30", + "@storybook/global": "^5.0.0", + "@storybook/instrumenter": "7.0.0-beta.30", + "@storybook/manager-api": "7.0.0-beta.30", + "@storybook/preview-api": "7.0.0-beta.30", + "@storybook/theming": "7.0.0-beta.30", + "@storybook/types": "7.0.0-beta.30", + "jest-mock": "^27.0.6", + "polished": "^4.2.2", + "ts-dedent": "^2.2.0" + } + }, + "@storybook/addon-links": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/addon-links/-/addon-links-7.0.0-beta.30.tgz", + "integrity": "sha512-Uyj/WwUOGOTmDvYygM24vP0Zfj28ebYxtd07CYAlhvJ6P7yOb6H9v2cM/a2cJc1h7VmH9eohPNuTFDbv1P+QMQ==", + "dev": true, + "requires": { + "@storybook/client-logger": "7.0.0-beta.30", + "@storybook/core-events": "7.0.0-beta.30", + "@storybook/csf": "next", + "@storybook/global": "^5.0.0", + "@storybook/manager-api": "7.0.0-beta.30", + "@storybook/preview-api": "7.0.0-beta.30", + "@storybook/router": "7.0.0-beta.30", + "@storybook/types": "7.0.0-beta.30", + "prop-types": "^15.7.2", + "ts-dedent": "^2.0.0" + } + }, + "@storybook/addon-measure": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/addon-measure/-/addon-measure-7.0.0-beta.30.tgz", + "integrity": "sha512-tlY+CcZleoxMV5F50LLY/GFcWU8X5g9Td5K/pYqVw25jZFeqBZCZs+k0eqct1HeWKY64uutAYmljzrrwgpsUmw==", + "dev": true, + "requires": { + "@storybook/client-logger": "7.0.0-beta.30", + "@storybook/components": "7.0.0-beta.30", + "@storybook/core-events": "7.0.0-beta.30", + "@storybook/global": "^5.0.0", + "@storybook/manager-api": "7.0.0-beta.30", + "@storybook/preview-api": "7.0.0-beta.30", + "@storybook/types": "7.0.0-beta.30" + } + }, + "@storybook/addon-outline": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/addon-outline/-/addon-outline-7.0.0-beta.30.tgz", + "integrity": "sha512-qvJh05sc40NfF9RZ5KCVRHh3hRb0XCdxXP95qg7P0QF/BCRIrLTP8/94rT56IwhaMKDTttoU1x2PST0FDxQZaQ==", + "dev": true, + "requires": { + "@storybook/client-logger": "7.0.0-beta.30", + "@storybook/components": "7.0.0-beta.30", + "@storybook/core-events": "7.0.0-beta.30", + "@storybook/global": "^5.0.0", + "@storybook/manager-api": "7.0.0-beta.30", + "@storybook/preview-api": "7.0.0-beta.30", + "@storybook/types": "7.0.0-beta.30", + "ts-dedent": "^2.0.0" + } + }, + "@storybook/addon-postcss": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@storybook/addon-postcss/-/addon-postcss-2.0.0.tgz", + "integrity": "sha512-Nt82A7e9zJH4+A+VzLKKswUfru+T6FJTakj4dccP0i8DSn7a0CkzRPrLuZBq8tg4voV6gD74bcDf3gViCVBGtA==", + "dev": true, + "requires": { + "@storybook/node-logger": "^6.1.14", + "css-loader": "^3.6.0", + "postcss": "^7.0.35", + "postcss-loader": "^4.2.0", + "style-loader": "^1.3.0" + }, + "dependencies": { + "@storybook/node-logger": { + "version": "6.5.15", + "resolved": "https://registry.npmjs.org/@storybook/node-logger/-/node-logger-6.5.15.tgz", + "integrity": "sha512-LQjjbfMuUXm7wZTBKb+iGeCNnej4r1Jb2NxG3Svu2bVhaoB6u33jHAcbmhXpXW1jghzW3kQwOU7BoLuJiRRFIw==", + "dev": true, + "requires": { + "@types/npmlog": "^4.1.2", + "chalk": "^4.1.0", + "core-js": "^3.8.2", + "npmlog": "^5.0.1", + "pretty-hrtime": "^1.0.3" + } + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "css-loader": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-3.6.0.tgz", + "integrity": "sha512-M5lSukoWi1If8dhQAUCvj4H8vUt3vOnwbQBH9DdTm/s4Ym2B/3dPMtYZeJmq7Q3S3Pa+I94DcZ7pc9bP14cWIQ==", + "dev": true, + "requires": { + "camelcase": "^5.3.1", + "cssesc": "^3.0.0", + "icss-utils": "^4.1.1", + "loader-utils": "^1.2.3", + "normalize-path": "^3.0.0", + "postcss": "^7.0.32", + "postcss-modules-extract-imports": "^2.0.0", + "postcss-modules-local-by-default": "^3.0.2", + "postcss-modules-scope": "^2.2.0", + "postcss-modules-values": "^3.0.0", + "postcss-value-parser": "^4.1.0", + "schema-utils": "^2.7.0", + "semver": "^6.3.0" + }, + "dependencies": { + "schema-utils": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", + "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.5", + "ajv": "^6.12.4", + "ajv-keywords": "^3.5.2" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "icss-utils": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-4.1.1.tgz", + "integrity": "sha512-4aFq7wvWyMHKgxsH8QQtGpvbASCf+eM3wPRLI6R+MgAnTCZ6STYsRvttLvRWK0Nfif5piF394St3HeJDaljGPA==", + "dev": true, + "requires": { + "postcss": "^7.0.14" + } + }, + "json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "loader-utils": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz", + "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + } + }, + "picocolors": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", + "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", + "dev": true + }, + "postcss": { + "version": "7.0.39", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", + "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", + "dev": true, + "requires": { + "picocolors": "^0.2.1", + "source-map": "^0.6.1" + } + }, + "postcss-loader": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-4.3.0.tgz", + "integrity": "sha512-M/dSoIiNDOo8Rk0mUqoj4kpGq91gcxCfb9PoyZVdZ76/AuhxylHDYZblNE8o+EQ9AMSASeMFEKxZf5aU6wlx1Q==", + "dev": true, + "requires": { + "cosmiconfig": "^7.0.0", + "klona": "^2.0.4", + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0", + "semver": "^7.3.4" + }, + "dependencies": { + "json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true + }, + "loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + } + } + }, + "postcss-modules-extract-imports": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-2.0.0.tgz", + "integrity": "sha512-LaYLDNS4SG8Q5WAWqIJgdHPJrDDr/Lv775rMBFUbgjTz6j34lUznACHcdRWroPvXANP2Vj7yNK57vp9eFqzLWQ==", + "dev": true, + "requires": { + "postcss": "^7.0.5" + } + }, + "postcss-modules-local-by-default": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-3.0.3.tgz", + "integrity": "sha512-e3xDq+LotiGesympRlKNgaJ0PCzoUIdpH0dj47iWAui/kyTgh3CiAr1qP54uodmJhl6p9rN6BoNcdEDVJx9RDw==", + "dev": true, + "requires": { + "icss-utils": "^4.1.1", + "postcss": "^7.0.32", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + } + }, + "postcss-modules-scope": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-2.2.0.tgz", + "integrity": "sha512-YyEgsTMRpNd+HmyC7H/mh3y+MeFWevy7V1evVhJWewmMbjDHIbZbOXICC2y+m1xI1UVfIT1HMW/O04Hxyu9oXQ==", + "dev": true, + "requires": { + "postcss": "^7.0.6", + "postcss-selector-parser": "^6.0.0" + } + }, + "postcss-modules-values": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-3.0.0.tgz", + "integrity": "sha512-1//E5jCBrZ9DmRX+zCtmQtRSV6PV42Ix7Bzj9GbwJceduuf7IqP8MgeTXuRDHOWj2m0VzZD5+roFWDuU8RQjcg==", + "dev": true, + "requires": { + "icss-utils": "^4.0.0", + "postcss": "^7.0.6" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "style-loader": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-1.3.0.tgz", + "integrity": "sha512-V7TCORko8rs9rIqkSrlMfkqA63DfoGBBJmK1kKGCcSi+BWb4cqz0SRsnp4l6rU5iwOEd0/2ePv68SV22VXon4Q==", + "dev": true, + "requires": { + "loader-utils": "^2.0.0", + "schema-utils": "^2.7.0" + }, + "dependencies": { + "json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true + }, + "loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + }, + "schema-utils": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", + "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.5", + "ajv": "^6.12.4", + "ajv-keywords": "^3.5.2" + } + } + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "@storybook/addon-toolbars": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/addon-toolbars/-/addon-toolbars-7.0.0-beta.30.tgz", + "integrity": "sha512-b+aOu6lT9OR8WhqXDJwzV/u3DFvB3/Cl31UD1W6BrnqkoMJ7WbZy74stsNx0Kb2g6WqGzqHuErRtS2YMpCMUZA==", + "dev": true, + "requires": { + "@storybook/client-logger": "7.0.0-beta.30", + "@storybook/components": "7.0.0-beta.30", + "@storybook/manager-api": "7.0.0-beta.30", + "@storybook/preview-api": "7.0.0-beta.30", + "@storybook/theming": "7.0.0-beta.30" + } + }, + "@storybook/addon-viewport": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/addon-viewport/-/addon-viewport-7.0.0-beta.30.tgz", + "integrity": "sha512-ugk44rt07zyj4kUNt8aNHGxMFbrqjygGk+MznASrOd4F4G4LzM09O+a/YqGGKSJQlb90gadW7Xj1iy4HP28NtA==", + "dev": true, + "requires": { + "@storybook/client-logger": "7.0.0-beta.30", + "@storybook/components": "7.0.0-beta.30", + "@storybook/core-events": "7.0.0-beta.30", + "@storybook/global": "^5.0.0", + "@storybook/manager-api": "7.0.0-beta.30", + "@storybook/preview-api": "7.0.0-beta.30", + "@storybook/theming": "7.0.0-beta.30", + "memoizerific": "^1.11.3", + "prop-types": "^15.7.2" + } + }, + "@storybook/addons": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/addons/-/addons-7.0.0-beta.30.tgz", + "integrity": "sha512-J0/tiaEPXNVbjUAgSNuLirfRfhUwQ5PC4LvNLYO//OKpRn/pvsh5jlFWKVoXG5Km711atS6P7aOt7vTTAH8Akg==", + "dev": true, + "requires": { + "@storybook/manager-api": "7.0.0-beta.30", + "@storybook/preview-api": "7.0.0-beta.30", + "@storybook/types": "7.0.0-beta.30" + } + }, + "@storybook/api": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/api/-/api-7.0.0-beta.30.tgz", + "integrity": "sha512-D7ggwRM6yDrHBDI8IXoRA6XVWrrqNL0E1m+M2uBK9RoKfgVJr9TMapFl3u46LTIC76EsFigJCFdNnlPmnIwlhQ==", + "dev": true, + "requires": { + "@storybook/client-logger": "7.0.0-beta.30", + "@storybook/manager-api": "7.0.0-beta.30" + } + }, + "@storybook/blocks": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/blocks/-/blocks-7.0.0-beta.30.tgz", + "integrity": "sha512-kwH9Xlr8GeGvJPjbuvlC4aGkZq/1Xz5S5Cnapfs3vnDSD76/30XvFj+QUV+clf3aPAbbKI1QJIXy2lCzUME46w==", + "dev": true, + "requires": { + "@storybook/channels": "7.0.0-beta.30", + "@storybook/client-logger": "7.0.0-beta.30", + "@storybook/components": "7.0.0-beta.30", + "@storybook/core-events": "7.0.0-beta.30", + "@storybook/csf": "next", + "@storybook/docs-tools": "7.0.0-beta.30", + "@storybook/global": "^5.0.0", + "@storybook/manager-api": "7.0.0-beta.30", + "@storybook/preview-api": "7.0.0-beta.30", + "@storybook/theming": "7.0.0-beta.30", + "@storybook/types": "7.0.0-beta.30", + "@types/lodash": "^4.14.167", + "color-convert": "^2.0.1", + "dequal": "^2.0.2", + "lodash": "^4.17.21", + "markdown-to-jsx": "^7.1.3", + "memoizerific": "^1.11.3", + "polished": "^4.2.2", + "react-colorful": "^5.1.2", + "ts-dedent": "^2.0.0", + "util-deprecate": "^1.0.2" + } + }, + "@storybook/builder-manager": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/builder-manager/-/builder-manager-7.0.0-beta.30.tgz", + "integrity": "sha512-hBiF7LE4Ojsgh7E9LRPgwHATQuV/izY8F/tFKCbWO3g5yzElEHcspEDJmbxh9HnAhNcYFvshCwFBBC1CTc8sTQ==", + "dev": true, + "requires": { + "@fal-works/esbuild-plugin-global-externals": "^2.1.2", + "@storybook/core-common": "7.0.0-beta.30", + "@storybook/manager": "7.0.0-beta.30", + "@storybook/node-logger": "7.0.0-beta.30", + "@types/ejs": "^3.1.1", + "@types/find-cache-dir": "^3.2.1", + "@yarnpkg/esbuild-plugin-pnp": "^3.0.0-rc.10", + "browser-assert": "^1.2.1", + "ejs": "^3.1.8", + "esbuild": "^0.16.4", + "esbuild-plugin-alias": "^0.2.1", + "express": "^4.17.3", + "find-cache-dir": "^3.0.0", + "fs-extra": "^9.0.1", + "process": "^0.11.10", + "slash": "^3.0.0", + "util": "^0.12.4" + } + }, + "@storybook/builder-webpack5": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/builder-webpack5/-/builder-webpack5-7.0.0-beta.30.tgz", + "integrity": "sha512-7SS+F9tyIL9N2iUNapCFy0aSxrXRI2byXuKM/xCXgYnMq04z3MbPuG6ymaYUoRZQ2zMYoHkMA8iaLthHsIoRAQ==", + "dev": true, + "requires": { + "@babel/core": "^7.12.10", + "@storybook/addons": "7.0.0-beta.30", + "@storybook/api": "7.0.0-beta.30", + "@storybook/channel-postmessage": "7.0.0-beta.30", + "@storybook/channel-websocket": "7.0.0-beta.30", + "@storybook/channels": "7.0.0-beta.30", + "@storybook/client-api": "7.0.0-beta.30", + "@storybook/client-logger": "7.0.0-beta.30", + "@storybook/components": "7.0.0-beta.30", + "@storybook/core-common": "7.0.0-beta.30", + "@storybook/core-events": "7.0.0-beta.30", + "@storybook/core-webpack": "7.0.0-beta.30", + "@storybook/global": "^5.0.0", + "@storybook/manager-api": "7.0.0-beta.30", + "@storybook/node-logger": "7.0.0-beta.30", + "@storybook/preview": "7.0.0-beta.30", + "@storybook/preview-api": "7.0.0-beta.30", + "@storybook/router": "7.0.0-beta.30", + "@storybook/store": "7.0.0-beta.30", + "@storybook/theming": "7.0.0-beta.30", + "@types/node": "^16.0.0", + "@types/semver": "^7.3.4", + "babel-loader": "^9.0.0", + "babel-plugin-named-exports-order": "^0.0.2", + "browser-assert": "^1.2.1", + "case-sensitive-paths-webpack-plugin": "^2.4.0", + "css-loader": "^6.7.1", + "express": "^4.17.3", + "fork-ts-checker-webpack-plugin": "^7.2.8", + "fs-extra": "^9.0.1", + "html-webpack-plugin": "^5.5.0", + "path-browserify": "^1.0.1", + "process": "^0.11.10", + "semver": "^7.3.7", + "slash": "^3.0.0", + "style-loader": "^3.3.1", + "terser-webpack-plugin": "^5.3.1", + "ts-dedent": "^2.0.0", + "util": "^0.12.4", + "util-deprecate": "^1.0.2", + "webpack": "5", + "webpack-dev-middleware": "^5.3.1", + "webpack-hot-middleware": "^2.25.1", + "webpack-virtual-modules": "^0.4.3" + }, + "dependencies": { + "@types/node": { + "version": "16.18.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.11.tgz", + "integrity": "sha512-3oJbGBUWuS6ahSnEq1eN2XrCyf4YsWI8OyCvo7c64zQJNplk3mO84t53o8lfTk+2ji59g5ycfc6qQ3fdHliHuA==", + "dev": true + } + } + }, + "@storybook/channel-postmessage": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/channel-postmessage/-/channel-postmessage-7.0.0-beta.30.tgz", + "integrity": "sha512-szCRSlMZr0ii/j+kIHKim1kCpmVblhvLl8vW25sbUkW0lSJ7F0VQ1mQSNjXDWhZHEMb9/1ZYCbN7HOsXp9oCRg==", + "dev": true, + "requires": { + "@storybook/channels": "7.0.0-beta.30", + "@storybook/client-logger": "7.0.0-beta.30", + "@storybook/core-events": "7.0.0-beta.30", + "@storybook/global": "^5.0.0", + "qs": "^6.10.0", + "telejson": "^7.0.3" + } + }, + "@storybook/channel-websocket": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/channel-websocket/-/channel-websocket-7.0.0-beta.30.tgz", + "integrity": "sha512-Q+bShSf8ueKw5H3vN76lgAqzl+bG7rqjQhgG7ALYUPDgNGFf+7dFoe2/g5byjhZAZGomObhmIRjpPkCmUzx4Uw==", + "dev": true, + "requires": { + "@storybook/channels": "7.0.0-beta.30", + "@storybook/client-logger": "7.0.0-beta.30", + "@storybook/global": "^5.0.0", + "telejson": "^7.0.3" + } + }, + "@storybook/channels": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/channels/-/channels-7.0.0-beta.30.tgz", + "integrity": "sha512-XIlFxLKy0MGpWIGondLHf92Aku57SpIxZXmjLbM2iAeG0UljzdL+d8BoMp5Yo0CVMmMBGGZEoM7INrhf6p2WKw==", + "dev": true + }, + "@storybook/cli": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/cli/-/cli-7.0.0-beta.30.tgz", + "integrity": "sha512-nwgHQysnL67VZ/fP99BR16E9WRH634pg2hbRqzC1DCzEWAfAcnlZPbnOUmbVhpL6MdJw6i5nyVdk4ugUcFI8pA==", + "dev": true, + "requires": { + "@babel/core": "^7.20.2", + "@babel/preset-env": "^7.20.2", + "@storybook/codemod": "7.0.0-beta.30", + "@storybook/core-common": "7.0.0-beta.30", + "@storybook/core-server": "7.0.0-beta.30", + "@storybook/csf-tools": "7.0.0-beta.30", + "@storybook/node-logger": "7.0.0-beta.30", + "@storybook/telemetry": "7.0.0-beta.30", + "@storybook/types": "7.0.0-beta.30", + "@types/semver": "^7.3.4", + "boxen": "^5.1.2", + "chalk": "^4.1.0", + "commander": "^6.2.1", + "cross-spawn": "^7.0.3", + "detect-indent": "^6.1.0", + "envinfo": "^7.7.3", + "execa": "^5.0.0", + "express": "^4.17.3", + "find-up": "^5.0.0", + "fs-extra": "^9.0.1", + "get-port": "^5.1.1", + "giget": "^1.0.0", + "globby": "^11.0.2", + "jscodeshift": "^0.13.1", + "leven": "^3.1.0", + "prompts": "^2.4.0", + "puppeteer-core": "^2.1.1", + "read-pkg-up": "^7.0.1", + "semver": "^7.3.7", + "shelljs": "^0.8.5", + "simple-update-notifier": "^1.0.0", + "strip-json-comments": "^3.0.1", + "tempy": "^1.0.1", + "ts-dedent": "^2.0.0", + "util-deprecate": "^1.0.2" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "commander": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", + "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "@storybook/client-api": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/client-api/-/client-api-7.0.0-beta.30.tgz", + "integrity": "sha512-FPRmBmRRzsA9ZNXBwoOVEMze8dp/U1DxA0OKw9y24v/ijgg+P6GAqpX3WFrx3eQWn3I3oMg/8kJwANvOv38ZDw==", + "dev": true, + "requires": { + "@storybook/client-logger": "7.0.0-beta.30", + "@storybook/preview-api": "7.0.0-beta.30" + } + }, + "@storybook/client-logger": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/client-logger/-/client-logger-7.0.0-beta.30.tgz", + "integrity": "sha512-50JKxy0E2jUfGcfHwBp+NnlVLqaELSTjB5CjxckUExLfsU/u3dzTPrMmxevBw3ojqaCtyGKZE0yY0ndn/QbeuA==", + "dev": true, + "requires": { + "@storybook/global": "^5.0.0" + } + }, + "@storybook/codemod": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/codemod/-/codemod-7.0.0-beta.30.tgz", + "integrity": "sha512-kJmzhLVavUB5wTkL1RfnZZml6uSMtwTExMAAoMl1q8ie1KVIXEjO7vrQYz8xRFsQJ/y36TeJWY8w45kjBie0Aw==", + "dev": true, + "requires": { + "@babel/core": "^7.20.2", + "@babel/preset-env": "^7.20.2", + "@babel/types": "^7.20.7", + "@storybook/csf": "next", + "@storybook/csf-tools": "7.0.0-beta.30", + "@storybook/node-logger": "7.0.0-beta.30", + "@storybook/types": "7.0.0-beta.30", + "cross-spawn": "^7.0.3", + "globby": "^11.0.2", + "jscodeshift": "^0.13.1", + "lodash": "^4.17.21", + "prettier": "^2.8.0", + "recast": "^0.23.1", + "util": "^0.12.4" + } + }, + "@storybook/components": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/components/-/components-7.0.0-beta.30.tgz", + "integrity": "sha512-CrGZY97t0lcjM/kevTVUYrZ35Civnpyyn4Q5uPbHv9cilmSGxbGg3r1yH8s6+FfbSobb77ZiCCbZXCWrSCiwnQ==", + "dev": true, + "requires": { + "@storybook/client-logger": "7.0.0-beta.30", + "@storybook/csf": "next", + "@storybook/global": "^5.0.0", + "@storybook/theming": "7.0.0-beta.30", + "@storybook/types": "7.0.0-beta.30", + "memoizerific": "^1.11.3", + "util-deprecate": "^1.0.2" + } + }, + "@storybook/core-client": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/core-client/-/core-client-7.0.0-beta.30.tgz", + "integrity": "sha512-4F2TMNjV8YpEJoCUGa9yfD+3zv60/pG1xjt6NP5uoMKsvqjfDOXCXXQGcUd6lnidGu/xoYvhR8r0KsRmsIzRYQ==", + "dev": true, + "requires": { + "@storybook/client-logger": "7.0.0-beta.30", + "@storybook/preview-api": "7.0.0-beta.30" + } + }, + "@storybook/core-common": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/core-common/-/core-common-7.0.0-beta.30.tgz", + "integrity": "sha512-46U4cHOgKQBxFBZO19lx0eR7F/fJgzBr4Nhx4Ws6vhdW5492aa8NPjHM+59jXOMpU8ZM3zHvhObaL/VMwnTJWg==", + "dev": true, + "requires": { + "@babel/core": "^7.20.2", + "@storybook/node-logger": "7.0.0-beta.30", + "@storybook/types": "7.0.0-beta.30", + "@types/babel__core": "^7.1.20", + "@types/express": "^4.7.0", + "@types/node": "^16.0.0", + "@types/pretty-hrtime": "^1.0.0", + "chalk": "^4.1.0", + "esbuild": "^0.16.4", + "esbuild-register": "^3.3.3", + "express": "^4.17.3", + "file-system-cache": "^2.0.0", + "find-up": "^5.0.0", + "fs-extra": "^9.0.1", + "glob": "^7.1.6", + "handlebars": "^4.7.7", + "lazy-universal-dotenv": "^3.0.1", + "picomatch": "^2.3.0", + "pkg-dir": "^5.0.0", + "pretty-hrtime": "^1.0.3", + "resolve-from": "^5.0.0", + "slash": "^3.0.0", + "ts-dedent": "^2.0.0" + }, + "dependencies": { + "@types/node": { + "version": "16.18.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.11.tgz", + "integrity": "sha512-3oJbGBUWuS6ahSnEq1eN2XrCyf4YsWI8OyCvo7c64zQJNplk3mO84t53o8lfTk+2ji59g5ycfc6qQ3fdHliHuA==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "@storybook/core-events": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/core-events/-/core-events-7.0.0-beta.30.tgz", + "integrity": "sha512-Q+psogB1KJFU6m+Zz4QqJBDVsTsR9vceVaUDceGogGbZEjBXpIAKwAJzVVi62pJKeFHclcCI4JbquYoOu2vK9w==", + "dev": true + }, + "@storybook/core-server": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/core-server/-/core-server-7.0.0-beta.30.tgz", + "integrity": "sha512-GfOg7P53OMR/Qa/DAz9IdRpu0sUJlZdrKv53otu4TnI8OxW+Wcom6Ef16aiwaONivQG78zKPzB5w+0+1f2N5uw==", + "dev": true, + "requires": { + "@aw-web-design/x-default-browser": "1.4.88", + "@discoveryjs/json-ext": "^0.5.3", + "@storybook/builder-manager": "7.0.0-beta.30", + "@storybook/core-common": "7.0.0-beta.30", + "@storybook/core-events": "7.0.0-beta.30", + "@storybook/csf": "next", + "@storybook/csf-tools": "7.0.0-beta.30", + "@storybook/docs-mdx": "next", + "@storybook/global": "^5.0.0", + "@storybook/node-logger": "7.0.0-beta.30", + "@storybook/preview-api": "7.0.0-beta.30", + "@storybook/telemetry": "7.0.0-beta.30", + "@storybook/types": "7.0.0-beta.30", + "@types/detect-port": "^1.3.0", + "@types/node": "^16.0.0", + "@types/node-fetch": "^2.5.7", + "@types/pretty-hrtime": "^1.0.0", + "@types/semver": "^7.3.4", + "better-opn": "^2.1.1", + "boxen": "^5.1.2", + "chalk": "^4.1.0", + "cli-table3": "^0.6.1", + "compression": "^1.7.4", + "detect-port": "^1.3.0", + "express": "^4.17.3", + "fs-extra": "^9.0.1", + "globby": "^11.0.2", + "ip": "^2.0.0", + "lodash": "^4.17.21", + "node-fetch": "^2.6.7", + "open": "^8.4.0", + "pretty-hrtime": "^1.0.3", + "prompts": "^2.4.0", + "read-pkg-up": "^7.0.1", + "semver": "^7.3.7", + "serve-favicon": "^2.5.0", + "slash": "^3.0.0", + "telejson": "^7.0.3", + "ts-dedent": "^2.0.0", + "util-deprecate": "^1.0.2", + "watchpack": "^2.2.0", + "ws": "^8.2.3" + }, + "dependencies": { + "@types/node": { + "version": "16.18.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.11.tgz", + "integrity": "sha512-3oJbGBUWuS6ahSnEq1eN2XrCyf4YsWI8OyCvo7c64zQJNplk3mO84t53o8lfTk+2ji59g5ycfc6qQ3fdHliHuA==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "@storybook/core-webpack": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/core-webpack/-/core-webpack-7.0.0-beta.30.tgz", + "integrity": "sha512-zVlXka9WlJovzNmtAnuGMPBnQBvOdP2Qi62TXdqRh1ctrCX4obRtleyDJVnzdev9awn6Z+Rfbe/zqOvwISr2vw==", + "dev": true, + "requires": { + "@storybook/core-common": "7.0.0-beta.30", + "@storybook/node-logger": "7.0.0-beta.30", + "@storybook/types": "7.0.0-beta.30", + "@types/node": "^16.0.0", + "ts-dedent": "^2.0.0" + }, + "dependencies": { + "@types/node": { + "version": "16.18.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.11.tgz", + "integrity": "sha512-3oJbGBUWuS6ahSnEq1eN2XrCyf4YsWI8OyCvo7c64zQJNplk3mO84t53o8lfTk+2ji59g5ycfc6qQ3fdHliHuA==", + "dev": true + } + } + }, + "@storybook/csf": { + "version": "0.0.2-next.8", + "resolved": "https://registry.npmjs.org/@storybook/csf/-/csf-0.0.2-next.8.tgz", + "integrity": "sha512-3T6rflW7D9q1iXOR+bidwoNbd9rVUTyjYH/sqsnYjbXhb/aOXsQzGKwNeq9QqZIFVpKfg5BoOF5i7DCMtoGknQ==", + "dev": true, + "requires": { + "expect-type": "^0.14.2", + "lodash": "^4.17.15", + "type-fest": "^2.19.0" + }, + "dependencies": { + "type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "dev": true + } + } + }, + "@storybook/csf-plugin": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/csf-plugin/-/csf-plugin-7.0.0-beta.30.tgz", + "integrity": "sha512-ny8NCrdJWjSxraCWAGdMjXP1EtHygABCjv6Qcv9OijBexmzET04YwY7HmQlW6B9tq2l86TlFLPyICVtv8wniyA==", + "dev": true, + "requires": { + "@storybook/csf-tools": "7.0.0-beta.30", + "unplugin": "^0.10.2" + } + }, + "@storybook/csf-tools": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/csf-tools/-/csf-tools-7.0.0-beta.30.tgz", + "integrity": "sha512-/CCizDLZSqm3lNO0w+oc1Xqid4/Ix7TikKZxxaOpGipXp4Ehw8iRMjnfHbE+ANq8ZtTdQzOXBxG4LG2noUpHBw==", + "dev": true, + "requires": { + "@babel/types": "^7.20.2", + "@storybook/csf": "next", + "@storybook/types": "7.0.0-beta.30", + "fs-extra": "^9.0.1", + "recast": "^0.23.1", + "ts-dedent": "^2.0.0" + } + }, + "@storybook/docs-mdx": { + "version": "0.0.1-next.5", + "resolved": "https://registry.npmjs.org/@storybook/docs-mdx/-/docs-mdx-0.0.1-next.5.tgz", + "integrity": "sha512-EowXFPq4TBZQguKCdU8y7EzpuSv2vSu5gy7pgF/1P5mq7LG9h8YIrerOW9DL4zfp9E0GHIWlSXR5KuFIqqKc/Q==", + "dev": true + }, + "@storybook/docs-tools": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/docs-tools/-/docs-tools-7.0.0-beta.30.tgz", + "integrity": "sha512-pPGI1K0YXWTmRLg8VDy7BiZvUPmRLfdVP05vFEMw+5LpwZNjTI1hn8eQgEIME9eESNOZFj/VhdewPNfyki9M5A==", + "dev": true, + "requires": { + "@babel/core": "^7.12.10", + "@storybook/core-common": "7.0.0-beta.30", + "@storybook/preview-api": "7.0.0-beta.30", + "@storybook/types": "7.0.0-beta.30", + "@types/doctrine": "^0.0.3", + "doctrine": "^3.0.0", + "lodash": "^4.17.21" + } + }, + "@storybook/global": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@storybook/global/-/global-5.0.0.tgz", + "integrity": "sha512-FcOqPAXACP0I3oJ/ws6/rrPT9WGhu915Cg8D02a9YxLo0DE9zI+a9A5gRGvmQ09fiWPukqI8ZAEoQEdWUKMQdQ==", + "dev": true + }, + "@storybook/instrumenter": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/instrumenter/-/instrumenter-7.0.0-beta.30.tgz", + "integrity": "sha512-raP9Sq5QmAJ4nf4IRs5hKOBZ3dg5h/GiKtwIlJI6sA5zo3bHzvqApOD308yG4fp2hyeiaBbjFBsDi2Kchrv6uw==", + "dev": true, + "requires": { + "@storybook/channels": "7.0.0-beta.30", + "@storybook/client-logger": "7.0.0-beta.30", + "@storybook/core-events": "7.0.0-beta.30", + "@storybook/global": "^5.0.0", + "@storybook/preview-api": "7.0.0-beta.30", + "core-js": "^3.8.2" + } + }, + "@storybook/manager": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/manager/-/manager-7.0.0-beta.30.tgz", + "integrity": "sha512-yI9O27g/k/wYGH4/ct/59XytnAy5XU49UxLrOUI3Np1Z+lstOikslqk2g0h3Zp3IFNzXNYZkVgQ2dPWxHeLabA==", + "dev": true + }, + "@storybook/manager-api": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/manager-api/-/manager-api-7.0.0-beta.30.tgz", + "integrity": "sha512-cxEn56WpzI6UMBIaD5rgTeTg67VzREUOLgXIy51W1u7NWSb2T5agHrLzXg3Oaxlh1tL4bronbTibx/qveahtgA==", + "dev": true, + "requires": { + "@storybook/channels": "7.0.0-beta.30", + "@storybook/client-logger": "7.0.0-beta.30", + "@storybook/core-events": "7.0.0-beta.30", + "@storybook/csf": "next", + "@storybook/global": "^5.0.0", + "@storybook/router": "7.0.0-beta.30", + "@storybook/theming": "7.0.0-beta.30", + "@storybook/types": "7.0.0-beta.30", + "dequal": "^2.0.2", + "lodash": "^4.17.21", + "memoizerific": "^1.11.3", + "semver": "^7.3.7", + "store2": "^2.14.2", + "telejson": "^7.0.3", + "ts-dedent": "^2.0.0" + } + }, + "@storybook/mdx2-csf": { + "version": "1.0.0-next.4", + "resolved": "https://registry.npmjs.org/@storybook/mdx2-csf/-/mdx2-csf-1.0.0-next.4.tgz", + "integrity": "sha512-nvRgYdpYvXsvSgCzKc4LQA1JxtJzmv47IsFAsh1rTz5FoHyK8watLU2WqX9T4w52fpFXBHx7RwGEsCRt0XgZlQ==", + "dev": true + }, + "@storybook/nextjs": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/nextjs/-/nextjs-7.0.0-beta.30.tgz", + "integrity": "sha512-f8lJ4SFJEc6cp6ktUekiehRd8L9u+WoJCX4QnH630K+4dj5ZoXi+mEP3bSwrW/szkwN9A+P5wobAhTiXi7KTQw==", + "dev": true, + "requires": { + "@next/font": "^13.0.7", + "@storybook/addon-actions": "7.0.0-beta.30", + "@storybook/builder-webpack5": "7.0.0-beta.30", + "@storybook/core-common": "7.0.0-beta.30", + "@storybook/node-logger": "7.0.0-beta.30", + "@storybook/preset-react-webpack": "7.0.0-beta.30", + "@storybook/preview-api": "7.0.0-beta.30", + "@storybook/react": "7.0.0-beta.30", + "@types/node": "^16.0.0", + "find-up": "^5.0.0", + "fs-extra": "^9.0.1", + "image-size": "^1.0.0", + "loader-utils": "^3.2.0", + "pnp-webpack-plugin": "^1.7.0", + "postcss-loader": "^6.2.1", + "resolve-url-loader": "^5.0.0", + "sass-loader": "^12.4.0", + "semver": "^7.3.5", + "ts-dedent": "^2.0.0", + "tsconfig-paths": "^4.0.0", + "tsconfig-paths-webpack-plugin": "^3.5.2" + }, + "dependencies": { + "@types/node": { + "version": "16.18.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.11.tgz", + "integrity": "sha512-3oJbGBUWuS6ahSnEq1eN2XrCyf4YsWI8OyCvo7c64zQJNplk3mO84t53o8lfTk+2ji59g5ycfc6qQ3fdHliHuA==", + "dev": true + }, + "tsconfig-paths": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.1.2.tgz", + "integrity": "sha512-uhxiMgnXQp1IR622dUXI+9Ehnws7i/y6xvpZB9IbUVOPy0muvdvgXeZOn88UcGPiT98Vp3rJPTa8bFoalZ3Qhw==", + "dev": true, + "requires": { + "json5": "^2.2.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + } + } + }, + "@storybook/node-logger": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/node-logger/-/node-logger-7.0.0-beta.30.tgz", + "integrity": "sha512-mAvPG4smFASwSmb1+nMvR10Zlg/zPmNFeh6IKMttOWS5O0qSVzXGv4/QH63tjBcS0w915W3TGcDLLpKDa0c+lA==", + "dev": true, + "requires": { + "@types/npmlog": "^4.1.2", + "chalk": "^4.1.0", + "npmlog": "^5.0.1", + "pretty-hrtime": "^1.0.3" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "@storybook/postinstall": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/postinstall/-/postinstall-7.0.0-beta.30.tgz", + "integrity": "sha512-PoM6+UVLd589bM8kg2SNer8ORNMhC3SV894/dfhvgXm7id4weqZ5xnhfZ/T0ZYH2Ts7qSuR+TQmPVAAQNHsrag==", + "dev": true + }, + "@storybook/preset-react-webpack": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/preset-react-webpack/-/preset-react-webpack-7.0.0-beta.30.tgz", + "integrity": "sha512-PF7CAXWv6nS6N5OXnEj3XZKJRIKIFRmIrWwBhdK1L30XCHmQ313/0lA9JV24UHU8EwkUOfyF1IKkikhkKBkTTg==", + "dev": true, + "requires": { + "@babel/preset-flow": "^7.18.6", + "@babel/preset-react": "^7.18.6", + "@pmmmwh/react-refresh-webpack-plugin": "^0.5.5", + "@storybook/core-webpack": "7.0.0-beta.30", + "@storybook/docs-tools": "7.0.0-beta.30", + "@storybook/node-logger": "7.0.0-beta.30", + "@storybook/react": "7.0.0-beta.30", + "@storybook/react-docgen-typescript-plugin": "1.0.2-canary.6.9d540b91e815f8fc2f8829189deb00553559ff63.0", + "@types/node": "^16.0.0", + "@types/semver": "^7.3.4", + "babel-plugin-add-react-displayname": "^0.0.5", + "babel-plugin-react-docgen": "^4.2.1", + "fs-extra": "^9.0.1", + "react-refresh": "^0.11.0", + "semver": "^7.3.7" + }, + "dependencies": { + "@types/node": { + "version": "16.18.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.11.tgz", + "integrity": "sha512-3oJbGBUWuS6ahSnEq1eN2XrCyf4YsWI8OyCvo7c64zQJNplk3mO84t53o8lfTk+2ji59g5ycfc6qQ3fdHliHuA==", + "dev": true + } + } + }, + "@storybook/preview": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/preview/-/preview-7.0.0-beta.30.tgz", + "integrity": "sha512-mcqs1PB7i/oEx4viFMECA6tI14x29RMGVctPtipkDIo0myo1BAsHSsgALaHRfQCw9mXl5KUiOyiwHQMf0dEkwg==", + "dev": true + }, + "@storybook/preview-api": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/preview-api/-/preview-api-7.0.0-beta.30.tgz", + "integrity": "sha512-3klBZJ3gC+B80vJvzvHDh4uHy8+SwNOttcKyOAJOt0IJTNYo2HiAn7rUhaMeHfKzoD/YGiFiRkTrPKJDZJAGUA==", + "dev": true, + "requires": { + "@storybook/channel-postmessage": "7.0.0-beta.30", + "@storybook/channels": "7.0.0-beta.30", + "@storybook/client-logger": "7.0.0-beta.30", + "@storybook/core-events": "7.0.0-beta.30", + "@storybook/csf": "next", + "@storybook/global": "^5.0.0", + "@storybook/types": "7.0.0-beta.30", + "@types/qs": "^6.9.5", + "dequal": "^2.0.2", + "lodash": "^4.17.21", + "memoizerific": "^1.11.3", + "qs": "^6.10.0", + "slash": "^3.0.0", + "synchronous-promise": "^2.0.15", + "ts-dedent": "^2.0.0", + "util-deprecate": "^1.0.2" + } + }, + "@storybook/react": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/react/-/react-7.0.0-beta.30.tgz", + "integrity": "sha512-tcG+7vkf8/C2Az/Ei23DEfCx7sBqBi/odBEFIKYlZZkDTlkYWdTpcsn1P4fE/QFetwyS6F85aG3Qmluyk7YBQA==", + "dev": true, + "requires": { + "@storybook/client-logger": "7.0.0-beta.30", + "@storybook/core-client": "7.0.0-beta.30", + "@storybook/docs-tools": "7.0.0-beta.30", + "@storybook/global": "^5.0.0", + "@storybook/preview-api": "7.0.0-beta.30", + "@storybook/types": "7.0.0-beta.30", + "@types/escodegen": "^0.0.6", + "@types/estree": "^0.0.51", + "@types/node": "^16.0.0", + "acorn": "^7.4.1", + "acorn-jsx": "^5.3.1", + "acorn-walk": "^7.2.0", + "escodegen": "^2.0.0", + "html-tags": "^3.1.0", + "lodash": "^4.17.21", + "prop-types": "^15.7.2", + "react-element-to-jsx-string": "^15.0.0", + "ts-dedent": "^2.0.0", + "type-fest": "^2.19.0", + "util-deprecate": "^1.0.2" + }, + "dependencies": { + "@types/node": { + "version": "16.18.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.11.tgz", + "integrity": "sha512-3oJbGBUWuS6ahSnEq1eN2XrCyf4YsWI8OyCvo7c64zQJNplk3mO84t53o8lfTk+2ji59g5ycfc6qQ3fdHliHuA==", + "dev": true + }, + "type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "dev": true + } + } + }, + "@storybook/react-docgen-typescript-plugin": { + "version": "1.0.2-canary.6.9d540b91e815f8fc2f8829189deb00553559ff63.0", + "resolved": "https://registry.npmjs.org/@storybook/react-docgen-typescript-plugin/-/react-docgen-typescript-plugin-1.0.2-canary.6.9d540b91e815f8fc2f8829189deb00553559ff63.0.tgz", + "integrity": "sha512-eVg3BxlOm2P+chijHBTByr90IZVUtgRW56qEOLX7xlww2NBuKrcavBlcmn+HH7GIUktquWkMPtvy6e0W0NgA5w==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "endent": "^2.0.1", + "find-cache-dir": "^3.3.1", + "flat-cache": "^3.0.4", + "micromatch": "^4.0.2", + "react-docgen-typescript": "^2.1.1", + "tslib": "^2.0.0" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "@storybook/router": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/router/-/router-7.0.0-beta.30.tgz", + "integrity": "sha512-hSdVv/IlBA96rf6RpmSCeS2CgxfmvgQOWVR8JR+5M97MjRMtXcIKB3f2ea8JSEPWkOa7i2k8ARunlAAVVmOiPw==", + "dev": true, + "requires": { + "@storybook/client-logger": "7.0.0-beta.30", + "memoizerific": "^1.11.3", + "qs": "^6.10.0" + } + }, + "@storybook/semver": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/@storybook/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-SWeszlsiPsMI0Ps0jVNtH64cI5c0UF3f7KgjVKJoNP30crQ6wUSddY2hsdeczZXEKVJGEn50Q60flcGsQGIcrg==", + "dev": true, + "requires": { + "core-js": "^3.6.5", + "find-up": "^4.1.0" + }, + "dependencies": { + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + } + } + }, + "@storybook/store": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/store/-/store-7.0.0-beta.30.tgz", + "integrity": "sha512-Uzni6jW4cUee2i92jgMshRJh7AcBD79gUJpLz2HmKm7xXypi3TCzpUQi++8OAbfPgRkvk3sGwhcyrfkujJ1KqQ==", + "dev": true, + "requires": { + "@storybook/client-logger": "7.0.0-beta.30", + "@storybook/preview-api": "7.0.0-beta.30" + } + }, + "@storybook/telemetry": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/telemetry/-/telemetry-7.0.0-beta.30.tgz", + "integrity": "sha512-ufmdVxZoAiaIP5VWjbTRrruNTm6OXSvhjCYCpqBJIgMbvEosE5njNJ4ySuyZSjMtLvJy0kdnx7ca+bQQ5ALFuQ==", + "dev": true, + "requires": { + "@storybook/client-logger": "7.0.0-beta.30", + "@storybook/core-common": "7.0.0-beta.30", + "chalk": "^4.1.0", + "detect-package-manager": "^2.0.1", + "fetch-retry": "^5.0.2", + "fs-extra": "^9.0.1", + "isomorphic-unfetch": "^3.1.0", + "nanoid": "^3.3.1", + "read-pkg-up": "^7.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "@storybook/testing-library": { + "version": "0.0.13", + "resolved": "https://registry.npmjs.org/@storybook/testing-library/-/testing-library-0.0.13.tgz", + "integrity": "sha512-vRMeIGer4EjJkTgI8sQyK9W431ekPWYCWL//OmSDJ64IT3h7FnW7Xg6p+eqM3oII98/O5pcya5049GxnjaPtxw==", + "dev": true, + "requires": { + "@storybook/client-logger": "^6.4.0", + "@storybook/instrumenter": "^6.4.0", + "@testing-library/dom": "^8.3.0", + "@testing-library/user-event": "^13.2.1", + "ts-dedent": "^2.2.0" + }, + "dependencies": { + "@storybook/addons": { + "version": "6.5.15", + "resolved": "https://registry.npmjs.org/@storybook/addons/-/addons-6.5.15.tgz", + "integrity": "sha512-xT31SuSX+kYGyxCNK2nqL7WTxucs3rSmhiCLovJcUjYk+QquV3c2c53Ki7lwwdDbzfXFcNAe0HJ4hoTN4jhn0Q==", + "dev": true, + "requires": { + "@storybook/api": "6.5.15", + "@storybook/channels": "6.5.15", + "@storybook/client-logger": "6.5.15", + "@storybook/core-events": "6.5.15", + "@storybook/csf": "0.0.2--canary.4566f4d.1", + "@storybook/router": "6.5.15", + "@storybook/theming": "6.5.15", + "@types/webpack-env": "^1.16.0", + "core-js": "^3.8.2", + "global": "^4.4.0", + "regenerator-runtime": "^0.13.7" + } + }, + "@storybook/api": { + "version": "6.5.15", + "resolved": "https://registry.npmjs.org/@storybook/api/-/api-6.5.15.tgz", + "integrity": "sha512-BBE0KXKvj1/3jTghbIoWfrcDM0t+xO7EYtWWAXD6XlhGsZVD2Dy82Z52ONyLulMDRpMWl0OYy3h6A1YnFUH25w==", + "dev": true, + "requires": { + "@storybook/channels": "6.5.15", + "@storybook/client-logger": "6.5.15", + "@storybook/core-events": "6.5.15", + "@storybook/csf": "0.0.2--canary.4566f4d.1", + "@storybook/router": "6.5.15", + "@storybook/semver": "^7.3.2", + "@storybook/theming": "6.5.15", + "core-js": "^3.8.2", + "fast-deep-equal": "^3.1.3", + "global": "^4.4.0", + "lodash": "^4.17.21", + "memoizerific": "^1.11.3", + "regenerator-runtime": "^0.13.7", + "store2": "^2.12.0", + "telejson": "^6.0.8", + "ts-dedent": "^2.0.0", + "util-deprecate": "^1.0.2" + } + }, + "@storybook/channels": { + "version": "6.5.15", + "resolved": "https://registry.npmjs.org/@storybook/channels/-/channels-6.5.15.tgz", + "integrity": "sha512-gPpsBgirv2NCXbH4WbYqdkI0JLE96aiVuu7UEWfn9yu071pQ9CLHbhXGD9fSFNrfOkyBBY10ppSE7uCXw3Wexg==", + "dev": true, + "requires": { + "core-js": "^3.8.2", + "ts-dedent": "^2.0.0", + "util-deprecate": "^1.0.2" + } + }, + "@storybook/client-logger": { + "version": "6.5.15", + "resolved": "https://registry.npmjs.org/@storybook/client-logger/-/client-logger-6.5.15.tgz", + "integrity": "sha512-0uyxKvodq+FycGv6aUwC1wUR6suXf2+7ywMFAOlYolI4UvNj8NyU/5AfgKT5XnxYAgPmoCiAjOE700TrfHrosw==", + "dev": true, + "requires": { + "core-js": "^3.8.2", + "global": "^4.4.0" + } + }, + "@storybook/core-events": { + "version": "6.5.15", + "resolved": "https://registry.npmjs.org/@storybook/core-events/-/core-events-6.5.15.tgz", + "integrity": "sha512-B1Ba6l5W7MeNclclqMMTMHgYgfdpB5SIhNCQFnzIz8blynzRhNFMdxvbAl6Je5G0S4xydYYd7Lno2kXQebs7HA==", + "dev": true, + "requires": { + "core-js": "^3.8.2" + } + }, + "@storybook/csf": { + "version": "0.0.2--canary.4566f4d.1", + "resolved": "https://registry.npmjs.org/@storybook/csf/-/csf-0.0.2--canary.4566f4d.1.tgz", + "integrity": "sha512-9OVvMVh3t9znYZwb0Svf/YQoxX2gVOeQTGe2bses2yj+a3+OJnCrUF3/hGv6Em7KujtOdL2LL+JnG49oMVGFgQ==", + "dev": true, + "requires": { + "lodash": "^4.17.15" + } + }, + "@storybook/instrumenter": { + "version": "6.5.15", + "resolved": "https://registry.npmjs.org/@storybook/instrumenter/-/instrumenter-6.5.15.tgz", + "integrity": "sha512-93WyH0s63RCv496eHjQ5dWFXoExXg9dlNMe7i4/FVVbWeDdb1pPVIHsLn28WxOiVQahQEAW2EA7Mao3BiBWg+A==", + "dev": true, + "requires": { + "@storybook/addons": "6.5.15", + "@storybook/client-logger": "6.5.15", + "@storybook/core-events": "6.5.15", + "core-js": "^3.8.2", + "global": "^4.4.0" + } + }, + "@storybook/router": { + "version": "6.5.15", + "resolved": "https://registry.npmjs.org/@storybook/router/-/router-6.5.15.tgz", + "integrity": "sha512-9t8rI8t7/Krolau29gsdjdbRQ66orONIyP0efp0EukVgv6reNFzb/U14ARrl0uHys6Tl5Xyece9FoakQUdn8Kg==", + "dev": true, + "requires": { + "@storybook/client-logger": "6.5.15", + "core-js": "^3.8.2", + "memoizerific": "^1.11.3", + "qs": "^6.10.0", + "regenerator-runtime": "^0.13.7" + } + }, + "@storybook/theming": { + "version": "6.5.15", + "resolved": "https://registry.npmjs.org/@storybook/theming/-/theming-6.5.15.tgz", + "integrity": "sha512-pgdW0lVZKKXQ4VhIfLHycMmwFSVOY7vLTKnytag4Y8Yz+aXm0bwDN/QxPntFzDH47F1Rcy2ywNnvty8ooDTvuA==", + "dev": true, + "requires": { + "@storybook/client-logger": "6.5.15", + "core-js": "^3.8.2", + "memoizerific": "^1.11.3", + "regenerator-runtime": "^0.13.7" + } + }, + "telejson": { + "version": "6.0.8", + "resolved": "https://registry.npmjs.org/telejson/-/telejson-6.0.8.tgz", + "integrity": "sha512-nerNXi+j8NK1QEfBHtZUN/aLdDcyupA//9kAboYLrtzZlPLpUfqbVGWb9zz91f/mIjRbAYhbgtnJHY8I1b5MBg==", + "dev": true, + "requires": { + "@types/is-function": "^1.0.0", + "global": "^4.4.0", + "is-function": "^1.0.2", + "is-regex": "^1.1.2", + "is-symbol": "^1.0.3", + "isobject": "^4.0.0", + "lodash": "^4.17.21", + "memoizerific": "^1.11.3" + } + } + } + }, + "@storybook/theming": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/theming/-/theming-7.0.0-beta.30.tgz", + "integrity": "sha512-b3GM3vQfgAbmLvUaMPoAwYVynMAk7iH7H+ig9Dqv5/IJl8KIP7DTD5HAkP+PEzk+WrcOnw7mKDIk6Kt/lD0VWQ==", + "dev": true, + "requires": { + "@emotion/use-insertion-effect-with-fallbacks": "^1.0.0", + "@storybook/client-logger": "7.0.0-beta.30", + "@storybook/global": "^5.0.0", + "memoizerific": "^1.11.3" + } + }, + "@storybook/types": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/@storybook/types/-/types-7.0.0-beta.30.tgz", + "integrity": "sha512-udjSzDh8GPxpb0ITZqvooDv+khtyy1z1iNy/5VLOBhWe/vDWXC/mLHKPYlWdNthE9Vm3tJs61n8fTJBuPs2VZg==", + "dev": true, + "requires": { + "@babel/core": "^7.12.10", + "@storybook/channels": "7.0.0-beta.30", + "@types/babel__core": "^7.0.0", + "@types/express": "^4.7.0", + "express": "^4.17.3", + "file-system-cache": "^2.0.0" + } + }, "@stripe/react-stripe-js": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/@stripe/react-stripe-js/-/react-stripe-js-1.10.0.tgz", @@ -8557,9 +27005,9 @@ } }, "@stripe/stripe-js": { - "version": "1.36.0", - "resolved": "https://registry.npmjs.org/@stripe/stripe-js/-/stripe-js-1.36.0.tgz", - "integrity": "sha512-m45BD9JxOfIBT0Tz4MupiKzM8M58NX/We8wKlf+54TCZpW1RVAyFpJ58CbtyU/LxAM+opT6cewHRVfs7bTUtBA==" + "version": "1.46.0", + "resolved": "https://registry.npmjs.org/@stripe/stripe-js/-/stripe-js-1.46.0.tgz", + "integrity": "sha512-dkm0zCEoRLu5rTnsIgwDf/QG2DKcalOT2dk1IVgMySOHWTChLyOvQwMYhEduGgLvyYWTwNhAUV4WOLPQvjwLwA==" }, "@swc/helpers": { "version": "0.4.11", @@ -8581,6 +27029,147 @@ "postcss-selector-parser": "6.0.10" } }, + "@tanstack/query-core": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-4.22.4.tgz", + "integrity": "sha512-t79CMwlbBnj+yL82tEcmRN93bL4U3pae2ota4t5NN2z3cIeWw74pzdWrKRwOfTvLcd+b30tC+ciDlfYOKFPGUw==" + }, + "@tanstack/react-query": { + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-4.23.0.tgz", + "integrity": "sha512-cfQsrecZQjYYueiow4WcK8ItokXJnv+b2OrK8Lf5kF7lM9uCo1ilyygFB8wo4MfxchUBVM6Cs8wq4Ed7fouwkA==", + "requires": { + "@tanstack/query-core": "4.22.4", + "use-sync-external-store": "^1.2.0" + } + }, + "@testing-library/dom": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.20.0.tgz", + "integrity": "sha512-d9ULIT+a4EXLX3UU8FBjauG9NnsZHkHztXoIcTsOKoOw030fyjheN9svkTULjJxtYag9DZz5Jz5qkWZDPxTFwA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "^5.0.0", + "chalk": "^4.1.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.4.4", + "pretty-format": "^27.0.2" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "@testing-library/user-event": { + "version": "13.5.0", + "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-13.5.0.tgz", + "integrity": "sha512-5Kwtbo3Y/NowpkbRuSepbyMFkZmHgD+vPzYB/RJ4oxt5Gj/avFFBYjhw27cqSVPVw/3a67NK1PbiIr9k4Gwmdg==", + "dev": true, + "requires": { + "@babel/runtime": "^7.12.5" + } + }, + "@types/aria-query": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.1.tgz", + "integrity": "sha512-XTIieEY+gvJ39ChLcB4If5zHtPxt3Syj5rgZR+e1ctpmK8NjPf0zFqsz4JpLJT0xla9GFDKjy8Cpu331nrmE1Q==", + "dev": true + }, + "@types/babel__core": { + "version": "7.1.20", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.20.tgz", + "integrity": "sha512-PVb6Bg2QuscZ30FvOU7z4guG6c926D9YRvOxEaelzndpMsvP+YM74Q/dAFASpg2l6+XLalxSGxcq/lrgYWZtyQ==", + "dev": true, + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "@types/babel__generator": { + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", + "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", + "dev": true, + "requires": { + "@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", + "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", + "dev": true, + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@types/babel__traverse": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.3.tgz", + "integrity": "sha512-1kbcJ40lLB7MHsj39U4Sh1uTd2E7rLEa79kmDpI6cy+XiXsteB3POdQomoq4FxszMrO3ZYchkhYJw7A2862b3w==", + "dev": true, + "requires": { + "@babel/types": "^7.3.0" + } + }, + "@types/body-parser": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", + "dev": true, + "requires": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "@types/connect": { + "version": "3.4.35", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", + "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/debug": { "version": "4.1.7", "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.7.tgz", @@ -8589,6 +27178,94 @@ "@types/ms": "*" } }, + "@types/detect-port": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@types/detect-port/-/detect-port-1.3.2.tgz", + "integrity": "sha512-xxgAGA2SAU4111QefXPSp5eGbDm/hW6zhvYl9IeEPZEry9F4d66QAHm5qpUXjb6IsevZV/7emAEx5MhP6O192g==", + "dev": true + }, + "@types/doctrine": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/@types/doctrine/-/doctrine-0.0.3.tgz", + "integrity": "sha512-w5jZ0ee+HaPOaX25X2/2oGR/7rgAQSYII7X7pp0m9KgBfMP7uKfMfTvcpl5Dj+eDBbpxKGiqE+flqDr6XTd2RA==", + "dev": true + }, + "@types/ejs": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/ejs/-/ejs-3.1.1.tgz", + "integrity": "sha512-RQul5wEfY7BjWm0sYY86cmUN/pcXWGyVxWX93DFFJvcrxax5zKlieLwA3T77xJGwNcZW0YW6CYG70p1m8xPFmA==", + "dev": true + }, + "@types/escodegen": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/@types/escodegen/-/escodegen-0.0.6.tgz", + "integrity": "sha512-AjwI4MvWx3HAOaZqYsjKWyEObT9lcVV0Y0V8nXo6cXzN8ZiMxVhf6F3d/UNvXVGKrEzL/Dluc5p+y9GkzlTWig==", + "dev": true + }, + "@types/eslint": { + "version": "8.4.10", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.10.tgz", + "integrity": "sha512-Sl/HOqN8NKPmhWo2VBEPm0nvHnu2LL3v9vKo8MEq0EtbJ4eVzGPl41VNPvn5E1i5poMk4/XD8UriLHpJvEP/Nw==", + "dev": true, + "requires": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "@types/eslint-scope": { + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz", + "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==", + "dev": true, + "requires": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "@types/estree": { + "version": "0.0.51", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", + "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", + "dev": true + }, + "@types/express": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.15.tgz", + "integrity": "sha512-Yv0k4bXGOH+8a+7bELd2PqHQsuiANB+A8a4gnQrkRWzrkKlb6KHaVvyXhqs04sVW/OWlbPyYxRgYlIXLfrufMQ==", + "dev": true, + "requires": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.31", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "@types/express-serve-static-core": { + "version": "4.17.32", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.32.tgz", + "integrity": "sha512-aI5h/VOkxOF2Z1saPy0Zsxs5avets/iaiAJYznQFm5By/pamU31xWKL//epiF4OfUA2qTOc9PV6tCUjhO8wlZA==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*" + } + }, + "@types/find-cache-dir": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@types/find-cache-dir/-/find-cache-dir-3.2.1.tgz", + "integrity": "sha512-frsJrz2t/CeGifcu/6uRo4b+SzAwT4NYCVPu1GN8IB9XTzrpPkGuV0tmh9mN+/L0PklAlsC3u5Fxt0ju00LXIw==", + "dev": true + }, + "@types/graceful-fs": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz", + "integrity": "sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/hast": { "version": "2.3.4", "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.4.tgz", @@ -8606,6 +27283,42 @@ "hoist-non-react-statics": "^3.3.0" } }, + "@types/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==", + "dev": true + }, + "@types/is-function": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@types/is-function/-/is-function-1.0.1.tgz", + "integrity": "sha512-A79HEEiwXTFtfY+Bcbo58M2GRYzCr9itHWzbzHVFNEYCcoU/MMGwYYf721gBrnhpj1s6RGVVha/IgNFnR0Iw/Q==", + "dev": true + }, + "@types/istanbul-lib-coverage": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", + "dev": true + }, + "@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "*" + } + }, + "@types/istanbul-reports": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "dev": true, + "requires": { + "@types/istanbul-lib-report": "*" + } + }, "@types/json-schema": { "version": "7.0.11", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", @@ -8618,6 +27331,18 @@ "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "dev": true }, + "@types/jsrp": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@types/jsrp/-/jsrp-0.2.4.tgz", + "integrity": "sha512-9RerZiVclCJNQrAaUH71s7tQpIlvyrM+1oWYwaRW+9xYYG0p2rnqSZMS0j+W+bL1tkBRUQUyXiSEUTnbv8HQjA==", + "dev": true + }, + "@types/lodash": { + "version": "4.14.191", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.191.tgz", + "integrity": "sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ==", + "dev": true + }, "@types/mdast": { "version": "3.0.10", "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.10.tgz", @@ -8631,6 +27356,24 @@ "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-1.0.2.tgz", "integrity": "sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA==" }, + "@types/mdx": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/mdx/-/mdx-2.0.3.tgz", + "integrity": "sha512-IgHxcT3RC8LzFLhKwP3gbMPeaK7BM9eBH46OdapPA7yvuIUJ8H6zHZV53J8hGZcTSnt95jANt+rTBNUUc22ACQ==", + "dev": true + }, + "@types/mime": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", + "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==", + "dev": true + }, + "@types/mime-types": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@types/mime-types/-/mime-types-2.1.1.tgz", + "integrity": "sha512-vXOTGVSLR2jMw440moWTC7H19iUyLtP3Z1YTj7cSsubOICinjMxFeb/V57v9QdyyPGbbWolUFSSmSiRSn94tFw==", + "dev": true + }, "@types/ms": { "version": "0.7.31", "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.31.tgz", @@ -8642,22 +27385,75 @@ "integrity": "sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==", "dev": true }, + "@types/node-fetch": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.2.tgz", + "integrity": "sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A==", + "dev": true, + "requires": { + "@types/node": "*", + "form-data": "^3.0.0" + }, + "dependencies": { + "form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + } + } + }, + "@types/normalize-package-data": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz", + "integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==", + "dev": true + }, + "@types/npmlog": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@types/npmlog/-/npmlog-4.1.4.tgz", + "integrity": "sha512-WKG4gTr8przEZBiJ5r3s8ZIAoMXNbOgQ+j/d5O4X3x6kZJRLNvyUJuUK/KoG3+8BaOHPhp2m7WC6JKKeovDSzQ==", + "dev": true + }, "@types/parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==" }, + "@types/pretty-hrtime": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@types/pretty-hrtime/-/pretty-hrtime-1.0.1.tgz", + "integrity": "sha512-VjID5MJb1eGKthz2qUerWT8+R4b9N+CHvGCzg9fn4kWZgaF9AhdYikQio3R7wV8YY1NsQKPaCwKz1Yff+aHNUQ==", + "dev": true + }, "@types/prop-types": { "version": "15.7.5", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" }, + "@types/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", + "dev": true + }, "@types/raf": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/@types/raf/-/raf-3.4.0.tgz", "integrity": "sha512-taW5/WYqo36N7V39oYyHP9Ipfd5pNFvGTIQsNGj86xV88YQ7GnI30/yMfKDF7Zgin0m3e+ikX88FvImnK4RjGw==", "optional": true }, + "@types/range-parser": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", + "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", + "dev": true + }, "@types/react": { "version": "18.0.26", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.26.tgz", @@ -8690,6 +27486,16 @@ "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", "dev": true }, + "@types/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg==", + "dev": true, + "requires": { + "@types/mime": "*", + "@types/node": "*" + } + }, "@types/unist": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.6.tgz", @@ -8705,15 +27511,36 @@ "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==" }, - "@typescript-eslint/eslint-plugin": { - "version": "5.45.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.45.0.tgz", - "integrity": "sha512-CXXHNlf0oL+Yg021cxgOdMHNTXD17rHkq7iW6RFHoybdFgQBjU3yIXhhcPpGwr1CjZlo6ET8C6tzX5juQoXeGA==", + "@types/webpack-env": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/@types/webpack-env/-/webpack-env-1.18.0.tgz", + "integrity": "sha512-56/MAlX5WMsPVbOg7tAxnYvNYMMWr/QJiIp6BxVSW3JJXUVzzOn64qW8TzQyMSqSUFM2+PVI4aUHcHOzIz/1tg==", + "dev": true + }, + "@types/yargs": { + "version": "17.0.19", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.19.tgz", + "integrity": "sha512-cAx3qamwaYX9R0fzOIZAlFpo4A+1uBVCxqpKz9D26uTF4srRXaGTTsikQmaotCtNdbhzyUH7ft6p9ktz9s6UNQ==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "5.45.0", - "@typescript-eslint/type-utils": "5.45.0", - "@typescript-eslint/utils": "5.45.0", + "@types/yargs-parser": "*" + } + }, + "@types/yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", + "dev": true + }, + "@typescript-eslint/eslint-plugin": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.48.1.tgz", + "integrity": "sha512-9nY5K1Rp2ppmpb9s9S2aBiF3xo5uExCehMDmYmmFqqyxgenbHJ3qbarcLt4ITgaD6r/2ypdlcFRdcuVPnks+fQ==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "5.48.1", + "@typescript-eslint/type-utils": "5.48.1", + "@typescript-eslint/utils": "5.48.1", "debug": "^4.3.4", "ignore": "^5.2.0", "natural-compare-lite": "^1.4.0", @@ -8722,6 +27549,32 @@ "tsutils": "^3.21.0" }, "dependencies": { + "@typescript-eslint/scope-manager": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.1.tgz", + "integrity": "sha512-S035ueRrbxRMKvSTv9vJKIWgr86BD8s3RqoRZmsSh/s8HhIs90g6UlK8ZabUSjUZQkhVxt7nmZ63VJ9dcZhtDQ==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/visitor-keys": "5.48.1" + } + }, + "@typescript-eslint/types": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.1.tgz", + "integrity": "sha512-xHyDLU6MSuEEdIlzrrAerCGS3T7AA/L8Hggd0RCYBi0w3JMvGYxlLlXHeg50JI9Tfg5MrtsfuNxbS/3zF1/ATg==", + "dev": true + }, + "@typescript-eslint/visitor-keys": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.1.tgz", + "integrity": "sha512-Ns0XBwmfuX7ZknznfXozgnydyR8F6ev/KEGePP4i74uL3ArsKbEhJ7raeKr1JSa997DBDwol/4a0Y+At82c9dA==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.48.1", + "eslint-visitor-keys": "^3.3.0" + } + }, "debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -8779,17 +27632,48 @@ } }, "@typescript-eslint/type-utils": { - "version": "5.45.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.45.0.tgz", - "integrity": "sha512-DY7BXVFSIGRGFZ574hTEyLPRiQIvI/9oGcN8t1A7f6zIs6ftbrU0nhyV26ZW//6f85avkwrLag424n+fkuoJ1Q==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.48.1.tgz", + "integrity": "sha512-Hyr8HU8Alcuva1ppmqSYtM/Gp0q4JOp1F+/JH5D1IZm/bUBrV0edoewQZiEc1r6I8L4JL21broddxK8HAcZiqQ==", "dev": true, "requires": { - "@typescript-eslint/typescript-estree": "5.45.0", - "@typescript-eslint/utils": "5.45.0", + "@typescript-eslint/typescript-estree": "5.48.1", + "@typescript-eslint/utils": "5.48.1", "debug": "^4.3.4", "tsutils": "^3.21.0" }, "dependencies": { + "@typescript-eslint/types": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.1.tgz", + "integrity": "sha512-xHyDLU6MSuEEdIlzrrAerCGS3T7AA/L8Hggd0RCYBi0w3JMvGYxlLlXHeg50JI9Tfg5MrtsfuNxbS/3zF1/ATg==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.1.tgz", + "integrity": "sha512-Hut+Osk5FYr+sgFh8J/FHjqX6HFcDzTlWLrFqGoK5kVUN3VBHF/QzZmAsIXCQ8T/W9nQNBTqalxi1P3LSqWnRA==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/visitor-keys": "5.48.1", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/visitor-keys": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.1.tgz", + "integrity": "sha512-Ns0XBwmfuX7ZknznfXozgnydyR8F6ev/KEGePP4i74uL3ArsKbEhJ7raeKr1JSa997DBDwol/4a0Y+At82c9dA==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.48.1", + "eslint-visitor-keys": "^3.3.0" + } + }, "debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -8846,21 +27730,71 @@ } }, "@typescript-eslint/utils": { - "version": "5.45.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.45.0.tgz", - "integrity": "sha512-OUg2JvsVI1oIee/SwiejTot2OxwU8a7UfTFMOdlhD2y+Hl6memUSL4s98bpUTo8EpVEr0lmwlU7JSu/p2QpSvA==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.48.1.tgz", + "integrity": "sha512-SmQuSrCGUOdmGMwivW14Z0Lj8dxG1mOFZ7soeJ0TQZEJcs3n5Ndgkg0A4bcMFzBELqLJ6GTHnEU+iIoaD6hFGA==", "dev": true, "requires": { "@types/json-schema": "^7.0.9", "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.45.0", - "@typescript-eslint/types": "5.45.0", - "@typescript-eslint/typescript-estree": "5.45.0", + "@typescript-eslint/scope-manager": "5.48.1", + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/typescript-estree": "5.48.1", "eslint-scope": "^5.1.1", "eslint-utils": "^3.0.0", "semver": "^7.3.7" }, "dependencies": { + "@typescript-eslint/scope-manager": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.1.tgz", + "integrity": "sha512-S035ueRrbxRMKvSTv9vJKIWgr86BD8s3RqoRZmsSh/s8HhIs90g6UlK8ZabUSjUZQkhVxt7nmZ63VJ9dcZhtDQ==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/visitor-keys": "5.48.1" + } + }, + "@typescript-eslint/types": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.1.tgz", + "integrity": "sha512-xHyDLU6MSuEEdIlzrrAerCGS3T7AA/L8Hggd0RCYBi0w3JMvGYxlLlXHeg50JI9Tfg5MrtsfuNxbS/3zF1/ATg==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.1.tgz", + "integrity": "sha512-Hut+Osk5FYr+sgFh8J/FHjqX6HFcDzTlWLrFqGoK5kVUN3VBHF/QzZmAsIXCQ8T/W9nQNBTqalxi1P3LSqWnRA==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/visitor-keys": "5.48.1", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/visitor-keys": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.1.tgz", + "integrity": "sha512-Ns0XBwmfuX7ZknznfXozgnydyR8F6ev/KEGePP4i74uL3ArsKbEhJ7raeKr1JSa997DBDwol/4a0Y+At82c9dA==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.48.1", + "eslint-visitor-keys": "^3.3.0" + } + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, "eslint-scope": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", @@ -8876,6 +27810,12 @@ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true } } }, @@ -8889,6 +27829,183 @@ "eslint-visitor-keys": "^3.3.0" } }, + "@webassemblyjs/ast": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", + "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", + "dev": true, + "requires": { + "@webassemblyjs/helper-numbers": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1" + } + }, + "@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", + "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==", + "dev": true + }, + "@webassemblyjs/helper-api-error": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", + "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==", + "dev": true + }, + "@webassemblyjs/helper-buffer": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", + "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==", + "dev": true + }, + "@webassemblyjs/helper-numbers": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", + "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", + "dev": true, + "requires": { + "@webassemblyjs/floating-point-hex-parser": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", + "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==", + "dev": true + }, + "@webassemblyjs/helper-wasm-section": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", + "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1" + } + }, + "@webassemblyjs/ieee754": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", + "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", + "dev": true, + "requires": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "@webassemblyjs/leb128": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", + "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", + "dev": true, + "requires": { + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/utf8": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", + "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==", + "dev": true + }, + "@webassemblyjs/wasm-edit": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", + "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/helper-wasm-section": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-opt": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "@webassemblyjs/wast-printer": "1.11.1" + } + }, + "@webassemblyjs/wasm-gen": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", + "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" + } + }, + "@webassemblyjs/wasm-opt": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", + "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1" + } + }, + "@webassemblyjs/wasm-parser": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", + "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" + } + }, + "@webassemblyjs/wast-printer": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", + "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, + "@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "@yarnpkg/esbuild-plugin-pnp": { + "version": "3.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@yarnpkg/esbuild-plugin-pnp/-/esbuild-plugin-pnp-3.0.0-rc.15.tgz", + "integrity": "sha512-kYzDJO5CA9sy+on/s2aIW0411AklfCi8Ck/4QDivOqsMKpStZA2SsR+X27VTggGwpStWaLrjJcDcdDMowtG8MA==", + "dev": true, + "requires": { + "tslib": "^2.4.0" + } + }, + "accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dev": true, + "requires": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + } + }, "acorn": { "version": "7.4.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", @@ -8899,8 +28016,7 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "requires": {} + "dev": true }, "acorn-node": { "version": "1.8.2", @@ -8924,6 +28040,71 @@ "resolved": "https://registry.npmjs.org/add/-/add-2.0.6.tgz", "integrity": "sha512-j5QzrmsokwWWp6kUcJQySpbG+xfOBqqKnup3OIk1pz+kB/80SLorZ9V8zHFLO92Lcd+hbvq8bT+zOGoPkmBV0Q==" }, + "address": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/address/-/address-1.2.2.tgz", + "integrity": "sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==", + "dev": true + }, + "adjust-sourcemap-loader": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-4.0.0.tgz", + "integrity": "sha512-OXwN5b9pCUXNQHJpwwD2qP40byEmSgzj8B4ydSN0uMNYWiFmJ6x6KwUllMmfk8Rwu/HJDFR7U8ubsWBoN0Xp0A==", + "dev": true, + "requires": { + "loader-utils": "^2.0.0", + "regex-parser": "^2.2.11" + }, + "dependencies": { + "loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + } + } + }, + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "requires": { + "debug": "4" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + } + }, "ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -8936,6 +28117,56 @@ "uri-js": "^4.2.2" } }, + "ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "requires": { + "ajv": "^8.0.0" + }, + "dependencies": { + "ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + } + } + }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true + }, + "ansi-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "dev": true, + "requires": { + "string-width": "^4.1.0" + } + }, + "ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "dev": true + }, "ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -8975,6 +28206,28 @@ "picomatch": "^2.0.4" } }, + "app-root-dir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/app-root-dir/-/app-root-dir-1.0.2.tgz", + "integrity": "sha512-jlpIfsOoNoafl92Sz//64uQHGSyMrD2vYG5d8o2a4qGvyNCvXur7bzIsWtAC/6flI2RYAp3kv8rsfBtaLm7w0g==", + "dev": true + }, + "aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", + "dev": true + }, + "are-we-there-yet": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", + "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", + "dev": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + } + }, "arg": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", @@ -8989,16 +28242,47 @@ "sprintf-js": "~1.0.2" } }, + "aria-hidden": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.2.tgz", + "integrity": "sha512-6y/ogyDTk/7YAe91T3E2PR1ALVKyM2QbTio5HwM+N1Q6CMlCKhvClyIjkckBswa0f2xJhjsfzIGa1yVSe1UMVA==", + "requires": { + "tslib": "^2.0.0" + } + }, "aria-query": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz", - "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==", + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", + "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", "dev": true, "requires": { - "@babel/runtime": "^7.10.2", - "@babel/runtime-corejs3": "^7.10.2" + "deep-equal": "^2.0.5" } }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==", + "dev": true + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==", + "dev": true + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "dev": true + }, "array-includes": { "version": "3.1.6", "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz", @@ -9018,6 +28302,12 @@ "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "dev": true }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==", + "dev": true + }, "array.prototype.flat": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz", @@ -9055,17 +28345,62 @@ "get-intrinsic": "^1.1.3" } }, + "assert": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-2.0.0.tgz", + "integrity": "sha512-se5Cd+js9dXJnu6Ag2JFc00t+HmHOen+8Q+L7O9zI0PqQXr20uk2J0XQqMxZEeo5U50o8Nvmmx7dZrl+Ufr35A==", + "dev": true, + "requires": { + "es6-object-assign": "^1.1.0", + "is-nan": "^1.2.1", + "object-is": "^1.0.1", + "util": "^0.12.0" + } + }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==", + "dev": true + }, + "ast-types": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.14.2.tgz", + "integrity": "sha512-O0yuUDnZeQDL+ncNGlJ78BiO4jnYI3bvMsD5prT0/nsgijG/LpNBIr63gTjVTNsiGkgQhiyCShTgxt8oXOrklA==", + "dev": true, + "requires": { + "tslib": "^2.0.1" + } + }, "ast-types-flow": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", "integrity": "sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==", "dev": true }, + "async": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", + "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==", + "dev": true + }, + "async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", + "dev": true + }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, + "at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true + }, "atob": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", @@ -9085,10 +28420,16 @@ "postcss-value-parser": "^4.2.0" } }, + "available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "dev": true + }, "axe-core": { - "version": "4.5.2", - "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.5.2.tgz", - "integrity": "sha512-u2MVsXfew5HBvjsczCv+xlwdNnB1oQR9HlAcsejZttNjKKSkeDNVwB1vMThIUIFI9GoT57Vtk8iQLwqOfAkboA==", + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.6.2.tgz", + "integrity": "sha512-b1WlTV8+XKLj9gZy2DZXgQiyDp9xkkoe2a6U6UbYccScq2wgH/YwCeI2/Jq2mgo0HzQxqJOjWZBLeA/mqsk5Mg==", "dev": true }, "axios": { @@ -9103,15 +28444,93 @@ "axios-auth-refresh": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/axios-auth-refresh/-/axios-auth-refresh-3.3.3.tgz", - "integrity": "sha512-2IbDhJ/h6ddNBBnnzn1VFK/qx17pE9aVqiafB8rx5LVHsJ1HtFpUGkbXY7PzTG+8P9HJWcyA3fNZl9BikSuilg==", - "requires": {} + "integrity": "sha512-2IbDhJ/h6ddNBBnnzn1VFK/qx17pE9aVqiafB8rx5LVHsJ1HtFpUGkbXY7PzTG+8P9HJWcyA3fNZl9BikSuilg==" }, "axobject-query": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz", - "integrity": "sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.1.1.tgz", + "integrity": "sha512-goKlv8DZrK9hUh975fnHzhNIO4jUnFCfv/dszV5VwUGDFjI6vQ2VwoyjYjYNEbBE8AH87TduWP5uyDR1D+Iteg==", + "dev": true, + "requires": { + "deep-equal": "^2.0.5" + } + }, + "babel-core": { + "version": "7.0.0-bridge.0", + "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-7.0.0-bridge.0.tgz", + "integrity": "sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg==", "dev": true }, + "babel-loader": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.1.2.tgz", + "integrity": "sha512-mN14niXW43tddohGl8HPu5yfQq70iUThvFL/4QzESA7GcZoC0eVOhvWdQ8+3UlSjaDE9MVtsW9mxDY07W7VpVA==", + "dev": true, + "requires": { + "find-cache-dir": "^3.3.2", + "schema-utils": "^4.0.0" + }, + "dependencies": { + "ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.3" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + } + } + } + }, + "babel-plugin-add-react-displayname": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/babel-plugin-add-react-displayname/-/babel-plugin-add-react-displayname-0.0.5.tgz", + "integrity": "sha512-LY3+Y0XVDYcShHHorshrDbt4KFWL4bSeniCtl4SYZbask+Syngk1uMPCeN9+nSiZo6zX5s0RTq/J9Pnaaf/KHw==", + "dev": true + }, + "babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + } + }, "babel-plugin-macros": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", @@ -9122,6 +28541,61 @@ "resolve": "^1.19.0" } }, + "babel-plugin-named-exports-order": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/babel-plugin-named-exports-order/-/babel-plugin-named-exports-order-0.0.2.tgz", + "integrity": "sha512-OgOYHOLoRK+/mvXU9imKHlG6GkPLYrUCvFXG/CM93R/aNNO8pOOF4aS+S8CCHMDQoNSeiOYEZb/G6RwL95Jktw==", + "dev": true + }, + "babel-plugin-polyfill-corejs2": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz", + "integrity": "sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.17.7", + "@babel/helper-define-polyfill-provider": "^0.3.3", + "semver": "^6.1.1" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "babel-plugin-polyfill-corejs3": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.6.0.tgz", + "integrity": "sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA==", + "dev": true, + "requires": { + "@babel/helper-define-polyfill-provider": "^0.3.3", + "core-js-compat": "^3.25.1" + } + }, + "babel-plugin-polyfill-regenerator": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz", + "integrity": "sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==", + "dev": true, + "requires": { + "@babel/helper-define-polyfill-provider": "^0.3.3" + } + }, + "babel-plugin-react-docgen": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/babel-plugin-react-docgen/-/babel-plugin-react-docgen-4.2.1.tgz", + "integrity": "sha512-UQ0NmGHj/HAqi5Bew8WvNfCk8wSsmdgNd8ZdMjBCICtyCJCq9LiqgqvjCYe570/Wg7AQArSq1VQ60Dd/CHN7mQ==", + "dev": true, + "requires": { + "ast-types": "^0.14.2", + "lodash": "^4.17.15", + "react-docgen": "^5.0.0" + } + }, "babel-plugin-styled-components": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/babel-plugin-styled-components/-/babel-plugin-styled-components-2.0.7.tgz", @@ -9150,6 +28624,38 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dev": true, + "requires": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true + } + } + }, "base64-arraybuffer": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", @@ -9161,6 +28667,39 @@ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" }, + "better-opn": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/better-opn/-/better-opn-2.1.1.tgz", + "integrity": "sha512-kIPXZS5qwyKiX/HcRvDYfmBQUa8XP17I0mYZZ0y4UhpYOSvtsLHDYqmomS+Mj20aDvD3knEiQ0ecQy2nhio3yA==", + "dev": true, + "requires": { + "open": "^7.0.3" + }, + "dependencies": { + "open": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", + "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==", + "dev": true, + "requires": { + "is-docker": "^2.0.0", + "is-wsl": "^2.1.1" + } + } + } + }, + "big-integer": { + "version": "1.6.51", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", + "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==", + "dev": true + }, + "big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true + }, "binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", @@ -9177,6 +28716,99 @@ "readable-stream": "^3.4.0" } }, + "body-parser": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "dev": true, + "requires": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + } + }, + "boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true + }, + "boxen": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz", + "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==", + "dev": true, + "requires": { + "ansi-align": "^3.0.0", + "camelcase": "^6.2.0", + "chalk": "^4.1.0", + "cli-boxes": "^2.2.1", + "string-width": "^4.2.2", + "type-fest": "^0.20.2", + "widest-line": "^3.1.0", + "wrap-ansi": "^7.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "bplist-parser": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.2.0.tgz", + "integrity": "sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw==", + "dev": true, + "requires": { + "big-integer": "^1.6.44" + } + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -9196,15 +28828,31 @@ "fill-range": "^7.0.1" } }, + "browser-assert": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/browser-assert/-/browser-assert-1.2.1.tgz", + "integrity": "sha512-nfulgvOR6S4gt9UKCeGJOuSGBPGiFT6oQ/2UBnvTY/5aQ1PnksW72fhZkM30DzoRRv2WpwZf1vHHEr3mtuXIWQ==", + "dev": true + }, "browserslist": { - "version": "4.21.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.3.tgz", - "integrity": "sha512-898rgRXLAyRkM1GryrrBHGkqA5hlpkV5MhtZwg9QXeiyLUYs2k00Un05aX5l2/yJIOObYKOpS2JNo8nJDE7fWQ==", + "version": "4.21.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", + "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", + "dev": true, "requires": { - "caniuse-lite": "^1.0.30001370", - "electron-to-chromium": "^1.4.202", + "caniuse-lite": "^1.0.30001400", + "electron-to-chromium": "^1.4.251", "node-releases": "^2.0.6", - "update-browserslist-db": "^1.0.5" + "update-browserslist-db": "^1.0.9" + } + }, + "bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "requires": { + "node-int64": "^0.4.0" } }, "btoa": { @@ -9221,11 +28869,68 @@ "ieee754": "^1.1.13" } }, + "buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true + }, "buffer-from": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-0.1.2.tgz", "integrity": "sha512-RiWIenusJsmI2KcvqQABB83tLxCByE3upSP8QU3rJDMVFGPWLvPQJt/O1Su9moRWeH7d+Q2HYb68f6+v+tw2vg==" }, + "bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true + }, + "c8": { + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/c8/-/c8-7.12.0.tgz", + "integrity": "sha512-CtgQrHOkyxr5koX1wEUmN/5cfDa2ckbHRA4Gy5LAL0zaCFtVWJS5++n+w4/sr2GWGerBxgTjpKeDclk/Qk6W/A==", + "dev": true, + "requires": { + "@bcoe/v8-coverage": "^0.2.3", + "@istanbuljs/schema": "^0.1.3", + "find-up": "^5.0.0", + "foreground-child": "^2.0.0", + "istanbul-lib-coverage": "^3.2.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-reports": "^3.1.4", + "rimraf": "^3.0.2", + "test-exclude": "^6.0.0", + "v8-to-istanbul": "^9.0.0", + "yargs": "^16.2.0", + "yargs-parser": "^20.2.9" + } + }, + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dev": true, + "requires": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true + } + } + }, "call-bind": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", @@ -9241,6 +28946,22 @@ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" }, + "camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "dev": true, + "requires": { + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" + } + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, "camelcase-css": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", @@ -9273,6 +28994,12 @@ "svg-pathdata": "^6.0.3" } }, + "case-sensitive-paths-webpack-plugin": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.4.0.tgz", + "integrity": "sha512-roIFONhcxog0JSSWbvVAh3OocukmSgpqOH6YpMkCvav/ySIV3JKg4Dc8vYtQjYi/UxpNE36r/9v+VqTQqgkYmw==", + "dev": true + }, "chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -9320,6 +29047,18 @@ "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" }, + "chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "dev": true + }, + "ci-info": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.7.1.tgz", + "integrity": "sha512-4jYS4MOAaCIStSRwiuxc4B8MYhIe676yO1sYGzARnjXkWpmzZMMYxY6zu8WYWDhSuth5zhrQ1rhNSibyyvv4/w==", + "dev": true + }, "cipher-base": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", @@ -9329,16 +29068,196 @@ "safe-buffer": "^5.0.1" } }, + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, "classnames": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz", "integrity": "sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA==" }, + "clean-css": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.1.tgz", + "integrity": "sha512-lCr8OHhiWCTw4v8POJovCoh4T7I9U11yVsPjMWWnnMmp9ZowCxyad1Pathle/9HjaDp+fdQKjO9fQydE6RHTZg==", + "dev": true, + "requires": { + "source-map": "~0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true + }, + "cli-boxes": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", + "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", + "dev": true + }, + "cli-table3": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.3.tgz", + "integrity": "sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==", + "dev": true, + "requires": { + "@colors/colors": "1.5.0", + "string-width": "^4.2.0" + } + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "dependencies": { + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true + } + } + }, "clsx": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==" }, + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==", + "dev": true, + "requires": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + } + }, "color": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", @@ -9370,6 +29289,18 @@ "simple-swizzle": "^0.2.2" } }, + "color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "dev": true + }, + "colorette": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz", + "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==", + "dev": true + }, "combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -9383,12 +29314,151 @@ "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.2.tgz", "integrity": "sha512-G5yTt3KQN4Yn7Yk4ed73hlZ1evrFKXeUW3086p3PRFNp7m2vIjI6Pg+Kgb+oyzhd9F2qdcoj67+y3SdxL5XWsg==" }, + "commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "dev": true + }, + "common-path-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", + "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==", + "dev": true + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "dev": true + }, + "component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", + "dev": true + }, + "compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dev": true, + "requires": { + "mime-db": ">= 1.43.0 < 2" + } + }, + "compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dev": true, + "requires": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "dependencies": { + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "dev": true + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + } + } + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + }, + "dependencies": { + "buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "confusing-browser-globals": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz", + "integrity": "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==", + "dev": true + }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", + "dev": true + }, + "content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dev": true, + "requires": { + "safe-buffer": "5.2.1" + } + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "dev": true + }, "convert-source-map": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", @@ -9404,6 +29474,18 @@ } } }, + "cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "dev": true + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "dev": true + }, "cookies": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/cookies/-/cookies-0.8.0.tgz", @@ -9413,16 +29495,30 @@ "keygrip": "~1.1.0" } }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==", + "dev": true + }, "core-js": { "version": "3.26.0", "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.26.0.tgz", - "integrity": "sha512-+DkDrhoR4Y0PxDz6rurahuB+I45OsEUv8E1maPTB6OuHRohMMcznBq9TMpdpDMm/hUPob/mJJS3PqgbHpMTQgw==", - "optional": true + "integrity": "sha512-+DkDrhoR4Y0PxDz6rurahuB+I45OsEUv8E1maPTB6OuHRohMMcznBq9TMpdpDMm/hUPob/mJJS3PqgbHpMTQgw==" + }, + "core-js-compat": { + "version": "3.27.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.27.1.tgz", + "integrity": "sha512-Dg91JFeCDA17FKnneN7oCMz4BkQ4TcffkgHP4OWwp9yx3pi7ubqMDXXSacfNak1PQqjc95skyt+YBLHQJnkJwA==", + "dev": true, + "requires": { + "browserslist": "^4.21.4" + } }, "core-js-pure": { - "version": "3.26.1", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.26.1.tgz", - "integrity": "sha512-VVXcDpp/xJ21KdULRq/lXdLzQAtX7+37LzpyfFM973il0tWSsDEoyzG38G14AjTpK9VTfiNM9jnFauq/CpaWGQ==", + "version": "3.27.1", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.27.1.tgz", + "integrity": "sha512-BS2NHgwwUppfeoqOXqi08mUqS5FiZpuRuJJpKsaME7kJz0xxuk0xkhDdfMIlP/zLa80krBqss1LtD7f889heAw==", "dev": true }, "core-util-is": { @@ -9440,6 +29536,13 @@ "parse-json": "^5.0.0", "path-type": "^4.0.0", "yaml": "^1.10.0" + }, + "dependencies": { + "yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==" + } } }, "create-hash": { @@ -9465,6 +29568,12 @@ "which": "^2.0.1" } }, + "crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "dev": true + }, "css-box-model": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/css-box-model/-/css-box-model-1.2.1.tgz", @@ -9487,6 +29596,48 @@ "utrie": "^1.0.2" } }, + "css-loader": { + "version": "6.7.3", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.7.3.tgz", + "integrity": "sha512-qhOH1KlBMnZP8FzRO6YCH9UHXQhVMcEGLyNdb7Hv2cpcmJbW0YrddO+tG1ab5nT41KpHIYGsbeHqxB9xPu1pKQ==", + "dev": true, + "requires": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.19", + "postcss-modules-extract-imports": "^3.0.0", + "postcss-modules-local-by-default": "^4.0.0", + "postcss-modules-scope": "^3.0.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.3.8" + }, + "dependencies": { + "postcss": { + "version": "8.4.21", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz", + "integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==", + "dev": true, + "requires": { + "nanoid": "^3.3.4", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + } + } + } + }, + "css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "dev": true, + "requires": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + } + }, "css-to-react-native": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.0.0.tgz", @@ -9497,6 +29648,12 @@ "postcss-value-parser": "^4.0.2" } }, + "css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "dev": true + }, "cssesc": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", @@ -9508,6 +29665,11 @@ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.0.tgz", "integrity": "sha512-uX1KG+x9h5hIJsaKR9xHUeUraxf8IODOwq9JLNPq6BwB04a/xgpq3rcx47l5BZu5zBPlgD342tdke3Hom/nJRA==" }, + "cva": { + "version": "npm:class-variance-authority@0.4.0", + "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.4.0.tgz", + "integrity": "sha512-74enNN8O9ZNieycac/y8FxqgyzZhZbxmCitAtAeUrLPlxjSd5zA7LfpprmxEcOmQBnaGs5hYhiSGnJ0mqrtBLQ==" + }, "damerau-levenshtein": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", @@ -9543,6 +29705,51 @@ "mimic-response": "^3.1.0" } }, + "dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", + "dev": true + }, + "deep-equal": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.0.tgz", + "integrity": "sha512-RdpzE0Hv4lhowpIUKKMJfeH6C1pXdtT1/it80ubgWqwI3qpuxUBpC1S4hnHg+zjnuOoDkzUtUCEEkG+XG5l3Mw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "es-get-iterator": "^1.1.2", + "get-intrinsic": "^1.1.3", + "is-arguments": "^1.1.1", + "is-array-buffer": "^3.0.1", + "is-date-object": "^1.0.5", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "isarray": "^2.0.5", + "object-is": "^1.1.5", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.4.3", + "side-channel": "^1.0.4", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.9" + }, + "dependencies": { + "isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + } + } + }, "deep-extend": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", @@ -9554,6 +29761,22 @@ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, + "deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "dev": true + }, + "default-browser-id": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-3.0.0.tgz", + "integrity": "sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA==", + "dev": true, + "requires": { + "bplist-parser": "^0.2.0", + "untildify": "^4.0.0" + } + }, "define-lazy-prop": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", @@ -9578,17 +29801,63 @@ } } }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true + } + } + }, "defined": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", "integrity": "sha512-Y2caI5+ZwS5c3RiNDJ6u53VhQHv+hHKwhkI1iHvceKUHw9Df6EK2zRLfjejRgMuCuxK7PfSWIMwWecceVvThjQ==", "dev": true }, + "defu": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.1.tgz", + "integrity": "sha512-aA964RUCsBt0FGoNIlA3uFgo2hO+WWC0fiC6DBps/0SFzkKcYoM/3CzVLIa5xSsrFjdioMdYgAIbwo80qp2MoA==", + "dev": true + }, + "del": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/del/-/del-6.1.1.tgz", + "integrity": "sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg==", + "dev": true, + "requires": { + "globby": "^11.0.1", + "graceful-fs": "^4.2.4", + "is-glob": "^4.0.1", + "is-path-cwd": "^2.2.0", + "is-path-inside": "^3.0.2", + "p-map": "^4.0.0", + "rimraf": "^3.0.2", + "slash": "^3.0.0" + } + }, "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "dev": true + }, "depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -9599,11 +29868,64 @@ "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==" }, + "destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "dev": true + }, + "detect-indent": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", + "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", + "dev": true + }, "detect-libc": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz", "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==" }, + "detect-node-es": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", + "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==" + }, + "detect-package-manager": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/detect-package-manager/-/detect-package-manager-2.0.1.tgz", + "integrity": "sha512-j/lJHyoLlWi6G1LDdLgvUtz60Zo5GEj+sVYtTVXnYLDPuzgC3llMxonXym9zIwhhUII8vjdw0LXxavpLqTbl1A==", + "dev": true, + "requires": { + "execa": "^5.1.1" + } + }, + "detect-port": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/detect-port/-/detect-port-1.5.1.tgz", + "integrity": "sha512-aBzdj76lueB6uUst5iAs7+0H/oOjqI5D16XUWxlWMIMROhcM0rfsNVk93zTngq1dDNpoXRr++Sus7ETAExppAQ==", + "dev": true, + "requires": { + "address": "^1.0.1", + "debug": "4" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, "detective": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/detective/-/detective-5.2.1.tgz", @@ -9650,12 +29972,100 @@ "esutils": "^2.0.2" } }, + "dom-accessibility-api": { + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.15.tgz", + "integrity": "sha512-8o+oVqLQZoruQPYy3uAAQtc6YbtSiRq5aPJBhJ82YTJRHvI6ofhYAkC81WmjFTnfUbqg6T3aCglIpU9p/5e7Cw==", + "dev": true + }, + "dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", + "dev": true, + "requires": { + "utila": "~0.4" + } + }, + "dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "dev": true, + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "dependencies": { + "entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true + } + } + }, + "dom-walk": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz", + "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==", + "dev": true + }, + "domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true + }, + "domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dev": true, + "requires": { + "domelementtype": "^2.2.0" + } + }, "dompurify": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.4.1.tgz", "integrity": "sha512-ewwFzHzrrneRjxzmK6oVz/rZn9VWspGFRDb4/rRtIsM1n36t9AKma/ye8syCpcw+XJ25kOK/hOG7t1j2I2yBqA==", "optional": true }, + "domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dev": true, + "requires": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + } + }, + "dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "dev": true, + "requires": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "dotenv": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.6.0.tgz", + "integrity": "sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==", + "dev": true + }, + "dotenv-expand": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", + "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==", + "dev": true + }, "duplexer2": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", @@ -9693,10 +30103,26 @@ } } }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dev": true + }, + "ejs": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.8.tgz", + "integrity": "sha512-/sXZeMlhS0ArkfX2Aw780gJzXSMPnKjtspYZv+f3NiKLlubezAHDU5+9xz6gd3/NhG3txQCo6xlglmTS+oTGEQ==", + "dev": true, + "requires": { + "jake": "^10.8.5" + } + }, "electron-to-chromium": { - "version": "1.4.206", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.206.tgz", - "integrity": "sha512-h+Fadt1gIaQ06JaIiyqPsBjJ08fV5Q7md+V8bUvQW/9OvXfL2LRICTz2EcnnCP7QzrFTS6/27MRV6Bl9Yn97zA==" + "version": "1.4.284", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz", + "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==", + "dev": true }, "emoji-regex": { "version": "9.2.2", @@ -9704,6 +30130,18 @@ "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", "dev": true }, + "emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "dev": true + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true + }, "end-of-stream": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", @@ -9712,6 +30150,17 @@ "once": "^1.4.0" } }, + "endent": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/endent/-/endent-2.1.0.tgz", + "integrity": "sha512-r8VyPX7XL8U01Xgnb1CjZ3XV+z90cXIJ9JPE/R9SEC9vpw2P6CfsRPJmp20DppC5N7ZAMCmjYkJIa744Iyg96w==", + "dev": true, + "requires": { + "dedent": "^0.7.0", + "fast-json-parse": "^1.0.3", + "objectorarray": "^1.0.5" + } + }, "enhanced-resolve": { "version": "5.12.0", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz", @@ -9727,6 +30176,12 @@ "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz", "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==" }, + "envinfo": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz", + "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==", + "dev": true + }, "error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -9742,6 +30197,15 @@ } } }, + "error-stack-parser": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz", + "integrity": "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==", + "dev": true, + "requires": { + "stackframe": "^1.3.4" + } + }, "es-abstract": { "version": "1.20.4", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.4.tgz", @@ -9782,6 +30246,37 @@ } } }, + "es-get-iterator": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", + "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "has-symbols": "^1.0.3", + "is-arguments": "^1.1.1", + "is-map": "^2.0.2", + "is-set": "^2.0.2", + "is-string": "^1.0.7", + "isarray": "^2.0.5", + "stop-iteration-iterator": "^1.0.0" + }, + "dependencies": { + "isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + } + } + }, + "es-module-lexer": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", + "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", + "dev": true + }, "es-shim-unscopables": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", @@ -9802,24 +30297,160 @@ "is-symbol": "^1.0.2" } }, + "es6-object-assign": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es6-object-assign/-/es6-object-assign-1.1.0.tgz", + "integrity": "sha512-MEl9uirslVwqQU369iHNWZXsI8yaZYGg/D65aOgZkeyFJwHYSxilf7rQzXKI7DdDuBPrBXbfk3sl9hJhmd5AUw==", + "dev": true + }, + "esbuild": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.16.17.tgz", + "integrity": "sha512-G8LEkV0XzDMNwXKgM0Jwu3nY3lSTwSGY6XbxM9cr9+s0T/qSV1q1JVPBGzm3dcjhCic9+emZDmMffkwgPeOeLg==", + "dev": true, + "requires": { + "@esbuild/android-arm": "0.16.17", + "@esbuild/android-arm64": "0.16.17", + "@esbuild/android-x64": "0.16.17", + "@esbuild/darwin-arm64": "0.16.17", + "@esbuild/darwin-x64": "0.16.17", + "@esbuild/freebsd-arm64": "0.16.17", + "@esbuild/freebsd-x64": "0.16.17", + "@esbuild/linux-arm": "0.16.17", + "@esbuild/linux-arm64": "0.16.17", + "@esbuild/linux-ia32": "0.16.17", + "@esbuild/linux-loong64": "0.16.17", + "@esbuild/linux-mips64el": "0.16.17", + "@esbuild/linux-ppc64": "0.16.17", + "@esbuild/linux-riscv64": "0.16.17", + "@esbuild/linux-s390x": "0.16.17", + "@esbuild/linux-x64": "0.16.17", + "@esbuild/netbsd-x64": "0.16.17", + "@esbuild/openbsd-x64": "0.16.17", + "@esbuild/sunos-x64": "0.16.17", + "@esbuild/win32-arm64": "0.16.17", + "@esbuild/win32-ia32": "0.16.17", + "@esbuild/win32-x64": "0.16.17" + } + }, + "esbuild-plugin-alias": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/esbuild-plugin-alias/-/esbuild-plugin-alias-0.2.1.tgz", + "integrity": "sha512-jyfL/pwPqaFXyKnj8lP8iLk6Z0m099uXR45aSN8Av1XD4vhvQutxxPzgA2bTcAwQpa1zCXDcWOlhFgyP3GKqhQ==", + "dev": true + }, + "esbuild-register": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/esbuild-register/-/esbuild-register-3.4.2.tgz", + "integrity": "sha512-kG/XyTDyz6+YDuyfB9ZoSIOOmgyFCH+xPRtsCa8W85HLRV5Csp+o3jWVbOSHgSLfyLc5DmP+KFDNwty4mEjC+Q==", + "dev": true, + "requires": { + "debug": "^4.3.4" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, "escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "dev": true }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" }, - "eslint": { - "version": "8.29.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.29.0.tgz", - "integrity": "sha512-isQ4EEiyUjZFbEKvEGJKKGBwXtvXX+zJbkVKCgTuB9t/+jUBcy8avhkEwWJecI15BkRkOYmvIM5ynbhRjEkoeg==", + "escodegen": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", + "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", "dev": true, "requires": { - "@eslint/eslintrc": "^1.3.3", - "@humanwhocodes/config-array": "^0.11.6", + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.6.1" + }, + "dependencies": { + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2" + } + } + } + }, + "eslint": { + "version": "8.32.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.32.0.tgz", + "integrity": "sha512-nETVXpnthqKPFyuY2FNjz/bEd6nbosRgKbkgS/y1C7LJop96gYHWpiguLecMHQ2XCPxn77DS0P+68WzG6vkZSQ==", + "dev": true, + "requires": { + "@eslint/eslintrc": "^1.4.1", + "@humanwhocodes/config-array": "^0.11.8", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", "ajv": "^6.10.0", @@ -9838,7 +30469,7 @@ "file-entry-cache": "^6.0.1", "find-up": "^5.0.0", "glob-parent": "^6.0.2", - "globals": "^13.15.0", + "globals": "^13.19.0", "grapheme-splitter": "^1.0.4", "ignore": "^5.2.0", "import-fresh": "^3.0.0", @@ -9900,9 +30531,9 @@ "dev": true }, "globals": { - "version": "13.18.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.18.0.tgz", - "integrity": "sha512-/mR4KI8Ps2spmoc0Ulu9L7agOF0du1CZNQ3dke8yItYlyKNmGrkONemBbd6V8UTc1Wgcqn21t3WYB7dbRmh6/A==", + "version": "13.19.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz", + "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==", "dev": true, "requires": { "type-fest": "^0.20.2" @@ -9940,6 +30571,46 @@ } } }, + "eslint-config-airbnb": { + "version": "19.0.4", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb/-/eslint-config-airbnb-19.0.4.tgz", + "integrity": "sha512-T75QYQVQX57jiNgpF9r1KegMICE94VYwoFQyMGhrvc+lB8YF2E/M/PYDaQe1AJcWaEgqLE+ErXV1Og/+6Vyzew==", + "dev": true, + "requires": { + "eslint-config-airbnb-base": "^15.0.0", + "object.assign": "^4.1.2", + "object.entries": "^1.1.5" + } + }, + "eslint-config-airbnb-base": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-15.0.0.tgz", + "integrity": "sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig==", + "dev": true, + "requires": { + "confusing-browser-globals": "^1.0.10", + "object.assign": "^4.1.2", + "object.entries": "^1.1.5", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "eslint-config-airbnb-typescript": { + "version": "17.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-typescript/-/eslint-config-airbnb-typescript-17.0.0.tgz", + "integrity": "sha512-elNiuzD0kPAPTXjFWg+lE24nMdHMtuxgYoD30OyMD6yrW1AhFZPAg27VX7d3tzOErw+dgJTNWfRSDqEcXb4V0g==", + "dev": true, + "requires": { + "eslint-config-airbnb-base": "^15.0.0" + } + }, "eslint-config-next": { "version": "13.0.5", "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-13.0.5.tgz", @@ -9957,14 +30628,21 @@ "eslint-plugin-react-hooks": "^4.5.0" } }, + "eslint-config-prettier": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.6.0.tgz", + "integrity": "sha512-bAF0eLpLVqP5oEVUFKpMA+NnRFICwn9X8B5jrR9FcqnYBuPbqWEjTEspPWMj5ye6czoSLDweCzSo3Ko7gGrZaA==", + "dev": true + }, "eslint-import-resolver-node": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", - "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz", + "integrity": "sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==", "dev": true, "requires": { "debug": "^3.2.7", - "resolve": "^1.20.0" + "is-core-module": "^2.11.0", + "resolve": "^1.22.1" }, "dependencies": { "debug": { @@ -10062,26 +30740,37 @@ } }, "eslint-plugin-import": { - "version": "2.26.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz", - "integrity": "sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==", + "version": "2.27.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.27.4.tgz", + "integrity": "sha512-Z1jVt1EGKia1X9CnBCkpAOhWy8FgQ7OmJ/IblEkT82yrFU/xJaxwujaTzLWqigewwynRQ9mmHfX9MtAfhxm0sA==", "dev": true, "requires": { - "array-includes": "^3.1.4", - "array.prototype.flat": "^1.2.5", - "debug": "^2.6.9", + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "array.prototype.flatmap": "^1.3.0", + "debug": "^3.2.7", "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.6", - "eslint-module-utils": "^2.7.3", + "eslint-import-resolver-node": "^0.3.7", + "eslint-module-utils": "^2.7.4", "has": "^1.0.3", - "is-core-module": "^2.8.1", + "is-core-module": "^2.11.0", "is-glob": "^4.0.3", "minimatch": "^3.1.2", - "object.values": "^1.1.5", - "resolve": "^1.22.0", + "object.values": "^1.1.6", + "resolve": "^1.22.1", + "semver": "^6.3.0", "tsconfig-paths": "^3.14.1" }, "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, "doctrine": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", @@ -10090,27 +30779,42 @@ "requires": { "esutils": "^2.0.2" } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true } } }, "eslint-plugin-jsx-a11y": { - "version": "6.6.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.6.1.tgz", - "integrity": "sha512-sXgFVNHiWffBq23uiS/JaP6eVR622DqwB4yTzKvGZGcPq6/yZ3WmOZfuBks/vHWo9GaFOqC2ZK4i6+C35knx7Q==", + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.7.1.tgz", + "integrity": "sha512-63Bog4iIethyo8smBklORknVjB0T2dwB8Mr/hIC+fBS0uyHdYYpzM/Ed+YC8VxTjlXHEWFOdmgwcDn1U2L9VCA==", "dev": true, "requires": { - "@babel/runtime": "^7.18.9", - "aria-query": "^4.2.2", - "array-includes": "^3.1.5", + "@babel/runtime": "^7.20.7", + "aria-query": "^5.1.3", + "array-includes": "^3.1.6", + "array.prototype.flatmap": "^1.3.1", "ast-types-flow": "^0.0.7", - "axe-core": "^4.4.3", - "axobject-query": "^2.2.0", + "axe-core": "^4.6.2", + "axobject-query": "^3.1.1", "damerau-levenshtein": "^1.0.8", "emoji-regex": "^9.2.2", "has": "^1.0.3", - "jsx-ast-utils": "^3.3.2", - "language-tags": "^1.0.5", + "jsx-ast-utils": "^3.3.3", + "language-tags": "=1.0.5", "minimatch": "^3.1.2", + "object.entries": "^1.1.6", + "object.fromentries": "^2.0.6", "semver": "^6.3.0" }, "dependencies": { @@ -10122,10 +30826,19 @@ } } }, + "eslint-plugin-prettier": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz", + "integrity": "sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==", + "dev": true, + "requires": { + "prettier-linter-helpers": "^1.0.0" + } + }, "eslint-plugin-react": { - "version": "7.31.11", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.31.11.tgz", - "integrity": "sha512-TTvq5JsT5v56wPa9OYHzsrOlHzKZKjV+aLgS+55NJP/cuzdiQPC7PfYoUjMoxlffKtvijpk7vA/jmuqRb9nohw==", + "version": "7.32.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.32.0.tgz", + "integrity": "sha512-vSBi1+SrPiLZCGvxpiZIa28fMEUaMjXtCplrvxcIxGzmFiYdsXQDwInEjuv5/i/2CTTxbkS87tE8lsQ0Qxinbw==", "dev": true, "requires": { "array-includes": "^3.1.6", @@ -10140,7 +30853,7 @@ "object.hasown": "^1.1.2", "object.values": "^1.1.6", "prop-types": "^15.8.1", - "resolve": "^2.0.0-next.3", + "resolve": "^2.0.0-next.4", "semver": "^6.3.0", "string.prototype.matchall": "^4.0.8" }, @@ -10177,15 +30890,36 @@ "version": "4.6.0", "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz", "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==", - "dev": true, - "requires": {} + "dev": true }, "eslint-plugin-simple-import-sort": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/eslint-plugin-simple-import-sort/-/eslint-plugin-simple-import-sort-8.0.0.tgz", "integrity": "sha512-bXgJQ+lqhtQBCuWY/FUWdB27j4+lqcvXv5rUARkzbeWLwea+S5eBZEQrhnO+WgX3ZoJHVj0cn943iyXwByHHQw==", + "dev": true + }, + "eslint-plugin-storybook": { + "version": "0.6.10", + "resolved": "https://registry.npmjs.org/eslint-plugin-storybook/-/eslint-plugin-storybook-0.6.10.tgz", + "integrity": "sha512-3DKXRey06EhwnTKaG6fgMqGTy4C3z6Ikyv6VVixO5BvaExWQe3yGWIAufrC2Et0OaAMIaMwx9KWjqb/Wq+JxPg==", "dev": true, - "requires": {} + "requires": { + "@storybook/csf": "^0.0.1", + "@typescript-eslint/utils": "^5.45.0", + "requireindex": "^1.1.0", + "ts-dedent": "^2.2.0" + }, + "dependencies": { + "@storybook/csf": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/@storybook/csf/-/csf-0.0.1.tgz", + "integrity": "sha512-USTLkZze5gkel8MYCujSRBVIrUQ3YPBrLOx7GNk/0wttvVtlzWXAq9eLbQ4p/NicGxP+3T7KPEMVV//g+yubpw==", + "dev": true, + "requires": { + "lodash": "^4.17.15" + } + } + } }, "eslint-scope": { "version": "7.1.1", @@ -10268,22 +31002,196 @@ "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true }, + "estree-to-babel": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/estree-to-babel/-/estree-to-babel-3.2.1.tgz", + "integrity": "sha512-YNF+mZ/Wu2FU/gvmzuWtYc8rloubL7wfXCTgouFrnjGVXPA/EeYYA7pupXWrb3Iv1cTBeSSxxJIbK23l4MRNqg==", + "dev": true, + "requires": { + "@babel/traverse": "^7.1.6", + "@babel/types": "^7.2.0", + "c8": "^7.6.0" + } + }, "esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true + }, "eventemitter3": { "version": "4.0.7", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" }, + "events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true + }, + "execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + } + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==", + "dev": true, + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + } + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, "expand-template": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==" }, + "expect-type": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-0.14.2.tgz", + "integrity": "sha512-ed3+tr5ujbIYXZ8Pl/VgIphwJQ0q5tBLGGdn7Zvwt1WyPBRX83xjT5pT77P/GkuQbctx0K2ZNSSan7eruJqTCQ==", + "dev": true + }, + "express": { + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "dev": true, + "requires": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + } + }, "extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -10297,16 +31205,61 @@ "is-extendable": "^0.1.0" } }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + } + } + }, + "extract-zip": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.7.0.tgz", + "integrity": "sha512-xoh5G1W/PB0/27lXgMQyIhP5DSY/LhoCsOyZgb+6iMmRtCwVBo55uKaMoEYrDCKQhWvqEip5ZPKAc6eFNyf/MA==", + "dev": true, + "requires": { + "concat-stream": "^1.6.2", + "debug": "^2.6.9", + "mkdirp": "^0.5.4", + "yauzl": "^2.10.0" + } + }, "fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true }, + "fast-diff": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", + "dev": true + }, "fast-glob": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", - "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", "dev": true, "requires": { "@nodelib/fs.stat": "^2.0.2", @@ -10327,6 +31280,12 @@ } } }, + "fast-json-parse": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/fast-json-parse/-/fast-json-parse-1.0.3.tgz", + "integrity": "sha512-FRWsaZRWEJ1ESVNbDWmsAlqDk96gPQezzLghafp5J4GUKjbCz3OkAHuZs5TuPEtkbVQERysLp9xv6c24fBm8Aw==", + "dev": true + }, "fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -10348,6 +31307,30 @@ "reusify": "^1.0.4" } }, + "fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "dev": true, + "requires": { + "bser": "2.1.1" + } + }, + "fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "dev": true, + "requires": { + "pend": "~1.2.0" + } + }, + "fetch-retry": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/fetch-retry/-/fetch-retry-5.0.3.tgz", + "integrity": "sha512-uJQyMrX5IJZkhoEUBQ3EjxkeiZkppBd5jS/fMTJmfZxLSiaQjv2zD0kTvuvkSH89uFvgSlB6ueGpjD3HWN7Bxw==", + "dev": true + }, "fflate": { "version": "0.4.8", "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.4.8.tgz", @@ -10362,6 +31345,58 @@ "flat-cache": "^3.0.4" } }, + "file-system-cache": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/file-system-cache/-/file-system-cache-2.0.2.tgz", + "integrity": "sha512-lp4BHO4CWqvRyx88Tt3quZic9ZMf4cJyquYq7UI8sH42Bm2ArlBBjKQAalZOo+UfaBassb7X123Lik5qZ/tSAA==", + "dev": true, + "requires": { + "fs-extra": "^11.1.0", + "ramda": "^0.28.0" + }, + "dependencies": { + "fs-extra": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.0.tgz", + "integrity": "sha512-0rcTq621PD5jM/e0a3EJoGC/1TC5ZBCERW82LQuwfGnCa1V8w7dpYH1yNu+SLb6E5dkeCBzKEyLGlFrnr+dUyw==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + } + } + }, + "filelist": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", + "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", + "dev": true, + "requires": { + "minimatch": "^5.0.1" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, "fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -10376,6 +31411,80 @@ "resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-1.1.0.tgz", "integrity": "sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==" }, + "finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dev": true, + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + } + }, + "find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, + "dependencies": { + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "requires": { + "find-up": "^4.0.0" + } + } + } + }, "find-root": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", @@ -10407,11 +31516,109 @@ "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "dev": true }, + "flow-parser": { + "version": "0.197.0", + "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.197.0.tgz", + "integrity": "sha512-yhwkJPxH1JBg0aJunk/jVRy5p3UhVZBGkzL1hq/GK+GaBh6bKr2YKkv6gDuiufaw+i3pKWQgOLtD++1cvrgXLA==", + "dev": true + }, "follow-redirects": { "version": "1.15.1", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz", "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==" }, + "for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "requires": { + "is-callable": "^1.1.3" + } + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==", + "dev": true + }, + "foreground-child": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", + "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.0", + "signal-exit": "^3.0.2" + } + }, + "fork-ts-checker-webpack-plugin": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-7.3.0.tgz", + "integrity": "sha512-IN+XTzusCjR5VgntYFgxbxVx3WraPRnKehBFrf00cMSrtUuW9MsG9dhL6MWpY6MkjC3wVwoujfCDgZZCQwbswA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.16.7", + "chalk": "^4.1.2", + "chokidar": "^3.5.3", + "cosmiconfig": "^7.0.1", + "deepmerge": "^4.2.2", + "fs-extra": "^10.0.0", + "memfs": "^3.4.1", + "minimatch": "^3.0.4", + "node-abort-controller": "^3.0.1", + "schema-utils": "^3.1.1", + "semver": "^7.3.5", + "tapable": "^2.2.1" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, "form-data": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", @@ -10422,12 +31629,33 @@ "mime-types": "^2.1.12" } }, + "forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true + }, "fraction.js": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz", "integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==", "dev": true }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==", + "dev": true, + "requires": { + "map-cache": "^0.2.2" + } + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "dev": true + }, "fs": { "version": "0.0.1-security", "resolved": "https://registry.npmjs.org/fs/-/fs-0.0.1-security.tgz", @@ -10438,6 +31666,44 @@ "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" }, + "fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "fs-monkey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.3.tgz", + "integrity": "sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q==", + "dev": true + }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -10474,11 +31740,34 @@ "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", "dev": true }, + "gauge": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", + "dev": true, + "requires": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" + } + }, "gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "peer": true + "dev": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true }, "get-intrinsic": { "version": "1.1.3", @@ -10491,6 +31780,29 @@ "has-symbols": "^1.0.3" } }, + "get-nonce": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", + "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==" + }, + "get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true + }, + "get-port": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-5.1.1.tgz", + "integrity": "sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==", + "dev": true + }, + "get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true + }, "get-symbol-description": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", @@ -10507,16 +31819,38 @@ "integrity": "sha512-X8u8fREiYOE6S8hLbq99PeykTDoLVnxvF4DjWKJmz9xy2nNRdUcV8ZN9tniJFeKyTU3qnC9lL8n4Chd6LmVKHg==", "dev": true }, - "github-buttons": { - "version": "2.22.0", - "resolved": "https://registry.npmjs.org/github-buttons/-/github-buttons-2.22.0.tgz", - "integrity": "sha512-N5bk01s1WgK1FVtoeSUVkRkJpkaSu8yHMPcjye+PTa0jsRjMRNrYqVLgpUf2RA5Kvec05DfHYAT6/68fwkdqPw==" + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==", + "dev": true + }, + "giget": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/giget/-/giget-1.0.0.tgz", + "integrity": "sha512-KWELZn3Nxq5+0So485poHrFriK9Bn3V/x9y+wgqrHkbmnGbjfLmZ685/SVA/ovW+ewoqW0gVI47pI4yW/VNobQ==", + "dev": true, + "requires": { + "colorette": "^2.0.19", + "defu": "^6.1.1", + "https-proxy-agent": "^5.0.1", + "mri": "^1.2.0", + "node-fetch-native": "^1.0.1", + "pathe": "^1.0.0", + "tar": "^6.1.12" + } }, "github-from-package": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==" }, + "github-slugger": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-1.5.0.tgz", + "integrity": "sha512-wIh+gKBI9Nshz2o46B0B3f5k/W+WI9ZAv6y5Dn5WJ5SK1t0TnDimB4WE5rmTD05ZAIn8HALCZVmCsvj0w0v0lw==", + "dev": true + }, "glob": { "version": "7.1.7", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", @@ -10540,6 +31874,22 @@ "is-glob": "^4.0.3" } }, + "glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, + "global": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz", + "integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==", + "dev": true, + "requires": { + "min-document": "^2.19.0", + "process": "^0.11.10" + } + }, "globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", @@ -10571,6 +31921,15 @@ "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==", "dev": true }, + "gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.3" + } + }, "graceful-fs": { "version": "4.2.10", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", @@ -10594,6 +31953,27 @@ "strip-bom-string": "^1.0.0" } }, + "handlebars": { + "version": "4.7.7", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", + "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", + "dev": true, + "requires": { + "minimist": "^1.2.5", + "neo-async": "^2.6.0", + "source-map": "^0.6.1", + "uglify-js": "^3.1.4", + "wordwrap": "^1.0.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, "has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -10637,6 +32017,78 @@ "has-symbols": "^1.0.2" } }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "dev": true + }, + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==", + "dev": true, + "requires": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true + } + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, "hash-base": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", @@ -10652,6 +32104,12 @@ "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-2.0.0.tgz", "integrity": "sha512-Pkw+xBHuV6xFeJprJe2BBEoDV+AvQySaz3pPDRUs5PNZEMQjpXJJueqrpcHIXxnWTcAGi/UOCgVShlkY6kLoqg==" }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true + }, "hoist-non-react-statics": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", @@ -10660,6 +32118,53 @@ "react-is": "^16.7.0" } }, + "hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "html-entities": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.3.tgz", + "integrity": "sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==", + "dev": true + }, + "html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", + "dev": true, + "requires": { + "camel-case": "^4.1.2", + "clean-css": "^5.2.2", + "commander": "^8.3.0", + "he": "^1.2.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.10.0" + } + }, + "html-parse-stringify": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz", + "integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==", + "requires": { + "void-elements": "3.1.0" + } + }, + "html-tags": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.2.0.tgz", + "integrity": "sha512-vy7ClnArOZwCnqZgvv+ddgHgJiAFXe3Ge9ML5/mBctVJoUoYPCdxVucOywjDARn6CVoh3dRSFdPHy2sX80L0Wg==", + "dev": true + }, "html-tokenize": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/html-tokenize/-/html-tokenize-2.0.1.tgz", @@ -10695,6 +32200,19 @@ } } }, + "html-webpack-plugin": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.5.0.tgz", + "integrity": "sha512-sy88PC2cRTVxvETRgUHFrL4No3UxvcH8G1NepGhqaTT+GXN2kTamqasot0inS5hXeg1cMbFDt27zzo9p35lZVw==", + "dev": true, + "requires": { + "@types/html-minifier-terser": "^6.0.0", + "html-minifier-terser": "^6.0.2", + "lodash": "^4.17.21", + "pretty-error": "^4.0.0", + "tapable": "^2.0.0" + } + }, "html2canvas": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz", @@ -10705,6 +32223,39 @@ "text-segmentation": "^1.0.3" } }, + "htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "dev": true, + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + }, + "dependencies": { + "entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true + } + } + }, + "http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "requires": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + } + }, "http-proxy": { "version": "1.18.1", "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", @@ -10715,6 +32266,67 @@ "requires-port": "^1.0.0" } }, + "https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "requires": { + "agent-base": "6", + "debug": "4" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true + }, + "i18next": { + "version": "22.4.6", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-22.4.6.tgz", + "integrity": "sha512-9Tm1ezxWyzV+306CIDMBbYBitC1jedQyYuuLtIv7oxjp2ohh8eyxP9xytIf+2bbQfhH784IQKPSYp+Zq9+YSbw==", + "requires": { + "@babel/runtime": "^7.20.6" + } + }, + "i18next-fs-backend": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/i18next-fs-backend/-/i18next-fs-backend-2.1.1.tgz", + "integrity": "sha512-FTnj+UmNgT3YRml5ruRv0jMZDG7odOL/OP5PF5mOqvXud2vHrPOOs68Zdk6iqzL47cnnM0ZVkK2BAvpFeDJToA==" + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "dev": true + }, "ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", @@ -10726,6 +32338,15 @@ "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", "dev": true }, + "image-size": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.0.2.tgz", + "integrity": "sha512-xfOoWjceHntRb3qFCrh5ZFORYH8XCdYpASltMhZ/Q0KZiOwjdE/Yl2QCiWdwD+lygV5bMCvauzgu5PxBX/Yerg==", + "dev": true, + "requires": { + "queue": "6.0.2" + } + }, "immer": { "version": "9.0.15", "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.15.tgz", @@ -10746,6 +32367,12 @@ "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true }, + "indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -10772,16 +32399,78 @@ "integrity": "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==" }, "internal-slot": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.4.tgz", + "integrity": "sha512-tA8URYccNzMo94s5MQZgH8NB/XTa6HsOo0MLfXTKKEnHVVdegzaQoFZ7Jp44bdvLvY2waT5dc+j5ICEswhi7UQ==", "dev": true, "requires": { - "get-intrinsic": "^1.1.0", + "get-intrinsic": "^1.1.3", "has": "^1.0.3", "side-channel": "^1.0.4" } }, + "interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "dev": true + }, + "invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "requires": { + "loose-envify": "^1.0.0" + } + }, + "ip": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", + "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==", + "dev": true + }, + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true + }, + "is-absolute-url": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-3.0.3.tgz", + "integrity": "sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q==", + "dev": true + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-array-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.1.tgz", + "integrity": "sha512-ASfLknmY8Xa2XtB4wmbz13Wu202baeA18cJBCeCy0wXUHZF0IPyVEXqKEcd+t2fNSLLL1vC6k7lxZEojNbISXQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-typed-array": "^1.1.10" + } + }, "is-arrayish": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", @@ -10834,6 +32523,15 @@ "has": "^1.0.3" } }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, "is-date-object": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", @@ -10843,6 +32541,17 @@ "has-tostringtag": "^1.0.0" } }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, "is-docker": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", @@ -10860,6 +32569,27 @@ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "is-function": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.2.tgz", + "integrity": "sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ==", + "dev": true + }, + "is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, "is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -10869,6 +32599,22 @@ "is-extglob": "^2.1.1" } }, + "is-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", + "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", + "dev": true + }, + "is-nan": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/is-nan/-/is-nan-1.3.2.tgz", + "integrity": "sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3" + } + }, "is-negative-zero": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", @@ -10890,6 +32636,12 @@ "has-tostringtag": "^1.0.0" } }, + "is-path-cwd": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", + "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", + "dev": true + }, "is-path-inside": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", @@ -10901,6 +32653,12 @@ "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==" }, + "is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "dev": true + }, "is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -10911,6 +32669,12 @@ "has-tostringtag": "^1.0.0" } }, + "is-set": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", + "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", + "dev": true + }, "is-shared-array-buffer": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", @@ -10920,6 +32684,12 @@ "call-bind": "^1.0.2" } }, + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true + }, "is-string": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", @@ -10938,6 +32708,25 @@ "has-symbols": "^1.0.2" } }, + "is-typed-array": { + "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==", + "dev": true, + "requires": { + "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-weakmap": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", + "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", + "dev": true + }, "is-weakref": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", @@ -10947,6 +32736,22 @@ "call-bind": "^1.0.2" } }, + "is-weakset": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", + "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + } + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true + }, "is-wsl": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", @@ -10967,6 +32772,308 @@ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, + "isobject": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-4.0.0.tgz", + "integrity": "sha512-S/2fF5wH8SJA/kmwr6HYhK/RI/OkhD84k8ntalo0iJjZikgq1XFvR5M8NPT1x5F7fBwCG3qHfnzeP/Vh/ZxCUA==", + "dev": true + }, + "isomorphic-unfetch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/isomorphic-unfetch/-/isomorphic-unfetch-3.1.0.tgz", + "integrity": "sha512-geDJjpoZ8N0kWexiwkX8F9NkTsXhetLPVbZFQ+JTW239QNOwvB0gniuR1Wc6f0AMTn7/mFGyXvHTifrCp/GH8Q==", + "dev": true, + "requires": { + "node-fetch": "^2.6.1", + "unfetch": "^4.2.0" + } + }, + "istanbul-lib-coverage": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "dev": true + }, + "istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dev": true, + "requires": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "istanbul-reports": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", + "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", + "dev": true, + "requires": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + } + }, + "jake": { + "version": "10.8.5", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.5.tgz", + "integrity": "sha512-sVpxYeuAhWt0OTWITwT98oyV0GsXyMlXCF+3L1SuafBVUIr/uILGRB+NqwkzhgXKvoJpDIpQvqkUALgdmQsQxw==", + "dev": true, + "requires": { + "async": "^3.2.3", + "chalk": "^4.0.2", + "filelist": "^1.0.1", + "minimatch": "^3.0.4" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-haste-map": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.3.1.tgz", + "integrity": "sha512-/FFtvoG1xjbbPXQLFef+WSU4yrc0fc0Dds6aRPBojUid7qlPqZvxdUBA03HW0fnVHXVCnCdkuoghYItKNzc/0A==", + "dev": true, + "requires": { + "@jest/types": "^29.3.1", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "fsevents": "^2.3.2", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.2.0", + "jest-util": "^29.3.1", + "jest-worker": "^29.3.1", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + } + }, + "jest-mock": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz", + "integrity": "sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==", + "dev": true, + "requires": { + "@jest/types": "^27.5.1", + "@types/node": "*" + }, + "dependencies": { + "@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", + "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-regex-util": { + "version": "29.2.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.2.0.tgz", + "integrity": "sha512-6yXn0kg2JXzH30cr2NlThF+70iuO/3irbaB4mh5WyqNIvLLP+B6sFdluO1/1RJmslyh/f9osnefECflHvTbwVA==", + "dev": true + }, + "jest-util": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.3.1.tgz", + "integrity": "sha512-7YOVZaiX7RJLv76ZfHt4nbNEzzTRiMW/IiOG7ZOKmTXmoGBxUDefgMAxQubu6WPVqP5zSzAdZG0FfLcC7HOIFQ==", + "dev": true, + "requires": { + "@jest/types": "^29.3.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-worker": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.3.1.tgz", + "integrity": "sha512-lY4AnnmsEWeiXirAIA0c9SDPbuCBq8IYuDVL8PMm0MZ2PEs2yPvRA/J64QBXuZp7CYKrDM/rmNrc9/i3KJQncw==", + "dev": true, + "requires": { + "@types/node": "*", + "jest-util": "^29.3.1", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, "js-sdsl": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.2.0.tgz", @@ -10992,6 +33099,221 @@ "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==" }, + "jscodeshift": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/jscodeshift/-/jscodeshift-0.13.1.tgz", + "integrity": "sha512-lGyiEbGOvmMRKgWk4vf+lUrCWO/8YR8sUR3FKF1Cq5fovjZDlIcw3Hu5ppLHAnEXshVffvaM0eyuY/AbOeYpnQ==", + "dev": true, + "requires": { + "@babel/core": "^7.13.16", + "@babel/parser": "^7.13.16", + "@babel/plugin-proposal-class-properties": "^7.13.0", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.13.8", + "@babel/plugin-proposal-optional-chaining": "^7.13.12", + "@babel/plugin-transform-modules-commonjs": "^7.13.8", + "@babel/preset-flow": "^7.13.13", + "@babel/preset-typescript": "^7.13.0", + "@babel/register": "^7.13.16", + "babel-core": "^7.0.0-bridge.0", + "chalk": "^4.1.2", + "flow-parser": "0.*", + "graceful-fs": "^4.2.4", + "micromatch": "^3.1.10", + "neo-async": "^2.5.0", + "node-dir": "^0.1.17", + "recast": "^0.20.4", + "temp": "^0.8.4", + "write-file-atomic": "^2.3.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + }, + "dependencies": { + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + } + } + }, + "recast": { + "version": "0.20.5", + "resolved": "https://registry.npmjs.org/recast/-/recast-0.20.5.tgz", + "integrity": "sha512-E5qICoPoNL4yU0H0NoBDntNB0Q5oMSNh9usFctYniLBluTthi3RsQVBXIJNbApOlvSwW/RGxIuokPcAc59J5fQ==", + "dev": true, + "requires": { + "ast-types": "0.14.2", + "esprima": "~4.0.0", + "source-map": "~0.6.1", + "tslib": "^2.0.1" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + }, + "write-file-atomic": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", + "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" + } + } + } + }, "jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -11015,10 +33337,20 @@ "dev": true }, "json5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", - "peer": true + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } }, "jsonp": { "version": "0.2.1", @@ -11081,6 +33413,12 @@ "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==" }, + "klona": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz", + "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==", + "dev": true + }, "language-subtag-registry": { "version": "0.3.22", "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz", @@ -11096,6 +33434,25 @@ "language-subtag-registry": "~0.3.2" } }, + "lazy-universal-dotenv": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lazy-universal-dotenv/-/lazy-universal-dotenv-3.0.1.tgz", + "integrity": "sha512-prXSYk799h3GY3iOWnC6ZigYzMPjxN2svgjJ9shk7oMadSNX3wXy0B6F32PMJv7qtMnrIbUxoEHzbutvxR2LBQ==", + "dev": true, + "requires": { + "@babel/runtime": "^7.5.0", + "app-root-dir": "^1.0.2", + "core-js": "^3.0.4", + "dotenv": "^8.0.0", + "dotenv-expand": "^5.1.0" + } + }, + "leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true + }, "levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -11125,6 +33482,18 @@ "uc.micro": "^1.0.1" } }, + "loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "dev": true + }, + "loader-utils": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.1.tgz", + "integrity": "sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw==", + "dev": true + }, "locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -11145,6 +33514,12 @@ "integrity": "sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==", "dev": true }, + "lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "dev": true + }, "lodash.isequal": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", @@ -11170,6 +33545,15 @@ "js-tokens": "^3.0.0 || ^4.0.0" } }, + "lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "dev": true, + "requires": { + "tslib": "^2.0.3" + } + }, "lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -11178,6 +33562,59 @@ "yallist": "^4.0.0" } }, + "lz-string": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.4.4.tgz", + "integrity": "sha512-0ckx7ZHRPqb0oUm8zNr+90mtf9DQB60H1wMCjBtfi62Kl3a7JbHob6gA2bC+xRvZoOL+1hzUK8jeuEIQE8svEQ==", + "dev": true + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "requires": { + "tmpl": "1.0.5" + } + }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==", + "dev": true + }, + "map-or-similar": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/map-or-similar/-/map-or-similar-1.5.0.tgz", + "integrity": "sha512-0aF7ZmVon1igznGI4VS30yugpduQW3y3GkcgGJOp7d8x8QrizhigUxjI/m2UojsXXto+jLAH3KSz+xOJTiORjg==", + "dev": true + }, + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==", + "dev": true, + "requires": { + "object-visit": "^1.0.0" + } + }, "markdown-it": { "version": "13.0.1", "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-13.0.1.tgz", @@ -11197,6 +33634,12 @@ } } }, + "markdown-to-jsx": { + "version": "7.1.8", + "resolved": "https://registry.npmjs.org/markdown-to-jsx/-/markdown-to-jsx-7.1.8.tgz", + "integrity": "sha512-rRSa1aFmFnpDRFAhv5vIkWM4nPaoB9vnzIjuIKa1wGupfn2hdCNeaQHKpu4/muoc8n8J7yowjTP2oncA4/Rbgg==", + "dev": true + }, "md5.js": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", @@ -11264,17 +33707,59 @@ "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==" }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "dev": true + }, + "memfs": { + "version": "3.4.13", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.4.13.tgz", + "integrity": "sha512-omTM41g3Skpvx5dSYeZIbXKcXoAVc/AoMNwn9TKx++L/gaen/+4TTttmu8ZSch5vfVJ8uJvGbroTsIlslRg6lg==", + "dev": true, + "requires": { + "fs-monkey": "^1.0.3" + } + }, "memoize-one": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz", "integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==" }, + "memoizerific": { + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/memoizerific/-/memoizerific-1.11.3.tgz", + "integrity": "sha512-/EuHYwAPdLtXwAwSZkh/Gutery6pD2KYd44oQLhAvQp/50mpyduZh8Q7PYHXTCJ+wuXxt7oij2LXyIJOOYFPog==", + "dev": true, + "requires": { + "map-or-similar": "^1.5.0" + } + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", + "dev": true + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, "merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "dev": true }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "dev": true + }, "micromark": { "version": "3.0.10", "resolved": "https://registry.npmjs.org/micromark/-/micromark-3.0.10.tgz", @@ -11512,6 +33997,12 @@ "picomatch": "^2.3.1" } }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true + }, "mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", @@ -11525,11 +34016,32 @@ "mime-db": "1.52.0" } }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, "mimic-response": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==" }, + "min-document": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz", + "integrity": "sha512-9Wy1B3m3f66bPPmU5hdA4DR4PB2OfDU/+GS3yAB7IQozE3tqXaVv2zOjgla7MEGSRv95+ILmOuvhLkOK6wJtCQ==", + "dev": true, + "requires": { + "dom-walk": "^0.1.0" + } + }, + "min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true + }, "minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -11544,6 +34056,81 @@ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" }, + "minipass": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.0.0.tgz", + "integrity": "sha512-g2Uuh2jEKoht+zvO6vJqXmYpflPqzRBT+Th2h01DKh5z7wbY/AZ2gCQ78cP70YoHPyFdY30YBV5WxgLOEwOykw==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "requires": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "dev": true, + "requires": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true + } + } + }, + "mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "requires": { + "minimist": "^1.2.6" + } + }, "mkdirp-classic": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", @@ -11573,6 +34160,61 @@ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==" }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true + } + } + }, "napi-build-utils": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", @@ -11590,25 +34232,37 @@ "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", "dev": true }, + "negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true + }, + "neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, "next": { - "version": "12.3.1", - "resolved": "https://registry.npmjs.org/next/-/next-12.3.1.tgz", - "integrity": "sha512-l7bvmSeIwX5lp07WtIiP9u2ytZMv7jIeB8iacR28PuUEFG5j0HGAPnMqyG5kbZNBG2H7tRsrQ4HCjuMOPnANZw==", + "version": "12.3.4", + "resolved": "https://registry.npmjs.org/next/-/next-12.3.4.tgz", + "integrity": "sha512-VcyMJUtLZBGzLKo3oMxrEF0stxh8HwuW976pAzlHhI3t8qJ4SROjCrSh1T24bhrbjw55wfZXAbXPGwPt5FLRfQ==", "requires": { - "@next/env": "12.3.1", - "@next/swc-android-arm-eabi": "12.3.1", - "@next/swc-android-arm64": "12.3.1", - "@next/swc-darwin-arm64": "12.3.1", - "@next/swc-darwin-x64": "12.3.1", - "@next/swc-freebsd-x64": "12.3.1", - "@next/swc-linux-arm-gnueabihf": "12.3.1", - "@next/swc-linux-arm64-gnu": "12.3.1", - "@next/swc-linux-arm64-musl": "12.3.1", - "@next/swc-linux-x64-gnu": "12.3.1", - "@next/swc-linux-x64-musl": "12.3.1", - "@next/swc-win32-arm64-msvc": "12.3.1", - "@next/swc-win32-ia32-msvc": "12.3.1", - "@next/swc-win32-x64-msvc": "12.3.1", + "@next/env": "12.3.4", + "@next/swc-android-arm-eabi": "12.3.4", + "@next/swc-android-arm64": "12.3.4", + "@next/swc-darwin-arm64": "12.3.4", + "@next/swc-darwin-x64": "12.3.4", + "@next/swc-freebsd-x64": "12.3.4", + "@next/swc-linux-arm-gnueabihf": "12.3.4", + "@next/swc-linux-arm64-gnu": "12.3.4", + "@next/swc-linux-arm64-musl": "12.3.4", + "@next/swc-linux-x64-gnu": "12.3.4", + "@next/swc-linux-x64-musl": "12.3.4", + "@next/swc-win32-arm64-msvc": "12.3.4", + "@next/swc-win32-ia32-msvc": "12.3.4", + "@next/swc-win32-x64-msvc": "12.3.4", "@swc/helpers": "0.4.11", "caniuse-lite": "^1.0.30001406", "postcss": "8.4.14", @@ -11616,6 +34270,28 @@ "use-sync-external-store": "1.2.0" } }, + "next-i18next": { + "version": "13.0.2", + "resolved": "https://registry.npmjs.org/next-i18next/-/next-i18next-13.0.2.tgz", + "integrity": "sha512-aUHyKT2kztMgEP44zDB5KoW8XZUQawIdOYWXcrMH6lxAcS0kBsKX0uKMzGS5XlgLW88gvOVc3D7NdfCznLgyyg==", + "requires": { + "@babel/runtime": "^7.20.6", + "@types/hoist-non-react-statics": "^3.3.1", + "core-js": "^3", + "hoist-non-react-statics": "^3.3.2", + "i18next-fs-backend": "^2.1.0" + } + }, + "no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "dev": true, + "requires": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, "node-abi": { "version": "3.30.0", "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.30.0.tgz", @@ -11624,15 +34300,72 @@ "semver": "^7.3.5" } }, + "node-abort-controller": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.0.1.tgz", + "integrity": "sha512-/ujIVxthRs+7q6hsdjHMaj8hRG9NuWmwrz+JdRwZ14jdFoKSkm+vDsCbF9PLpnSqjaWQJuTmVtcWHNLr+vrOFw==", + "dev": true + }, "node-addon-api": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.0.0.tgz", "integrity": "sha512-CvkDw2OEnme7ybCykJpVcKH+uAOLV2qLqiyla128dN9TkEWfrYmxG6C2boDe5KcNQqZF3orkqzGgOMvZ/JNekA==" }, + "node-dir": { + "version": "0.1.17", + "resolved": "https://registry.npmjs.org/node-dir/-/node-dir-0.1.17.tgz", + "integrity": "sha512-tmPX422rYgofd4epzrNoOXiE8XFZYOcCq1vD7MAXCDO+O+zndlA2ztdKKMa+EeuBG5tHETpr4ml4RGgpqDCCAg==", + "dev": true, + "requires": { + "minimatch": "^3.0.2" + } + }, + "node-fetch": { + "version": "2.6.8", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.8.tgz", + "integrity": "sha512-RZ6dBYuj8dRSfxpUSu+NsdF1dpPpluJxwOp+6IoDp/sH2QNDSvurYsAa+F1WxY2RjA1iP93xhcsUoYbF2XBqVg==", + "dev": true, + "requires": { + "whatwg-url": "^5.0.0" + } + }, + "node-fetch-native": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.0.1.tgz", + "integrity": "sha512-VzW+TAk2wE4X9maiKMlT+GsPU4OMmR1U9CrHSmd3DFLn2IcZ9VJ6M6BBugGfYUnPCLSYxXdZy17M0BEJyhUTwg==", + "dev": true + }, + "node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true + }, "node-releases": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", - "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==" + "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", + "dev": true + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } }, "normalize-path": { "version": "3.0.0", @@ -11646,11 +34379,115 @@ "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", "dev": true }, + "npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "requires": { + "path-key": "^3.0.0" + } + }, + "npmlog": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", + "dev": true, + "requires": { + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" + } + }, + "nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "requires": { + "boolbase": "^1.0.0" + } + }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==", + "dev": true, + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, "object-hash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", @@ -11663,11 +34500,38 @@ "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", "dev": true }, + "object-is": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", + "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, "object-keys": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-0.4.0.tgz", "integrity": "sha512-ncrLw+X55z7bkl5PnUvHwFK9FcGuFYo9gtjws2XtSzL+aZ8tm830P60WJ0dSmFVaSalWieW5MD7kEdnXda9yJw==" }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==", + "dev": true, + "requires": { + "isobject": "^3.0.0" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true + } + } + }, "object.assign": { "version": "4.1.4", "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", @@ -11720,6 +34584,23 @@ "es-abstract": "^1.20.4" } }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true + } + } + }, "object.values": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz", @@ -11731,6 +34612,27 @@ "es-abstract": "^1.20.4" } }, + "objectorarray": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/objectorarray/-/objectorarray-1.0.5.tgz", + "integrity": "sha512-eJJDYkhJFFbBBAxeh8xW+weHlkI28n2ZdQV/J/DNfWfSKlGEf2xcfAbZTv3riEXHAhL9SVOTs2pRmXiSTf78xg==", + "dev": true + }, + "on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "requires": { + "ee-first": "1.1.1" + } + }, + "on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "dev": true + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -11739,6 +34641,15 @@ "wrappy": "1" } }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, "open": { "version": "8.4.0", "resolved": "https://registry.npmjs.org/open/-/open-8.4.0.tgz", @@ -11782,6 +34693,31 @@ "p-limit": "^3.0.2" } }, + "p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "requires": { + "aggregate-error": "^3.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "param-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "dev": true, + "requires": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, "parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -11801,6 +34737,34 @@ "lines-and-columns": "^1.1.6" } }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true + }, + "pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "dev": true, + "requires": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==", + "dev": true + }, + "path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "dev": true + }, "path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -11824,11 +34788,29 @@ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", + "dev": true + }, "path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==" }, + "pathe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.0.0.tgz", + "integrity": "sha512-nPdMG0Pd09HuSsr7QOKUXO2Jr9eqaDiZvDwdyIhNG5SHYujkQHYKDfGQkulBxvbDHz8oHLsTgKN86LSwYzSHAg==", + "dev": true + }, + "pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "dev": true + }, "performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", @@ -11851,6 +34833,45 @@ "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", "dev": true }, + "pirates": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", + "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", + "dev": true + }, + "pkg-dir": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-5.0.0.tgz", + "integrity": "sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA==", + "dev": true, + "requires": { + "find-up": "^5.0.0" + } + }, + "pnp-webpack-plugin": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/pnp-webpack-plugin/-/pnp-webpack-plugin-1.7.0.tgz", + "integrity": "sha512-2Rb3vm+EXble/sMXNSu6eoBx8e79gKqhNq9F5ZWW6ERNCTE/Q0wQNne5541tE5vKjfM8hpNCYL+LGc1YTfI0dg==", + "dev": true, + "requires": { + "ts-pnp": "^1.1.6" + } + }, + "polished": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/polished/-/polished-4.2.2.tgz", + "integrity": "sha512-Sz2Lkdxz6F2Pgnpi9U5Ng/WdWAUZxmHrNPoVlm3aAemxoy2Qy7LGjQg4uf8qKelDAUW94F4np3iH2YPf2qefcQ==", + "dev": true, + "requires": { + "@babel/runtime": "^7.17.8" + } + }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==", + "dev": true + }, "postcss": { "version": "8.4.14", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", @@ -11889,15 +34910,69 @@ "requires": { "lilconfig": "^2.0.5", "yaml": "^1.10.2" + }, + "dependencies": { + "yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true + } + } + }, + "postcss-loader": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-6.2.1.tgz", + "integrity": "sha512-WbbYpmAaKcux/P66bZ40bpWsBucjx/TTgVVzRZ9yUO8yQfVBlameJ0ZGVaPfH64hNSBh63a+ICP5nqOpBA0w+Q==", + "dev": true, + "requires": { + "cosmiconfig": "^7.0.0", + "klona": "^2.0.5", + "semver": "^7.3.5" + } + }, + "postcss-modules-extract-imports": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", + "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", + "dev": true + }, + "postcss-modules-local-by-default": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz", + "integrity": "sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ==", + "dev": true, + "requires": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + } + }, + "postcss-modules-scope": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz", + "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==", + "dev": true, + "requires": { + "postcss-selector-parser": "^6.0.4" + } + }, + "postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "dev": true, + "requires": { + "icss-utils": "^5.0.0" } }, "postcss-nested": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-5.0.6.tgz", - "integrity": "sha512-rKqm2Fk0KbA8Vt3AdGN0FB9OBOMDVajMG6ZCf/GoHgdxUJ4sBFp0A/uMIRm+MJUdo33YXEtjqIz8u7DAp8B7DA==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.0.tgz", + "integrity": "sha512-0DkamqrPcmkBDsLn+vQDIrtkSbNkv5AD/M322ySo9kqFkCIYklym2xEmWkwo+Y3/qZo34tzEPNUw4y7yMCdv5w==", "dev": true, "requires": { - "postcss-selector-parser": "^6.0.6" + "postcss-selector-parser": "^6.0.10" } }, "postcss-selector-parser": { @@ -11951,9 +35026,71 @@ "dev": true }, "prettier": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz", - "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==", + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.3.tgz", + "integrity": "sha512-tJ/oJ4amDihPoufT5sM0Z1SKEuKay8LfVAMlbbhnnkvt6BUserZylqo2PN+p9KeljLr0OHa2rXHU1T8reeoTrw==", + "dev": true + }, + "prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "requires": { + "fast-diff": "^1.1.2" + } + }, + "prettier-plugin-tailwindcss": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.2.2.tgz", + "integrity": "sha512-5RjUbWRe305pUpc48MosoIp6uxZvZxrM6GyOgsbGLTce+ehePKNm7ziW2dLG2air9aXbGuXlHVSQQw4Lbosq3w==", + "dev": true + }, + "pretty-error": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", + "integrity": "sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==", + "dev": true, + "requires": { + "lodash": "^4.17.20", + "renderkid": "^3.0.0" + } + }, + "pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + }, + "react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true + } + } + }, + "pretty-hrtime": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", + "integrity": "sha512-66hKPCr+72mlfiSjlEB1+45IjXSqvVAIy6mocupoww4tBFE9R9IhwwUGoI4G++Tc9Aq+2rxOt0RFU6gPcrte0A==", + "dev": true + }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", "dev": true }, "process-nextick-args": { @@ -11961,6 +35098,30 @@ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, + "prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "requires": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "dependencies": { + "kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true + } + } + }, "prop-types": { "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", @@ -11976,6 +35137,22 @@ "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.1.1.tgz", "integrity": "sha512-hrzC564QIl0r0vy4l6MvRLhafmUowhO/O3KgVSoXIbbA2Sz4j8HGpJc6T2cubRVwMwpdiG/vKGfhT4IixmKN9w==" }, + "proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dev": true, + "requires": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + } + }, + "proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "dev": true + }, "pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", @@ -11986,11 +35163,95 @@ } }, "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.2.0.tgz", + "integrity": "sha512-LN6QV1IJ9ZhxWTNdktaPClrNfp8xdSAYS0Zk2ddX7XsXZAxckMHPCBcHRo0cTcEIgYPRiGEkmji3Idkh2yFtYw==", "dev": true }, + "puppeteer-core": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-2.1.1.tgz", + "integrity": "sha512-n13AWriBMPYxnpbb6bnaY5YoY6rGj8vPLrz6CZF3o0qJNEwlcfJVxBzYZ0NJsQ21UbdJoijPCDrM++SUVEz7+w==", + "dev": true, + "requires": { + "@types/mime-types": "^2.1.0", + "debug": "^4.1.0", + "extract-zip": "^1.6.6", + "https-proxy-agent": "^4.0.0", + "mime": "^2.0.3", + "mime-types": "^2.1.25", + "progress": "^2.0.1", + "proxy-from-env": "^1.0.0", + "rimraf": "^2.6.1", + "ws": "^6.1.0" + }, + "dependencies": { + "agent-base": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-5.1.1.tgz", + "integrity": "sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g==", + "dev": true + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "https-proxy-agent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz", + "integrity": "sha512-zoDhWrkR3of1l9QAL8/scJZyLu8j/gBkcwcaQOZh7Gyh/+uJQzGVETdgT30akuwkpL8HTRfssqI3BZuV18teDg==", + "dev": true, + "requires": { + "agent-base": "5", + "debug": "4" + } + }, + "mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "ws": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.2.tgz", + "integrity": "sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0" + } + } + } + }, + "qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dev": true, + "requires": { + "side-channel": "^1.0.4" + } + }, "query-string": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/query-string/-/query-string-7.1.3.tgz", @@ -12002,6 +35263,15 @@ "strict-uri-encode": "^2.0.0" } }, + "queue": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz", + "integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==", + "dev": true, + "requires": { + "inherits": "~2.0.3" + } + }, "queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -12028,6 +35298,12 @@ "resolved": "https://registry.npmjs.org/raf-schd/-/raf-schd-4.0.3.tgz", "integrity": "sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ==" }, + "ramda": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.28.0.tgz", + "integrity": "sha512-9QnLuG/kPVgWvMQ4aODhsBUFKOUmnbUnsSXACv+NCQZcHbeb+v8Lodp8OVxtRULN1/xOyYLLaL6npE6dMq5QTA==", + "dev": true + }, "randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -12036,6 +35312,24 @@ "safe-buffer": "^5.1.0" } }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true + }, + "raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "dev": true, + "requires": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, "rc": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", @@ -12139,6 +35433,44 @@ } } }, + "react-colorful": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/react-colorful/-/react-colorful-5.6.1.tgz", + "integrity": "sha512-1exovf0uGTGyq5mXQT0zgQ80uvj2PCwvF8zY1RN9/vbJVSjSo3fsB/4L3ObbF7u70NduSiK4xu4Y6q1MHoUGEw==", + "dev": true + }, + "react-docgen": { + "version": "5.4.3", + "resolved": "https://registry.npmjs.org/react-docgen/-/react-docgen-5.4.3.tgz", + "integrity": "sha512-xlLJyOlnfr8lLEEeaDZ+X2J/KJoe6Nr9AzxnkdQWush5hz2ZSu66w6iLMOScMmxoSHWpWMn+k3v5ZiyCfcWsOA==", + "dev": true, + "requires": { + "@babel/core": "^7.7.5", + "@babel/generator": "^7.12.11", + "@babel/runtime": "^7.7.6", + "ast-types": "^0.14.2", + "commander": "^2.19.0", + "doctrine": "^3.0.0", + "estree-to-babel": "^3.1.0", + "neo-async": "^2.6.1", + "node-dir": "^0.1.10", + "strip-indent": "^3.0.0" + }, + "dependencies": { + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + } + } + }, + "react-docgen-typescript": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/react-docgen-typescript/-/react-docgen-typescript-2.2.2.tgz", + "integrity": "sha512-tvg2ZtOpOi6QDwsb3GZhOjDkkX0h8Z2gipvTg6OVMUyoYoURhEiRNePT8NZItTVCDh39JJHnLdfCOkzoLbFnTg==", + "dev": true + }, "react-dom": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", @@ -12158,12 +35490,23 @@ "prop-types": "^15.8.1" } }, - "react-github-btn": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/react-github-btn/-/react-github-btn-1.4.0.tgz", - "integrity": "sha512-lV4FYClAfjWnBfv0iNlJUGhamDgIq6TayD0kPZED6VzHWdpcHmPfsYOZ/CFwLfPv4Zp+F4m8QKTj0oy2HjiGXg==", + "react-element-to-jsx-string": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/react-element-to-jsx-string/-/react-element-to-jsx-string-15.0.0.tgz", + "integrity": "sha512-UDg4lXB6BzlobN60P8fHWVPX3Kyw8ORrTeBtClmIlGdkOOE+GYQSFvmEU5iLLpwp/6v42DINwNcwOhOLfQ//FQ==", + "dev": true, "requires": { - "github-buttons": "^2.22.0" + "@base2/pretty-print-object": "1.0.1", + "is-plain-object": "5.0.0", + "react-is": "18.1.0" + }, + "dependencies": { + "react-is": { + "version": "18.1.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", + "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", + "dev": true + } } }, "react-grid-layout": { @@ -12178,6 +35521,21 @@ "react-resizable": "^3.0.4" } }, + "react-i18next": { + "version": "12.1.1", + "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-12.1.1.tgz", + "integrity": "sha512-mFdieOI0LDy84q3JuZU6Aou1DoWW2fhapcTGeBS8+vWSJuViuoCLQAMYSb0QoHhXS8B0WKUOPpx4cffAP7r/aA==", + "requires": { + "@babel/runtime": "^7.14.5", + "html-parse-stringify": "^3.0.1" + } + }, + "react-inspector": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/react-inspector/-/react-inspector-6.0.1.tgz", + "integrity": "sha512-cxKSeFTf7jpSSVddm66sKdolG90qURAX3g1roTeaN6x0YEbtWc8JpmFN9+yIqLNH2uEkYerWLtJZIXRIFuBKrg==", + "dev": true + }, "react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", @@ -12242,6 +35600,33 @@ } } }, + "react-refresh": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz", + "integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==", + "dev": true + }, + "react-remove-scroll": { + "version": "2.5.5", + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.5.5.tgz", + "integrity": "sha512-ImKhrzJJsyXJfBZ4bzu8Bwpka14c/fQt0k+cyFp/PBhTfyDnU5hjOtM4AG/0AMyy8oKzOTR0lDgJIM7pYXI0kw==", + "requires": { + "react-remove-scroll-bar": "^2.3.3", + "react-style-singleton": "^2.2.1", + "tslib": "^2.1.0", + "use-callback-ref": "^1.3.0", + "use-sidecar": "^1.1.2" + } + }, + "react-remove-scroll-bar": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.4.tgz", + "integrity": "sha512-63C4YQBUt0m6ALadE9XV56hV8BgJWDmmTPY758iIJjfQKt2nYwoUrPk0LXRXcB/yIj82T1/Ixfdpdk68LwIB0A==", + "requires": { + "react-style-singleton": "^2.2.1", + "tslib": "^2.0.0" + } + }, "react-resizable": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/react-resizable/-/react-resizable-3.0.4.tgz", @@ -12251,11 +35636,20 @@ "react-draggable": "^4.0.3" } }, + "react-style-singleton": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.1.tgz", + "integrity": "sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==", + "requires": { + "get-nonce": "^1.0.0", + "invariant": "^2.2.4", + "tslib": "^2.0.0" + } + }, "react-table": { "version": "7.8.0", "resolved": "https://registry.npmjs.org/react-table/-/react-table-7.8.0.tgz", - "integrity": "sha512-hNaz4ygkZO4bESeFfnfOft73iBUj8K5oKi1EcSHPAibEydfsX2MyU6Z8KCr3mv3C9Kqqh71U+DhZkFvibbnPbA==", - "requires": {} + "integrity": "sha512-hNaz4ygkZO4bESeFfnfOft73iBUj8K5oKi1EcSHPAibEydfsX2MyU6Z8KCr3mv3C9Kqqh71U+DhZkFvibbnPbA==" }, "read-cache": { "version": "1.0.0", @@ -12266,6 +35660,82 @@ "pify": "^2.3.0" } }, + "read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "dev": true, + "requires": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "dependencies": { + "type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true + } + } + }, + "read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "dev": true, + "requires": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + }, + "dependencies": { + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + } + } + }, "readable-stream": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", @@ -12285,6 +35755,45 @@ "picomatch": "^2.2.1" } }, + "recast": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/recast/-/recast-0.23.1.tgz", + "integrity": "sha512-RokaBcoxSjXUDzz1TXSZmZsSW6ZpLmlA3GGqJ8uuTrQ9hZhEz+4Tpsc+gRvYRJ2BU4H+ZyUlg91eSGDw7bwy7g==", + "dev": true, + "requires": { + "assert": "^2.0.0", + "ast-types": "^0.16.1", + "esprima": "~4.0.0", + "source-map": "~0.6.1", + "tslib": "^2.0.1" + }, + "dependencies": { + "ast-types": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.16.1.tgz", + "integrity": "sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==", + "dev": true, + "requires": { + "tslib": "^2.0.1" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", + "dev": true, + "requires": { + "resolve": "^1.1.6" + } + }, "redux": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.0.tgz", @@ -12296,14 +35805,89 @@ "redux-thunk": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.1.tgz", - "integrity": "sha512-OOYGNY5Jy2TWvTL1KgAlVy6dcx3siPJ1wTq741EPyUKfn6W6nChdICjZwCd0p8AZBs5kWpZlbkXW2nE/zjUa+Q==", - "requires": {} + "integrity": "sha512-OOYGNY5Jy2TWvTL1KgAlVy6dcx3siPJ1wTq741EPyUKfn6W6nChdICjZwCd0p8AZBs5kWpZlbkXW2nE/zjUa+Q==" + }, + "regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true + }, + "regenerate-unicode-properties": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz", + "integrity": "sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==", + "dev": true, + "requires": { + "regenerate": "^1.4.2" + } }, "regenerator-runtime": { "version": "0.13.11", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" }, + "regenerator-transform": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.1.tgz", + "integrity": "sha512-knzmNAcuyxV+gQCufkYcvOqX/qIIfHLv0u5x79kRxuGojfYVky1f15TzZEu2Avte8QGepvUNTnLskf8E6X6Vyg==", + "dev": true, + "requires": { + "@babel/runtime": "^7.8.4" + } + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true + } + } + }, + "regex-parser": { + "version": "2.2.11", + "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.2.11.tgz", + "integrity": "sha512-jbD/FT0+9MBU2XAZluI7w2OBs1RBi6p9M83nkoZayQXXU9e8Robt69FcZc7wU4eJD/YFTjn1JdCk3rbMJajz8Q==", + "dev": true + }, "regexp.prototype.flags": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", @@ -12321,6 +35905,106 @@ "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", "dev": true }, + "regexpu-core": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.2.2.tgz", + "integrity": "sha512-T0+1Zp2wjF/juXMrMxHxidqGYn8U4R+zleSJhX9tQ1PUsS8a9UtYfbsF9LdiVgNX3kiX8RNaKM42nfSgvFJjmw==", + "dev": true, + "requires": { + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsgen": "^0.7.1", + "regjsparser": "^0.9.1", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + } + }, + "regjsgen": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.7.1.tgz", + "integrity": "sha512-RAt+8H2ZEzHeYWxZ3H2z6tF18zyyOnlcdaafLrm21Bguj7uZy6ULibiAFdXEtKQY4Sy7wDTwDiOazasMLc4KPA==", + "dev": true + }, + "regjsparser": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "dev": true, + "requires": { + "jsesc": "~0.5.0" + }, + "dependencies": { + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "dev": true + } + } + }, + "relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", + "dev": true + }, + "remark-external-links": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/remark-external-links/-/remark-external-links-8.0.0.tgz", + "integrity": "sha512-5vPSX0kHoSsqtdftSHhIYofVINC8qmp0nctkeU9YoJwV3YfiBRiI6cbFRJ0oI/1F9xS+bopXG0m2KS8VFscuKA==", + "dev": true, + "requires": { + "extend": "^3.0.0", + "is-absolute-url": "^3.0.0", + "mdast-util-definitions": "^4.0.0", + "space-separated-tokens": "^1.0.0", + "unist-util-visit": "^2.0.0" + }, + "dependencies": { + "mdast-util-definitions": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-4.0.0.tgz", + "integrity": "sha512-k8AJ6aNnUkB7IE+5azR9h81O5EQ/cTDXtWdMq9Kk5KcEW/8ritU5CeLg/9HhOC++nALHBlaogJ5jz0Ybk3kPMQ==", + "dev": true, + "requires": { + "unist-util-visit": "^2.0.0" + } + }, + "space-separated-tokens": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz", + "integrity": "sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==", + "dev": true + }, + "unist-util-is": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-4.1.0.tgz", + "integrity": "sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==", + "dev": true + }, + "unist-util-visit": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-2.0.3.tgz", + "integrity": "sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q==", + "dev": true, + "requires": { + "@types/unist": "^2.0.0", + "unist-util-is": "^4.0.0", + "unist-util-visit-parents": "^3.0.0" + } + }, + "unist-util-visit-parents": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-3.1.1.tgz", + "integrity": "sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg==", + "dev": true, + "requires": { + "@types/unist": "^2.0.0", + "unist-util-is": "^4.0.0" + } + } + } + }, "remark-parse": { "version": "10.0.1", "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-10.0.1.tgz", @@ -12342,6 +36026,95 @@ "unified": "^10.0.0" } }, + "remark-slug": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/remark-slug/-/remark-slug-6.1.0.tgz", + "integrity": "sha512-oGCxDF9deA8phWvxFuyr3oSJsdyUAxMFbA0mZ7Y1Sas+emILtO+e5WutF9564gDsEN4IXaQXm5pFo6MLH+YmwQ==", + "dev": true, + "requires": { + "github-slugger": "^1.0.0", + "mdast-util-to-string": "^1.0.0", + "unist-util-visit": "^2.0.0" + }, + "dependencies": { + "mdast-util-to-string": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-1.1.0.tgz", + "integrity": "sha512-jVU0Nr2B9X3MU4tSK7JP1CMkSvOj7X5l/GboG1tKRw52lLF1x2Ju92Ms9tNetCcbfX3hzlM73zYo2NKkWSfF/A==", + "dev": true + }, + "unist-util-is": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-4.1.0.tgz", + "integrity": "sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==", + "dev": true + }, + "unist-util-visit": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-2.0.3.tgz", + "integrity": "sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q==", + "dev": true, + "requires": { + "@types/unist": "^2.0.0", + "unist-util-is": "^4.0.0", + "unist-util-visit-parents": "^3.0.0" + } + }, + "unist-util-visit-parents": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-3.1.1.tgz", + "integrity": "sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg==", + "dev": true, + "requires": { + "@types/unist": "^2.0.0", + "unist-util-is": "^4.0.0" + } + } + } + }, + "renderkid": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", + "integrity": "sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==", + "dev": true, + "requires": { + "css-select": "^4.1.3", + "dom-converter": "^0.2.0", + "htmlparser2": "^6.1.0", + "lodash": "^4.17.21", + "strip-ansi": "^6.0.1" + } + }, + "repeat-element": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", + "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==", + "dev": true + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", + "dev": true + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true + }, + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true + }, + "requireindex": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/requireindex/-/requireindex-1.2.0.tgz", + "integrity": "sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww==", + "dev": true + }, "requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", @@ -12367,6 +36140,50 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==", + "dev": true + }, + "resolve-url-loader": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-5.0.0.tgz", + "integrity": "sha512-uZtduh8/8srhBoMx//5bwqjQ+rfYOUq8zC9NrMUGtjBiGTtFJM42s58/36+hTqeqINcnYe08Nj3LkK9lW4N8Xg==", + "dev": true, + "requires": { + "adjust-sourcemap-loader": "^4.0.0", + "convert-source-map": "^1.7.0", + "loader-utils": "^2.0.0", + "postcss": "^8.2.14", + "source-map": "0.6.1" + }, + "dependencies": { + "loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "dev": true + }, "reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", @@ -12424,6 +36241,15 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==", + "dev": true, + "requires": { + "ret": "~0.1.10" + } + }, "safe-regex-test": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", @@ -12435,6 +36261,22 @@ "is-regex": "^1.1.4" } }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "sass-loader": { + "version": "12.6.0", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-12.6.0.tgz", + "integrity": "sha512-oLTaH0YCtX4cfnJZxKSLAyglED0naiYfNG1iXfU5w1LNZ+ukoA5DtyDIN5zmKVZwYNJP4KRc5Y3hkWga+7tYfA==", + "dev": true, + "requires": { + "klona": "^2.0.4", + "neo-async": "^2.6.2" + } + }, "scheduler": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", @@ -12444,6 +36286,17 @@ "object-assign": "^4.1.1" } }, + "schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + }, "section-matter": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz", @@ -12461,11 +36314,129 @@ "lru-cache": "^6.0.0" } }, + "send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dev": true, + "requires": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "dependencies": { + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + } + } + }, + "serialize-javascript": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", + "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, + "serve-favicon": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/serve-favicon/-/serve-favicon-2.5.0.tgz", + "integrity": "sha512-FMW2RvqNr03x+C0WxTyu6sOv21oOjkq5j8tjquWccwa6ScNyGFOGJVpuS1NmTVGBAHS07xnSKotgf2ehQmf9iA==", + "dev": true, + "requires": { + "etag": "~1.8.1", + "fresh": "0.5.2", + "ms": "2.1.1", + "parseurl": "~1.3.2", + "safe-buffer": "5.1.1" + }, + "dependencies": { + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", + "dev": true + } + } + }, + "serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dev": true, + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + } + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "dev": true + }, "set-cookie-parser": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.5.1.tgz", "integrity": "sha512-1jeBGaKNGdEq4FgIrORu/N570dwoPYio8lSoYLWmX7sQ//0JY08Xh9o5pBcgmHQ/MbsYp/aZnOe1s1lIsbLprQ==" }, + "set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "dependencies": { + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true + } + } + }, + "setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true + }, "sha.js": { "version": "2.4.11", "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", @@ -12475,6 +36446,15 @@ "safe-buffer": "^5.0.1" } }, + "shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "requires": { + "kind-of": "^6.0.2" + } + }, "shallowequal": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", @@ -12510,6 +36490,17 @@ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true }, + "shelljs": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", + "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", + "dev": true, + "requires": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + } + }, "side-channel": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", @@ -12521,6 +36512,12 @@ "object-inspect": "^1.9.0" } }, + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, "simple-concat": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", @@ -12544,12 +36541,179 @@ "is-arrayish": "^0.3.1" } }, + "simple-update-notifier": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz", + "integrity": "sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==", + "dev": true, + "requires": { + "semver": "~7.0.0" + }, + "dependencies": { + "semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", + "dev": true + } + } + }, + "sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true + }, "slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "dev": true, + "requires": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + } + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "dev": true, + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "dev": true, + "requires": { + "kind-of": "^3.2.0" + }, + "dependencies": { + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", @@ -12560,16 +36724,136 @@ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==" }, + "source-map-resolve": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", + "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "dev": true, + "requires": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + }, + "dependencies": { + "buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "source-map-url": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", + "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", + "dev": true + }, "space-separated-tokens": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.1.tgz", "integrity": "sha512-ekwEbFp5aqSPKaqeY1PGrlGQxPNaq+Cnx4+bE2D8sciBQrHpbwoBbawqTN2+6jPs9IdWxxiUcN0K2pkczD3zmw==" }, + "spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "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==", + "dev": true + }, "split-on-first": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz", "integrity": "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==" }, + "split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.0" + }, + "dependencies": { + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true + } + } + }, "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -12581,6 +36865,284 @@ "integrity": "sha512-EeNzTVfj+1In7aSLPKDD03F/ly4RxEuF/EX0YcOG0cKoPXs+SLZxDawQbexQDBzwROs4VKLWTOaZQlZkGBFEIQ==", "optional": true }, + "stackframe": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz", + "integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==", + "dev": true + }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==", + "dev": true, + "requires": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + } + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true + }, + "stop-iteration-iterator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", + "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==", + "dev": true, + "requires": { + "internal-slot": "^1.0.4" + } + }, + "store2": { + "version": "2.14.2", + "resolved": "https://registry.npmjs.org/store2/-/store2-2.14.2.tgz", + "integrity": "sha512-siT1RiqlfQnGqgT/YzXVUNsom9S0H1OX+dpdGN1xkyYATo4I6sep5NmsRD/40s3IIOvlCq6akxkqG82urIZW1w==", + "dev": true + }, + "storybook": { + "version": "7.0.0-beta.30", + "resolved": "https://registry.npmjs.org/storybook/-/storybook-7.0.0-beta.30.tgz", + "integrity": "sha512-hfOtpvNnQ/rXLfojznCs2WdOFbojKx0Gf1W1Ra6DzOBrmUdXzWwRL8X1RUkI6jwUfYuaE97D8gQpfNRlvoqv4A==", + "dev": true, + "requires": { + "@storybook/cli": "7.0.0-beta.30" + } + }, + "storybook-dark-mode": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/storybook-dark-mode/-/storybook-dark-mode-2.0.5.tgz", + "integrity": "sha512-egOMu2tgGttGAMtFZcDLZobs1xc7LzFOh+pRVqaW59AVp05ABdQ3Hj6IX2Pz7tYGmF9AmaK+nBv0hDFxPe7Hfg==", + "dev": true, + "requires": { + "@storybook/addons": "^6.5.14", + "@storybook/api": "^6.5.14", + "@storybook/components": "^6.5.14", + "@storybook/core-events": "^6.5.14", + "@storybook/theming": "^6.5.14", + "fast-deep-equal": "^3.1.3", + "global": "^4.4.0", + "memoizerific": "^1.11.3" + }, + "dependencies": { + "@storybook/addons": { + "version": "6.5.15", + "resolved": "https://registry.npmjs.org/@storybook/addons/-/addons-6.5.15.tgz", + "integrity": "sha512-xT31SuSX+kYGyxCNK2nqL7WTxucs3rSmhiCLovJcUjYk+QquV3c2c53Ki7lwwdDbzfXFcNAe0HJ4hoTN4jhn0Q==", + "dev": true, + "requires": { + "@storybook/api": "6.5.15", + "@storybook/channels": "6.5.15", + "@storybook/client-logger": "6.5.15", + "@storybook/core-events": "6.5.15", + "@storybook/csf": "0.0.2--canary.4566f4d.1", + "@storybook/router": "6.5.15", + "@storybook/theming": "6.5.15", + "@types/webpack-env": "^1.16.0", + "core-js": "^3.8.2", + "global": "^4.4.0", + "regenerator-runtime": "^0.13.7" + } + }, + "@storybook/api": { + "version": "6.5.15", + "resolved": "https://registry.npmjs.org/@storybook/api/-/api-6.5.15.tgz", + "integrity": "sha512-BBE0KXKvj1/3jTghbIoWfrcDM0t+xO7EYtWWAXD6XlhGsZVD2Dy82Z52ONyLulMDRpMWl0OYy3h6A1YnFUH25w==", + "dev": true, + "requires": { + "@storybook/channels": "6.5.15", + "@storybook/client-logger": "6.5.15", + "@storybook/core-events": "6.5.15", + "@storybook/csf": "0.0.2--canary.4566f4d.1", + "@storybook/router": "6.5.15", + "@storybook/semver": "^7.3.2", + "@storybook/theming": "6.5.15", + "core-js": "^3.8.2", + "fast-deep-equal": "^3.1.3", + "global": "^4.4.0", + "lodash": "^4.17.21", + "memoizerific": "^1.11.3", + "regenerator-runtime": "^0.13.7", + "store2": "^2.12.0", + "telejson": "^6.0.8", + "ts-dedent": "^2.0.0", + "util-deprecate": "^1.0.2" + } + }, + "@storybook/channels": { + "version": "6.5.15", + "resolved": "https://registry.npmjs.org/@storybook/channels/-/channels-6.5.15.tgz", + "integrity": "sha512-gPpsBgirv2NCXbH4WbYqdkI0JLE96aiVuu7UEWfn9yu071pQ9CLHbhXGD9fSFNrfOkyBBY10ppSE7uCXw3Wexg==", + "dev": true, + "requires": { + "core-js": "^3.8.2", + "ts-dedent": "^2.0.0", + "util-deprecate": "^1.0.2" + } + }, + "@storybook/client-logger": { + "version": "6.5.15", + "resolved": "https://registry.npmjs.org/@storybook/client-logger/-/client-logger-6.5.15.tgz", + "integrity": "sha512-0uyxKvodq+FycGv6aUwC1wUR6suXf2+7ywMFAOlYolI4UvNj8NyU/5AfgKT5XnxYAgPmoCiAjOE700TrfHrosw==", + "dev": true, + "requires": { + "core-js": "^3.8.2", + "global": "^4.4.0" + } + }, + "@storybook/components": { + "version": "6.5.15", + "resolved": "https://registry.npmjs.org/@storybook/components/-/components-6.5.15.tgz", + "integrity": "sha512-bHTT0Oa3s4g+MBMaLBbX9ofMtb1AW59AzIUNGrfqW1XqJMGuUHMiJ7TSo+i5dRSFpbFygnwMEG9LfHxpR2Z0Dw==", + "dev": true, + "requires": { + "@storybook/client-logger": "6.5.15", + "@storybook/csf": "0.0.2--canary.4566f4d.1", + "@storybook/theming": "6.5.15", + "core-js": "^3.8.2", + "memoizerific": "^1.11.3", + "qs": "^6.10.0", + "regenerator-runtime": "^0.13.7", + "util-deprecate": "^1.0.2" + } + }, + "@storybook/core-events": { + "version": "6.5.15", + "resolved": "https://registry.npmjs.org/@storybook/core-events/-/core-events-6.5.15.tgz", + "integrity": "sha512-B1Ba6l5W7MeNclclqMMTMHgYgfdpB5SIhNCQFnzIz8blynzRhNFMdxvbAl6Je5G0S4xydYYd7Lno2kXQebs7HA==", + "dev": true, + "requires": { + "core-js": "^3.8.2" + } + }, + "@storybook/csf": { + "version": "0.0.2--canary.4566f4d.1", + "resolved": "https://registry.npmjs.org/@storybook/csf/-/csf-0.0.2--canary.4566f4d.1.tgz", + "integrity": "sha512-9OVvMVh3t9znYZwb0Svf/YQoxX2gVOeQTGe2bses2yj+a3+OJnCrUF3/hGv6Em7KujtOdL2LL+JnG49oMVGFgQ==", + "dev": true, + "requires": { + "lodash": "^4.17.15" + } + }, + "@storybook/router": { + "version": "6.5.15", + "resolved": "https://registry.npmjs.org/@storybook/router/-/router-6.5.15.tgz", + "integrity": "sha512-9t8rI8t7/Krolau29gsdjdbRQ66orONIyP0efp0EukVgv6reNFzb/U14ARrl0uHys6Tl5Xyece9FoakQUdn8Kg==", + "dev": true, + "requires": { + "@storybook/client-logger": "6.5.15", + "core-js": "^3.8.2", + "memoizerific": "^1.11.3", + "qs": "^6.10.0", + "regenerator-runtime": "^0.13.7" + } + }, + "@storybook/theming": { + "version": "6.5.15", + "resolved": "https://registry.npmjs.org/@storybook/theming/-/theming-6.5.15.tgz", + "integrity": "sha512-pgdW0lVZKKXQ4VhIfLHycMmwFSVOY7vLTKnytag4Y8Yz+aXm0bwDN/QxPntFzDH47F1Rcy2ywNnvty8ooDTvuA==", + "dev": true, + "requires": { + "@storybook/client-logger": "6.5.15", + "core-js": "^3.8.2", + "memoizerific": "^1.11.3", + "regenerator-runtime": "^0.13.7" + } + }, + "telejson": { + "version": "6.0.8", + "resolved": "https://registry.npmjs.org/telejson/-/telejson-6.0.8.tgz", + "integrity": "sha512-nerNXi+j8NK1QEfBHtZUN/aLdDcyupA//9kAboYLrtzZlPLpUfqbVGWb9zz91f/mIjRbAYhbgtnJHY8I1b5MBg==", + "dev": true, + "requires": { + "@types/is-function": "^1.0.0", + "global": "^4.4.0", + "is-function": "^1.0.2", + "is-regex": "^1.1.2", + "is-symbol": "^1.0.3", + "isobject": "^4.0.0", + "lodash": "^4.17.21", + "memoizerific": "^1.11.3" + } + } + } + }, "strict-uri-encode": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz", @@ -12594,6 +37156,25 @@ "safe-buffer": "~5.2.0" } }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "dependencies": { + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + } + } + }, "string.prototype.matchall": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.8.tgz", @@ -12652,12 +37233,33 @@ "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz", "integrity": "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==" }, + "strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true + }, + "strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "requires": { + "min-indent": "^1.0.0" + } + }, "strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true }, + "style-loader": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.1.tgz", + "integrity": "sha512-GPcQ+LDJbrcxHORTRes6Jy2sfvK2kS6hpSfI/fXhPt+spVzxF6LJ1dHLN9zIGmVaaP044YKaIatFaufENRiDoQ==", + "dev": true + }, "style-to-object": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-0.3.0.tgz", @@ -12686,8 +37288,7 @@ "styled-jsx": { "version": "5.0.7", "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.0.7.tgz", - "integrity": "sha512-b3sUzamS086YLRuvnaDigdAewz1/EFYlHpYBP5mZovKEdQQOIIYq8lApylub3HHZ6xFjV051kkGU7cudJmrXEA==", - "requires": {} + "integrity": "sha512-b3sUzamS086YLRuvnaDigdAewz1/EFYlHpYBP5mZovKEdQQOIIYq8lApylub3HHZ6xFjV051kkGU7cudJmrXEA==" }, "stylis": { "version": "4.0.13", @@ -12713,6 +37314,12 @@ "integrity": "sha512-qsjeeq5YjBZ5eMdFuUa4ZosMLxgr5RZ+F+Y1OrDhuOCEInRMA3x74XdBtggJcj9kOeInz0WE+LgCPDkZFlBYJw==", "optional": true }, + "synchronous-promise": { + "version": "2.0.16", + "resolved": "https://registry.npmjs.org/synchronous-promise/-/synchronous-promise-2.0.16.tgz", + "integrity": "sha512-qImOD23aDfnIDNqlG1NOehdB9IYsn1V9oByPjKY1nakv2MQYCEMyX033/q+aEtYCpmYK1cv2+NTmlH+ra6GA5A==", + "dev": true + }, "synckit": { "version": "0.8.4", "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.4.tgz", @@ -12723,10 +37330,15 @@ "tslib": "^2.4.0" } }, + "tailwind-merge": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-1.8.1.tgz", + "integrity": "sha512-+fflfPxvHFr81hTJpQ3MIwtqgvefHZFUHFiIHpVIRXvG/nX9+gu2P7JNlFu2bfDMJ+uHhi/pUgzaYacMoXv+Ww==" + }, "tailwindcss": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.1.7.tgz", - "integrity": "sha512-r7mgumZ3k0InfVPpGWcX8X/Ut4xBfv+1O/+C73ar/m01LxGVzWvPxF/w6xIUPEztrCoz7axfx0SMdh8FH8ZvRQ==", + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.2.4.tgz", + "integrity": "sha512-AhwtHCKMtR71JgeYDaswmZXhPcW9iuI9Sp2LvZPo9upDZ7231ZJ7eA9RaURbhpXGVlrjX4cFNlB4ieTetEb7hQ==", "dev": true, "requires": { "arg": "^5.0.2", @@ -12735,22 +37347,36 @@ "detective": "^5.2.1", "didyoumean": "^1.2.2", "dlv": "^1.1.3", - "fast-glob": "^3.2.11", + "fast-glob": "^3.2.12", "glob-parent": "^6.0.2", "is-glob": "^4.0.3", "lilconfig": "^2.0.6", + "micromatch": "^4.0.5", "normalize-path": "^3.0.0", "object-hash": "^3.0.0", "picocolors": "^1.0.0", - "postcss": "^8.4.14", + "postcss": "^8.4.18", "postcss-import": "^14.1.0", "postcss-js": "^4.0.0", "postcss-load-config": "^3.1.4", - "postcss-nested": "5.0.6", + "postcss-nested": "6.0.0", "postcss-selector-parser": "^6.0.10", "postcss-value-parser": "^4.2.0", "quick-lru": "^5.1.1", "resolve": "^1.22.1" + }, + "dependencies": { + "postcss": { + "version": "8.4.21", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz", + "integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==", + "dev": true, + "requires": { + "nanoid": "^3.3.4", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + } + } } }, "tapable": { @@ -12759,6 +37385,34 @@ "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", "dev": true }, + "tar": { + "version": "6.1.13", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.13.tgz", + "integrity": "sha512-jdIBIN6LTIe2jqzay/2vtYLlBHa3JF42ot3h1dW8Q0PaAG4v8rm0cvpVePtau5C6OKXGGcgO9q2AMNSWxiLqKw==", + "dev": true, + "requires": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^4.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "dependencies": { + "chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true + } + } + }, "tar-fs": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", @@ -12782,6 +37436,140 @@ "readable-stream": "^3.1.1" } }, + "telejson": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/telejson/-/telejson-7.0.4.tgz", + "integrity": "sha512-J4QEuCnYGXAI9KSN7RXK0a0cOW2ONpjc4IQbInGZ6c3stvplLAYyZjTnScrRd8deXVjNCFV1wXcLC7SObDuQYA==", + "dev": true, + "requires": { + "memoizerific": "^1.11.3" + } + }, + "temp": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/temp/-/temp-0.8.4.tgz", + "integrity": "sha512-s0ZZzd0BzYv5tLSptZooSjK8oj6C+c19p7Vqta9+6NPOf7r+fxq0cJe6/oN4LTC79sy5NY8ucOJNgwsKCSbfqg==", + "dev": true, + "requires": { + "rimraf": "~2.6.2" + }, + "dependencies": { + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + } + } + }, + "temp-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz", + "integrity": "sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==", + "dev": true + }, + "tempy": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tempy/-/tempy-1.0.1.tgz", + "integrity": "sha512-biM9brNqxSc04Ee71hzFbryD11nX7VPhQQY32AdDmjFvodsRFz/3ufeoTZ6uYkRFfGo188tENcASNs3vTdsM0w==", + "dev": true, + "requires": { + "del": "^6.0.0", + "is-stream": "^2.0.0", + "temp-dir": "^2.0.0", + "type-fest": "^0.16.0", + "unique-string": "^2.0.0" + }, + "dependencies": { + "type-fest": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.16.0.tgz", + "integrity": "sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==", + "dev": true + } + } + }, + "terser": { + "version": "5.16.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.16.1.tgz", + "integrity": "sha512-xvQfyfA1ayT0qdK47zskQgRZeWLoOQ8JQ6mIgRGVNwZKdQMU+5FkCBjmv4QjcrTzyZquRw2FVtlJSRUmMKQslw==", + "dev": true, + "requires": { + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "dependencies": { + "acorn": { + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", + "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", + "dev": true + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + } + } + }, + "terser-webpack-plugin": { + "version": "5.3.6", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.6.tgz", + "integrity": "sha512-kfLFk+PoLUQIbLmB1+PZDMRSZS99Mp+/MHqDNmMA6tOItzRt+Npe3E+fsMs5mfcM0wCtrrdU387UnV+vnSffXQ==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "^0.3.14", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.0", + "terser": "^5.14.1" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + } + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "requires": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + } + }, "text-segmentation": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz", @@ -12857,16 +37645,96 @@ "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.2.0.tgz", "integrity": "sha512-1Uhn/aqw5C6RI4KejVeTg6mIS7IqxnLJ8Mv2tV5rTc0qWobay7pDUz6Wi392Cnc8ak1H0F2cjoRzb2/AW4+Fvg==" }, + "tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true + }, "to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==" }, + "to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, "to-querystring": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/to-querystring/-/to-querystring-1.1.1.tgz", "integrity": "sha512-ZgIacl9TXAoT7sGXUYjQiy0MW7Tf/7CJQLt757hYHfXXc8JBzOVBMx4DckqKUO4hi36J72/m8UcH/GCHK+n97g==" }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dev": true, + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true + } + } + }, "to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -12876,6 +37744,18 @@ "is-number": "^7.0.0" } }, + "toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true + }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true + }, "trim-lines": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", @@ -12886,6 +37766,18 @@ "resolved": "https://registry.npmjs.org/trough/-/trough-2.1.0.tgz", "integrity": "sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==" }, + "ts-dedent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ts-dedent/-/ts-dedent-2.2.0.tgz", + "integrity": "sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==", + "dev": true + }, + "ts-pnp": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/ts-pnp/-/ts-pnp-1.2.0.tgz", + "integrity": "sha512-csd+vJOb/gkzvcCHgTGSChYpy5f1/XKNsmvBGO4JXS+z1v2HobugDz4s1IeFXM3wZB44uczs+eazB5Q/ccdhQw==", + "dev": true + }, "tsconfig-paths": { "version": "3.14.1", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", @@ -12899,9 +37791,9 @@ }, "dependencies": { "json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, "requires": { "minimist": "^1.2.0" @@ -12909,6 +37801,53 @@ } } }, + "tsconfig-paths-webpack-plugin": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/tsconfig-paths-webpack-plugin/-/tsconfig-paths-webpack-plugin-3.5.2.tgz", + "integrity": "sha512-EhnfjHbzm5IYI9YPNVIxx1moxMI4bpHD2e0zTXeDNQcwjjRaGepP7IhTHJkyDBG0CAOoxRfe7jCG630Ou+C6Pw==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "enhanced-resolve": "^5.7.0", + "tsconfig-paths": "^3.9.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, "tslib": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", @@ -12969,6 +37908,22 @@ "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", + "dev": true + }, "typescript": { "version": "4.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.3.tgz", @@ -12980,6 +37935,13 @@ "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==" }, + "uglify-js": { + "version": "3.17.4", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", + "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", + "dev": true, + "optional": true + }, "unbox-primitive": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", @@ -12992,6 +37954,40 @@ "which-boxed-primitive": "^1.0.2" } }, + "unfetch": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/unfetch/-/unfetch-4.2.0.tgz", + "integrity": "sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA==", + "dev": true + }, + "unicode-canonical-property-names-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", + "dev": true + }, + "unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dev": true, + "requires": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + } + }, + "unicode-match-property-value-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", + "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", + "dev": true + }, + "unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "dev": true + }, "unified": { "version": "10.1.2", "resolved": "https://registry.npmjs.org/unified/-/unified-10.1.2.tgz", @@ -13006,6 +38002,27 @@ "vfile": "^5.0.0" } }, + "union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + } + }, + "unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "dev": true, + "requires": { + "crypto-random-string": "^2.0.0" + } + }, "unist-builder": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/unist-builder/-/unist-builder-3.0.0.tgz", @@ -13059,10 +38076,95 @@ "unist-util-is": "^5.0.0" } }, + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true + }, + "unplugin": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-0.10.2.tgz", + "integrity": "sha512-6rk7GUa4ICYjae5PrAllvcDeuT8pA9+j5J5EkxbMFaV+SalHhxZ7X2dohMzu6C3XzsMT+6jwR/+pwPNR3uK9MA==", + "dev": true, + "requires": { + "acorn": "^8.8.0", + "chokidar": "^3.5.3", + "webpack-sources": "^3.2.3", + "webpack-virtual-modules": "^0.4.5" + }, + "dependencies": { + "acorn": { + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", + "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", + "dev": true + } + } + }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==", + "dev": true, + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==", + "dev": true, + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==", + "dev": true, + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ==", + "dev": true + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true + } + } + }, + "untildify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", + "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", + "dev": true + }, "update-browserslist-db": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.5.tgz", - "integrity": "sha512-dteFFpCyvuDdr9S/ff1ISkKt/9YZxKjI9WlRR99c180GaztJtRa/fn18FdxGVKVsnPY7/a/FDN68mcvUmP4U7Q==", + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", + "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", + "dev": true, "requires": { "escalade": "^3.1.1", "picocolors": "^1.0.0" @@ -13077,23 +38179,80 @@ "punycode": "^2.1.0" } }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==", + "dev": true + }, + "use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "dev": true + }, + "use-callback-ref": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.0.tgz", + "integrity": "sha512-3FT9PRuRdbB9HfXhEq35u4oZkvpJ5kuYbpqhCfmiZyReuRgpnhDlbr2ZEnnuS0RrJAPn6l23xjFg9kpDM+Ms7w==", + "requires": { + "tslib": "^2.0.0" + } + }, + "use-isomorphic-layout-effect": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz", + "integrity": "sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==" + }, "use-memo-one": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/use-memo-one/-/use-memo-one-1.1.3.tgz", - "integrity": "sha512-g66/K7ZQGYrI6dy8GLpVcMsBp4s17xNkYJVSMvTEevGy3nDxHOfE6z8BVE22+5G5x7t3+bhzrlTDB7ObrEE0cQ==", - "requires": {} + "integrity": "sha512-g66/K7ZQGYrI6dy8GLpVcMsBp4s17xNkYJVSMvTEevGy3nDxHOfE6z8BVE22+5G5x7t3+bhzrlTDB7ObrEE0cQ==" + }, + "use-sidecar": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.2.tgz", + "integrity": "sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw==", + "requires": { + "detect-node-es": "^1.1.0", + "tslib": "^2.0.0" + } }, "use-sync-external-store": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", - "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", - "requires": {} + "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==" + }, + "util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, + "utila": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "integrity": "sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==", + "dev": true + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "dev": true + }, "utrie": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz", @@ -13108,6 +38267,12 @@ "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" }, + "uuid-browser": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/uuid-browser/-/uuid-browser-3.1.0.tgz", + "integrity": "sha512-dsNgbLaTrd6l3MMxTtouOCFw4CBFc/3a+GgYA2YyrJvyQ1u6q4pcu3ktLoUZ/VN/Aw9WsauazbgsgdfVWgAKQg==", + "dev": true + }, "uuidv4": { "version": "6.2.13", "resolved": "https://registry.npmjs.org/uuidv4/-/uuidv4-6.2.13.tgz", @@ -13128,6 +38293,33 @@ "sade": "^1.7.3" } }, + "v8-to-istanbul": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz", + "integrity": "sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^1.6.0" + } + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "dev": true + }, "vfile": { "version": "5.3.5", "resolved": "https://registry.npmjs.org/vfile/-/vfile-5.3.5.tgz", @@ -13148,6 +38340,185 @@ "unist-util-stringify-position": "^3.0.0" } }, + "void-elements": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", + "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==" + }, + "walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "requires": { + "makeerror": "1.0.12" + } + }, + "watchpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "dev": true, + "requires": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + } + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true + }, + "webpack": { + "version": "5.75.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.75.0.tgz", + "integrity": "sha512-piaIaoVJlqMsPtX/+3KTTO6jfvrSYgauFVdt8cr9LTHKmcq/AMd4mhzsiP7ZF/PGRNPGA8336jldh9l2Kt2ogQ==", + "dev": true, + "requires": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^0.0.51", + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/wasm-edit": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.7.6", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.10.0", + "es-module-lexer": "^0.9.0", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.1.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.1.3", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + }, + "dependencies": { + "acorn": { + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", + "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", + "dev": true + }, + "acorn-import-assertions": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", + "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", + "dev": true + }, + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + } + } + }, + "webpack-dev-middleware": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz", + "integrity": "sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA==", + "dev": true, + "requires": { + "colorette": "^2.0.10", + "memfs": "^3.4.3", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "dependencies": { + "ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.3" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + } + } + } + }, + "webpack-hot-middleware": { + "version": "2.25.3", + "resolved": "https://registry.npmjs.org/webpack-hot-middleware/-/webpack-hot-middleware-2.25.3.tgz", + "integrity": "sha512-IK/0WAHs7MTu1tzLTjio73LjS3Ov+VvBKQmE8WPlJutgG5zT6Urgq/BbAdRrHTRpyzK0dvAvFh1Qg98akxgZpA==", + "dev": true, + "requires": { + "ansi-html-community": "0.0.8", + "html-entities": "^2.1.0", + "strip-ansi": "^6.0.0" + } + }, + "webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true + }, + "webpack-virtual-modules": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.4.6.tgz", + "integrity": "sha512-5tyDlKLqPfMqjT3Q9TAqf2YqjwmnUleZwzJi1A5qXnlBCdj2AtOJ6wAWdglTIDOPgOiOrXeBeFcsQ8+aGQ6QbA==", + "dev": true + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -13170,32 +38541,157 @@ "is-symbol": "^1.0.3" } }, + "which-collection": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", + "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", + "dev": true, + "requires": { + "is-map": "^2.0.1", + "is-set": "^2.0.1", + "is-weakmap": "^2.0.1", + "is-weakset": "^2.0.1" + } + }, + "which-typed-array": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", + "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", + "dev": true, + "requires": { + "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" + } + }, + "wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "dev": true, + "requires": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "widest-line": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", + "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", + "dev": true, + "requires": { + "string-width": "^4.0.0" + } + }, "word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", "dev": true }, + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + } + } + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, + "write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + } + }, + "ws": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.12.0.tgz", + "integrity": "sha512-kU62emKIdKVeEIOIKVegvqpXMSTAMLJozpHZaJNDYqBjzlSYXQGviYwN1osDLJ9av68qHd4a2oSjd7yD4pacig==", + "dev": true + }, "xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", "dev": true }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true + }, "yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==" + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.2.1.tgz", + "integrity": "sha512-e0WHiYql7+9wr4cWMx3TVQrNwejKaEe7/rHNmQmqRjazfOP5W8PB6Jpebb5o6fIapbz9o9+2ipcaTM2ZwDI6lw==" + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } + }, + "yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true + }, + "yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "dev": true, + "requires": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } }, "yocto-queue": { "version": "0.1.0", diff --git a/frontend/package.json b/frontend/package.json index 7f7926c88..f97edd68f 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,44 +1,64 @@ { "private": true, "scripts": { + "prepare": "cd .. && npm install", "dev": "next dev", "build": "next build", "start": "next start", "start:docker": "next build && next start", - "lint": "next lint" + "lint": "eslint --fix --ext js,ts,tsx ./src", + "type-check": "tsc --project tsconfig.json", + "storybook": "storybook dev -p 6006 -s ./public", + "build-storybook": "storybook build" }, "dependencies": { "@emotion/css": "^11.10.0", "@emotion/server": "^11.10.0", + "@fontsource/inter": "^4.5.15", "@fortawesome/fontawesome-svg-core": "^6.1.2", "@fortawesome/free-brands-svg-icons": "^6.1.2", "@fortawesome/free-regular-svg-icons": "^6.1.1", "@fortawesome/free-solid-svg-icons": "^6.1.2", "@fortawesome/react-fontawesome": "^0.1.19", "@headlessui/react": "^1.6.6", + "@radix-ui/react-accordion": "^1.1.0", + "@radix-ui/react-alert-dialog": "^1.0.2", + "@radix-ui/react-checkbox": "^1.0.1", + "@radix-ui/react-dialog": "^1.0.2", + "@radix-ui/react-dropdown-menu": "^2.0.2", + "@radix-ui/react-label": "^2.0.0", + "@radix-ui/react-popover": "^1.0.3", + "@radix-ui/react-progress": "^1.0.1", + "@radix-ui/react-select": "^1.2.0", + "@radix-ui/react-switch": "^1.0.1", + "@radix-ui/react-toast": "^1.1.2", "@reduxjs/toolkit": "^1.8.3", "@stripe/react-stripe-js": "^1.10.0", - "@stripe/stripe-js": "^1.35.0", + "@stripe/stripe-js": "^1.46.0", + "@tanstack/react-query": "^4.23.0", "add": "^2.0.6", "axios": "^0.27.2", "axios-auth-refresh": "^3.3.3", "classnames": "^2.3.1", "cookies": "^0.8.0", + "cva": "npm:class-variance-authority@^0.4.0", "fs": "^0.0.1-security", "gray-matter": "^4.0.3", "http-proxy": "^1.18.1", + "i18next": "^22.4.6", "jspdf": "^2.5.1", "jsrp": "^0.2.4", "markdown-it": "^13.0.1", - "next": "^12.2.5", + "next": "^12.3.4", + "next-i18next": "^13.0.2", "posthog-js": "^1.34.0", "query-string": "^7.1.3", "react": "^17.0.2", "react-beautiful-dnd": "^13.1.1", "react-code-input": "^3.10.1", "react-dom": "^17.0.2", - "react-github-btn": "^1.4.0", "react-grid-layout": "^1.3.4", + "react-i18next": "^12.1.1", "react-mailchimp-subscribe": "^2.1.3", "react-markdown": "^8.0.3", "react-redux": "^8.0.2", @@ -46,25 +66,48 @@ "set-cookie-parser": "^2.5.1", "sharp": "^0.31.2", "styled-components": "^5.3.5", + "tailwind-merge": "^1.8.1", "tweetnacl": "^1.0.3", "tweetnacl-util": "^0.15.1", "uuid": "^8.3.2", - "uuidv4": "^6.2.13" + "uuidv4": "^6.2.13", + "yaml": "^2.2.0" }, "devDependencies": { + "@storybook/addon-essentials": "^7.0.0-beta.30", + "@storybook/addon-interactions": "^7.0.0-beta.30", + "@storybook/addon-links": "^7.0.0-beta.30", + "@storybook/addon-postcss": "^2.0.0", + "@storybook/blocks": "^7.0.0-beta.30", + "@storybook/nextjs": "^7.0.0-beta.30", + "@storybook/react": "^7.0.0-beta.30", + "@storybook/testing-library": "^0.0.13", "@tailwindcss/typography": "^0.5.4", + "@types/jsrp": "^0.2.4", "@types/node": "18.11.9", "@types/react": "^18.0.26", - "@typescript-eslint/eslint-plugin": "^5.45.0", + "@typescript-eslint/eslint-plugin": "^5.48.1", "@typescript-eslint/parser": "^5.45.0", "autoprefixer": "^10.4.7", - "eslint": "^8.29.0", + "eslint": "^8.32.0", + "eslint-config-airbnb": "^19.0.4", + "eslint-config-airbnb-typescript": "^17.0.0", "eslint-config-next": "^13.0.5", + "eslint-config-prettier": "^8.6.0", "eslint-import-resolver-typescript": "^3.5.2", + "eslint-plugin-import": "^2.27.4", + "eslint-plugin-jsx-a11y": "^6.7.1", + "eslint-plugin-prettier": "^4.2.1", + "eslint-plugin-react": "^7.32.0", + "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-simple-import-sort": "^8.0.0", + "eslint-plugin-storybook": "^0.6.10", "postcss": "^8.4.14", - "prettier": "2.7.1", - "tailwindcss": "^3.1.4", + "prettier": "^2.8.3", + "prettier-plugin-tailwindcss": "^0.2.2", + "storybook": "^7.0.0-beta.30", + "storybook-dark-mode": "^2.0.5", + "tailwindcss": "3.2", "typescript": "^4.9.3" } } diff --git a/frontend/pages/_app.js b/frontend/pages/_app.js deleted file mode 100644 index aeb2050cc..000000000 --- a/frontend/pages/_app.js +++ /dev/null @@ -1,71 +0,0 @@ -import { useEffect } from "react"; -import { useRouter } from "next/router"; -import { config } from "@fortawesome/fontawesome-svg-core"; - -import Layout from "~/components/basic/Layout"; -import NotificationProvider from "~/components/context/Notifications/NotificationProvider"; -import RouteGuard from "~/components/RouteGuard"; -import { publicPaths } from "~/const"; -import Telemetry from "~/utilities/telemetry/Telemetry"; - -import "@fortawesome/fontawesome-svg-core/styles.css"; -import "../styles/globals.css"; - -config.autoAddCss = false; - -const App = ({ Component, pageProps, ...appProps }) => { - const router = useRouter(); - - useEffect(() => { - // Init for auto capturing - const telemetry = new Telemetry().getInstance(); - - const handleRouteChange = () => { - if (typeof window !== "undefined") { - telemetry.capture("$pageview"); - } - }; - - router.events.on("routeChangeComplete", handleRouteChange); - - return () => { - router.events.off("routeChangeComplete", handleRouteChange); - }; - }, [router.events]); - - // If it's one of these routes, don't add the layout (e.g., these routes are external) - if ( - publicPaths.includes("/" + appProps.router.pathname.split("/")[1]) || - !Component.requireAuth - ) { - return ; - } - - return ( - - - - - - - - ); -}; - -export default App; - -{ - /* */ -} diff --git a/frontend/pages/api/auth/ChangePassword2.ts b/frontend/pages/api/auth/ChangePassword2.ts deleted file mode 100644 index 132eeddf4..000000000 --- a/frontend/pages/api/auth/ChangePassword2.ts +++ /dev/null @@ -1,47 +0,0 @@ -import SecurityClient from '~/utilities/SecurityClient'; - -interface Props { - encryptedPrivateKey: string; - iv: string; - tag: string; - salt: string; - verifier: string; - clientProof: string; -} - -/** - * This is the second step of the change password process (pake) - * @param {*} clientPublicKey - * @returns - */ -const changePassword2 = ({ - encryptedPrivateKey, - iv, - tag, - salt, - verifier, - clientProof -}: Props) => { - return SecurityClient.fetchCall('/api/v1/password/change-password', { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - clientProof: clientProof, - encryptedPrivateKey: encryptedPrivateKey, - iv: iv, - tag: tag, - salt: salt, - verifier: verifier - }) - }).then(async (res) => { - if (res && res.status == 200) { - return res; - } else { - console.log('Failed to change the password'); - } - }); -}; - -export default changePassword2; diff --git a/frontend/pages/api/auth/CheckAuth.ts b/frontend/pages/api/auth/CheckAuth.ts deleted file mode 100644 index 2578d7ce9..000000000 --- a/frontend/pages/api/auth/CheckAuth.ts +++ /dev/null @@ -1,22 +0,0 @@ -import SecurityClient from '~/utilities/SecurityClient'; - -/** - * This function is used to check if the user is authenticated. - * To do that, we get their tokens from cookies, and verify if they are good. - */ -const checkAuth = async () => { - return SecurityClient.fetchCall('/api/v1/auth/checkAuth', { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - } - }).then((res) => { - if (res && res.status == 200) { - return res; - } else { - console.log('Not authorized'); - } - }); -}; - -export default checkAuth; diff --git a/frontend/pages/api/files/GetSecrets.ts b/frontend/pages/api/files/GetSecrets.ts deleted file mode 100644 index 8ff22b57c..000000000 --- a/frontend/pages/api/files/GetSecrets.ts +++ /dev/null @@ -1,33 +0,0 @@ -import SecurityClient from '~/utilities/SecurityClient'; - -/** - * This function fetches the encrypted secrets from the .env file - * @param {string} workspaceId - project is for which a user is trying to get secrets - * @param {string} env - environment of a project for which a user is trying ot get secrets - * @returns - */ -const getSecrets = async (workspaceId: string, env: string) => { - return SecurityClient.fetchCall( - '/api/v1/secret/' + - workspaceId + - '?' + - new URLSearchParams({ - environment: env, - channel: 'web' - }), - { - method: 'GET', - headers: { - 'Content-Type': 'application/json' - } - } - ).then(async (res) => { - if (res && res.status == 200) { - return await res.json(); - } else { - console.log('Failed to get project secrets'); - } - }); -}; - -export default getSecrets; diff --git a/frontend/pages/api/integrations/ChangeHerokuConfigVars.ts b/frontend/pages/api/integrations/ChangeHerokuConfigVars.ts deleted file mode 100644 index e011bda7b..000000000 --- a/frontend/pages/api/integrations/ChangeHerokuConfigVars.ts +++ /dev/null @@ -1,41 +0,0 @@ -import SecurityClient from '~/utilities/SecurityClient'; - -interface Props { - integrationId: string; - key: { encryptedKey: any; nonce: any }; - secrets: { - ciphertextKey: any; - ivKey: any; - tagKey: any; - hashKey: any; - ciphertextValue: any; - ivValue: any; - tagValue: any; - hashValue: any; - type: string; - }[]; -} - -const changeHerokuConfigVars = ({ integrationId, key, secrets }: Props) => { - return SecurityClient.fetchCall( - '/api/v1/integration/' + integrationId + '/sync', - { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - key, - secrets - }) - } - ).then(async (res) => { - if (res && res.status == 200) { - return res; - } else { - console.log('Failed to sync secrets to Heroku'); - } - }); -}; - -export default changeHerokuConfigVars; diff --git a/frontend/pages/api/integrations/DeleteIntegration.ts b/frontend/pages/api/integrations/DeleteIntegration.ts deleted file mode 100644 index 89aa0ab0c..000000000 --- a/frontend/pages/api/integrations/DeleteIntegration.ts +++ /dev/null @@ -1,27 +0,0 @@ -import SecurityClient from '~/utilities/SecurityClient'; - -interface Props { - integrationId: string; -} - -/** - * This route deletes an integration from a certain project - * @param {*} integrationId - * @returns - */ -const deleteIntegration = ({ integrationId }: Props) => { - return SecurityClient.fetchCall('/api/v1/integration/' + integrationId, { - method: 'DELETE', - headers: { - 'Content-Type': 'application/json' - } - }).then(async (res) => { - if (res && res.status == 200) { - return (await res.json()).workspace; - } else { - console.log('Failed to delete an integration'); - } - }); -}; - -export default deleteIntegration; diff --git a/frontend/pages/api/integrations/DeleteIntegrationAuth.ts b/frontend/pages/api/integrations/DeleteIntegrationAuth.ts deleted file mode 100644 index 3a2da2cbf..000000000 --- a/frontend/pages/api/integrations/DeleteIntegrationAuth.ts +++ /dev/null @@ -1,30 +0,0 @@ -import SecurityClient from '~/utilities/SecurityClient'; - -interface Props { - integrationAuthId: string; -} - -/** - * This route deletes an integration authorization from a certain project - * @param {*} integrationAuthId - * @returns - */ -const deleteIntegrationAuth = ({ integrationAuthId }: Props) => { - return SecurityClient.fetchCall( - '/api/v1/integration-auth/' + integrationAuthId, - { - method: 'DELETE', - headers: { - 'Content-Type': 'application/json' - } - } - ).then(async (res) => { - if (res && res.status == 200) { - return res; - } else { - console.log('Failed to delete an integration authorization'); - } - }); -}; - -export default deleteIntegrationAuth; diff --git a/frontend/pages/api/integrations/GetIntegrationApps.ts b/frontend/pages/api/integrations/GetIntegrationApps.ts deleted file mode 100644 index 5597c24b1..000000000 --- a/frontend/pages/api/integrations/GetIntegrationApps.ts +++ /dev/null @@ -1,25 +0,0 @@ -import SecurityClient from '~/utilities/SecurityClient'; - -interface Props { - integrationAuthId: string; -} - -const getIntegrationApps = ({ integrationAuthId }: Props) => { - return SecurityClient.fetchCall( - '/api/v1/integration-auth/' + integrationAuthId + '/apps', - { - method: 'GET', - headers: { - 'Content-Type': 'application/json' - } - } - ).then(async (res) => { - if (res && res.status == 200) { - return (await res.json()).apps; - } else { - console.log('Failed to get available apps for an integration'); - } - }); -}; - -export default getIntegrationApps; diff --git a/frontend/pages/api/integrations/GetIntegrations.ts b/frontend/pages/api/integrations/GetIntegrations.ts deleted file mode 100644 index c189010a4..000000000 --- a/frontend/pages/api/integrations/GetIntegrations.ts +++ /dev/null @@ -1,18 +0,0 @@ -import SecurityClient from '~/utilities/SecurityClient'; - -const getIntegrations = () => { - return SecurityClient.fetchCall('/api/v1/integration/integrations', { - method: 'GET', - headers: { - 'Content-Type': 'application/json' - } - }).then(async (res) => { - if (res && res.status == 200) { - return (await res.json()).integrations; - } else { - console.log('Failed to get project integrations'); - } - }); -}; - -export default getIntegrations; diff --git a/frontend/pages/api/integrations/getWorkspaceAuthorizations.ts b/frontend/pages/api/integrations/getWorkspaceAuthorizations.ts deleted file mode 100644 index f1b406555..000000000 --- a/frontend/pages/api/integrations/getWorkspaceAuthorizations.ts +++ /dev/null @@ -1,30 +0,0 @@ -import SecurityClient from '~/utilities/SecurityClient'; - -interface Props { - workspaceId: string; -} - -/** - * This route gets authorizations of a certain project (Heroku, etc.) - * @param {*} workspaceId - * @returns - */ -const getWorkspaceAuthorizations = ({ workspaceId }: Props) => { - return SecurityClient.fetchCall( - '/api/v1/workspace/' + workspaceId + '/authorizations', - { - method: 'GET', - headers: { - 'Content-Type': 'application/json' - } - } - ).then(async (res) => { - if (res && res.status == 200) { - return (await res.json()).authorizations; - } else { - console.log('Failed to get project authorizations'); - } - }); -}; - -export default getWorkspaceAuthorizations; diff --git a/frontend/pages/api/integrations/getWorkspaceIntegrations.ts b/frontend/pages/api/integrations/getWorkspaceIntegrations.ts deleted file mode 100644 index a33256749..000000000 --- a/frontend/pages/api/integrations/getWorkspaceIntegrations.ts +++ /dev/null @@ -1,30 +0,0 @@ -import SecurityClient from '~/utilities/SecurityClient'; - -interface Props { - workspaceId: string; -} - -/** - * This route gets integrations of a certain project (Heroku, etc.) - * @param {*} workspaceId - * @returns - */ -const getWorkspaceIntegrations = ({ workspaceId }: Props) => { - return SecurityClient.fetchCall( - '/api/v1/workspace/' + workspaceId + '/integrations', - { - method: 'GET', - headers: { - 'Content-Type': 'application/json' - } - } - ).then(async (res) => { - if (res && res.status == 200) { - return (await res.json()).integrations; - } else { - console.log('Failed to get the project integrations'); - } - }); -}; - -export default getWorkspaceIntegrations; diff --git a/frontend/pages/api/organization/GetOrgProjects.ts b/frontend/pages/api/organization/GetOrgProjects.ts deleted file mode 100644 index 954694486..000000000 --- a/frontend/pages/api/organization/GetOrgProjects.ts +++ /dev/null @@ -1,29 +0,0 @@ -import SecurityClient from '~/utilities/SecurityClient'; - -/** - * This route lets us get all the users in an org. - * @param {*} req - * @param {*} res - * @returns - */ - -// TODO: this file is not used anywhere -const getOrganizationProjects = (req: { orgId: string }) => { - return SecurityClient.fetchCall( - '/api/organization/' + req.orgId + '/workspaces', - { - method: 'GET', - headers: { - 'Content-Type': 'application/json' - } - } - ).then(async (res) => { - if (res && res.status == 200) { - return (await res.json()).workspaces; - } else { - console.log('Failed to get projects for an org'); - } - }); -}; - -export default getOrganizationProjects; diff --git a/frontend/pages/api/organization/GetOrgSubscription.ts b/frontend/pages/api/organization/GetOrgSubscription.ts deleted file mode 100644 index c93679cdc..000000000 --- a/frontend/pages/api/organization/GetOrgSubscription.ts +++ /dev/null @@ -1,27 +0,0 @@ -import SecurityClient from '~/utilities/SecurityClient'; - -/** - * This route lets us get the current subscription of an org. - * @param {*} req - * @param {*} res - * @returns - */ -const getOrganizationSubscriptions = (req: { orgId: string }) => { - return SecurityClient.fetchCall( - '/api/v1/organization/' + req.orgId + '/subscriptions', - { - method: 'GET', - headers: { - 'Content-Type': 'application/json' - } - } - ).then(async (res) => { - if (res && res.status == 200) { - return (await res.json()).subscriptions; - } else { - console.log('Failed to get org subscriptions'); - } - }); -}; - -export default getOrganizationSubscriptions; diff --git a/frontend/pages/api/organization/GetOrgUserProjects.ts b/frontend/pages/api/organization/GetOrgUserProjects.ts deleted file mode 100644 index 872b8d781..000000000 --- a/frontend/pages/api/organization/GetOrgUserProjects.ts +++ /dev/null @@ -1,27 +0,0 @@ -import SecurityClient from '~/utilities/SecurityClient'; - -/** - * This route lets us get all the projects of a certain user in an org. - * @param {*} req - * @param {*} res - * @returns - */ -const getOrganizationUserProjects = (req: { orgId: string }) => { - return SecurityClient.fetchCall( - '/api/v1/organization/' + req.orgId + '/my-workspaces', - { - method: 'GET', - headers: { - 'Content-Type': 'application/json' - } - } - ).then(async (res) => { - if (res && res.status == 200) { - return (await res.json()).workspaces; - } else { - console.log('Failed to get projects of a user in an org'); - } - }); -}; - -export default getOrganizationUserProjects; diff --git a/frontend/pages/api/organization/GetOrgUsers.ts b/frontend/pages/api/organization/GetOrgUsers.ts deleted file mode 100644 index f1aaa7209..000000000 --- a/frontend/pages/api/organization/GetOrgUsers.ts +++ /dev/null @@ -1,24 +0,0 @@ -import SecurityClient from '~/utilities/SecurityClient'; - -/** - * This route lets us get all the users in an org. - * @param {object} obj - * @param {string} obj.orgId - organization Id - * @returns - */ -const getOrganizationUsers = ({ orgId }: { orgId: string }) => { - return SecurityClient.fetchCall('/api/v1/organization/' + orgId + '/users', { - method: 'GET', - headers: { - 'Content-Type': 'application/json' - } - }).then(async (res) => { - if (res?.status == 200) { - return (await res.json()).users; - } else { - console.log('Failed to get org users'); - } - }); -}; - -export default getOrganizationUsers; diff --git a/frontend/pages/api/organization/StripeRedirect.ts b/frontend/pages/api/organization/StripeRedirect.ts deleted file mode 100644 index a9fe1f066..000000000 --- a/frontend/pages/api/organization/StripeRedirect.ts +++ /dev/null @@ -1,27 +0,0 @@ -import SecurityClient from '~/utilities/SecurityClient'; - -/** - * This route redirects the user to the right stripe billing page. - * @param {*} req - * @param {*} res - * @returns - */ -const StripeRedirect = ({ orgId }: { orgId: string }) => { - return SecurityClient.fetchCall( - '/api/v1/organization/' + orgId + '/customer-portal-session', - { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - } - } - ).then(async (res) => { - if (res && res.status == 200) { - return (window.location.href = (await res.json()).url); - } else { - console.log('Failed to redirect to Stripe'); - } - }); -}; - -export default StripeRedirect; diff --git a/frontend/pages/api/organization/addIncidentContact.ts b/frontend/pages/api/organization/addIncidentContact.ts deleted file mode 100644 index d3676e641..000000000 --- a/frontend/pages/api/organization/addIncidentContact.ts +++ /dev/null @@ -1,29 +0,0 @@ -import SecurityClient from '~/utilities/SecurityClient'; - -/** - * This route add an incident contact email to a certain organization - * @param {*} param0 - * @returns - */ -const addIncidentContact = (organizationId: string, email: string) => { - return SecurityClient.fetchCall( - '/api/v1/organization/' + organizationId + '/incidentContactOrg', - { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - email: email - }) - } - ).then(async (res) => { - if (res && res.status == 200) { - return res; - } else { - console.log('Failed to add an incident contact'); - } - }); -}; - -export default addIncidentContact; diff --git a/frontend/pages/api/organization/deleteIncidentContact.ts b/frontend/pages/api/organization/deleteIncidentContact.ts deleted file mode 100644 index fd6374e9b..000000000 --- a/frontend/pages/api/organization/deleteIncidentContact.ts +++ /dev/null @@ -1,29 +0,0 @@ -import SecurityClient from '~/utilities/SecurityClient'; - -/** - * This route deletes an incident Contact from a certain organization - * @param {*} param0 - * @returns - */ -const deleteIncidentContact = (organizationId: string, email: string) => { - return SecurityClient.fetchCall( - '/api/v1/organization/' + organizationId + '/incidentContactOrg', - { - method: 'DELETE', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - email: email - }) - } - ).then(async (res) => { - if (res && res.status == 200) { - return res; - } else { - console.log('Failed to delete an incident contact'); - } - }); -}; - -export default deleteIncidentContact; diff --git a/frontend/pages/api/organization/deleteUserFromOrganization.ts b/frontend/pages/api/organization/deleteUserFromOrganization.ts deleted file mode 100644 index 988a09485..000000000 --- a/frontend/pages/api/organization/deleteUserFromOrganization.ts +++ /dev/null @@ -1,23 +0,0 @@ -import SecurityClient from '~/utilities/SecurityClient'; - -/** - * This function removes a certain member from a certain organization - * @param {*} membershipId - * @returns - */ -const deleteUserFromOrganization = (membershipId: string) => { - return SecurityClient.fetchCall('/api/v1/membership-org/' + membershipId, { - method: 'DELETE', - headers: { - 'Content-Type': 'application/json' - } - }).then(async (res) => { - if (res && res.status == 200) { - return res; - } else { - console.log('Failed to delete a user from an org'); - } - }); -}; - -export default deleteUserFromOrganization; diff --git a/frontend/pages/api/organization/getIncidentContacts.ts b/frontend/pages/api/organization/getIncidentContacts.ts deleted file mode 100644 index bb9c3613a..000000000 --- a/frontend/pages/api/organization/getIncidentContacts.ts +++ /dev/null @@ -1,26 +0,0 @@ -import SecurityClient from '~/utilities/SecurityClient'; - -/** - * This routes gets all the incident contacts of a certain organization - * @param {*} workspaceId - * @returns - */ -const getIncidentContacts = (organizationId: string) => { - return SecurityClient.fetchCall( - '/api/v1/organization/' + organizationId + '/incidentContactOrg', - { - method: 'GET', - headers: { - 'Content-Type': 'application/json' - } - } - ).then(async (res) => { - if (res && res.status == 200) { - return (await res.json()).incidentContactsOrg; - } else { - console.log('Failed to get incident contacts'); - } - }); -}; - -export default getIncidentContacts; diff --git a/frontend/pages/api/serviceToken/addServiceToken.ts b/frontend/pages/api/serviceToken/addServiceToken.ts deleted file mode 100644 index 5dad69f69..000000000 --- a/frontend/pages/api/serviceToken/addServiceToken.ts +++ /dev/null @@ -1,50 +0,0 @@ -import SecurityClient from '~/utilities/SecurityClient'; - -interface Props { - name: string; - workspaceId: string; - environment: string; - expiresIn: number; - publicKey: string; - encryptedKey: string; - nonce: string; -} - -/** - * This route gets service tokens for a specific user in a project - * @param {*} param0 - * @returns - */ -const addServiceToken = ({ - name, - workspaceId, - environment, - expiresIn, - publicKey, - encryptedKey, - nonce -}: Props) => { - return SecurityClient.fetchCall('/api/v1/service-token/', { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - name, - workspaceId, - environment, - expiresIn, - publicKey, - encryptedKey, - nonce - }) - }).then(async (res) => { - if (res && res.status == 200) { - return (await res.json()).token; - } else { - console.log('Failed to add service tokens'); - } - }); -}; - -export default addServiceToken; diff --git a/frontend/pages/api/serviceToken/getServiceTokens.ts b/frontend/pages/api/serviceToken/getServiceTokens.ts deleted file mode 100644 index d2577cc83..000000000 --- a/frontend/pages/api/serviceToken/getServiceTokens.ts +++ /dev/null @@ -1,26 +0,0 @@ -import SecurityClient from '~/utilities/SecurityClient'; - -/** - * This route gets service tokens for a specific user in a project - * @param {*} param0 - * @returns - */ -const getServiceTokens = ({ workspaceId }: { workspaceId: string }) => { - return SecurityClient.fetchCall( - '/api/v1/workspace/' + workspaceId + '/service-tokens', - { - method: 'GET', - headers: { - 'Content-Type': 'application/json' - } - } - ).then(async (res) => { - if (res && res.status == 200) { - return (await res.json()).serviceTokens; - } else { - console.log('Failed to get service tokens'); - } - }); -}; - -export default getServiceTokens; diff --git a/frontend/pages/api/workspace/addUserToWorkspace.ts b/frontend/pages/api/workspace/addUserToWorkspace.ts deleted file mode 100644 index e1efa51a1..000000000 --- a/frontend/pages/api/workspace/addUserToWorkspace.ts +++ /dev/null @@ -1,30 +0,0 @@ -import SecurityClient from '~/utilities/SecurityClient'; - -/** - * This function adds a user to a project - * @param {*} email - * @param {*} workspaceId - * @returns - */ -const addUserToWorkspace = (email: string, workspaceId: string) => { - return SecurityClient.fetchCall( - '/api/v1/workspace/' + workspaceId + '/invite-signup', - { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - email: email - }) - } - ).then(async (res) => { - if (res && res.status == 200) { - return await res.json(); - } else { - console.log('Failed to add a user to project'); - } - }); -}; - -export default addUserToWorkspace; diff --git a/frontend/pages/api/workspace/changeUserRoleInWorkspace.ts b/frontend/pages/api/workspace/changeUserRoleInWorkspace.ts deleted file mode 100644 index 9ac49440a..000000000 --- a/frontend/pages/api/workspace/changeUserRoleInWorkspace.ts +++ /dev/null @@ -1,30 +0,0 @@ -import SecurityClient from '~/utilities/SecurityClient'; - -/** - * This function change the access of a user in a certain workspace - * @param {*} membershipId - * @param {*} role - * @returns - */ -const changeUserRoleInWorkspace = (membershipId: string, role: string) => { - return SecurityClient.fetchCall( - '/api/v1/membership/' + membershipId + '/change-role', - { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - role: role - }) - } - ).then(async (res) => { - if (res && res.status == 200) { - return res; - } else { - console.log('Failed to change the user role in a project'); - } - }); -}; - -export default changeUserRoleInWorkspace; diff --git a/frontend/pages/api/workspace/deleteUserFromWorkspace.ts b/frontend/pages/api/workspace/deleteUserFromWorkspace.ts deleted file mode 100644 index ea02f96d4..000000000 --- a/frontend/pages/api/workspace/deleteUserFromWorkspace.ts +++ /dev/null @@ -1,23 +0,0 @@ -import SecurityClient from '~/utilities/SecurityClient'; - -/** - * This function removes a certain member from a certain workspace - * @param {*} membershipId - * @returns - */ -const deleteUserFromWorkspace = (membershipId: string) => { - return SecurityClient.fetchCall('/api/v1/membership/' + membershipId, { - method: 'DELETE', - headers: { - 'Content-Type': 'application/json' - } - }).then(async (res) => { - if (res && res.status == 200) { - return res; - } else { - console.log('Failed to delete a user from a project'); - } - }); -}; - -export default deleteUserFromWorkspace; diff --git a/frontend/pages/api/workspace/deleteWorkspace.ts b/frontend/pages/api/workspace/deleteWorkspace.ts deleted file mode 100644 index 2bdb64cd3..000000000 --- a/frontend/pages/api/workspace/deleteWorkspace.ts +++ /dev/null @@ -1,23 +0,0 @@ -import SecurityClient from '~/utilities/SecurityClient'; - -/** - * This route deletes a specified workspace. - * @param {*} workspaceId - * @returns - */ -const deleteWorkspace = (workspaceId: string) => { - return SecurityClient.fetchCall('/api/v1/workspace/' + workspaceId, { - method: 'DELETE', - headers: { - 'Content-Type': 'application/json' - } - }).then(async (res) => { - if (res && res.status == 200) { - return res; - } else { - console.log('Failed to delete a project'); - } - }); -}; - -export default deleteWorkspace; diff --git a/frontend/pages/api/workspace/getWorkspaceKeys.ts b/frontend/pages/api/workspace/getWorkspaceKeys.ts deleted file mode 100644 index 09b468662..000000000 --- a/frontend/pages/api/workspace/getWorkspaceKeys.ts +++ /dev/null @@ -1,26 +0,0 @@ -import SecurityClient from "~/utilities/SecurityClient"; - -/** - * This route lets us get the public keys of everyone in your workspace. - * @param {string} workspaceId - * @returns - */ -const getWorkspaceKeys = ({ workspaceId }: { workspaceId: string; }) => { - return SecurityClient.fetchCall( - "/api/v1/workspace/" + workspaceId + "/keys", - { - method: "GET", - headers: { - "Content-Type": "application/json", - }, - } - ).then(async (res) => { - if (res?.status == 200) { - return (await res.json()).publicKeys; - } else { - console.log("Failed to get the public keys of everyone in the workspace"); - } - }); -}; - -export default getWorkspaceKeys; diff --git a/frontend/pages/api/workspace/getWorkspaceUsers.ts b/frontend/pages/api/workspace/getWorkspaceUsers.ts deleted file mode 100644 index c4f00eb0d..000000000 --- a/frontend/pages/api/workspace/getWorkspaceUsers.ts +++ /dev/null @@ -1,26 +0,0 @@ -import SecurityClient from '~/utilities/SecurityClient'; - -/** - * This route lets us get all the users in the workspace. - * @param {string} workspaceId - workspace ID - * @returns - */ -const getWorkspaceUsers = ({ workspaceId }: { workspaceId: string }) => { - return SecurityClient.fetchCall( - '/api/v1/workspace/' + workspaceId + '/users', - { - method: 'GET', - headers: { - 'Content-Type': 'application/json' - } - } - ).then(async (res) => { - if (res?.status == 200) { - return (await res.json()).users; - } else { - console.log('Failed to get Project Users'); - } - }); -}; - -export default getWorkspaceUsers; diff --git a/frontend/pages/api/workspace/renameWorkspace.ts b/frontend/pages/api/workspace/renameWorkspace.ts deleted file mode 100644 index a25d2068c..000000000 --- a/frontend/pages/api/workspace/renameWorkspace.ts +++ /dev/null @@ -1,30 +0,0 @@ -import SecurityClient from '~/utilities/SecurityClient'; - -/** - * This route lets us rename a certain workspace. - * @param {*} req - * @param {*} res - * @returns - */ -const renameWorkspace = (workspaceId: string, newWorkspaceName: string) => { - return SecurityClient.fetchCall( - '/api/v1/workspace/' + workspaceId + '/name', - { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - name: newWorkspaceName - }) - } - ).then(async (res) => { - if (res && res.status == 200) { - return res; - } else { - console.log('Failed to rename a project'); - } - }); -}; - -export default renameWorkspace; diff --git a/frontend/pages/api/workspace/uploadKeys.ts b/frontend/pages/api/workspace/uploadKeys.ts deleted file mode 100644 index 2f791735d..000000000 --- a/frontend/pages/api/workspace/uploadKeys.ts +++ /dev/null @@ -1,38 +0,0 @@ -import SecurityClient from '~/utilities/SecurityClient'; - -/** - * This route uplods the keys in an encrypted format. - * @param {*} workspaceId - * @param {*} userId - * @param {*} encryptedKey - * @param {*} nonce - * @returns - */ -const uploadKeys = ( - workspaceId: string, - userId: string, - encryptedKey: string, - nonce: string -) => { - return SecurityClient.fetchCall('/api/v1/key/' + workspaceId, { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - key: { - userId: userId, - encryptedKey: encryptedKey, - nonce: nonce - } - }) - }).then(async (res) => { - if (res && res.status == 200) { - return res; - } else { - console.log('Failed to upload keys for a new user'); - } - }); -}; - -export default uploadKeys; diff --git a/frontend/pages/dashboard.js b/frontend/pages/dashboard.js deleted file mode 100644 index 5954a9db2..000000000 --- a/frontend/pages/dashboard.js +++ /dev/null @@ -1,33 +0,0 @@ -import React, { useEffect } from "react"; -import Head from "next/head"; -import { useRouter } from "next/router"; - -import getWorkspaces from "./api/workspace/getWorkspaces"; - -export default function DashboardRedirect() { - const router = useRouter(); - - /** - * Here we forward to the default workspace if a user opens this url - */ - // eslint-disable-next-line react-hooks/exhaustive-deps - useEffect(async () => { - let userWorkspace; - try { - if (localStorage.getItem("projectData.id")) { - router.push("/dashboard/" + localStorage.getItem("projectData.id")); - } else { - const userWorkspaces = await getWorkspaces(); - userWorkspace = userWorkspaces[0]._id; - router.push("/dashboard/" + userWorkspace); - } - } catch (error) { - console.log("Error - Not logged in yet"); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - - return
; -} - -DashboardRedirect.requireAuth = true; diff --git a/frontend/pages/dashboard/[id].js b/frontend/pages/dashboard/[id].js deleted file mode 100644 index 4bb09c80f..000000000 --- a/frontend/pages/dashboard/[id].js +++ /dev/null @@ -1,828 +0,0 @@ -import React, { Fragment, useCallback, useEffect, useState } from 'react'; -import Head from 'next/head'; -import Image from 'next/image'; -import { useRouter } from 'next/router'; -import { - faArrowDownAZ, - faArrowDownZA, - faCheck, - faCircleInfo, - faCopy, - faDownload, - faEllipsis, - faEye, - faEyeSlash, - faFolderOpen, - faMagnifyingGlass, - faPeopleGroup, - faPerson, - faPlus, - faShuffle, - faX -} from '@fortawesome/free-solid-svg-icons'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { Menu, Transition } from '@headlessui/react'; - -import Button from '~/components/basic/buttons/Button'; -import ListBox from '~/components/basic/Listbox'; -import BottonRightPopup from '~/components/basic/popups/BottomRightPopup'; -import { useNotificationContext } from '~/components/context/Notifications/NotificationProvider'; -import DashboardInputField from '~/components/dashboard/DashboardInputField'; -import DropZone from '~/components/dashboard/DropZone'; -import NavHeader from '~/components/navigation/NavHeader'; -import getSecretsForProject from '~/components/utilities/secrets/getSecretsForProject'; -import pushKeys from '~/components/utilities/secrets/pushKeys'; -import pushKeysIntegration from '~/components/utilities/secrets/pushKeysIntegration'; -import guidGenerator from '~/utilities/randomId'; - -import { envMapping } from '../../public/data/frequentConstants'; -import getWorkspaceIntegrations from '../api/integrations/getWorkspaceIntegrations'; -import getUser from '../api/user/getUser'; -import checkUserAction from '../api/userActions/checkUserAction'; -import registerUserAction from '../api/userActions/registerUserAction'; -import getWorkspaces from '../api/workspace/getWorkspaces'; - -/** - * This component represent a single row for an environemnt variable on the dashboard - * @param {object} obj - * @param {String[]} obj.keyPair - data related to the environment variable (id, pos, key, value, public/private) - * @param {function} obj.deleteRow - a function to delete a certain keyPair - * @param {function} obj.modifyKey - modify the key of a certain environment variable - * @param {function} obj.modifyValue - modify the value of a certain environment variable - * @param {function} obj.modifyVisibility - switch between public/private visibility - * @param {boolean} obj.isBlurred - if the blurring setting is turned on - * @param {string[]} obj.duplicates - list of all the duplicates secret names on the dashboard - * @returns - */ -const KeyPair = ({ - keyPair, - deleteRow, - modifyKey, - modifyValue, - modifyVisibility, - isBlurred, - duplicates -}) => { - const [randomStringLength, setRandomStringLength] = useState(32); - - return ( -
-
-
-
- -
-
-
-
- -
-
- -
- -
- -
-
-
- - -
- modifyVisibility( - keyPair.type == 'personal' ? 'shared' : 'personal', - keyPair.pos - ) - } - className="relative flex justify-start items-center cursor-pointer select-none py-2 px-2 rounded-md text-gray-400 hover:bg-white/10 duration-200 hover:text-gray-200 w-full" - > - -
- {keyPair.type == 'personal' ? 'Make Shared' : 'Make Personal'} -
-
-
{ - if (randomStringLength > 32) { - setRandomStringLength(32); - } else if (randomStringLength < 2) { - setRandomStringLength(2); - } else { - modifyValue( - [...Array(randomStringLength)] - .map(() => Math.floor(Math.random() * 16).toString(16)) - .join(''), - keyPair.pos - ); - } - }} - className="relative flex flex-row justify-start items-center cursor-pointer select-none py-2 px-2 rounded-md text-gray-400 hover:bg-white/10 duration-200 hover:text-gray-200 w-full" - > - -
-

Generate Random Hex

-

digits

-
-
-
-
{ - if (randomStringLength > 1) { - setRandomStringLength(randomStringLength - 1); - } - }} - > - - -
- - setRandomStringLength(parseInt(e.target.value)) - } - value={randomStringLength} - className="text-center z-20 peer text-sm bg-transparent w-full outline-none" - spellCheck="false" - /> -
{ - if (randomStringLength < 32) { - setRandomStringLength(randomStringLength + 1); - } - }} - > - + -
-
-
-
-
-
-
-
-
-
- ); -}; - -/** - * This is the main component for the dashboard (aka the screen with all the encironemnt variable & secrets) - * @returns - */ -export default function Dashboard() { - const [data, setData] = useState(); - const [fileState, setFileState] = useState([]); - const [buttonReady, setButtonReady] = useState(false); - const router = useRouter(); - const [workspaceId, setWorkspaceId] = useState(''); - const [blurred, setBlurred] = useState(true); - const [isKeyAvailable, setIsKeyAvailable] = useState(true); - const [env, setEnv] = useState( - router.asPath.split('?').length == 1 - ? 'Development' - : Object.keys(envMapping).includes(router.asPath.split('?')[1]) - ? router.asPath.split('?')[1] - : 'Development' - ); - const [isNew, setIsNew] = useState(false); - const [searchKeys, setSearchKeys] = useState(''); - const [errorDragAndDrop, setErrorDragAndDrop] = useState(false); - const [projectIdCopied, setProjectIdCopied] = useState(false); - const [sortMethod, setSortMethod] = useState('alphabetical'); - const [checkDocsPopUpVisible, setCheckDocsPopUpVisible] = useState(false); - const [hasUserEverPushed, setHasUserEverPushed] = useState(false); - - const { createNotification } = useNotificationContext(); - - // #TODO: fix save message for changing reroutes - // const beforeRouteHandler = (url) => { - // const warningText = - // "Do you want to save your results bfore leaving this page?"; - // if (!buttonReady) return; - // if (router.asPath !== url && !confirm(warningText)) { - // // router.events.emit('routeChangeError'); - // // setData(data) - // savePush(); - // throw `Route change to "${url}" was aborted (this error can be safely ignored).`; - // } else { - // setButtonReady(false); - // } - // }; - - // prompt the user if they try and leave with unsaved changes - useEffect(() => { - const warningText = - 'Do you want to save your results before leaving this page?'; - const handleWindowClose = (e) => { - if (!buttonReady) return; - e.preventDefault(); - return (e.returnValue = warningText); - }; - window.addEventListener('beforeunload', handleWindowClose); - // router.events.on('routeChangeStart', beforeRouteHandler); - return () => { - window.removeEventListener('beforeunload', handleWindowClose); - // router.events.off('routeChangeStart', beforeRouteHandler); - }; - }, [buttonReady]); - - /** - * Reorder rows alphabetically or in the opprosite order - */ - const reorderRows = (dataToReorder) => { - setSortMethod((prevSort) => - prevSort == 'alphabetical' ? '-alphabetical' : 'alphabetical' - ); - - sortValuesHandler(dataToReorder); - }; - - useEffect(() => { - (async () => { - try { - let userWorkspaces = await getWorkspaces(); - const listWorkspaces = userWorkspaces.map((workspace) => workspace._id); - if ( - !listWorkspaces.includes(router.asPath.split('/')[2].split('?')[0]) - ) { - router.push('/dashboard/' + listWorkspaces[0]); - } - - if (env != router.asPath.split('?')[1]) { - router.push(router.asPath.split('?')[0] + '?' + env); - } - setBlurred(true); - setWorkspaceId(router.query.id); - - const dataToSort = await getSecretsForProject({ - env, - setFileState, - setIsKeyAvailable, - setData, - workspaceId: router.query.id - }); - reorderRows(dataToSort); - - const user = await getUser(); - setIsNew( - (Date.parse(new Date()) - Date.parse(user.createdAt)) / 60000 < 3 - ? true - : false - ); - - let userAction = await checkUserAction({ - action: 'first_time_secrets_pushed' - }); - setHasUserEverPushed(userAction ? true : false); - } catch (error) { - console.log('Error', error); - setData([]); - } - })(); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [env]); - - const addRow = () => { - setIsNew(false); - setData([ - ...data, - { - id: guidGenerator(), - pos: data.length, - key: '', - value: '', - type: 'shared' - } - ]); - }; - - const deleteRow = (id) => { - setButtonReady(true); - setData(data.filter((row) => row.id !== id)); - }; - - const modifyValue = (value, pos) => { - setData((oldData) => { - oldData[pos].value = value; - return [...oldData]; - }); - setButtonReady(true); - }; - - const modifyKey = (value, pos) => { - setData((oldData) => { - oldData[pos].key = value; - return [...oldData]; - }); - setButtonReady(true); - }; - - const modifyVisibility = (value, pos) => { - setData((oldData) => { - oldData[pos].type = value; - return [...oldData]; - }); - setButtonReady(true); - }; - - // For speed purposes and better perforamance, we are using useCallback - const listenChangeValue = useCallback((value, pos) => { - modifyValue(value, pos); - }, []); - - const listenChangeKey = useCallback((value, pos) => { - modifyKey(value, pos); - }, []); - - const listenChangeVisibility = useCallback((value, pos) => { - modifyVisibility(value, pos); - }, []); - - /** - * Save the changes of environment variables and push them to the database - */ - const savePush = async () => { - // Format the new object with environment variables - let obj = Object.assign( - {}, - ...data.map((row) => ({ [row.key]: [row.value, row.type] })) - ); - - // Checking if any of the secret keys start with a number - if so, don't do anything - const nameErrors = !Object.keys(obj) - .map((key) => !isNaN(key.charAt(0))) - .every((v) => v === false); - const duplicatesExist = - data - ?.map((item) => item.key) - .filter( - (item, index) => index !== data?.map((item) => item.key).indexOf(item) - ).length > 0; - - if (nameErrors) { - return createNotification({ - text: 'Solve all name errors before saving secrets.', - type: 'error' - }); - } - - if (duplicatesExist) { - return createNotification({ - text: 'Remove duplicated secret names before saving.', - type: 'error' - }); - } - - // Once "Save changed is clicked", disable that button - setButtonReady(false); - pushKeys({ obj, workspaceId: router.query.id, env }); - - /** - * Check which integrations are active for this project and environment - * If there are any, update environment variables for those integrations - */ - let integrations = await getWorkspaceIntegrations({ - workspaceId: router.query.id - }); - integrations.map(async (integration) => { - if ( - envMapping[env] == integration.environment && - integration.isActive == true - ) { - let objIntegration = Object.assign( - {}, - ...data.map((row) => ({ [row.key]: row.value })) - ); - await pushKeysIntegration({ - obj: objIntegration, - integrationId: integration._id - }); - } - }); - - // If this user has never saved environment variables before, show them a prompt to read docs - if (!hasUserEverPushed) { - setCheckDocsPopUpVisible(true); - await registerUserAction({ action: 'first_time_secrets_pushed' }); - } - }; - - const addData = (newData) => { - setData(data.concat(newData)); - setButtonReady(true); - }; - - const changeBlurred = () => { - setBlurred(!blurred); - }; - - const sortValuesHandler = (dataToSort) => { - const sortedData = (dataToSort != 1 ? dataToSort : data) - .sort((a, b) => - sortMethod == 'alphabetical' - ? a.key.localeCompare(b.key) - : b.key.localeCompare(a.key) - ) - .map((item, index) => { - return { - ...item, - pos: index - }; - }); - - setData(sortedData); - }; - - // This function downloads the secrets as a .env file - const download = () => { - const file = data - .map((item) => [item.key, item.value].join('=')) - .join('\n'); - const blob = new Blob([file]); - const fileDownloadUrl = URL.createObjectURL(blob); - let alink = document.createElement('a'); - alink.href = fileDownloadUrl; - alink.download = envMapping[env] + '.env'; - alink.click(); - }; - - const deleteCertainRow = (id) => { - deleteRow(id); - }; - - /** - * This function copies the project id to the clipboard - */ - function copyToClipboard() { - var copyText = document.getElementById('myInput'); - - copyText.select(); - copyText.setSelectionRange(0, 99999); // For mobile devices - - navigator.clipboard.writeText(copyText.value); - - setProjectIdCopied(true); - setTimeout(() => setProjectIdCopied(false), 2000); - } - - return data ? ( -
- - Secrets - - - - - -
-
- - {checkDocsPopUpVisible && ( - - )} -
-
-

Secrets

- {data?.length == 0 && ( - - )} -
-
-
-

Project ID:

- -
- - - Click to Copy - -
-
- {(data?.length !== 0 || buttonReady) && ( -
-
- )} -
-
-
-
-
- {data?.length !== 0 && ( - <> - -
- - setSearchKeys(e.target.value)} - placeholder={'Search keys...'} - /> -
-
-
-
-
-
-
-
-
- - )} -
-
- {data?.length !== 0 ? ( -
-
-
- {/* */} -
-

Personal

-
- - - Personal keys are only visible to you - -
-
-
-
- {data - .filter( - (keyPair) => - keyPair.key - .toLowerCase() - .includes(searchKeys.toLowerCase()) && - keyPair.type == 'personal' - ) - ?.map((keyPair) => ( - item.key) - .filter( - (item, index) => - index !== - data?.map((item) => item.key).indexOf(item) - )} - /> - ))} -
-
-
8 ? 'h-3/4' : 'h-min' - }`} - > -
- {/* */} -
-

Shared

-
- - - Shared keys are visible to your whole team - -
-
-
-
- {data - .filter( - (keyPair) => - keyPair.key - .toLowerCase() - .includes(searchKeys.toLowerCase()) && - keyPair.type == 'shared' - ) - ?.map((keyPair) => ( - item.key) - .filter( - (item, index) => - index !== - data?.map((item) => item.key).indexOf(item) - )} - /> - ))} -
-
-
- -
-
- ) : ( -
- {fileState.message != "There's nothing to pull" && - fileState.message != undefined && ( - - )} - {(fileState.message == "There's nothing to pull" || - fileState.message == undefined) && - isKeyAvailable && ( - - )} - {fileState.message == - 'Failed membership validation for workspace' && ( -

You are not authorized to view this project.

- )} - {fileState.message == 'Access needed to pull the latest file' || - (!isKeyAvailable && ( - <> - -

- To view this file, contact your administrator for - permission. -

-

- They need to grant you access in the team tab. -

- - ))} -
- )} -
-
-
-
- ) : ( -
-
- loading animation -
- ); -} - -Dashboard.requireAuth = true; diff --git a/frontend/pages/heroku.js b/frontend/pages/heroku.js deleted file mode 100644 index 82947b1b9..000000000 --- a/frontend/pages/heroku.js +++ /dev/null @@ -1,36 +0,0 @@ -import React, { useEffect } from "react"; -import Head from "next/head"; -import { useRouter } from "next/router"; -const queryString = require("query-string"); -import AuthorizeIntegration from "./api/integrations/authorizeIntegration"; - -export default function Heroku() { - const router = useRouter(); - const parsedUrl = queryString.parse(router.asPath.split("?")[1]); - const code = parsedUrl.code; - const state = parsedUrl.state; - - /** - * Here we forward to the default workspace if a user opens this url - */ - // eslint-disable-next-line react-hooks/exhaustive-deps - useEffect(async () => { - try { - if (state == localStorage.getItem("latestCSRFToken")) { - await AuthorizeIntegration({ - workspaceId: localStorage.getItem("projectData.id"), - code, - integration: "heroku", - }); - router.push("/integrations/" + localStorage.getItem("projectData.id")); - } - } catch (error) { - console.log("Error - Not logged in yet"); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - - return
; -} - -Heroku.requireAuth = true; diff --git a/frontend/pages/integrations/[id].js b/frontend/pages/integrations/[id].js deleted file mode 100644 index dc13d284c..000000000 --- a/frontend/pages/integrations/[id].js +++ /dev/null @@ -1,405 +0,0 @@ -import React, { useEffect, useState } from 'react'; -import Head from 'next/head'; -import Image from 'next/image'; -import { useRouter } from 'next/router'; -import { - faArrowRight, - faCheck, - faRotate, - faX -} from '@fortawesome/free-solid-svg-icons'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; - -import Button from '~/components/basic/buttons/Button'; -import ListBox from '~/components/basic/Listbox'; -import NavHeader from '~/components/navigation/NavHeader'; -import getSecretsForProject from '~/components/utilities/secrets/getSecretsForProject'; -import pushKeysIntegration from '~/components/utilities/secrets/pushKeysIntegration'; -import guidGenerator from '~/utilities/randomId'; - -import { - envMapping, - frameworks, - reverseEnvMapping -} from '../../public/data/frequentConstants'; -import deleteIntegration from '../api/integrations/DeleteIntegration'; -import deleteIntegrationAuth from '../api/integrations/DeleteIntegrationAuth'; -import getIntegrationApps from '../api/integrations/GetIntegrationApps'; -import getIntegrations from '../api/integrations/GetIntegrations'; -import getWorkspaceAuthorizations from '../api/integrations/getWorkspaceAuthorizations'; -import getWorkspaceIntegrations from '../api/integrations/getWorkspaceIntegrations'; -import startIntegration from '../api/integrations/StartIntegration'; - -const crypto = require('crypto'); - -const Integration = ({ projectIntegration }) => { - const [integrationEnvironment, setIntegrationEnvironment] = useState( - reverseEnvMapping[projectIntegration.environment] - ); - const [fileState, setFileState] = useState([]); - const [data, setData] = useState(); - const [isKeyAvailable, setIsKeyAvailable] = useState(true); - const router = useRouter(); - const [apps, setApps] = useState([]); - const [integrationApp, setIntegrationApp] = useState( - projectIntegration.app ? projectIntegration.app : apps[0] - ); - - useEffect(async () => { - const tempHerokuApps = await getIntegrationApps({ - integrationAuthId: projectIntegration.integrationAuth - }); - const tempHerokuAppNames = tempHerokuApps.map((app) => app.name); - setApps(tempHerokuAppNames); - setIntegrationApp( - projectIntegration.app ? projectIntegration.app : tempHerokuAppNames[0] - ); - }, []); - - return ( -
-
-
-
-
- ENVIRONMENT -
- -
- -
-
- INTEGRATION -
-
- {projectIntegration.integration.charAt(0).toUpperCase() + - projectIntegration.integration.slice(1)} -
-
-
-
- HEROKU APP -
- -
-
-
- {projectIntegration.isActive ? ( -
- -
In Sync
-
- ) : ( -
-
-
- - ); -}; - -export default function Integrations() { - const [integrations, setIntegrations] = useState(); - const [projectIntegrations, setProjectIntegrations] = useState(); - const [authorizations, setAuthorizations] = useState(); - const router = useRouter(); - const [csrfToken, setCsrfToken] = useState(''); - - useEffect(async () => { - const tempCSRFToken = crypto.randomBytes(16).toString('hex'); - setCsrfToken(tempCSRFToken); - localStorage.setItem('latestCSRFToken', tempCSRFToken); - - let projectAuthorizations = await getWorkspaceAuthorizations({ - workspaceId: router.query.id - }); - setAuthorizations(projectAuthorizations); - - const projectIntegrations = await getWorkspaceIntegrations({ - workspaceId: router.query.id - }); - setProjectIntegrations(projectIntegrations); - - try { - const integrationsData = await getIntegrations(); - setIntegrations(integrationsData); - } catch (error) { - console.log('Error', error); - } - }, []); - - return integrations ? ( -
- - Dashboard - - - - - -
-
- -
-
-

Current Project Integrations

-
-

- Manage your integrations of Infisical with third-party services. -

-
- {projectIntegrations.length > 0 ? ( - projectIntegrations.map((projectIntegration) => ( - - )) - ) : ( -
-
-
- You {"don't"} have any integrations set up yet. When you do, - they will appear here. -
-
- To start, click on any of the options below. It takes 5 clicks - to set up. -
-
-
- )} -
-
-

- Platform & Cloud Integrations -

-
-

- Click on the itegration you want to connect. This will let your - environment variables flow automatically into selected third-party - services. -

-

- Note: during an integration with Heroku, for security reasons, it - is impossible to maintain end-to-end encryption. In theory, this - lets Infisical decrypt yor environment variables. In practice, we - can assure you that this will never be done, and it allows us to - protect your secrets from bad actors online. The core Infisical - service will always stay end-to-end encrypted. With any questions, - reach out support@infisical.com. -

-
-
- {Object.keys(integrations).map((integration) => ( -
- - integration logo - {integrations[integration].name.split(' ').length > 2 ? ( -
-
{integrations[integration].name.split(' ')[0]}
-
- {integrations[integration].name.split(' ')[1]}{' '} - {integrations[integration].name.split(' ')[2]} -
-
- ) : ( -
- {integrations[integration].name} -
- )} -
- {['Heroku'].includes(integrations[integration].name) && - authorizations - .map((authorization) => authorization.integration) - .includes(integrations[integration].name.toLowerCase()) && ( -
-
{ - deleteIntegrationAuth({ - integrationAuthId: authorizations - .filter( - (authorization) => - authorization.integration == - integrations[integration].name.toLowerCase() - ) - .map((authorization) => authorization._id)[0] - }); - router.reload(); - }} - className="cursor-pointer w-max bg-red py-0.5 px-2 rounded-b-md text-xs flex flex-row items-center opacity-0 group-hover:opacity-100 duration-200" - > - - Revoke -
-
- - Authorized -
-
- )} - {!['Heroku'].includes(integrations[integration].name) && ( -
-
- Coming Soon -
-
- )} -
- ))} -
-
-
-

Framework Integrations

-
-

- Click on a framework to get the setup instructions. -

-
- -
-
-
- ) : ( -
-
- loading animation -
- ); -} - -Integrations.requireAuth = true; diff --git a/frontend/pages/login.tsx b/frontend/pages/login.tsx deleted file mode 100644 index 63dae65a7..000000000 --- a/frontend/pages/login.tsx +++ /dev/null @@ -1,142 +0,0 @@ -import React, { useEffect, useState } from 'react'; -import Head from 'next/head'; -import Image from 'next/image'; -import Link from 'next/link'; -import { useRouter } from 'next/router'; -import { faWarning } from '@fortawesome/free-solid-svg-icons'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; - -import Button from '~/components/basic/buttons/Button'; -import Error from '~/components/basic/Error'; -import InputField from '~/components/basic/InputField'; -import attemptLogin from '~/utilities/attemptLogin'; - -import getWorkspaces from './api/workspace/getWorkspaces'; - -export default function Login() { - const [email, setEmail] = useState(''); - const [password, setPassword] = useState(''); - const [errorLogin, setErrorLogin] = useState(false); - const [isLoading, setIsLoading] = useState(false); - const router = useRouter(); - - useEffect(() => { - const redirectToDashboard = async () => { - let userWorkspace; - try { - const userWorkspaces = await getWorkspaces(); - userWorkspace = userWorkspaces[0]._id; - router.push('/dashboard/' + userWorkspace); - } catch (error) { - console.log('Error - Not logged in yet'); - } - }; - redirectToDashboard(); - }, []); - - /** - * This function check if the user entered the correct credentials and should be allowed to log in. - */ - const loginCheck = async () => { - setIsLoading(true); - await attemptLogin( - email, - password, - setErrorLogin, - router, - false, - true - ).then(() => { - setTimeout(function () { - setIsLoading(false); - }, 2000); - }); - }; - - return ( -
- - Login - - - - - - -
- long logo -
- -
-

- Log in to your account -

-
- -
-
- -
- Forgot password? -
-
- {errorLogin && } -
-
-
-
- {/*
-

I may have forgotten my password.

-
*/} -
- {false && ( -
- - We are experiencing minor technical difficulties. We are working on - solving it right now. Please come back in a few minutes. -
- )} -
-

- Need an Infisical account? -

- - - -
-
- ); -} diff --git a/frontend/pages/noprojects.js b/frontend/pages/noprojects.js deleted file mode 100644 index 2e55b0b4c..000000000 --- a/frontend/pages/noprojects.js +++ /dev/null @@ -1,24 +0,0 @@ -import React from "react"; -import { faFolderOpen } from "@fortawesome/free-regular-svg-icons"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; - -export default function NoProjects() { - return ( -
- -
- You are not part of any projects in this organization yet. When you do, - they will appear here. -
-
- Create a new project, or ask other organization members to give you - neccessary permissions. -
-
- ); -} - -NoProjects.requireAuth = true; diff --git a/frontend/pages/requestnewinvite.js b/frontend/pages/requestnewinvite.js deleted file mode 100644 index be6159988..000000000 --- a/frontend/pages/requestnewinvite.js +++ /dev/null @@ -1,22 +0,0 @@ -import React from "react"; -import Head from "next/head"; - -export default function Activity() { - return ( -
- - Request a New Invite - - -
-

Oops.

-

Your invite has expired.

-

Ask the administrator for a new one.

-

- Note: If it still {"doesn't work"}, please reach out to us at - support@infisical.com -

-
-
- ); -} diff --git a/frontend/pages/settings/billing/[id].js b/frontend/pages/settings/billing/[id].js deleted file mode 100644 index 00d1db23f..000000000 --- a/frontend/pages/settings/billing/[id].js +++ /dev/null @@ -1,109 +0,0 @@ -import React, { useEffect, useState } from "react"; -import Head from "next/head"; - -import Plan from "~/components/billing/Plan"; -import NavHeader from "~/components/navigation/NavHeader"; -import { STRIPE_PRODUCT_PRO, STRIPE_PRODUCT_STARTER } from "~/utilities/config"; - -import getOrganizationSubscriptions from "../../api/organization/GetOrgSubscription"; -import getOrganizationUsers from "../../api/organization/GetOrgUsers"; - -export default function SettingsBilling() { - let [currentPlan, setCurrentPlan] = useState(""); - let [numUsers, setNumUsers] = useState(""); - - const plans = [ - { - key: 1, - name: "Starter", - price: "Free", - priceExplanation: "up to 5 team members", - text: "Manage any project with 5 members for free!", - subtext: "$5 per member/month afterwards.", - buttonTextMain: "Downgrade", - buttonTextSecondary: "Learn More", - current: currentPlan == STRIPE_PRODUCT_STARTER, - }, - { - key: 2, - name: "Professional", - price: "$9", - priceExplanation: "/member/month", - subtext: "Includes unlimited projects & members.", - text: "Keep up with key management as you grow.", - buttonTextMain: "Upgrade", - buttonTextSecondary: "Learn More", - current: currentPlan == STRIPE_PRODUCT_PRO, - }, - { - key: 3, - name: "Enterprise", - price: "Custom Pricing", - text: "More control for advanced organizations.", - buttonTextMain: "Schedule a Demo", - buttonTextSecondary: "Learn More", - current: false, - }, - ]; - - useEffect(async () => { - const subscriptions = await getOrganizationSubscriptions({ - orgId: localStorage.getItem("orgData.id"), - }); - - setCurrentPlan(subscriptions.data[0].plan.id); - const orgUsers = await getOrganizationUsers({ - orgId: localStorage.getItem("orgData.id"), - }); - setNumUsers(orgUsers.length); - }, []); - - return ( -
- - Settings - Billing - - -
-
- -
-
-

- Usage & Billing -

-

- View and manage your {"organization's"} subscription here. -

-
-
-
-

Subscription

-
- {plans.map((plan) => ( - - ))} -
-

Current Usage

-
-
-

{numUsers}

-

- {numUsers > 1 - ? "Organization members" - : "Organization member"} -

-
- {/*
-

1

-

Organization projects

-
*/} -
-
-
-
-
- ); -} - -SettingsBilling.requireAuth = true; diff --git a/frontend/pages/settings/personal/[id].js b/frontend/pages/settings/personal/[id].js deleted file mode 100644 index aa497bbfd..000000000 --- a/frontend/pages/settings/personal/[id].js +++ /dev/null @@ -1,326 +0,0 @@ -import React, { useEffect, useState } from "react"; -import Head from "next/head"; -import { faCheck, faX } from "@fortawesome/free-solid-svg-icons"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; - -import Button from "~/components/basic/buttons/Button"; -import InputField from "~/components/basic/InputField"; -import NavHeader from "~/components/navigation/NavHeader"; -import changePassword from "~/components/utilities/cryptography/changePassword"; -import issueBackupKey from "~/components/utilities/cryptography/issueBackupKey"; -import passwordCheck from "~/utilities/checks/PasswordCheck"; - -import getUser from "../../api/user/getUser"; - -export default function PersonalSettings() { - const [personalEmail, setPersonalEmail] = useState(""); - const [personalName, setPersonalName] = useState(""); - const [passwordErrorLength, setPasswordErrorLength] = useState(false); - const [passwordErrorNumber, setPasswordErrorNumber] = useState(false); - const [passwordErrorLowerCase, setPasswordErrorLowerCase] = useState(false); - const [currentPasswordError, setCurrentPasswordError] = useState(false); - const [currentPassword, setCurrentPassword] = useState(""); - const [newPassword, setNewPassword] = useState(""); - const [backupPassword, setBackupPassword] = useState(""); - const [passwordChanged, setPasswordChanged] = useState(false); - const [backupKeyIssued, setBackupKeyIssued] = useState(false); - const [backupKeyError, setBackupKeyError] = useState(false); - - useEffect(async () => { - let user = await getUser(); - setPersonalEmail(user.email); - setPersonalName(user.firstName + " " + user.lastName); - }, []); - - return ( -
- - Personal Settings - - -
-
- -
-
-

- Personal Settings -

-

- View and manage your personal information here. -

-
-
-
-
-
- {/*
-
-

- Display Name -

- -
-
-
- {buttonReady ? ( - - ) : ( -
- -

- Saved -

-
- )} -
-
-
*/} -
-
-
-
-
-

- Change password -

-
-
-
- { - setCurrentPassword(password); - }} - type="password" - value={currentPassword} - isRequired - error={currentPasswordError} - errorText="The current password may be wrong" - autoComplete="current-password" - id="current-password" - /> -
- { - setNewPassword(password); - passwordCheck({ - password, - setPasswordErrorLength, - setPasswordErrorNumber, - setPasswordErrorLowerCase, - currentErrorCheck: false, - }); - }} - type="password" - value={newPassword} - isRequired - error={ - passwordErrorLength && - passwordErrorLowerCase && - passwordErrorNumber - } - autoComplete="new-password" - id="new-password" - /> -
- {passwordErrorLength || - passwordErrorLowerCase || - passwordErrorNumber ? ( -
-
- Password should contain at least: -
-
- {passwordErrorLength ? ( - - ) : ( - - )} -
- 14 characters -
-
-
- {passwordErrorLowerCase ? ( - - ) : ( - - )} -
- 1 lowercase character -
-
-
- {passwordErrorNumber ? ( - - ) : ( - - )} -
- 1 number -
-
-
- ) : ( -
- )} -
-
-
- -
-
-
-

- Emergency Kit -

-

- Your Emergency Kit contains the information youโ€™ll need to - sign in to your Infisical account. -

-

- Only the latest issued Emergency Kit remains valid. To get a - new Emergency Kit, verify your password. -

-
-
-
- -
-
-
-
-
-
-
-
- ); -} - -PersonalSettings.requireAuth = true; diff --git a/frontend/pages/settings/project/[id].js b/frontend/pages/settings/project/[id].js deleted file mode 100644 index ec4864919..000000000 --- a/frontend/pages/settings/project/[id].js +++ /dev/null @@ -1,275 +0,0 @@ -import React, { useEffect, useRef, useState } from "react"; -import Head from "next/head"; -import { useRouter } from "next/router"; -import { faCheck, faPlus } from "@fortawesome/free-solid-svg-icons"; - -import Button from "~/components/basic/buttons/Button"; -import AddServiceTokenDialog from "~/components/basic/dialog/AddServiceTokenDialog"; -import InputField from "~/components/basic/InputField"; -import ServiceTokenTable from "~/components/basic/table/ServiceTokenTable"; -import NavHeader from "~/components/navigation/NavHeader"; - -import getServiceTokens from "../../api/serviceToken/getServiceTokens"; -import deleteWorkspace from "../../api/workspace/deleteWorkspace"; -import getWorkspaces from "../../api/workspace/getWorkspaces"; -import renameWorkspace from "../../api/workspace/renameWorkspace"; - -export default function SettingsBasic() { - const [buttonReady, setButtonReady] = useState(false); - const router = useRouter(); - const [workspaceName, setWorkspaceName] = useState(""); - const [serviceTokens, setServiceTokens] = useState([]); - const [workspaceToBeDeletedName, setWorkspaceToBeDeletedName] = useState(""); - const [workspaceId, setWorkspaceId] = useState(""); - const [isAddOpen, setIsAddOpen] = useState(false); - let [isAddServiceTokenDialogOpen, setIsAddServiceTokenDialogOpen] = - useState(false); - - useEffect(async () => { - let userWorkspaces = await getWorkspaces(); - userWorkspaces.map((userWorkspace) => { - if (userWorkspace._id == router.query.id) { - setWorkspaceName(userWorkspace.name); - } - }); - let tempServiceTokens = await getServiceTokens({ - workspaceId: router.query.id, - }); - setServiceTokens(tempServiceTokens); - }, []); - - const modifyWorkspaceName = (newName) => { - setButtonReady(true); - setWorkspaceName(newName); - }; - - const submitChanges = (newWorkspaceName) => { - renameWorkspace(router.query.id, newWorkspaceName); - setButtonReady(false); - }; - - useEffect(async () => { - setWorkspaceId(router.query.id); - }, []); - - function closeAddModal() { - setIsAddOpen(false); - } - - function openAddModal() { - setIsAddOpen(true); - } - - const closeAddServiceTokenModal = () => { - setIsAddServiceTokenDialogOpen(false); - }; - - /** - * This function deleted a workspace. - * It first checks if there is more than one workspace aviable. Otherwise, it doesn't delete - * It then checks if the name of the workspace to be deleted is correct. Otherwise, it doesn't delete. - * It then deletes the workspace and forwards the user to another aviable workspace. - */ - const executeDeletingWorkspace = async () => { - let userWorkspaces = await getWorkspaces(); - - if (userWorkspaces.length > 1) { - if ( - userWorkspaces.filter( - (workspace) => workspace._id == router.query.id - )[0].name == workspaceToBeDeletedName - ) { - await deleteWorkspace(router.query.id); - let userWorkspaces = await getWorkspaces(); - router.push("/dashboard/" + userWorkspaces[0]._id); - } - } - }; - - return ( -
- - Settings - - - -
-
- -
-
-

- Project Settings -

-

- These settings only apply to the currently selected Project. -

-
-
-
-
-
-
-

Display Name

-
- -
-
-
-
-
-
-
-

Project ID

-

- To integrate Infisical into your code base and get automatic - injection of environmental variables, you should use the - following Project ID. -

-

- For more guidance, including code snipets for various - languages and frameworks, see{" "} - {/* eslint-disable-next-line react/jsx-no-target-blank */} - - Infisical Docs. - -

-
- -
-
-
-
-
-

- Service Tokens -

-

- Every service token is specific to you, a certain - project and a certain environment within this project. -

-
-
-
-
- -
- - {/*
-

- Project Environments -

-

- Choose which environments will show up - in your Dashboard. Some common ones - include Development, Staging, and - Production. Often, teams choose to add - Testing. -

-

- Note: the text in brackets shows how - these environmant should be accessed in - CLI. -

-
- {envOptions.map((env) => ( -
- {env} -
- ))} -
-
-
-
*/} -
-
-
-

Danger Zone

-

- As soon as you delete this project, you will not be able to undo - it. This will immediately remove all the keys. If you still want - to do that, please enter the name of the project below. -

-
- -
- -

- Note: You can only delete a project in case you have more than - one. -

-
-
-
-
-
- ); -} - -SettingsBasic.requireAuth = true; diff --git a/frontend/pages/signup.tsx b/frontend/pages/signup.tsx deleted file mode 100644 index 8991dc867..000000000 --- a/frontend/pages/signup.tsx +++ /dev/null @@ -1,563 +0,0 @@ -import React, { useEffect, useState } from 'react'; -import ReactCodeInput from 'react-code-input'; -import Head from 'next/head'; -import Image from 'next/image'; -import Link from 'next/link'; -import { useRouter } from 'next/router'; -import { faCheck, faWarning, faX } from '@fortawesome/free-solid-svg-icons'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; - -import Button from '~/components/basic/buttons/Button'; -import Error from '~/components/basic/Error'; -import InputField from '~/components/basic/InputField'; -import Aes256Gcm from '~/components/utilities/cryptography/aes-256-gcm'; -import issueBackupKey from '~/components/utilities/cryptography/issueBackupKey'; -import attemptLogin from '~/utilities/attemptLogin'; -import passwordCheck from '~/utilities/checks/PasswordCheck'; - -import checkEmailVerificationCode from './api/auth/CheckEmailVerificationCode'; -import completeAccountInformationSignup from './api/auth/CompleteAccountInformationSignup'; -import sendVerificationEmail from './api/auth/SendVerificationEmail'; -import getWorkspaces from './api/workspace/getWorkspaces'; - -// const ReactCodeInput = dynamic(import("react-code-input")); -const nacl = require('tweetnacl'); -const jsrp = require('jsrp'); -nacl.util = require('tweetnacl-util'); -const client = new jsrp.client(); - -// The stye for the verification code input -const props = { - inputStyle: { - fontFamily: 'monospace', - margin: '4px', - MozAppearance: 'textfield', - width: '55px', - borderRadius: '5px', - fontSize: '24px', - height: '55px', - paddingLeft: '7', - backgroundColor: '#0d1117', - color: 'white', - border: '1px solid gray', - textAlign: 'center' - } -} as const; -const propsPhone = { - inputStyle: { - fontFamily: 'monospace', - margin: '4px', - MozAppearance: 'textfield', - width: '40px', - borderRadius: '5px', - fontSize: '24px', - height: '40px', - paddingLeft: '7', - backgroundColor: '#0d1117', - color: 'white', - border: '1px solid gray', - textAlign: 'center' - } -} as const; - -export default function SignUp() { - const [email, setEmail] = useState(''); - const [password, setPassword] = useState(''); - const [firstName, setFirstName] = useState(''); - const [lastName, setLastName] = useState(''); - const [code, setCode] = useState(''); - const [codeError, setCodeError] = useState(false); - const [firstNameError, setFirstNameError] = useState(false); - const [lastNameError, setLastNameError] = useState(false); - const [passwordErrorLength, setPasswordErrorLength] = useState(false); - const [passwordErrorNumber, setPasswordErrorNumber] = useState(false); - const [passwordErrorUpperCase, setPasswordErrorUpperCase] = useState(false); - const [passwordErrorLowerCase, setPasswordErrorLowerCase] = useState(false); - const [passwordErrorSpecialChar, setPasswordErrorSpecialChar] = - useState(false); - const [emailError, setEmailError] = useState(false); - const [emailErrorMessage, setEmailErrorMessage] = useState(''); - const [step, setStep] = useState(1); - const router = useRouter(); - const [errorLogin, setErrorLogin] = useState(false); - const [isLoading, setIsLoading] = useState(false); - const [backupKeyError, setBackupKeyError] = useState(false); - const [verificationToken, setVerificationToken] = useState(''); - const [backupKeyIssued, setBackupKeyIssued] = useState(false); - - useEffect(() => { - const tryAuth = async () => { - try { - const userWorkspaces = await getWorkspaces(); - router.push('/dashboard/' + userWorkspaces[0]._id); - } catch (error) { - console.log('Error - Not logged in yet'); - } - }; - tryAuth(); - }, []); - - /** - * Goes to the following step (out of 3) of the signup process. - * Step 1 is submitting your email - * Step 2 is Verifying your email with the code that you received - * Step 3 is Giving the final info. - */ - const incrementStep = async () => { - if (step == 1) { - setStep(2); - } else if (step == 2) { - // Checking if the code matches the email. - const response = await checkEmailVerificationCode({ email, code }); - if (response.status === 200 || code == '111222') { - setVerificationToken((await response.json()).token); - setStep(3); - } else { - setCodeError(true); - } - } else if (step == 3) { - setStep(4); - } - }; - - /** - * Verifies if the entered email "looks" correct - */ - const emailCheck = () => { - let emailCheckBool = false; - if (!email) { - setEmailError(true); - setEmailErrorMessage('Please enter your email.'); - emailCheckBool = true; - } else if ( - !email.includes('@') || - !email.includes('.') || - !/[a-z]/.test(email) - ) { - setEmailError(true); - setEmailErrorMessage('Please enter a valid email.'); - emailCheckBool = true; - } else { - setEmailError(false); - } - - // If everything is correct, go to the next step - if (!emailCheckBool) { - sendVerificationEmail(email); - incrementStep(); - } - }; - - // Verifies if the imformation that the users entered (name, workspace) is there, and if the password matched the criteria. - const signupErrorCheck = async () => { - setIsLoading(true); - let errorCheck = false; - if (!firstName) { - setFirstNameError(true); - errorCheck = true; - } else { - setFirstNameError(false); - } - if (!lastName) { - setLastNameError(true); - errorCheck = true; - } else { - setLastNameError(false); - } - errorCheck = passwordCheck({ - password, - setPasswordErrorLength, - setPasswordErrorNumber, - setPasswordErrorLowerCase, - currentErrorCheck: errorCheck - }); - - if (!errorCheck) { - // Generate a random pair of a public and a private key - const pair = nacl.box.keyPair(); - const secretKeyUint8Array = pair.secretKey; - const publicKeyUint8Array = pair.publicKey; - const PRIVATE_KEY = nacl.util.encodeBase64(secretKeyUint8Array); - const PUBLIC_KEY = nacl.util.encodeBase64(publicKeyUint8Array); - - const { ciphertext, iv, tag } = Aes256Gcm.encrypt({ - text: PRIVATE_KEY, - secret: password - .slice(0, 32) - .padStart( - 32 + (password.slice(0, 32).length - new Blob([password]).size), - '0' - ) - }) as { ciphertext: string; iv: string; tag: string }; - - localStorage.setItem('PRIVATE_KEY', PRIVATE_KEY); - - client.init( - { - username: email, - password: password - }, - async () => { - client.createVerifier( - async (err: any, result: { salt: string; verifier: string }) => { - const response = await completeAccountInformationSignup({ - email, - firstName, - lastName, - organizationName: firstName + "'s organization", - publicKey: PUBLIC_KEY, - ciphertext, - iv, - tag, - salt: result.salt, - verifier: result.verifier, - token: verificationToken - }); - - // if everything works, go the main dashboard page. - if (response.status === 200) { - // response = await response.json(); - - localStorage.setItem('publicKey', PUBLIC_KEY); - localStorage.setItem('encryptedPrivateKey', ciphertext); - localStorage.setItem('iv', iv); - localStorage.setItem('tag', tag); - - try { - await attemptLogin( - email, - password, - setErrorLogin, - router, - true, - false - ); - incrementStep(); - } catch (error) { - setIsLoading(false); - } - } - } - ); - } - ); - } else { - setIsLoading(false); - } - }; - - // Step 1 of the sign up process (enter the email or choose google authentication) - const step1 = ( -
-

- {"Let'"}s get started -

-
- - - -
-
- -
- {/*
- -

I do not want to receive emails about Infisical and its products.

-
*/} -
-

- By creating an account, you agree to our Terms and have read and - acknowledged the Privacy Policy. -

-
-
-
-
- ); - - // Step 2 of the signup process (enter the email verification code) - const step2 = ( -
-

- {"We've"} sent a verification email to{' '} -

-

- {email}{' '} -

-
- -
-
- -
- {codeError && ( - - )} -
-
-
- {/* - - */} -

- Make sure to check your spam inbox. -

-
-
- ); - - // Step 3 of the signup process (enter the rest of the impformation) - const step3 = ( -
-

- Almost there! -

-
- -
-
- -
-
- { - setPassword(password); - passwordCheck({ - password, - setPasswordErrorLength, - setPasswordErrorNumber, - setPasswordErrorLowerCase, - currentErrorCheck: false - }); - }} - type="password" - value={password} - isRequired - error={ - passwordErrorLength && passwordErrorNumber && passwordErrorLowerCase - } - autoComplete="new-password" - id="new-password" - /> - {passwordErrorLength || - passwordErrorLowerCase || - passwordErrorNumber ? ( -
-
- Password should contain at least: -
-
- {passwordErrorLength ? ( - - ) : ( - - )} -
- 14 characters -
-
-
- {passwordErrorLowerCase ? ( - - ) : ( - - )} -
- 1 lowercase character -
-
-
- {passwordErrorNumber ? ( - - ) : ( - - )} -
- 1 number -
-
-
- ) : ( -
- )} -
-
-
-
- ); - - // Step 4 of the sign up process (download the emergency kit pdf) - const step4 = ( -
-

- Save your Emergency Kit -

-
-
- If you get locked out of your account, your Emergency Kit is the only - way to sign in. -
-
- We recommend you download it and keep it somewhere safe. -
-
-
- - It contains your Secret Key which we cannot access or recover for you if - you lose it. -
-
-
-
- ); - - return ( -
- - Infiscal | Sign Up - - - - - -
- -
- Infisical Wide Logo -
- - {step == 1 ? step1 : step == 2 ? step2 : step == 3 ? step3 : step4} -
-
- ); -} diff --git a/frontend/pages/users/[id].js b/frontend/pages/users/[id].js deleted file mode 100644 index fe96ded3a..000000000 --- a/frontend/pages/users/[id].js +++ /dev/null @@ -1,203 +0,0 @@ -import React, { useEffect, useState } from 'react'; -import Head from 'next/head'; -import Image from 'next/image'; -import { useRouter } from 'next/router'; -import { faMagnifyingGlass, faPlus } from '@fortawesome/free-solid-svg-icons'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; - -import Button from '~/components/basic/buttons/Button'; -import AddProjectMemberDialog from '~/components/basic/dialog/AddProjectMemberDialog'; -import UserTable from '~/components/basic/table/UserTable'; -import NavHeader from '~/components/navigation/NavHeader'; -import guidGenerator from '~/utilities/randomId'; - -import getOrganizationUsers from '../api/organization/GetOrgUsers'; -import getUser from '../api/user/getUser'; -// import DeleteUserDialog from '~/components/basic/dialog/DeleteUserDialog'; -import addUserToWorkspace from '../api/workspace/addUserToWorkspace'; -import getWorkspaceUsers from '../api/workspace/getWorkspaceUsers'; -import uploadKeys from '../api/workspace/uploadKeys'; - -// #TODO: Update all the workspaceIds -const crypto = require('crypto'); -const { - decryptAssymmetric, - encryptAssymmetric -} = require('../../components/utilities/cryptography/crypto'); -const nacl = require('tweetnacl'); -nacl.util = require('tweetnacl-util'); - -export default function Users() { - let [isAddOpen, setIsAddOpen] = useState(false); - // let [isDeleteOpen, setIsDeleteOpen] = useState(false); - // let [userIdToBeDeleted, setUserIdToBeDeleted] = useState(false); - let [email, setEmail] = useState(''); - const [personalEmail, setPersonalEmail] = useState(''); - const [searchUsers, setSearchUsers] = useState(''); - - const router = useRouter(); - let workspaceId; - - function closeAddModal() { - setIsAddOpen(false); - } - - // function closeDeleteModal() { - // setIsDeleteOpen(false); - // } - - // function deleteMembership(userId) { - // deleteUserFromWorkspace(userId, router.query.id) - // } - - // function openDeleteModal() { - // setIsDeleteOpen(true); - // } - - async function submitAddModal() { - let result = await addUserToWorkspace(email, router.query.id); - if (result?.invitee && result?.latestKey) { - const PRIVATE_KEY = localStorage.getItem('PRIVATE_KEY'); - - // assymmetrically decrypt symmetric key with local private key - const key = decryptAssymmetric({ - ciphertext: result.latestKey.encryptedKey, - nonce: result.latestKey.nonce, - publicKey: result.latestKey.sender.publicKey, - privateKey: PRIVATE_KEY - }); - - const { ciphertext, nonce } = encryptAssymmetric({ - plaintext: key, - publicKey: result.invitee.publicKey, - privateKey: PRIVATE_KEY - }); - - uploadKeys(router.query.id, result.invitee._id, ciphertext, nonce); - } - setEmail(''); - setIsAddOpen(false); - router.reload(); - } - - function openAddModal() { - setIsAddOpen(true); - } - - const [userList, setUserList] = useState(); - const [orgUserList, setOrgUserList] = useState([]); - // eslint-disable-next-line react-hooks/exhaustive-deps - useEffect(async () => { - const user = await getUser(); - setPersonalEmail(user.email); - - workspaceId = router.query.id; - let workspaceUsers = await getWorkspaceUsers({ - workspaceId - }); - const tempUserList = workspaceUsers.map((user) => ({ - key: guidGenerator(), - firstName: user.user?.firstName, - lastName: user.user?.lastName, - email: user.user?.email == null ? user.inviteEmail : user.user?.email, - role: user?.role, - status: user?.status, - userId: user.user?._id, - membershipId: user._id, - publicKey: user.user?.publicKey - })); - setUserList(tempUserList); - const orgUsers = await getOrganizationUsers({ - orgId: localStorage.getItem('orgData.id') - }); - setOrgUserList(orgUsers); - setEmail( - orgUsers - ?.filter((user) => user.status == 'accepted') - .map((user) => user.user.email) - .filter( - (email) => !tempUserList?.map((user1) => user1.email).includes(email) - )[0] - ); - }, []); - - return userList ? ( -
- - Users - - - -
-

Project Members

-

- This pages shows the members of the selected project. -

-
- user.status == 'accepted') - .map((user) => user.user.email) - .filter( - (email) => !userList?.map((user1) => user1.email).includes(email) - )} - workspaceId={workspaceId} - setEmail={setEmail} - /> - {/* */} -
-
- - setSearchUsers(e.target.value)} - placeholder={'Search members...'} - /> -
-
-
-
-
- -
-
- ) : ( -
-
- loading animation -
- ); -} - -Users.requireAuth = true; diff --git a/frontend/public/data/frequentConstants.ts b/frontend/public/data/frequentConstants.ts index fbc0034d3..2ff525e54 100644 --- a/frontend/public/data/frequentConstants.ts +++ b/frontend/public/data/frequentConstants.ts @@ -1,82 +1,54 @@ -const envMapping = { +interface Mapping { + [key: string]: string; +} + +const envMapping: Mapping = { Development: "dev", Staging: "staging", Production: "prod", Testing: "test", }; - -const reverseEnvMapping = { + +const reverseEnvMapping: Mapping = { dev: "Development", staging: "Staging", prod: "Production", test: "Testing", }; -const frameworks = [{ - "name": "Docker", - "image": "Docker", - "link": "https://infisical.com/docs/integrations/platforms/docker" - }, { - "name": "Docker Compose", - "image": "Docker Compose", - "link": "https://infisical.com/docs/integrations/platforms/docker-compose" - }, { - "name": "React", - "image": "React", - "link": "https://infisical.com/docs/integrations/frameworks/react" - }, { - "name": "Vue", - "image": "Vue", - "link": "https://infisical.com/docs/integrations/frameworks/vue" - }, { - "image": "Express", - "link": "https://infisical.com/docs/integrations/frameworks/express" - },{ - "image": "Next.js", - "link": "https://infisical.com/docs/integrations/frameworks/nextjs" - }, { - "name": "Django", - "image": "Django", - "link": "https://infisical.com/docs/integrations/frameworks/django" - }, { - "name": "NestJS", - "image": "NestJS", - "link": "https://infisical.com/docs/integrations/frameworks/nestjs" - }, { - "name": "Nuxt", - "image": "Nuxt", - "link": "https://infisical.com/docs/integrations/frameworks/nuxt" - }, { - "name": "Gatsby", - "image": "Gatsby", - "link": "https://infisical.com/docs/integrations/frameworks/gatsby" - }, { - "name": "Remix", - "image": "Remix", - "link": "https://infisical.com/docs/integrations/frameworks/remix" - }, { - "name": "Vite", - "image": "Vite", - "link": "https://infisical.com/docs/integrations/frameworks/vite" - }, { - "image": "Fiber", - "link": "https://infisical.com/docs/integrations/frameworks/fiber" - }, { - "name": "Flask", - "image": "Flask", - "link": "https://infisical.com/docs/integrations/frameworks/flask" - }, { - "name": "Laravel", - "image": "Laravel", - "link": "https://infisical.com/docs/integrations/frameworks/laravel" - }, { - "image": "Rails", - "link": "https://infisical.com/docs/integrations/frameworks/rails" - } -] +const contextNetlifyMapping: Mapping = { + "dev": "Local development", + "branch-deploy": "Branch deploys", + "deploy-review": "Deploy Previews", + "production": "Production" +} + +const reverseContextNetlifyMapping: Mapping = { + "Local development": "dev", + "Branch deploys": "branch-deploy", + "Deploy Previews": "deploy-preview", + "Production": "production" +} + +const plansDev: Mapping = { + "starter": "prod_Mb4ATFT5QAHoPM", + "team": "prod_NEpD2WMXUS2eDn", + "professional": "prod_Mb4CetZ2jE7jdl", + "enterprise": "licence_key_required" +} + +const plansProd: Mapping = { + "starter": "prod_Mb8oR5XNwyFTul", + "team": "prod_NEp7fAB3UJWK6A", + "professional": "prod_Mb8pUIpA0OUi5N", + "enterprise": "licence_key_required" +} + +const plans = plansProd || plansDev; export { + contextNetlifyMapping, envMapping, - frameworks, - reverseEnvMapping -}; + plans, + reverseContextNetlifyMapping, + reverseEnvMapping} diff --git a/frontend/public/data/frequentInterfaces.ts b/frontend/public/data/frequentInterfaces.ts new file mode 100644 index 000000000..c2fa797fd --- /dev/null +++ b/frontend/public/data/frequentInterfaces.ts @@ -0,0 +1,8 @@ +export interface SecretDataProps { + pos: number; + key: string; + value: string; + valueOverride: string | undefined; + id: string; + comment: string; +} \ No newline at end of file diff --git a/frontend/public/images/dragon-404.svg b/frontend/public/images/dragon-404.svg new file mode 100644 index 000000000..dcd7f715a --- /dev/null +++ b/frontend/public/images/dragon-404.svg @@ -0,0 +1,475 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/frontend/public/images/dragon-cant-find.svg b/frontend/public/images/dragon-cant-find.svg new file mode 100644 index 000000000..8a6eed443 --- /dev/null +++ b/frontend/public/images/dragon-cant-find.svg @@ -0,0 +1,246 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/public/images/dragon-signupinvite.svg b/frontend/public/images/dragon-signupinvite.svg new file mode 100644 index 000000000..7a69f1dc5 --- /dev/null +++ b/frontend/public/images/dragon-signupinvite.svg @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/public/images/integrations/Flyio.svg b/frontend/public/images/integrations/Flyio.svg new file mode 100644 index 000000000..0d0086b7e --- /dev/null +++ b/frontend/public/images/integrations/Flyio.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/public/images/integrations/GitHub.png b/frontend/public/images/integrations/GitHub.png new file mode 100644 index 000000000..9490ffc6d Binary files /dev/null and b/frontend/public/images/integrations/GitHub.png differ diff --git a/frontend/public/images/integrations/Render.png b/frontend/public/images/integrations/Render.png new file mode 100644 index 000000000..39103f5e4 Binary files /dev/null and b/frontend/public/images/integrations/Render.png differ diff --git a/frontend/public/images/integrations/Vercel.png b/frontend/public/images/integrations/Vercel.png new file mode 100644 index 000000000..7bdcd2a19 Binary files /dev/null and b/frontend/public/images/integrations/Vercel.png differ diff --git a/frontend/public/images/invitation-expired.svg b/frontend/public/images/invitation-expired.svg new file mode 100644 index 000000000..9ac60e82f --- /dev/null +++ b/frontend/public/images/invitation-expired.svg @@ -0,0 +1,305 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/public/json/frameworkIntegrations.json b/frontend/public/json/frameworkIntegrations.json new file mode 100644 index 000000000..fb8b30c9e --- /dev/null +++ b/frontend/public/json/frameworkIntegrations.json @@ -0,0 +1,98 @@ +[ + { + "name": "Docker", + "slug": "docker", + "image": "Docker", + "docsLink": "https://infisical.com/docs/integrations/platforms/docker" + }, + { + "name": "Docker Compose", + "slug": "docker-compose", + "image": "Docker Compose", + "docsLink": "https://infisical.com/docs/integrations/platforms/docker-compose" + }, + { + "name": "React", + "slug": "react", + "image": "React", + "docsLink": "https://infisical.com/docs/integrations/frameworks/react" + }, + { + "name": "Vue", + "slug": "vue", + "image": "Vue", + "docsLink": "https://infisical.com/docs/integrations/frameworks/vue" + }, + { + "name": "Express", + "slug": "express", + "image": "Express", + "docsLink": "https://infisical.com/docs/integrations/frameworks/express" + }, + { + "name": "Next.js", + "slug": "nextjs", + "image": "Next.js", + "docsLink": "https://infisical.com/docs/integrations/frameworks/nextjs" + }, + { + "name": "Django", + "slug": "django", + "image": "Django", + "docsLink": "https://infisical.com/docs/integrations/frameworks/django" + }, + { + "name": "NestJS", + "slug": "nestjs", + "image": "NestJS", + "docsLink": "https://infisical.com/docs/integrations/frameworks/nestjs" + }, + { + "name": "Nuxt", + "slug": "nuxt", + "image": "Nuxt", + "docsLink": "https://infisical.com/docs/integrations/frameworks/nuxt" + }, + { + "name": "Gatsby", + "slug": "gatsby", + "image": "Gatsby", + "docsLink": "https://infisical.com/docs/integrations/frameworks/gatsby" + }, + { + "name": "Remix", + "slug": "remix", + "image": "Remix", + "docsLink": "https://infisical.com/docs/integrations/frameworks/remix" + }, + { + "name": "Vite", + "slug": "vite", + "image": "Vite", + "docsLink": "https://infisical.com/docs/integrations/frameworks/vite" + }, + { + "name": "Fiber", + "slug": "fiber", + "image": "Fiber", + "docsLink": "https://infisical.com/docs/integrations/frameworks/fiber" + }, + { + "name": "Flask", + "slug": "flask", + "image": "Flask", + "docsLink": "https://infisical.com/docs/integrations/frameworks/flask" + }, + { + "name": "Laravel", + "slug": "laravel", + "image": "Laravel", + "docsLink": "https://infisical.com/docs/integrations/frameworks/laravel" + }, + { + "name": "Rails", + "slug": "rails", + "image": "Rails", + "docsLink": "https://infisical.com/docs/integrations/frameworks/rails" + } +] \ No newline at end of file diff --git a/frontend/public/locales/en/activity.json b/frontend/public/locales/en/activity.json new file mode 100644 index 000000000..648e4d42c --- /dev/null +++ b/frontend/public/locales/en/activity.json @@ -0,0 +1,11 @@ +{ + "title": "Activity Logs", + "subtitle": "Event history for this Infisical project.", + "event": { + "readSecrets": "Secrets Viewed", + "updateSecrets": "Secrets Updated", + "addSecrets": "Secrets Added", + "deleteSecrets": "Secrets Deleted" + }, + "ip-address": "IP Address" +} diff --git a/frontend/public/locales/en/billing.json b/frontend/public/locales/en/billing.json new file mode 100644 index 000000000..20c43c0a3 --- /dev/null +++ b/frontend/public/locales/en/billing.json @@ -0,0 +1,28 @@ +{ + "title": "Usage & Billing", + "description": "View and manage your organization's subscription here", + "subscription": "Subscription", + "starter": { + "name": "Starter", + "price-explanation": "up to 5 team members", + "text": "Manage any project with 5 members for free!", + "subtext": "$5 per member/month afterwards." + }, + "professional": { + "name": "Professional", + "price-explanation": "/member/month", + "subtext": "Includes unlimited projects & members.", + "text": "Keep up with key management as you grow." + }, + "enterprise": { + "name": "Enterprise", + "text": "Keep up with key management as you grow." + }, + "current-usage": "Current Usage", + "free": "Free", + "downgrade": "Downgrade", + "upgrade": "Upgrade", + "learn-more": "Learn More", + "custom-pricing": "Custom Pricing", + "schedule-demo": "Schedule a Demo" +} diff --git a/frontend/public/locales/en/common.json b/frontend/public/locales/en/common.json new file mode 100644 index 000000000..e02c4f474 --- /dev/null +++ b/frontend/public/locales/en/common.json @@ -0,0 +1,34 @@ +{ + "head-title": "{{title}} | Infisical", + "error_project-already-exists": "A project with this name already exists.", + "no-mobile": " To use Infisical, please log in through a device with larger dimensions. ", + "email": "Email", + "password": "Password", + "first-name": "First Name", + "last-name": "Last Name", + "logout": "Log Out", + "validate-required": "Please input your {{name}}", + "maintenance-alert": "We are experiencing minor technical difficulties. We are working on solving it right now. Please come back in a few minutes.", + "click-to-copy": "Click to copy", + "project-id": "Project ID", + "save-changes": "Save Changes", + "saved": "Saved", + "drop-zone": "Drag and drop a .env or .yml file here.", + "drop-zone-keys": "Drag and drop a .env or .yml file here to add more keys.", + "role": "Role", + "role_admin": "admin", + "display-name": "Display Name", + "environment": "Environment", + "expired-in": "Expires in", + "language": "Language", + "search": "Search...", + "note": "Note", + "view-more": "View More", + "end-of-history": "End of History", + "select-event": "Select an event", + "event": "Event", + "user": "User", + "source": "Source", + "time": "Time", + "timestamp": "Timestamp" +} \ No newline at end of file diff --git a/frontend/public/locales/en/dashboard.json b/frontend/public/locales/en/dashboard.json new file mode 100644 index 000000000..263887360 --- /dev/null +++ b/frontend/public/locales/en/dashboard.json @@ -0,0 +1,36 @@ +{ + "title": "Secrets", + "og-title": "Manage your .env files in seconds", + "og-description": "Infisical a simple end-to-end encrypted platform that enables teams to sync and manage their .env files.", + "search-keys": "Search keys...", + "add-key": "Add Key", + "personal": "Personal", + "personal-description": "Personal keys are only visible to you", + "shared": "Shared", + "shared-description": "Shared keys are visible to your whole team", + "make-shared": "Make Shared", + "make-personal": "Make Personal", + "add-secret": "Add a new secret", + "check-docs": { + "button": "Check Docs", + "title": "Good job!", + "line1": "Congrats on adding more secrets.", + "line2": "Here is how to connect them to your codebase." + }, + "sidebar": { + "secret": "Secret", + "key": "Key", + "value": "Value", + "override": "Override value with a personal value", + "version-history": "Version History", + "comments": "Comments & Notes", + "personal-explanation": "This secret is personal. It is not shared with any of your teammates.", + "generate-random-hex": "Generate Random Hex", + "digits": "digits", + "delete-key-dialog": { + "title": "Delete Key", + "confirm-delete-message": "Are you sure you want to delete this secret? This cannot be undone." + } + } + +} diff --git a/frontend/public/locales/en/integrations.json b/frontend/public/locales/en/integrations.json new file mode 100644 index 000000000..1fc92ca4e --- /dev/null +++ b/frontend/public/locales/en/integrations.json @@ -0,0 +1,16 @@ +{ + "title": "Project Integrations", + "description": "Manage your integrations of Infisical with third-party services.", + "no-integrations1": "You don't have any integrations set up yet. When you do, they will appear here.", + "no-integrations2": "To start, click on any of the options below. It takes 5 clicks to set up.", + "available": "Platform & Cloud Integrations", + "available-text1": "Click on the integration you want to connect. This will let your environment variables flow automatically into selected third-party services.", + "available-text2": "Note: during an integration with Heroku, for security reasons, it is impossible to maintain end-to-end encryption. In theory, this lets Infisical decrypt yor environment variables. In practice, we can assure you that this will never be done, and it allows us to protect your secrets from bad actors online. The core Infisical service will always stay end-to-end encrypted. With any questions, reach out support@infisical.com.", + "cloud-integrations": "Cloud Integrations", + "framework-integrations": "Framework Integrations", + "click-to-start": "Click on an integration to begin syncing secrets to it.", + "click-to-setup": "Click on a framework to get the setup instructions.", + "grant-access-to-secrets": "Grant Infisical access to your secrets", + "why-infisical-needs-access": "Most cloud integrations require Infisical to be able to decrypt your secrets so they can be forwarded over.", + "grant-access-button": "Grant access" +} diff --git a/frontend/public/locales/en/login.json b/frontend/public/locales/en/login.json new file mode 100644 index 000000000..75b56a014 --- /dev/null +++ b/frontend/public/locales/en/login.json @@ -0,0 +1,10 @@ +{ + "title": "Login", + "og-title": "Log In to Infisical", + "og-description": "Infisical a simple end-to-end encrypted platform that enables teams to sync and manage their .env files.", + "login": "Log In", + "need-account": "Need an Infisical account?", + "create-account": "Create an account", + "forgot-password": "Forgot your password?", + "error-login": "Wrong credentials." +} diff --git a/frontend/public/locales/en/nav.json b/frontend/public/locales/en/nav.json new file mode 100644 index 000000000..de5218619 --- /dev/null +++ b/frontend/public/locales/en/nav.json @@ -0,0 +1,22 @@ +{ + "support": { + "slack": "[NEW] Join Slack Forum", + "docs": "Read Docs", + "issue": "Open a Github Issue", + "email": "Send us an Email" + }, + "user": { + "signed-in-as": "SIGNED IN AS", + "current-organization": "CURRENT ORGANIZATION", + "usage-billing": "Usage & Billing", + "invite": "Invite Members", + "other-organizations": "OTHER ORGANIZATION" + }, + "menu": { + "project": "PROJECT", + "secrets": "Secrets", + "members": "Members", + "integrations": "Integrations", + "project-settings": "Project Settings" + } +} diff --git a/frontend/public/locales/en/section-api-key.json b/frontend/public/locales/en/section-api-key.json new file mode 100644 index 000000000..3419744fe --- /dev/null +++ b/frontend/public/locales/en/section-api-key.json @@ -0,0 +1,13 @@ +{ + "api-keys": "Service Tokens", + "api-keys-description": "Every service token is specific to you, a certain project and a certain environment within this project.", + "add-new": "Add New Token", + "add-dialog": { + "title": "Add an API Key", + "description": "Specify the name and expiry period. When an API key is generated, you will only be able to see it once before it disappears. Make sure to save it somewhere.", + "name": "API Key Name", + "add": "Add API Key", + "copy-service-token": "Copy your API key", + "copy-service-token-description": "Once you close this popup, you will never see your API key again" + } +} diff --git a/frontend/public/locales/en/section-incident.json b/frontend/public/locales/en/section-incident.json new file mode 100644 index 000000000..de8f3e7b7 --- /dev/null +++ b/frontend/public/locales/en/section-incident.json @@ -0,0 +1,11 @@ +{ + "incident-contacts": "Incident Contacts", + "incident-contacts-description": "These contacts will be notified in the unlikely event of a severe incident.", + "no-incident-contacts": "No incident contacts found.", + "add-contact": "Add Contact", + "add-dialog": { + "title": "Add an Incident Contact", + "description": "This contact will be notified in the unlikely event of a severe incident.", + "add-incident": "Add Incident Contact" + } +} diff --git a/frontend/public/locales/en/section-members.json b/frontend/public/locales/en/section-members.json new file mode 100644 index 000000000..89dbd2fea --- /dev/null +++ b/frontend/public/locales/en/section-members.json @@ -0,0 +1,14 @@ +{ + "add-member": "Add Member", + "org-members": "Organization Members", + "org-members-description": "Manage members of your organization. These users could afterwards be formed into projects.", + "search-members": "Search members...", + "add-dialog": { + "add-member-to-project": "Add a member to your project", + "already-all-invited": "All the users in your organization are already invited.", + "add-user-org-first": "Add more users to the organization first.", + "user-will-email": "The user will receive an email with the instructions.", + "looking-add": "<0>If you are looking to add users to your org,<1>click here", + "add-user-to-org": "Add Users to Organization" + } +} diff --git a/frontend/public/locales/en/section-password.json b/frontend/public/locales/en/section-password.json new file mode 100644 index 000000000..9c0410d6c --- /dev/null +++ b/frontend/public/locales/en/section-password.json @@ -0,0 +1,11 @@ +{ + "password": "Password", + "change": "Change password", + "current": "Current password", + "current-wrong": "The current password may be wrong", + "new": "New password", + "validate-base": "Password should contain at least:", + "validate-length": "14 characters", + "validate-case": "1 lowercase character", + "validate-number": "1 number" +} diff --git a/frontend/public/locales/en/section-token.json b/frontend/public/locales/en/section-token.json new file mode 100644 index 000000000..d12bd202c --- /dev/null +++ b/frontend/public/locales/en/section-token.json @@ -0,0 +1,13 @@ +{ + "service-tokens": "Service Tokens", + "service-tokens-description": "Every service token is specific to you, a certain project and a certain environment within this project.", + "add-new": "Add New Token", + "add-dialog": { + "title": "Add a service token for {{target}}", + "description": "Specify the name, environment, and expiry period. When a token is generated, you will only be able to see it once before it disappears. Make sure to save it somewhere.", + "name": "Service Token Name", + "add": "Add Service Token", + "copy-service-token": "Copy your service token", + "copy-service-token-description": "Once you close this popup, you will never see your service token again" + } +} diff --git a/frontend/public/locales/en/settings-members.json b/frontend/public/locales/en/settings-members.json new file mode 100644 index 000000000..128a649a0 --- /dev/null +++ b/frontend/public/locales/en/settings-members.json @@ -0,0 +1,4 @@ +{ + "title": "Project Members", + "description": "This page shows the members of the selected project, and allows you to modify their permissions." +} diff --git a/frontend/public/locales/en/settings-org.json b/frontend/public/locales/en/settings-org.json new file mode 100644 index 000000000..d17baa7cd --- /dev/null +++ b/frontend/public/locales/en/settings-org.json @@ -0,0 +1,4 @@ +{ + "title": "Organization Settings", + "description": "Manage members of your organization. These users could afterwards be formed into projects." +} diff --git a/frontend/public/locales/en/settings-personal.json b/frontend/public/locales/en/settings-personal.json new file mode 100644 index 000000000..66a90b6c3 --- /dev/null +++ b/frontend/public/locales/en/settings-personal.json @@ -0,0 +1,16 @@ +{ + "title": "Personal Settings", + "description": "View and manage your personal information here.", + "emergency": { + "name": "Emergency Kit", + "text1": "Your Emergency Kit contains the information youโ€™ll need to sign in to your Infisical account.", + "text2": "Only the latest issued Emergency Kit remains valid. To get a new Emergency Kit, verify your password.", + "download": "Download Emergency Kit" + }, + "change-language": "Change Language", + "api-keys": { + "title": "API Keys", + "description": "Manage your personal API Keys to access the Infisical API.", + "add-new": "Add new" + } +} diff --git a/frontend/public/locales/en/settings-project.json b/frontend/public/locales/en/settings-project.json new file mode 100644 index 000000000..03e4b1459 --- /dev/null +++ b/frontend/public/locales/en/settings-project.json @@ -0,0 +1,13 @@ +{ + "title": "Project Settings", + "description": "These settings only apply to the currently selected Project.", + "danger-zone": "Danger Zone", + "delete-project": "Delete Project", + "project-to-delete": "Project to be Deleted", + "danger-zone-note": "As soon as you delete this project, you will not be able to undo it. This will immediately remove all the keys. If you still want to do that, please enter the name of the project below.", + "delete-project-note": "Note: You can only delete a project in case you have more than one", + "project-id-description": "To integrate Infisical into your code base and get automatic injection of environmental variables, you should use the following Project ID.", + "project-id-description2": "For more guidance, including code snipets for various languages and frameworks, see ", + "auto-generated": "This is your project's auto-generated unique identifier. It can't be changed.", + "docs": "Infisical Docs" +} diff --git a/frontend/public/locales/en/signup.json b/frontend/public/locales/en/signup.json new file mode 100644 index 000000000..bee993727 --- /dev/null +++ b/frontend/public/locales/en/signup.json @@ -0,0 +1,28 @@ +{ + "title": "Sign Up", + "og-title": "Replace .env files with 1 line of code. Sign Up for Infisical in 3 minutes.", + "og-description": "Infisical a simple end-to-end encrypted platform that enables teams to sync and manage API-keys and environemntal variables. Works with Node.js, Next.js, Gatsby, Nest.js...", + "signup": "Sign Up", + "already-have-account": "Have an account? Log in", + "forgot-password": "Forgot your password?", + "verify": "Verify", + "step1-start": "Let's get started", + "step1-privacy": "By creating an account, you agree to our Terms and have read and acknowledged the Privacy Policy.", + "step1-submit": "Get Started", + "step2-message": "We've sent a verification email to", + "step2-code-error": "Oops. Your code is wrong. Please try again.", + "step2-resend-alert": "Don't see the email?", + "step2-resend-submit": "Resend", + "step2-resend-progress": "Resending...", + "step2-spam-alert": "Make sure to check your spam inbox.", + "step3-message": "Almost there!", + "step4-message": "Save your Emergency Kit", + "step4-description1": "If you get locked out of your account, your Emergency Kit is the only way to sign in.", + "step4-description2": "We recommend you download it and keep it somewhere safe.", + "step4-description3": "It contains your Secret Key which we cannot access or recover for you if you lose it.", + "step4-download": "Download PDF", + "step5-send-invites": "Send Invites", + "step5-invite-team": "Invite your team", + "step5-subtitle": "Infisical is meant to be used with your teammates. Invite them to test it out.", + "step5-skip": "Skip" +} diff --git a/frontend/public/locales/fr/activity.json b/frontend/public/locales/fr/activity.json new file mode 100644 index 000000000..4360d7d0c --- /dev/null +++ b/frontend/public/locales/fr/activity.json @@ -0,0 +1,11 @@ +{ + "title": "Journaux d'activitรฉ", + "subtitle": "Historique des รฉvรฉnements pour ce projet Infisical.", + "event": { + "readSecrets": "Secrets Visualisรฉs", + "updateSecrets": "Secrets Mis ร  jour", + "addSecrets": "Secrets Ajoutรฉs", + "deleteSecrets": "Secrets Supprimรฉs" + }, + "ip-address": "Adresse IP" +} diff --git a/frontend/public/locales/fr/billing.json b/frontend/public/locales/fr/billing.json new file mode 100644 index 000000000..1acb44339 --- /dev/null +++ b/frontend/public/locales/fr/billing.json @@ -0,0 +1,28 @@ +{ + "title": "Utilisation et Facturation", + "description": "Voir et gรฉrer l'abonnement de votre organisation ici", + "subscription": "Abonnement", + "starter": { + "name": "Starter", + "price-explanation": "jusqu'ร  5 membres de l'รฉquipe", + "text": "Gรฉrez n'importe quel projet jusqu'ร  5 membres gratuitement!", + "subtext": "$5 par membre / mois par la suite." + }, + "professional": { + "name": "Professionnel", + "price-explanation": "/membre/mois", + "subtext": "Comprend des projets et des membres illimitรฉs.", + "text": "Suivez la gestion clรฉ ร  mesure que vous grandissez." + }, + "enterprise": { + "name": "Entreprise", + "text": "Suivez la gestion clรฉ ร  mesure que vous grandissez." + }, + "current-usage": "Utilisation actuelle", + "free": "Gratuit", + "downgrade": "Rรฉtrograder", + "upgrade": "Amรฉliorer", + "learn-more": "En savoir plus", + "custom-pricing": "Prix personnalisรฉs", + "schedule-demo": "Planifier une dรฉmo" +} diff --git a/frontend/public/locales/fr/common.json b/frontend/public/locales/fr/common.json new file mode 100644 index 000000000..1f6a52447 --- /dev/null +++ b/frontend/public/locales/fr/common.json @@ -0,0 +1,34 @@ +{ + "head-title": "{{title}} | Infisical", + "error_project-already-exists": "Un projet avec ce nom existe dรฉjร .", + "no-mobile": " Pour utiliser Infisical, veuillez vous connecter avec un appareil avec des dimensions plus grandes. ", + "email": "Email", + "password": "Mot de passe", + "first-name": "Prรฉnom", + "last-name": "Nom", + "logout": "Dรฉconnexion", + "validate-required": "Veuillez saisir votre {{name}}", + "maintenance-alert": "Nous rencontrons des difficultรฉs techniques mineures. Nous travaillons sur leurs rรฉsolution dรจs maintenant. Revenez dans quelques minutes.", + "click-to-copy": "Cliquez pour copiez", + "project-id": "Identifiant du Projet", + "save-changes": "Sauvegarder les modifications", + "saved": "Enregistrรฉe", + "drop-zone": "Glissez et dรฉposez un fichier .env ou .yml ici.", + "drop-zone-keys": "Glissez et dรฉposez un fichier .env ou .yml ici pour ajouter plus de clรฉs.", + "role": "Rรดle", + "role_admin": "administrateur", + "display-name": "Nom d'affichage", + "environment": "Environnement", + "expired-in": "Expire dans", + "language": "Langue", + "search": "Recherche...", + "note": "Note", + "view-more": "Voir plus", + "end-of-history": "Fin de l'historique", + "select-event": "Sรฉlectionnez un รฉvรฉnement", + "event": "ร‰vรฉnement", + "user": "Utilisateur", + "source": "Source", + "time": "Heure", + "timestamp": "Horodatage" +} \ No newline at end of file diff --git a/frontend/public/locales/fr/dashboard.json b/frontend/public/locales/fr/dashboard.json new file mode 100644 index 000000000..f90bf1fc2 --- /dev/null +++ b/frontend/public/locales/fr/dashboard.json @@ -0,0 +1,36 @@ +{ + "title": "Secrets", + "og-title": "Gรฉrez vos fichiers .env rapidement", + "og-description": "Infisical une plate-forme simple et chiffrรฉ de bout en bout qui permet aux รฉquipes de synchroniser et de gรฉrer leurs fichiers .env.", + "search-keys": "Recherche les clefs...", + "add-key": "Ajouter une clef", + "personal": "Personnel", + "personal-description": "Les clรฉs personnelles ne sont visibles que pour vous", + "shared": "Partagรฉ", + "shared-description": "Les clรฉs partagรฉes sont visibles ร  toute votre รฉquipe", + "make-shared": "Rendre Partagรฉ", + "make-personal": "Rendre Personnel", + "add-secret": "Ajouter un nouveau secret", + "check-docs": { + "button": "Vรฉrifier la documentation", + "title": "Bon travail!", + "line1": "Fรฉlicitations pour avoir ajoutรฉ plus de secrets.", + "line2": "Voici comment les connecter ร  votre base de code." + }, + "sidebar": { + "secret": "Secret", + "key": "Clef", + "value": "Valeur", + "override": "Remplacer la valeur avec une valeur personnelle", + "version-history": "Historique des versions", + "comments": "Commentaires & Notes", + "personal-explanation": "Ce secret est personnel. Il n'est partagรฉ avec aucun de vos coรฉquipiers.", + "generate-random-hex": "Gรฉnรฉrer un Hex alรฉatoire", + "digits": "chiffres", + "delete-key-dialog": { + "title": "Supprimer la clef", + "confirm-delete-message": "รŠtes-vous sรปr de vouloir supprimer ce secret? Cela ne peut pas รชtre annulรฉ." + } + } + +} diff --git a/frontend/public/locales/fr/integrations.json b/frontend/public/locales/fr/integrations.json new file mode 100644 index 000000000..887e79dfd --- /dev/null +++ b/frontend/public/locales/fr/integrations.json @@ -0,0 +1,16 @@ +{ + "title": "Intรฉgrations de Projet", + "description": "Gรฉrez vos intรฉgrations d'Infisical avec des services tiers.", + "no-integrations1": "Vous n'avez pas encore d'intรฉgration. Quand vous en aurez, elles apparaรฎtront ici.", + "no-integrations2": "Pour commencer, cliquez sur l'une des options ci-dessous. La configuration se fait en 5 clics.", + "available": "Intรฉgrations de plate-forme et cloud", + "available-text1": "Cliquez sur l'intรฉgration que vous souhaitez connecter. Cela permettra ร  vos variables d'environnement de circuler automatiquement dans les services tiers sรฉlectionnรฉs.", + "available-text2": "Remarque: Lors d'une intรฉgration avec Heroku, pour des raisons de sรฉcuritรฉ, il est impossible de maintenir le chiffrage de bout en bout. En thรฉorie, cela permet ร  Infisical de dรฉchiffrer les variables d'environnement. En pratique, nous pouvons vous assurer que cela ne sera jamais fait, et cela nous permet de protรฉger vos secrets des mauvais acteurs en ligne. Le service Infisical de base restera toujours chiffrรฉ de bout en bout. Pour toutes vos intรฉrogations, contactez support@infisical.com.", + "cloud-integrations": "Intรฉgrations Cloud", + "framework-integrations": "Intรฉgrations Framework", + "click-to-start": "Cliquez sur une intรฉgration pour commencer ร  synchroniser les secrets avec elle.", + "click-to-setup": "Cliquez sur un framework pour obtenir les instructions de configuration.", + "grant-access-to-secrets": "Accordez un accรจs Infisical ร  vos secrets", + "why-infisical-needs-access": "La plupart des intรฉgrations cloud nรฉcessitent qu'Infisical puisse dรฉchiffrer vos secrets afin qu'ils puissent รชtre transmis.", + "grant-access-button": "Autoriser l'accรจs" +} diff --git a/frontend/public/locales/fr/login.json b/frontend/public/locales/fr/login.json new file mode 100644 index 000000000..8c93da9fb --- /dev/null +++ b/frontend/public/locales/fr/login.json @@ -0,0 +1,10 @@ +{ + "title": "Connexion", + "og-title": "Connectez-vous ร  Infisical", + "og-description": "Infisical, une plate-forme simple et chiffrรฉ de bout en bout permettant aux รฉquipes de synchroniser et de gรฉrer leurs fichiers .env.", + "login": "Se connecter", + "need-account": "Besoin d'un compte Infisical?", + "create-account": "Crรฉer un compte", + "forgot-password": "Mot de passe oubliรฉ?", + "error-login": "Mauvais identifiants." +} diff --git a/frontend/public/locales/fr/nav.json b/frontend/public/locales/fr/nav.json new file mode 100644 index 000000000..1fda27af9 --- /dev/null +++ b/frontend/public/locales/fr/nav.json @@ -0,0 +1,22 @@ +{ + "support": { + "slack": "[NEW] Rejoignez le forum Slack", + "docs": "Lire les documentations", + "issue": "Ouvrir une issue Github", + "email": "Envoyez-nous un email" + }, + "user": { + "signed-in-as": "CONNECTร‰ EN TANT QUE", + "current-organization": "ORGANISATION ACTUELLE", + "usage-billing": "Utilisation & Facturation", + "invite": "Inviter des membres", + "other-organizations": "AUTRE ORGANISATION" + }, + "menu": { + "project": "PROJET", + "secrets": "Secrets", + "members": "Membres", + "integrations": "Intรฉgrations", + "project-settings": "Paramรจtres du Projet" + } +} diff --git a/frontend/public/locales/fr/section-incident.json b/frontend/public/locales/fr/section-incident.json new file mode 100644 index 000000000..95b77ea13 --- /dev/null +++ b/frontend/public/locales/fr/section-incident.json @@ -0,0 +1,11 @@ +{ + "incident-contacts": "Contacts Incidents", + "incident-contacts-description": "Ces contacts seront informรฉs dans le cas improbable d'un incident grave.", + "no-incident-contacts": "Aucun contact incident trouvรฉ.", + "add-contact": "Ajouter un contact", + "add-dialog": { + "title": "Ajouter un contact incident", + "description": "Ce contact sera informรฉ dans le cas improbable d'un incident grave.", + "add-incident": "Ajouter un contact incident" + } +} diff --git a/frontend/public/locales/fr/section-members.json b/frontend/public/locales/fr/section-members.json new file mode 100644 index 000000000..8faed80e7 --- /dev/null +++ b/frontend/public/locales/fr/section-members.json @@ -0,0 +1,14 @@ +{ + "add-member": "Ajouter un Membre", + "org-members": "Membres de l'organisation", + "org-members-description": "Gรฉrer les membres de votre organisation. Ces utilisateurs pourraient ensuite รชtre rรฉpartis en projets.", + "search-members": "Recherche des membres...", + "add-dialog": { + "add-member-to-project": "Ajoutez un membre ร  votre projet", + "already-all-invited": "Tous les utilisateurs de votre organisation sont dรฉjร  invitรฉs.", + "add-user-org-first": "Ajoutez d'abord plus d'utilisateurs ร  l'organisation.", + "user-will-email": "L'utilisateur recevra un email avec les instructions.", + "looking-add": "<0>Si vous cherchez ร  ajouter des utilisateurs ร  votre organisation,<1>cliquez ici", + "add-user-to-org": "Ajouter des Utilisateurs ร  l'Organisation" + } +} diff --git a/frontend/public/locales/fr/section-password.json b/frontend/public/locales/fr/section-password.json new file mode 100644 index 000000000..0928233e6 --- /dev/null +++ b/frontend/public/locales/fr/section-password.json @@ -0,0 +1,11 @@ +{ + "password": "Mot de passe", + "change": "Changer le mot de passe", + "current": "Mot de passe actuel", + "current-wrong": "Le mot de passe actuel peut รชtre รฉrronรฉ", + "new": "Nouveau mot de passe", + "validate-base": "Le mot de passe doit contenir au moins:", + "validate-length": "14 caractรจres", + "validate-case": "1 caractรจre miniscule", + "validate-number": "1 chiffre" +} diff --git a/frontend/public/locales/fr/section-token.json b/frontend/public/locales/fr/section-token.json new file mode 100644 index 000000000..1f2a3b233 --- /dev/null +++ b/frontend/public/locales/fr/section-token.json @@ -0,0 +1,13 @@ +{ + "service-tokens": "Jetons de service", + "service-tokens-description": "Chaque jeton de service vous est spรฉcifique, ร  un certain projet et ร  un certain environnement dans ce projet.", + "add-new": "Ajouter un nouveau jeton", + "add-dialog": { + "title": "Ajouter un jeton de service pour {{target}}", + "description": "Spรฉcifiez le nom, l'environnement et la pรฉriode d'expiration. Lorsqu'un jeton est gรฉnรฉrรฉ, vous ne pourrez le voir qu'une seule fois avant qu'il ne disparaisse. Assurez-vous de le sauvegarder quelque part.", + "name": "Nom du jeton de service", + "add": "Ajouter un jeton de service", + "copy-service-token": "Copiez votre jeton de service", + "copy-service-token-description": "Une fois que vous aurez fermรฉ cette fenรชtre, vous ne reverrez plus jamais votre jeton de service" + } +} diff --git a/frontend/public/locales/fr/settings-members.json b/frontend/public/locales/fr/settings-members.json new file mode 100644 index 000000000..9f34c7a68 --- /dev/null +++ b/frontend/public/locales/fr/settings-members.json @@ -0,0 +1,4 @@ +{ + "title": "Membres du projet", + "description": "Cette page affiche les membres du projet sรฉlectionnรฉ." +} diff --git a/frontend/public/locales/fr/settings-org.json b/frontend/public/locales/fr/settings-org.json new file mode 100644 index 000000000..952bd68c8 --- /dev/null +++ b/frontend/public/locales/fr/settings-org.json @@ -0,0 +1,4 @@ +{ + "title": "Paramรจtres d'Organisation", + "description": "Gรฉrer les membres de votre organisation. Ces utilisateurs pourraient ensuite รชtre rรฉpartis en projets." +} diff --git a/frontend/public/locales/fr/settings-personal.json b/frontend/public/locales/fr/settings-personal.json new file mode 100644 index 000000000..30a3d6fa3 --- /dev/null +++ b/frontend/public/locales/fr/settings-personal.json @@ -0,0 +1,11 @@ +{ + "title": "Paramรจtres Personnels", + "description": "Consultez et gรฉrez vos informations personnelles ici.", + "emergency": { + "name": "Kit d'urgence", + "text1": "Votre kit d'urgence contient les informations dont vous aurez besoin pour vous connecter ร  votre compte Infisical.", + "text2": "Seul le dernier kit d'urgence รฉmis reste valide. Pour obtenir un nouveau kit d'urgence, vรฉrifiez votre mot de passe.", + "download": "Tรฉlรฉcharger le kit d'urgence" + }, + "change-language": "Changer de langue" +} diff --git a/frontend/public/locales/fr/settings-project.json b/frontend/public/locales/fr/settings-project.json new file mode 100644 index 000000000..a5a3f1ee3 --- /dev/null +++ b/frontend/public/locales/fr/settings-project.json @@ -0,0 +1,13 @@ +{ + "title": "Paramรจtres du Projet", + "description": "Ces paramรจtres ne s'appliquent qu'au Projet actuellement sรฉlectionnรฉ.", + "danger-zone": "Zone de danger", + "delete-project": "Supprimer le Projet", + "project-to-delete": "Projet ร  Supprimer", + "danger-zone-note": "Dรจs que vous supprimez ce projet, vous ne pourrez plus revenir en arriรจre. Cela supprimera immรฉdiatement toutes les clefs. Si vous voulez toujours le faire, veuillez saisir le nom du projet ci-dessous.", + "delete-project-note": "Remarque: Vous ne pouvez supprimer qu'un projet que si vous en avez plus d'un.", + "project-id-description": "Pour intรฉgrer Infisical dans votre base de code et obtenir une injection automatique de variables d'environnement, vous devez utiliser l'ID du projet suivant.", + "project-id-description2": "Pour plus de conseils, y compris des extraits de code pour diverses langues et frameworks, voir ", + "auto-generated": "Ceci est l'identifiant unique gรฉnรฉrรฉ automatiquement pour votre projet. Il ne peut pas รชtre modifiรฉ.", + "docs": "Documentation Infisical" +} diff --git a/frontend/public/locales/fr/signup.json b/frontend/public/locales/fr/signup.json new file mode 100644 index 000000000..48b36e203 --- /dev/null +++ b/frontend/public/locales/fr/signup.json @@ -0,0 +1,28 @@ +{ + "title": "S'inscrire", + "og-title": "Remplacez les fichiers .env par 1 ligne de code. Inscrivez-vous ร  Infisical en 3 minutes.", + "og-description": "Infisical, une plate-forme simple et chiffrรฉ de bout en bout qui permet aux รฉquipes de synchroniser et de gรฉrer des clefs API et des variables d'environnement. Fonctionne avec Node.js, Next.js, Gatsby, Nest.js ...", + "signup": "S'inscrire", + "already-have-account": "Dรฉjร  inscris? Se connecter", + "forgot-password": "Mot de passe oubliรฉ?", + "verify": "Vรฉrifier", + "step1-start": "Bon, on commence!", + "step1-privacy": "En crรฉant votre compte, vous acceptez nos conditions et avez lu et reconnu notre politique de confidentialitรฉ.", + "step1-submit": "C'est parti", + "step2-message": "Nous avons envoyรฉ un email de vรฉrification ร ", + "step2-code-error": "Oops. Votre code est faux. Veuillez rรฉessayer.", + "step2-resend-alert": "Vous ne voyez pas l'email?", + "step2-resend-submit": "Renvoyer", + "step2-resend-progress": "Envoie en cours...", + "step2-spam-alert": "Assurez-vous de vรฉrifier vos spams.", + "step3-message": "Nous y sommes presque!", + "step4-message": "Enregistrez votre kit d'urgence", + "step4-description1": "Si vous n'arrivez plus ร  vous connecter ร  votre compte, votre kit d'urgence est le seul moyen d'y arriver.", + "step4-description2": "Nous vous recommandons de le tรฉlรฉcharger et de le garder en sรฉcuritรฉ.", + "step4-description3": "Il contient votre clef secrรจte que nous ne pouvons pas rรฉcupรฉrer pour vous si vous la perdez.", + "step4-download": "Tรฉlรฉchargez le PDF", + "step5-send-invites": "Envoyer les invitations", + "step5-invite-team": "Invitez votre รฉquipe", + "step5-subtitle": "Infisical a pour but d'รชtre utilisรฉ avec vos coรฉquipiers. Invitez-les ร  le tester.", + "step5-skip": "Passer" +} diff --git a/frontend/public/locales/ko/billing.json b/frontend/public/locales/ko/billing.json new file mode 100644 index 000000000..788afa8e4 --- /dev/null +++ b/frontend/public/locales/ko/billing.json @@ -0,0 +1,28 @@ +{ + "title": "์š”๊ธˆ์ œ & ๊ฒฐ์ œ", + "description": "์ด๊ณณ์—์„œ ์กฐ์ง์˜ ๊ตฌ๋…์„ ํ™•์ธํ•˜๊ณ  ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์–ด์š”.", + "subscription": "๊ตฌ๋…", + "starter": { + "name": "์Šคํƒ€ํ„ฐ", + "price-explanation": "5๋ช…์˜ ํŒ€ ๋งด๋ฒ„๊นŒ์ง€", + "text": "์–ด๋–ค ํ”„๋กœ์ ํŠธ๋“  ๋‹ค์„ฏ๋ช…์˜ ๋งด๋ฒ„๊นŒ์ง€ ๋ฌด๋ฃŒ๋กœ ์ด์šฉํ•  ์ˆ˜ ์žˆ์–ด์š”!", + "subtext": "$5๋ช…/๋‹ฌ ๋กœ ๋ฐ”๋€” ์˜ˆ์ •์ž…๋‹ˆ๋‹ค." + }, + "professional": { + "name": "์ „๋ฌธ๊ฐ€", + "price-explanation": "/๋งด๋ฒ„/๋‹ฌ", + "subtext": "๋ฌด์ œํ•œ์˜ ํ”„๋กœ์ ํŠธ์™€ ๋งด๋ฒ„", + "text": "์กฐ์ง์˜ ์„ฑ์žฅ์— ๋”ฐ๋ผ ์œ ์—ฐํ•˜๊ฒŒ ์‹œํฌ๋ฆฟ์„ ๊ด€๋ฆฌํ•˜์„ธ์š”." + }, + "enterprise": { + "name": "์—”ํ„ฐํ”„๋ผ์ด์ฆˆ", + "text": "์กฐ์ง์˜ ์„ฑ์žฅ์— ๋”ฐ๋ผ ์œ ์—ฐํ•˜๊ฒŒ ์‹œํฌ๋ฆฟ์„ ๊ด€๋ฆฌํ•˜์„ธ์š”." + }, + "current-usage": "ํ˜„์žฌ ์š”๊ธˆ์ œ", + "free": "๋ฌด๋ฃŒ", + "downgrade": "๋‹ค์šด๊ทธ๋ ˆ์ด๋“œ", + "upgrade": "์—…๊ทธ๋ ˆ์ด๋“œ", + "learn-more": "์ž์„ธํžˆ ์•Œ์•„๋ณด๊ธฐ", + "custom-pricing": "์ปค์Šคํ…€ ๊ฐ€๊ฒฉ", + "schedule-demo": "๋ฐ๋ชจ ์˜ˆ์•ฝํ•˜๊ธฐ" +} diff --git a/frontend/public/locales/ko/common.json b/frontend/public/locales/ko/common.json new file mode 100644 index 000000000..f0692ebf7 --- /dev/null +++ b/frontend/public/locales/ko/common.json @@ -0,0 +1,26 @@ +{ + "head-title": "{{title}} | Infisical", + "error_project-already-exists": "๋™์ผํ•œ ์ด๋ฆ„์„ ๊ฐ€์ง„ ํ”„๋กœ์ ํŠธ๊ฐ€ ์ด๋ฏธ ์กด์žฌํ•ด์š”.", + "no-mobile": " Infisical์„ ์‚ฌ์šฉํ•˜๋ ค๋ฉด, ํฐ ํ™”๋ฉด์„ ๊ฐ€์ง„ ๋””๋ฐ”์ด์Šค๋กœ ๋กœ๊ทธ์ธํ•˜์—ฌ ์ฃผ์„ธ์š”.", + "email": "๋ฉ”์ผ", + "password": "๋น„๋ฐ€๋ฒˆํ˜ธ", + "first-name": "์ด๋ฆ„", + "last-name": "์„ฑ", + "logout": "๋กœ๊ทธ์•„์›ƒ", + "validate-required": "{{name}} ์„/๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”.", + "maintenance-alert": "We are experiencing minor technical difficulties. We are working on solving it right now. Please come back in a few minutes.", + "click-to-copy": "ํด๋ฆญํ•˜์—ฌ ๋ณต์‚ฌํ•˜๊ธฐ", + "project-id": "ํ”„๋กœ์ ํŠธ ID", + "save-changes": "๋ณ€๊ฒฝ์‚ฌํ•ญ ์ €์žฅํ•˜๊ธฐ", + "saved": "์ €์žฅ๋จ", + "drop-zone": ".env ํŒŒ์ผ์„ ์ด๊ณณ์— ๋“œ๋ž˜๊ทธ & ๋“œ๋กญ ํ•˜์„ธ์š”.", + "drop-zone-keys": "์ด๊ณณ์— .env ํŒŒ์ผ์„ ๋“œ๋ž˜๊ทธ & ๋“œ๋กญ ํ•˜์—ฌ ๋” ๋งŽ์€ ํ‚ค๋“ค์„ ์ถ”๊ฐ€ํ•˜์„ธ์š”.", + "role": "Role", + "role_admin": "admin", + "display-name": "ํ‘œ์‹œ ์ด๋ฆ„", + "environment": "ํ™˜๊ฒฝ", + "expired-in": "๋งŒ๋ฃŒ ๊ธฐํ•œ:", + "language": "์–ธ์–ด", + "search": "๊ฒ€์ƒ‰ํ•˜๊ธฐ...", + "note": "Note" +} \ No newline at end of file diff --git a/frontend/public/locales/ko/dashboard.json b/frontend/public/locales/ko/dashboard.json new file mode 100644 index 000000000..73fcf155b --- /dev/null +++ b/frontend/public/locales/ko/dashboard.json @@ -0,0 +1,30 @@ +{ + "title": "์‹œํฌ๋ฆฟ", + "og-title": "๋น ๋ฅด๊ฒŒ .env ํŒŒ์ผ์„ ๊ด€๋ฆฌํ•˜์„ธ์š”", + "og-description": "Infisical์€ ํŒ€์›๊ณผ .envํŒŒ์ผ์„ ๊ณต์œ ํ•  ์ˆ˜ ์žˆ๋Š” ์‹ฌํ”Œํ•œ end-to-end ์•”ํ˜ธํ™” ํ”Œ๋ ›ํผ์ž…๋‹ˆ๋‹ค.", + "search-keys": "ํ‚ค ๊ฒ€์ƒ‰ํ•˜๊ธฐ...", + "add-key": "ํ‚ค ์ถ”๊ฐ€ํ•˜๊ธฐ", + "personal": "๊ฐœ์ธ", + "personal-description": "๊ฐœ์ธ ํ‚ค๋Š” ์˜ค์ง ๋ณธ์ธ๋งŒ ๋ณผ ์ˆ˜ ์žˆ์–ด์š”", + "shared": "๊ณต์œ ", + "shared-description": "๊ณต์œ  ํ‚ค๋Š” ํŒ€ ์ „์ฒด๊ฐ€ ๋ณผ ์ˆ˜ ์žˆ์–ด์š”", + "make-shared": "๊ณต์œ ๋กœ ๋งŒ๋“ค๊ธฐ", + "make-personal": "๊ฐœ์ธ์œผ๋กœ ๋งŒ๋“ค๊ธฐ", + "check-docs": { + "button": "๋ฌธ์„œ ํ™•์ธํ•˜๊ธฐ", + "title": "์ข‹์•˜์–ด์š”!", + "line1": "๋” ๋งŽ์€ ์‹œํฌ๋ฆฟ๋“ค์„ ์ถ”๊ฐ€ํ•œ ๊ฒƒ์„ ์ถ•ํ•˜ํ•ฉ๋‹ˆ๋‹ค.", + "line2": "์ฝ”๋“œ์™€ ์—ฐ๊ฒฐํ•˜๋Š” ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ํ•œ๋ฒˆ ์•Œ์•„๋ณด์ง€ ์•Š์„๋ž˜์š”?" + }, + "sidebar": { + "secret": "Secret", + "key": "Key", + "value": "Value", + "override": "Override value with a personal value", + "version-history": "Version History", + "comments": "Comments & Notes", + "personal-explanation": "This secret is personal. It is not shared with any of your teammates.", + "generate-random-hex": "Generate Random Hex", + "digits": "digits" + } +} diff --git a/frontend/public/locales/ko/integrations.json b/frontend/public/locales/ko/integrations.json new file mode 100644 index 000000000..7431831ae --- /dev/null +++ b/frontend/public/locales/ko/integrations.json @@ -0,0 +1,16 @@ +{ + "available": "์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์—ฐ๋™", + "available-text1": "์—ฐ๊ฒฐํ•˜๊ณ  ์‹ถ์€ ์„œ๋น„์Šค๋ฅผ ํด๋ฆญํ•˜์„ธ์š”. ํ™˜๊ฒฝ ๋ณ€์ˆ˜๊ฐ€ ์„ ํƒํ•œ ์™ธ๋ถ€ ์„œ๋น„์Šค์™€ ์ž๋™์œผ๋กœ ์—ฐ๋™๋ฉ๋‹ˆ๋‹ค.", + "available-text2": "์ฐธ๊ณ : Heroku์™€์˜ ์—ฐ๋™์—์„œ๋Š” ๋ณด์•ˆ์ƒ์˜ ์ด์œ ๋กœ End-To-End ์•”ํ˜ธํ™”๋ฅผ ์œ ์ง€ํ•˜๋Š” ๊ฒƒ์ด ๋ถˆ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ์ด๋ก ์ ์œผ๋กœ๋Š” Infisical์ด ์‹œํฌ๋ฆฟ์„ ์ฝ๋Š”๊ฒƒ์ด ๊ฐ€๋Šฅํ•˜์ง€๋งŒ, ์ ˆ๋Œ€ ๊ทธ๋Ÿฌ์ง€ ์•Š๋Š”๋‹ค๊ณ  ํ™•์‹ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•ต์‹ฌ Infisical ์„œ๋น„์Šค๋Š” ํ•ญ์ƒ End-To-End ์•”ํ˜ธํ™” ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค. ์งˆ๋ฌธ์ด ์žˆ์œผ๋ฉด support@infisical.com์œผ๋กœ ๋ฌธ์˜ํ•˜์„ธ์š”.", + "description": "์™ธ๋ถ€ ์„œ๋น„์Šค์™€ ํ•จ๊ป˜ Infisical์„ ์—ฐ๋™ํ•˜๊ณ  ๊ด€๋ฆฌํ•˜์„ธ์š”", + "no-integrations1": "์—ฐ๋™๋œ ์„œ๋น„์Šค๊ฐ€ ์—†์–ด์š”. ์—ฐ๋™ํ•˜๊ฒŒ ๋œ๋‹ค๋ฉด ์ด๊ณณ์—์„œ ํ‘œ์‹œ๋ผ์š”.", + "no-integrations2": "์‹œ์ž‘ํ•˜๋ ค๋ฉด, ์•„๋ž˜์˜ ์˜ต์…˜์„ ํด๋ฆญํ•˜์„ธ์š”. ๋Œ€์ฒด๋กœ 5๋ถ„ ์ด๋‚ด๋กœ ๊ฐ€๋Šฅํ•ด์š”.", + "title": "ํ”„๋กœ์ ํŠธ ์—ฐ๋™", + "cloud-integrations": "Cloud Integrations", + "framework-integrations": "Framework Integrations", + "click-to-start": "Click on an integration to begin syncing secrets to it.", + "click-to-setup": "Click on a framework to get the setup instructions.", + "grant-access-to-secrets": "Grant Infisical access to your secrets", + "why-infisical-needs-access": "Most cloud integrations require Infisical to be able to decrypt your secrets so they can be forwarded over.", + "grant-access-button": "Grant access" +} diff --git a/frontend/public/locales/ko/login.json b/frontend/public/locales/ko/login.json new file mode 100644 index 000000000..70a77d69f --- /dev/null +++ b/frontend/public/locales/ko/login.json @@ -0,0 +1,8 @@ +{ + "title": "๋กœ๊ทธ์ธ", + "og-title": "Infisical์— ๋กœ๊ทธ์ธํ•˜๊ธฐ", + "og-description": "Infisical a simple end-to-end encrypted platform that enables teams to sync and manage their .env files.", + "login": "๋กœ๊ทธ์ธ", + "need-account": "Infisical๊ณ„์ •์ด ํ•„์š”ํ•˜์‹ ๊ฐ€์š”?", + "create-account": "ํšŒ์›๊ฐ€์ž… ํ•˜๊ธฐ" +} diff --git a/frontend/public/locales/ko/nav.json b/frontend/public/locales/ko/nav.json new file mode 100644 index 000000000..b07510ff4 --- /dev/null +++ b/frontend/public/locales/ko/nav.json @@ -0,0 +1,22 @@ +{ + "support": { + "slack": "[NEW] ์Šฌ๋ž™ ํฌ๋Ÿผ์— ๊ฐ€์ž…ํ•˜๊ธฐ", + "docs": "๋ฌธ์„œ ๋ณด๊ธฐ", + "issue": "๊นƒํ—ˆ๋ธŒ ์ด์Šˆ ์—ด๊ธฐ", + "email": "InfisicalํŒ€์—๊ฒŒ ๋ฉ”์ผ ๋ณด๋‚ด๊ธฐ" + }, + "user": { + "signed-in-as": "๋‹ค์Œ์œผ๋กœ ๋กœ๊ทธ์ธ๋จ", + "current-organization": "ํ˜„์žฌ ์กฐ์ง", + "usage-billing": "์š”๊ธˆ์ œ & ๊ฒฐ์ œ", + "invite": "๋งด๋ฒ„ ์ดˆ๋Œ€ํ•˜๊ธฐ", + "other-organizations": "๋‹ค๋ฅธ ์กฐ์ง" + }, + "menu": { + "project": "ํ”„๋กœ์ ํŠธ", + "secrets": "์‹œํฌ๋ฆฟ", + "members": "๋งด๋ฒ„", + "integrations": "์—ฐ๋™", + "project-settings": "ํ”„๋กœ์ ํŠธ ์„ค์ •" + } +} diff --git a/frontend/public/locales/ko/section-incident.json b/frontend/public/locales/ko/section-incident.json new file mode 100644 index 000000000..cbafc5ecb --- /dev/null +++ b/frontend/public/locales/ko/section-incident.json @@ -0,0 +1,11 @@ +{ + "add-contact": "์—ฐ๋ฝ์ฒ˜ ์ถ”๊ฐ€ํ•˜๊ธฐ", + "add-dialog": { + "add-incident": "๋น„์ƒ ์—ฐ๋ฝ์ฒ˜ ์ถ”๊ฐ€ํ•˜๊ธฐ", + "description": "์ค‘๋Œ€ํ•œ ์ผ์ด ์ƒ๊ธธ ๊ฒฝ์šฐ, ์ด ์—ฐ๋ฝ์ฒ˜๋กœ ์•Œ๋ฆผ์ด ์ „์†ก๋ฉ๋‹ˆ๋‹ค.", + "title": "๋น„์ƒ ์—ฐ๋ฝ์ฒ˜ ์ถ”๊ฐ€ํ•˜๊ธฐ" + }, + "incident-contacts": "๋น„์ƒ ์—ฐ๋ฝ๋ง", + "incident-contacts-description": "์ค‘๋Œ€ํ•œ ์ผ์ด ์ƒ๊ธธ ๊ฒฝ์šฐ, ์•„๋ž˜์˜ ์—ฐ๋ฝ์ฒ˜๋กœ ์•Œ๋ฆผ์ด ์ „์†ก๋ฉ๋‹ˆ๋‹ค.", + "no-incident-contacts": "๋น„์ƒ ์—ฐ๋ฝ๋ง์ด ์กด์žฌํ•˜์ง€ ์•Š์•„์š”." +} diff --git a/frontend/public/locales/ko/section-members.json b/frontend/public/locales/ko/section-members.json new file mode 100644 index 000000000..848574aff --- /dev/null +++ b/frontend/public/locales/ko/section-members.json @@ -0,0 +1,14 @@ +{ + "add-member": "๋งด๋ฒ„ ์ถ”๊ฐ€ํ•˜๊ธฐ", + "org-members": "์กฐ์ง ๋งด๋ฒ„", + "search-members": "๋งด๋ฒ„๋ฅผ ๊ฒ€์ƒ‰ํ•˜๊ธฐ...", + "add-dialog": { + "add-member-to-project": "ํ”„๋กœ์ ํŠธ์— ๋งด๋ฒ„ ์ถ”๊ฐ€ํ•˜๊ธฐ", + "already-all-invited": "์กฐ์ง์˜ ๋ชจ๋“  ์œ ์ €๊ฐ€ ์ด๋ฏธ ์ดˆ๋Œ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค.", + "add-user-org-first": "์œ ์ €๋ฅผ ๋จผ์ € ์กฐ์ง์— ์ถ”๊ฐ€ํ•ด ์ฃผ์„ธ์š”.", + "user-will-email": "์œ ์ €๋Š” ์•ˆ๋‚ด๊ฐ€ ํฌํ•จ๋œ ๋ฉ”์ผ์„ ๋ฐ›๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.", + "looking-add": "<0>์กฐ์ง์— ์œ ์ €๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด,<1>์—ฌ๊ธฐ๋ฅผ ํด๋ฆญํ•˜์„ธ์š”", + "add-user-to-org": "์กฐ์ง์— ์œ ์ € ์ถ”๊ฐ€ํ•˜๊ธฐ" + }, + "org-members-description": "์กฐ์ง์˜ ๋งด๋ฒ„๋“ค์„ ๊ด€๋ฆฌํ•˜์„ธ์š”." +} diff --git a/frontend/public/locales/ko/section-password.json b/frontend/public/locales/ko/section-password.json new file mode 100644 index 000000000..e7c6a6b74 --- /dev/null +++ b/frontend/public/locales/ko/section-password.json @@ -0,0 +1,11 @@ +{ + "password": "๋น„๋ฐ€๋ฒˆํ˜ธ", + "change": "๋น„๋ฐ€๋ฒˆํ˜ธ ๋ณ€๊ฒฝ", + "current": "ํ˜„์žฌ ๋น„๋ฐ€๋ฒˆํ˜ธ", + "new": "์ƒˆ ๋น„๋ฐ€๋ฒˆํ˜ธ", + "current-wrong": "ํ˜„์žฌ ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ์ž˜๋ชป๋˜์—ˆ์–ด์š”", + "validate-base": "๋น„๋ฐ€๋ฒˆํ˜ธ๋Š” ๋‹ค์Œ ์กฐ๊ฑด์„ ๋งŒ์กฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค:", + "validate-length": "14 ๊ธ€์ž ์ด์ƒ", + "validate-case": "1๊ฐœ ์ด์ƒ์˜ ์†Œ๋ฌธ์ž", + "validate-number": "1๊ฐœ ์ด์ƒ์˜ ์ˆซ์ž" +} diff --git a/frontend/public/locales/ko/section-token.json b/frontend/public/locales/ko/section-token.json new file mode 100644 index 000000000..936c6066c --- /dev/null +++ b/frontend/public/locales/ko/section-token.json @@ -0,0 +1,13 @@ +{ + "add-dialog": { + "add": "์„œ๋น„์Šค ํ† ํฐ ์ถ”๊ฐ€ํ•˜๊ธฐ", + "copy-service-token": "์„œ๋น„์Šค ํ† ํฐ ๋ณต์‚ฌํ•˜๊ธฐ", + "copy-service-token-description": "ํŒ์—…์„ ๋‹ซ์„ ์‹œ ๋‹ค์‹œ๋Š” ํ† ํฐ์„ ํ™•์ธํ•  ์ˆ˜ ์—†์–ด์š”.", + "description": "์ด๋ฆ„, ํ™˜๊ฒฝ, ๋งŒ๋ฃŒ์ผ์„ ์ง€์ •ํ•˜์„ธ์š”. ํ† ํฐ์ด ์ƒ์„ฑ๋˜๋ฉด ์ตœ์ดˆ ํ•œ๋ฒˆ๋งŒ ๋ณผ ์ˆ˜ ์žˆ์–ด์š”. ์•ˆ์ „ํ•œ ๊ณณ์— ์ €์žฅํ•˜์„ธ์š”.", + "name": "์„œ๋น„์Šค ํ† ํฐ ์ด๋ฆ„", + "title": "{{target}}์˜ ํ† ํฐ ์ถ”๊ฐ€ํ•˜๊ธฐ" + }, + "add-new": "์ƒˆ ํ† ํฐ ์ถ”๊ฐ€ํ•˜๊ธฐ", + "service-tokens": "์„œ๋น„์Šค ํ† ํฐ", + "service-tokens-description": "๋ชจ๋“  ์„œ๋น„์Šค ํ† ํฐ์€ ํ”„๋กœ์ ํŠธ ๋ฐ ํ™˜๊ฒฝ์— ๋”ฐ๋ผ ๋‹ค๋ฆ…๋‹ˆ๋‹ค." +} diff --git a/frontend/public/locales/ko/settings-members.json b/frontend/public/locales/ko/settings-members.json new file mode 100644 index 000000000..5954b2bb5 --- /dev/null +++ b/frontend/public/locales/ko/settings-members.json @@ -0,0 +1,4 @@ +{ + "title": "๋งด๋ฒ„ ์„ค์ •", + "description": "์„ ํƒํ•œ ํ”„๋กœ์ ํŠธ์˜ ๋งด๋ฒ„๋ฅผ ํ™•์ธํ•˜์„ธ์š”." +} diff --git a/frontend/public/locales/ko/settings-org.json b/frontend/public/locales/ko/settings-org.json new file mode 100644 index 000000000..64b5e5e3e --- /dev/null +++ b/frontend/public/locales/ko/settings-org.json @@ -0,0 +1,4 @@ +{ + "title": "์กฐ์ง ์„ค์ •", + "description": "์กฐ์ง์˜ ๋งด๋ฒ„๋ฅผ ๊ด€๋ฆฌํ•˜์„ธ์š”." +} diff --git a/frontend/public/locales/ko/settings-personal.json b/frontend/public/locales/ko/settings-personal.json new file mode 100644 index 000000000..2234272e4 --- /dev/null +++ b/frontend/public/locales/ko/settings-personal.json @@ -0,0 +1,11 @@ +{ + "title": "๊ฐœ์ธ ์„ค์ •", + "description": "๊ณ„์ • ๋ฐ ๊ธฐ๋ณธ์ ์ธ ์„ค์ •์„ ํ™•์ธํ•˜๊ณ  ๋ณ€๊ฒฝํ•˜์„ธ์š”.", + "emergency": { + "name": "๊ธด๊ธ‰๋ณต๊ตฌ ํ‚คํŠธ", + "text1": "๊ธด๊ธ‰๋ณต๊ตฌ ํ‚คํŠธ๋Š” Infisical๊ณ„์ •์— ๋กœ๊ทธ์ธ ํ•  ์ˆ˜ ์žˆ๋Š” ์ •๋ณด๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์–ด์š”.", + "text2": "์˜ค์ง ๋งˆ์ง€๋ง‰์œผ๋กœ ๋ฐœ๊ธ‰ํ•œ ๊ธด๊ธ‰๋ณต๊ตฌ ํ‚คํŠธ๋งŒ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•ด์š”. ์ƒˆ๋กœ์šด ๊ธด๊ธ‰๋ณต๊ตฌ ํ‚คํŠธ๋ฅผ ๋ฐ›์œผ๋ ค๋ฉด, ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”.", + "download": "๊ธด๊ธ‰๋ณต๊ตฌ ํ‚คํŠธ ๋‹ค์šด๋กœ๋“œ" + }, + "change-language": "์–ธ์–ด ๋ณ€๊ฒฝํ•˜๊ธฐ" +} diff --git a/frontend/public/locales/ko/settings-project.json b/frontend/public/locales/ko/settings-project.json new file mode 100644 index 000000000..8dca5941c --- /dev/null +++ b/frontend/public/locales/ko/settings-project.json @@ -0,0 +1,13 @@ +{ + "title": "ํ”„๋กœ์ ํŠธ ์„ค์ •", + "description": "ํ˜„์žฌ ์„ ํƒํ•œ ํ”„๋กœ์ ํŠธ์— ๋Œ€ํ•ด์„œ ์„ค์ •ํ•ด์š”.", + "auto-generated": "์ž๋™์œผ๋กœ ์ƒ์„ฑ๋œ ๊ณ ์œ ํ•œ ํ‚ค ์ž…๋‹ˆ๋‹ค. ๋ณ€๊ฒฝํ•  ์ˆ˜ ์—†์–ด์š”.", + "danger-zone": "์œ„ํ—˜์กด", + "danger-zone-note": "ํ”„๋กœ์ ํŠธ๋ฅผ ์‚ญ์ œํ•œ๋‹ค๋ฉด ๋ชจ๋“  ํ‚ค๊ฐ€ ์ฆ‰์‹œ ์‚ญ์ œ๋˜๋ฉฐ ๋‹ค์‹œ๋Š” ๋˜๋Œ๋ฆด ์ˆ˜ ์—†์–ด์š”. ์‚ญ์ œ๋ฅผ ์›ํ•œ๋‹ค๋ฉด ํ”„๋กœ์ ํŠธ ์ด๋ฆ„์„ ์•„๋ž˜์— ์ ์–ด์ฃผ์„ธ์š”.", + "delete-project": "ํ”„๋กœ์ ํŠธ ์‚ญ์ œ", + "delete-project-note": "๋…ธํŠธ: ์ตœ์†Œ ํ•œ๊ฐœ ์ด์ƒ์˜ ํ”„๋กœ์ ํŠธ๋Š” ์กฐ์ง์— ์กด์žฌํ•ด์•ผ ํ•ด์š”.", + "docs": "Infisical ๋ฌธ์„œ", + "project-id-description": "๋‹ค๋ฅธ ์ฝ”๋“œ์—์„œ Infisical๊ณผ ํ™˜๊ฒฝ๋ณ€์ˆ˜๋ฅผ ์—ฐ๋™ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ํ”„๋กœ์ ํŠธ ID๊ฐ€ ํ•„์š”ํ•ด์š”.", + "project-id-description2": "๋‹ค์–‘ํ•œ ์–ธ์–ด ๋ฐ ํ”„๋ ˆ์ž„์›Œํฌ์— ๋Œ€ํ•œ ๊ฐ€์ด๋“œ๋ฅผ ํ™•์ธํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด, ๋‹ค์Œ์„ ํ™•์ธํ•˜์„ธ์š”. ", + "project-to-delete": "์‚ญ์ œํ•  ํ”„๋กœ์ ํŠธ" +} diff --git a/frontend/public/locales/ko/signup.json b/frontend/public/locales/ko/signup.json new file mode 100644 index 000000000..3b4576963 --- /dev/null +++ b/frontend/public/locales/ko/signup.json @@ -0,0 +1,21 @@ +{ + "title": "ํšŒ์›๊ฐ€์ž…", + "og-title": "ํ•œ์ค„์˜ ์ฝ”๋“œ๋ฅด .envํŒŒ์ผ์„ ๊ต์ฒดํ•˜์„ธ์š”. 3๋ถ„์ด๋ฉด ๊ฐ€์ž…ํ•  ์ˆ˜ ์žˆ์–ด์š”.", + "og-description": "Infisical์€ ํŒ€์›๊ณผ .envํŒŒ์ผ์„ ๊ณต์œ ํ•˜๊ณ  ์—ฐ๋™ํ•  ์ˆ˜ ์žˆ๋Š” ์‹ฌํ”Œํ•œ end-to-end ์•”ํ˜ธํ™” ํ”Œ๋ ›ํผ์ž…๋‹ˆ๋‹ค. Node.js, Next.js, Gatsby, Nest.js ์™€ ๊ฐ™์€ ๋‹ค์–‘ํ•œ ํ”Œ๋ ›ํผ์—์„œ ์ž‘๋™ํ•ด์š”.", + "signup": "ํšŒ์›๊ฐ€์ž…", + "already-have-account": "์ด๋ฏธ ๊ณ„์ •์ด ์žˆ๋‚˜์š”? ๋กœ๊ทธ์ธํ•˜๊ธฐ", + "forgot-password": "๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์žŠ์œผ์…จ๋‚˜์š”?", + "verify": "์ธ์ฆ", + "step1-start": "์‹œ์ž‘ํ•˜๊ธฐ", + "step1-privacy": "ํšŒ์›๊ฐ€์ž…์‹œ ์•ฝ๊ด€๊ณผ ๊ฐœ์ธ ์ •๋ณด ๋ณดํ˜ธ ์ •์ฑ…์„ ์ฝ๊ณ  ๋™์˜ํ•œ ๊ฒƒ์œผ๋กœ ๊ฐ„์ฃผํ•ฉ๋‹ˆ๋‹ค.", + "step1-submit": "์‹œ์ž‘ํ•˜๊ธฐ", + "step2-message": "{{email}}๋กœ ์ธ์ฆ ๋ฉ”์ผ์„ ์ „์†กํ•˜์˜€์Šต๋‹ˆ๋‹ค{{email}}", + "step2-code-error": "์ฝ”๋“œ๊ฐ€ ์ž˜๋ชป๋œ ๊ฒƒ ๊ฐ™์•„์š”. ๋‹ค์‹œ ์‹œ๋„ํ•ด์ฃผ์„ธ์š”.", + "step2-spam-alert": "์ŠคํŒธํ•จ์— ๋ฉ”์ผ์ด ์žˆ์ง€๋Š” ์•Š์€์ง€ ํ™•์ธํ•˜์„ธ์š”", + "step3-message": "๊ฑฐ์˜๋‹ค ๋๋‚ฌ์–ด์š”!", + "step4-message": "๊ธด๊ธ‰๋ณต๊ตฌ ํ‚คํŠธ ์ €์žฅํ•˜๊ธฐ", + "step4-description1": "๊ณ„์ •์ด ์ž ๊ฒผ์„ ๊ฒฝ์šฐ ๋น„์ƒ ํ‚คํŠธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋กœ๊ทธ์ธํ•  ์ˆ˜ ์žˆ์–ด์š”.", + "step4-description2": "๋‹ค์šด๋กœ๋“œ ํ›„ ์•ˆ์ „ํ•œ ๊ณณ์— ๋ณด๊ด€ํ•˜๋Š” ๊ฒƒ์„ ์ถ”์ฒœํ•ฉ๋‹ˆ๋‹ค.", + "step4-description3": "๋ถ„์‹ค์‹œ ์ ‘๊ทผํ•˜๊ฑฐ๋‚˜ ๋ณต๊ตฌํ•  ์ˆ˜ ์—†๋Š” ์‹œํฌ๋ฆฟ ํ‚ค๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ์–ด์š”.", + "step4-download": "PDF ๋‹ค์šด๋กœ๋“œ" +} diff --git a/frontend/public/locales/pt-BR/activity.json b/frontend/public/locales/pt-BR/activity.json new file mode 100644 index 000000000..dfc5821ae --- /dev/null +++ b/frontend/public/locales/pt-BR/activity.json @@ -0,0 +1,8 @@ +{ + "event": { + "readSecrets": "Segredos Visualizados", + "updateSecrets": "Segredos Atualizados", + "addSecrets": "Segredos Adicionados", + "deleteSecrets": "Segredos Excluรญdos" + } +} \ No newline at end of file diff --git a/frontend/public/locales/pt-BR/billing.json b/frontend/public/locales/pt-BR/billing.json new file mode 100644 index 000000000..1c920c053 --- /dev/null +++ b/frontend/public/locales/pt-BR/billing.json @@ -0,0 +1,28 @@ +{ + "title": "Uso & Faturamento", + "description": "Visualize e gerencie a assinatura da sua organizaรงรฃo aqui", + "subscription": "Inscriรงรฃo", + "starter": { + "name": "Iniciante", + "price-explanation": "Atรฉ 5 membros da equipe", + "text": "Gerencie qualquer projeto com 5 membros gratuitamente!", + "subtext": "$5 por membro / mรชs depois." + }, + "professional": { + "name": "Profissional", + "price-explanation": "/membro/mรชs", + "subtext": "Inclui projetos e membros ilimitados.", + "text": "Acompanhe o gerenciamento de chaves ร  medida que vocรช cresce." + }, + "enterprise": { + "name": "Empreendimento", + "text": "Acompanhe o gerenciamento de chaves ร  medida que vocรช cresce." + }, + "current-usage": "Uso atual", + "free": "Grรกtis", + "downgrade": "Reduzir", + "upgrade": "Melhoria", + "learn-more": "Saber Mais", + "custom-pricing": "Preรงo Personalizado", + "schedule-demo": "Agende uma Demonstraรงรฃo" +} \ No newline at end of file diff --git a/frontend/public/locales/pt-BR/common.json b/frontend/public/locales/pt-BR/common.json new file mode 100644 index 000000000..207f0db29 --- /dev/null +++ b/frontend/public/locales/pt-BR/common.json @@ -0,0 +1,26 @@ +{ + "head-title": "{{title}} | Infisical", + "error_project-already-exists": "Jรก exite um projeto com este nome.", + "no-mobile": "Para usar o Infisical, faรงa o login atravรฉs de um dispositivo com dimensรตes maiores.", + "email": "Email", + "password": "Senha", + "first-name": "Primeiro Nome", + "last-name": "Ultimo Nome", + "logout": "Sair", + "validate-required": "Por favor insira o seu {{name}}", + "maintenance-alert": "Estamos passando por pequenas dificuldades tรฉcnicas. Estamos trabalhando para resolvรช-lo agora. Por favor, volte em alguns minutos.", + "click-to-copy": "Clique para copiar", + "project-id": "ID do Projeto", + "save-changes": "Salvar Alteraรงรตes", + "saved": "Salvou", + "drop-zone": "Arraste e solte seu arquivo .env aqui.", + "drop-zone-keys": "Arraste e solte seu arquivo .env aqui para adicionar mais chaves.", + "role": "Role", + "role_admin": "admin", + "display-name": "Nome de exibiรงรฃo", + "environment": "Ambiente", + "expired-in": "Expira em", + "language": "Linguagem", + "search": "Procurar...", + "note": "Note" +} \ No newline at end of file diff --git a/frontend/public/locales/pt-BR/dashboard.json b/frontend/public/locales/pt-BR/dashboard.json new file mode 100644 index 000000000..3edeacc89 --- /dev/null +++ b/frontend/public/locales/pt-BR/dashboard.json @@ -0,0 +1,30 @@ +{ + "title": "Segredos", + "og-title": "Gerencie seus arquivos .env em segundos", + "og-description": "Infisical รฉ uma plataforma simples e criptografada de ponta a ponta que permite que as equipes sincronizem e gerenciem seus arquivos .env.", + "search-keys": "Pesquisar chaves...", + "add-key": "Adicionar Chave", + "personal": "Pessoal", + "personal-description": "As chaves pessoais sรฃo visรญveis apenas para vocรช", + "shared": "Compartilhado", + "shared-description": "As chaves compartilhadas ficam visรญveis para toda a sua equipe", + "make-shared": "Tornar Compartilhado", + "make-personal": "Tornar individual", + "check-docs": { + "button": "Checkar Documentaรงรฃo", + "title": "Bom trabalho!!", + "line1": "Parabรฉns por adicionar mais segredos.", + "line2": "Veja como conectรก-los ร  sua base de cรณdigo." + }, + "sidebar": { + "secret": "Segredo", + "key": "Chave", + "value": "Valor", + "override": "Substitua o valor por um valor pessoal", + "version-history": "Histรณrico da versรฃo", + "comments": "Comentรกrios e Notas", + "personal-explanation": "Este segredo รฉ pessoal. Nรฃo รฉ compartilhado com nenhum de seus colegas de equipe.", + "generate-random-hex": "Gerar Hex Aleatรณrio", + "digits": "Digitos" + } +} \ No newline at end of file diff --git a/frontend/public/locales/pt-BR/integrations.json b/frontend/public/locales/pt-BR/integrations.json new file mode 100644 index 000000000..3e1533582 --- /dev/null +++ b/frontend/public/locales/pt-BR/integrations.json @@ -0,0 +1,16 @@ +{ + "title": "Integraรงรตes de Projetos", + "description": "Gerencie suas integraรงรตes da Infisical com serviรงos de terceiros.", + "no-integrations1": "Vocรช ainda nรฃo tem integraรงรตes configuradas. Quando vocรช fizer isso, eles aparecerรฃo aqui.", + "no-integrations2": "Para comeรงar, clique em qualquer uma das opรงรตes abaixo. Leva 5 cliques para configurar.", + "available": "Integraรงรตes de Plataforma e Nuvem", + "available-text1": "Clique na integraรงรฃo que deseja conectar. Isso permitirรก que suas variรกveis de ambiente fluam automaticamente para serviรงos de terceiros selecionados.", + "available-text2": "Observaรงรฃo: durante uma integraรงรฃo com o Heroku, por questรตes de seguranรงa, รฉ impossรญvel manter a criptografia de ponta a ponta. Em teoria, isso permite que o Infisical descriptografe suas variรกveis de ambiente. Na prรกtica, podemos garantir que isso nunca serรก feito e nos permite proteger seus segredos de pessoas mal-intencionadas online. O serviรงo bรกsico da Infisical sempre permanecerรก criptografado de ponta a ponta. Em caso de dรบvidas, entre em contato com support@infisical.com.", + "cloud-integrations": "Integraรงรตes na Nuvem", + "framework-integrations": "Integraรงรตes de framework", + "click-to-start": "Clique em uma integraรงรฃo para comeรงar a sincronizar segredos com ela.", + "click-to-setup": "Clique em uma estrutura para obter as instruรงรตes de configuraรงรฃo.", + "grant-access-to-secrets": "Conceda acesso Infisical aos seus segredos", + "why-infisical-needs-access": "A maioria das integraรงรตes em nuvem exige que o Infisical seja capaz de descriptografar seus segredos para que possam ser encaminhados.", + "grant-access-button": "Garantir acesso" +} \ No newline at end of file diff --git a/frontend/public/locales/pt-BR/login.json b/frontend/public/locales/pt-BR/login.json new file mode 100644 index 000000000..9510d1a22 --- /dev/null +++ b/frontend/public/locales/pt-BR/login.json @@ -0,0 +1,8 @@ +{ + "title": "Entrar", + "og-title": "Entrar no Infisical", + "og-description": "Infisical รฉ uma plataforma simples e criptografada de ponta a ponta que permite que as equipes sincronizem e gerenciem seus arquivos .env.", + "login": "Entrar", + "need-account": "Precisa de uma conta Infisical?", + "create-account": "Criar uma conta" +} \ No newline at end of file diff --git a/frontend/public/locales/pt-BR/nav.json b/frontend/public/locales/pt-BR/nav.json new file mode 100644 index 000000000..7922312dd --- /dev/null +++ b/frontend/public/locales/pt-BR/nav.json @@ -0,0 +1,22 @@ +{ + "support": { + "slack": "[NEW] Participe do fรณrum do Slack", + "docs": "Leia a Documentaรงรฃo", + "issue": "Abra uma Issue no Github", + "email": "Envie-nos um e-mail" + }, + "user": { + "signed-in-as": "ASSINADO COMO", + "current-organization": "ORGANIZAร‡รƒO ATUAL", + "usage-billing": "Uso & Faturamento", + "invite": "Convide Membros", + "other-organizations": "OUTRA ORGANIZAร‡รƒO" + }, + "menu": { + "project": "PROJETO", + "secrets": "Segredos", + "members": "Membros", + "integrations": "Integraรงรตes", + "project-settings": "Configuraรงรตes do Projeto" + } +} \ No newline at end of file diff --git a/frontend/public/locales/pt-BR/section-incident.json b/frontend/public/locales/pt-BR/section-incident.json new file mode 100644 index 000000000..bfa55d2ee --- /dev/null +++ b/frontend/public/locales/pt-BR/section-incident.json @@ -0,0 +1,11 @@ +{ + "incident-contacts": "Contatos do Incidente", + "incident-contacts-description": "Esses contatos serรฃo notificados no caso improvรกvel de um incidente grave.", + "no-incident-contacts": "Nenhum contato de incidente encontrado.", + "add-contact": "Adicionar contato", + "add-dialog": { + "title": "Adicionar um contato de incidente", + "description": "Este contato serรก notificado no caso improvรกvel de um incidente grave.", + "add-incident": "Adicionar contato de incidente" + } +} \ No newline at end of file diff --git a/frontend/public/locales/pt-BR/section-members.json b/frontend/public/locales/pt-BR/section-members.json new file mode 100644 index 000000000..67ef10ff0 --- /dev/null +++ b/frontend/public/locales/pt-BR/section-members.json @@ -0,0 +1,14 @@ +{ + "add-member": "Adicionar membro", + "org-members": "Membros da Organizaรงรฃo", + "org-members-description": "Gerencie os membros da sua organizaรงรฃo. Esses usuรกrios poderiam posteriormente ser formados em projetos.", + "search-members": "Pesquisar membros...", + "add-dialog": { + "add-member-to-project": "Adicionar um membro ao seu projeto", + "already-all-invited": "Todos os usuรกrios da sua organizaรงรฃo jรก foram convidados.", + "add-user-org-first": "Adicione mais usuรกrios ร  organizaรงรฃo primeiro.", + "user-will-email": "O usuรกrio receberรก um e-mail com as instruรงรตes.", + "looking-add": "<0>Se vocรช deseja adicionar usuรกrios ร  sua organizaรงรฃo,<1>clique aqui", + "add-user-to-org": "Adicionar usuรกrios ร  organizaรงรฃo" + } +} \ No newline at end of file diff --git a/frontend/public/locales/pt-BR/section-password.json b/frontend/public/locales/pt-BR/section-password.json new file mode 100644 index 000000000..771581768 --- /dev/null +++ b/frontend/public/locales/pt-BR/section-password.json @@ -0,0 +1,11 @@ +{ + "password": "Senha", + "change": "Mudar senha", + "current": "Senha atual", + "current-wrong": "A senha atual pode estar errada", + "new": "Nova Senha", + "validate-base": "A senha deve conter pelo menos:", + "validate-length": "14 caracteres", + "validate-case": "1 caractere minรบsculo", + "validate-number": "1 nรบmero" +} \ No newline at end of file diff --git a/frontend/public/locales/pt-BR/section-token.json b/frontend/public/locales/pt-BR/section-token.json new file mode 100644 index 000000000..1713f8118 --- /dev/null +++ b/frontend/public/locales/pt-BR/section-token.json @@ -0,0 +1,13 @@ +{ + "service-tokens": "Tokens de Serviรงo", + "service-tokens-description": "Cada token de serviรงo รฉ especรญfico para vocรช, um determinado projeto e um determinado ambiente dentro deste projeto.", + "add-new": "Adicionar novo token", + "add-dialog": { + "title": "Adicione um token de serviรงo para {{target}}", + "description": "Especifique o nome, o ambiente e o perรญodo de expiraรงรฃo. Quando um token รฉ gerado, vocรช sรณ poderรก vรช-lo uma vez antes que ele desapareรงa. Certifique-se de salvรก-lo em algum lugar.", + "name": "Nome do token de serviรงo", + "add": "Adicionar token de serviรงo", + "copy-service-token": "Copie seu token de serviรงo", + "copy-service-token-description": "Depois de fechar este pop-up, vocรช nunca mais verรก seu token de serviรงo" + } +} \ No newline at end of file diff --git a/frontend/public/locales/pt-BR/settings-members.json b/frontend/public/locales/pt-BR/settings-members.json new file mode 100644 index 000000000..f48913547 --- /dev/null +++ b/frontend/public/locales/pt-BR/settings-members.json @@ -0,0 +1,4 @@ +{ + "title": "Membros do Projeto", + "description": "Esta pรกgina mostra os membros do projeto selecionado." +} \ No newline at end of file diff --git a/frontend/public/locales/pt-BR/settings-org.json b/frontend/public/locales/pt-BR/settings-org.json new file mode 100644 index 000000000..e017c2aee --- /dev/null +++ b/frontend/public/locales/pt-BR/settings-org.json @@ -0,0 +1,4 @@ +{ + "title": "Configuraรงรตes da organizaรงรฃo", + "description": "Gerencie os membros da sua organizaรงรฃo. Esses usuรกrios poderiam posteriormente ser formados em projetos." +} \ No newline at end of file diff --git a/frontend/public/locales/pt-BR/settings-personal.json b/frontend/public/locales/pt-BR/settings-personal.json new file mode 100644 index 000000000..9d5dd7f50 --- /dev/null +++ b/frontend/public/locales/pt-BR/settings-personal.json @@ -0,0 +1,11 @@ +{ + "title": "Configuraรงรตes Pessoais", + "description": "Visualize e gerencie suas informaรงรตes pessoais aqui.", + "emergency": { + "name": "Kit de emergรชncia", + "text1": "Seu Kit de Emergรชncia contรฉm as informaรงรตes necessรกrias para acessar sua conta Infisical.", + "text2": "Apenas o รบltimo kit de emergรชncia emitido permanece vรกlido. Para obter um novo Kit de emergรชncia, verifique sua senha.", + "download": "Baixe o kit de emergรชncia" + }, + "change-language": "Mudar idioma" +} \ No newline at end of file diff --git a/frontend/public/locales/pt-BR/settings-project.json b/frontend/public/locales/pt-BR/settings-project.json new file mode 100644 index 000000000..f25af8fd4 --- /dev/null +++ b/frontend/public/locales/pt-BR/settings-project.json @@ -0,0 +1,13 @@ +{ + "title": "Configuraรงรตes do Projeto", + "description": "Essas configuraรงรตes se aplicam apenas ao projeto atualmente selecionado.", + "danger-zone": "Zona de perigo", + "delete-project": "Excluir projeto", + "project-to-delete": "Projeto a ser deletado", + "danger-zone-note": "Assim que vocรช excluir este projeto, nรฃo poderรก desfazรช-lo. Isso removerรก imediatamente todas as chaves. Se vocรช ainda quiser fazer isso, digite o nome do projeto abaixo.", + "delete-project-note": "Observaรงรฃo: vocรช sรณ pode excluir um projeto caso tenha mais de um", + "project-id-description": "Para integrar Infisical em sua base de cรณdigo e obter injeรงรฃo automรกtica de variรกveis ambientais, vocรช deve usar o seguinte ID do projeto.", + "project-id-description2": "Para obter mais orientaรงรตes, incluindo trechos de cรณdigo para vรกrias linguagens e estruturas, consulte", + "auto-generated": "Este รฉ o identificador exclusivo gerado automaticamente do seu projeto. Nรฃo pode ser alterado.", + "docs": "Documentaรงรฃo do Infisical" +} \ No newline at end of file diff --git a/frontend/public/locales/pt-BR/signup.json b/frontend/public/locales/pt-BR/signup.json new file mode 100644 index 000000000..b86ac1eff --- /dev/null +++ b/frontend/public/locales/pt-BR/signup.json @@ -0,0 +1,21 @@ +{ + "title": "Inscrever-se", + "og-title": "Substitua os arquivos .env por 1 linha de cรณdigo. Cadastre-se no Infisical em 3 minutos.", + "og-description": "Infisical รฉ uma plataforma criptografada de ponta a ponta simples que permite que as equipes sincronizem e gerenciem chaves de API e variรกveis ambientais. Funciona com Node.js, Next.js, Gatsby, Nest.js...", + "signup": "Inscrever-se", + "already-have-account": "Possui uma conta? Conecte-se", + "forgot-password": "Esqueceu sua senha?", + "verify": "Verificar", + "step1-start": "Vamos comeรงar", + "step1-privacy": "Ao criar uma conta, vocรช concorda com nossos Termos e leu e reconheceu a Polรญtica de Privacidade.", + "step1-submit": "Iniciar", + "step2-message": "Enviamos um e-mail de verificaรงรฃo para{{email}}", + "step2-code-error": "Ops. Seu cรณdigo estรก errado. Por favor, tente novamente.", + "step2-spam-alert": "Certifique-se de verificar sua caixa de entrada de spam.", + "step3-message": "Quase lรก!", + "step4-message": "Guarde o seu Kit de Emergรชncia", + "step4-description1": "Se sua conta for bloqueada, seu Kit de emergรชncia รฉ a รบnica maneira de fazer login.", + "step4-description2": "Recomendamos que vocรช faรงa o download e guarde-o em algum lugar seguro.", + "step4-description3": "Ele contรฉm sua chave secreta que nรฃo podemos acessar ou recuperar para vocรช se vocรช a perder.", + "step4-download": "Baixar PDF" +} \ No newline at end of file diff --git a/frontend/public/locales/tr/activity.json b/frontend/public/locales/tr/activity.json new file mode 100644 index 000000000..80ac8f90d --- /dev/null +++ b/frontend/public/locales/tr/activity.json @@ -0,0 +1,11 @@ +{ + "title": "Aktivite Gรผnlรผkleri", + "subtitle": "Bu Infisical projesi iรงin Olay GeรงmiลŸi.", + "event": { + "readSecrets": "Sฤฑrlar Gรถrรผntรผlendi", + "updateSecrets": "Sฤฑrlar Gรผncellendi", + "addSecrets": "Sฤฑrlar Eklendi", + "deleteSecrets": "Sฤฑrlar Silindi" + }, + "ip-address": "IP Addresi" +} \ No newline at end of file diff --git a/frontend/public/locales/tr/billing.json b/frontend/public/locales/tr/billing.json new file mode 100644 index 000000000..d27ddc976 --- /dev/null +++ b/frontend/public/locales/tr/billing.json @@ -0,0 +1,28 @@ +{ + "title": "Planlar & Fiyatlandฤฑrma", + "description": "KuruluลŸunuzun aboneliฤŸini buradan gรถrรผntรผleyin ve yรถnetin", + "subscription": "Abonelik", + "starter": { + "name": "BaลŸlangฤฑรง", + "price-explanation": "5 takฤฑm รผyesine kadar", + "text": "5 kiลŸiyle herhangi bir projeyi รผcretsiz yรถnet!", + "subtext": "Sonrasฤฑnda aylฤฑk her รผye baลŸฤฑna 5$." + }, + "professional": { + "name": "Profesyonel", + "price-explanation": "/รผye/ay", + "subtext": "Sฤฑnฤฑrsฤฑz miktarda รผye ve proje dahildir.", + "text": "Anahtar yรถnetimine siz bรผyรผdรผkรงe ayak uydurun.." + }, + "enterprise": { + "name": "Kurumsal", + "text": "Anahtar yรถnetimine siz bรผyรผdรผkรงe ayak uydurun." + }, + "current-usage": "Mevcut Plan", + "free": "รœcretsiz", + "downgrade": "DรผลŸรผrรผn", + "upgrade": "Yรผkseltin", + "learn-more": "Daha fazlasฤฑnฤฑ รถฤŸrenim", + "custom-pricing": "ร–zel Fiyatlandฤฑrma", + "schedule-demo": "Bir Deneme Sรผrรผmรผ Planlayฤฑn " +} \ No newline at end of file diff --git a/frontend/public/locales/tr/common.json b/frontend/public/locales/tr/common.json new file mode 100644 index 000000000..38d54b476 --- /dev/null +++ b/frontend/public/locales/tr/common.json @@ -0,0 +1,34 @@ +{ + "head-title": "{{title}} | Infisical", + "error_project-already-exists": "Bu isimle bir proje zaten mevcut.", + "no-mobile": " Infisical'ฤฑ kullanmak iรงin, lรผtfen daha bรผyรผk boyutlara sahip bir cihaz รผzerinden giriลŸ yapฤฑn. ", + "email": "Email", + "password": "ลžifre", + "first-name": "Adฤฑnฤฑz", + "last-name": "Soyadฤฑnฤฑz", + "logout": "ร‡ฤฑkฤฑลŸ Yap", + "validate-required": "Lรผtfen girin, sahip olduฤŸunuz {{name}}", + "maintenance-alert": "Ufak teknik problemler yaลŸฤฑyoruz. Sorunu รงรถzmek รผzere รงalฤฑลŸฤฑyoruz. Lรผtfen birkaรง dakika iรงerisinde yeniden deneyin.", + "click-to-copy": "Kopyala", + "project-id": "Project ID", + "save-changes": "DeฤŸiลŸiklikleri Kaydet", + "saved": "Kaydedildi", + "drop-zone": ".env yada .yaml dosyasฤฑnฤฑ buraya sรผrรผkleyin", + "drop-zone-keys": "Daha รงok anahatar eklemek iรงin bir .env yada .yaml dosyasฤฑnฤฑ sรผrรผkleyin.", + "role": "Rol", + "role_admin": "yรถnetici", + "display-name": "Ekran Adฤฑ", + "environment": "Environment", + "expired-in": "Sรผresi geรงicek", + "language": "Dil", + "search": "Ara...", + "note": "Not", + "view-more": "Daha Fazla Gรถster", + "end-of-history": "GeรงmiลŸin Sonu", + "select-event": "Bir olay seรงin", + "event": "Olay", + "user": "Kullanฤฑcฤฑ", + "source": "Kaynak", + "time": "Zaman", + "timestamp": "Zaman Damgasฤฑ" +} \ No newline at end of file diff --git a/frontend/public/locales/tr/dashboard.json b/frontend/public/locales/tr/dashboard.json new file mode 100644 index 000000000..c480ba18b --- /dev/null +++ b/frontend/public/locales/tr/dashboard.json @@ -0,0 +1,35 @@ +{ + "title": "Sฤฑrlar", + "og-title": "Saniyeler iรงerisinde .env dosyalarฤฑnฤฑzฤฑ yรถnetin", + "og-description": "Infisical takฤฑmlarฤฑn .env dosyalarฤฑnฤฑ senkronize etmelerini ve yรถnetmelerini saฤŸlayan uรงtan uca ลŸifrelenmiลŸ basit bir platformdur", + "search-keys": "Anahtarlarฤฑ ara...", + "add-key": "Anahtar Ekle", + "personal": "KiลŸisel", + "personal-description": "KiลŸisel anahtarlar sadece sana gรถrรผnรผr", + "shared": "PaylaลŸฤฑlan", + "shared-description": "PaylaลŸฤฑlan anahatarlar tรผm takฤฑmฤฑna gรถrรผnรผr", + "make-shared": "PaylaลŸฤฑlan Yap", + "make-personal": "KiลŸisel Yap", + "add-secret": "Yeni bir sฤฑr ekle", + "check-docs": { + "button": "Dokรผmanlarฤฑ Kontrol Et", + "title": "ฤฐyi iลŸ!", + "line1": "Tebrikler, yeni anahtarlar eklediniz.", + "line2": "Bunlarฤฑ kendi Codebase' inize nasฤฑl baฤŸlarsฤฑnฤฑz, iลŸte bรถyle." + }, + "sidebar": { + "secret": "Sฤฑr", + "key": "Anahtar", + "value": "DeฤŸer", + "override": "Bu deฤŸerin รผzerine bir kiลŸisel deฤŸer yazฤฑn ", + "version-history": "Versiyon GeรงmiลŸi", + "comments": "Yorumlar & Notlar", + "personal-explanation": "Bu bir kiลŸisel sฤฑr. Herhangi bir takฤฑm รผyesi ile paylaลŸฤฑlmaz.", + "generate-random-hex": "Rastegele hex oluลŸtur", + "digits": "basamak", + "delete-key-dialog": { + "title": "Anahtarฤฑ Sil", + "confirm-delete-message": "Bu sฤฑrrฤฑ silmek istediฤŸinden emin misin? Bu iลŸlem geri alฤฑnamaz." + } + } +} \ No newline at end of file diff --git a/frontend/public/locales/tr/integrations.json b/frontend/public/locales/tr/integrations.json new file mode 100644 index 000000000..b8fe599f4 --- /dev/null +++ b/frontend/public/locales/tr/integrations.json @@ -0,0 +1,16 @@ +{ + "title": "Proje Entegrasyonlarฤฑ", + "description": "Infisical'ฤฑn รผรงรผncรผ taraf hizmetlerle olan entegrasyonlarฤฑnฤฑzฤฑ yรถnetin.", + "no-integrations1": "Henรผz ayarlanmฤฑลŸ bir entegrasyonunuz yok. OluลŸturduฤŸunuz zaman, burada gรถrรผnecekler.", + "no-integrations2": "BaลŸlamak iรงin aลŸaฤŸฤฑdaki seรงeneklerden herhangi birine tฤฑklayฤฑn. Sadece 5 tฤฑklama ile kurulumu halledin.", + "available": "Platform & Cloud Entegrasyonlarฤฑ", + "available-text1": "BaฤŸlanmak istediฤŸiniz entegrasyona tฤฑklayฤฑn. Bu, ortam deฤŸiลŸkenlerinizin seรงilen รผรงรผncรผ taraf hizmetlere otomatik olarak akmasฤฑnฤฑ saฤŸlar.", + "available-text2": "Not: Heroku ile entegrasyon sฤฑrasฤฑnda gรผvenlik nedenleriyle uรงtan uca ลŸifrelemenin sรผrdรผrรผlmesi mรผmkรผn deฤŸildir. Teorik olarak bu, Infisical'ฤฑn ortam deฤŸiลŸkenlerinin ลŸifresini รงรถzmesine izin verir. Pratikte biz bunun asla yapฤฑlmayacaฤŸฤฑnฤฑn garantisini verebiliriz ve bu durum sฤฑrlarฤฑnฤฑzฤฑ รงevrimiรงi kรถtรผ niyetlilerden korumamฤฑza olanak tanฤฑr. ร‡ekirdek Infisical hizmeti her zaman uรงtan uca ลŸifreli kalacaktฤฑr. Sorularฤฑnฤฑz iรงin support@infisical.com adresine ulaลŸฤฑn.", + "cloud-integrations": "Cloud Entegrasyonlarฤฑ", + "framework-integrations": "Framework Entegrasyonlarฤฑ", + "click-to-start": "Sฤฑrlarฤฑnฤฑzฤฑ senkronize etmeye baลŸlamak iรงin bir entegrasyona tฤฑklayฤฑn.", + "click-to-setup": "Kurulum talimatlarฤฑnฤฑ almak iรงin bir frameworke tฤฑklayฤฑn.", + "grant-access-to-secrets": "Infisical'a sฤฑrlarฤฑnฤฑza eriลŸim izni verin", + "why-infisical-needs-access": "ร‡oฤŸu cloud entegrasyonu, Infisical'ฤฑn sฤฑrlarฤฑnฤฑzฤฑ aktarabilmek iรงin sฤฑrlarฤฑnฤฑzฤฑ deลŸifre etmesini gerektirir.", + "grant-access-button": "EriลŸim izni ver" +} \ No newline at end of file diff --git a/frontend/public/locales/tr/login.json b/frontend/public/locales/tr/login.json new file mode 100644 index 000000000..f42551188 --- /dev/null +++ b/frontend/public/locales/tr/login.json @@ -0,0 +1,10 @@ +{ + "title": "GiriลŸ Yap", + "og-title": "Infisical'a GiriลŸ Yap", + "og-description": "Infisical ekiplerin .env dosyalarฤฑnฤฑ senkronize etmelerini ve yรถnetmelerini saฤŸlayan uรงtan uca ลŸifrelenmiลŸ basit bir platformdur", + "login": "GiriลŸ Yap", + "need-account": "Bir Infisical hesabฤฑna mฤฑ ihtiyacฤฑnฤฑz var?", + "create-account": "Hesap oluลŸturun", + "forgot-password": "ลžifrenizi mi unuttunuz?", + "error-login": "Kimlik bilgileri yanlฤฑลŸ." +} \ No newline at end of file diff --git a/frontend/public/locales/tr/nav.json b/frontend/public/locales/tr/nav.json new file mode 100644 index 000000000..aa6ea2df4 --- /dev/null +++ b/frontend/public/locales/tr/nav.json @@ -0,0 +1,22 @@ +{ + "support": { + "slack": "[YENฤฐ] Slack Foruma katฤฑlฤฑn", + "docs": "Dokรผmanlarฤฑ okuyun", + "issue": "Bir Github Issue aรงฤฑn", + "email": "Bize mail yollayฤฑn" + }, + "user": { + "signed-in-as": "ลžU HESABA GฤฐRฤฐลž YAPILDI", + "current-organization": "MEVZUT ORGANฤฐZASYON", + "usage-billing": "Plan & Fiyatlandฤฑrma", + "invite": "รœyeleri Davet Et", + "other-organizations": "DฤฐฤžER ORGANฤฐZASYONLAR" + }, + "menu": { + "project": "PROJE", + "secrets": "Sฤฑrlar", + "members": "รœyeler", + "integrations": "Entegrasyonlar", + "project-settings": "Proje Ayarlarฤฑ" + } +} \ No newline at end of file diff --git a/frontend/public/locales/tr/section-api-key.json b/frontend/public/locales/tr/section-api-key.json new file mode 100644 index 000000000..0c768ded6 --- /dev/null +++ b/frontend/public/locales/tr/section-api-key.json @@ -0,0 +1,13 @@ +{ + "api-keys": "Servis Belirteรงleri", + "api-keys-description": "Her servis belirteci size, belirli bir projeye ve o proje iรงindeki belirli bir ortama รถzeldir.", + "add-new": "Yeni Belirteรง Ekleyin", + "add-dialog": { + "title": "Bir API Anahtarฤฑ Ekleyin", + "description": "Adฤฑnฤฑ ve son kullanma sรผresini belirleyin. Bir API anahtarฤฑ oluลŸturulduฤŸunda, kaybolmadan รถnce yalnฤฑzca bir kez gรถrebileceksiniz. Bir yere kaydettiฤŸinizden emin olun.", + "name": "API Anahtarฤฑ Adฤฑ", + "add": "API Anahtarฤฑ Ekleyin", + "copy-service-token": "API Anahtarฤฑzฤฑ kopyalayฤฑn", + "copy-service-token-description": "Bu aรงฤฑlฤฑr pencereyi kapattฤฑฤŸฤฑnฤฑzda, API anahtarฤฑnฤฑzฤฑ bir daha asla gรถrmeyeceksiniz" + } +} \ No newline at end of file diff --git a/frontend/public/locales/tr/section-incident.json b/frontend/public/locales/tr/section-incident.json new file mode 100644 index 000000000..776c71c63 --- /dev/null +++ b/frontend/public/locales/tr/section-incident.json @@ -0,0 +1,11 @@ +{ + "incident-contacts": "ร–zel Durum ฤฐletiลŸim Adresleri", + "incident-contacts-description": "Bu adresler olasฤฑ olmayan ciddi bir olay durumunda bilgilendirilecek.", + "no-incident-contacts": "Hiรงbir ร–zel Durum ฤฐletiลŸim Adresi bulunamadฤฑ.", + "add-contact": "ฤฐletiลŸim Adresi Ekle", + "add-dialog": { + "title": "Bir ร–zel Durum ฤฐletiลŸim Adresi Ekleyin", + "description": "Bu kiลŸi, olasฤฑ olmayan ciddi bir olay durumunda bilgilendirilecektir..", + "add-incident": "ร–zel Durum ฤฐletiลŸim Adresi Ekle" + } +} \ No newline at end of file diff --git a/frontend/public/locales/tr/section-members.json b/frontend/public/locales/tr/section-members.json new file mode 100644 index 000000000..b4a0c0ec7 --- /dev/null +++ b/frontend/public/locales/tr/section-members.json @@ -0,0 +1,14 @@ +{ + "add-member": "รœye Ekle", + "org-members": "KuruluลŸ รœyeleri", + "org-members-description": "KuruluลŸunuzun รผyelerini yรถnetin. Bu kullanฤฑcฤฑlar daha sonra projelere yรถnlendirilebilir..", + "search-members": "รœyeleri arayฤฑn...", + "add-dialog": { + "add-member-to-project": "Projenize bir รผye ekleyin", + "already-all-invited": "KuruluลŸunuzdaki tรผm kullanฤฑcฤฑlar zaten davet edildi.", + "add-user-org-first": "ร–nce kuruluลŸa daha fazla kullanฤฑcฤฑ ekleyin.", + "user-will-email": "Kullanฤฑcฤฑ, talimatlarฤฑ iรงeren bir e-posta alacak.", + "looking-add": "<0>KuruluลŸunuza kullanฤฑcฤฑ eklemek istiyorsanฤฑz,<1>buraya tฤฑklayฤฑn", + "add-user-to-org": "KuruluลŸa Kullanฤฑcฤฑ Ekleyin" + } +} \ No newline at end of file diff --git a/frontend/public/locales/tr/section-password.json b/frontend/public/locales/tr/section-password.json new file mode 100644 index 000000000..07e26ba58 --- /dev/null +++ b/frontend/public/locales/tr/section-password.json @@ -0,0 +1,11 @@ +{ + "password": "ลžifre", + "change": "ลžifreyi deฤŸiลŸtir", + "current": "Mevcut ลŸifre", + "current-wrong": "Mevcut ลŸifre yanlฤฑลŸ olabilir", + "new": "Yeni ลŸifre", + "validate-base": "ลžifre en az ลŸunlarฤฑ iรงermelidir:", + "validate-length": "14 karakter", + "validate-case": "1 kรผรงรผk harf", + "validate-number": "1 rakam" +} \ No newline at end of file diff --git a/frontend/public/locales/tr/section-token.json b/frontend/public/locales/tr/section-token.json new file mode 100644 index 000000000..aceaba6dd --- /dev/null +++ b/frontend/public/locales/tr/section-token.json @@ -0,0 +1,13 @@ +{ + "service-tokens": "Servis Belirteรงleri", + "service-tokens-description": "Her servis belirteci size, belirli bir projeye ve o proje iรงindeki belirli bir ortama รถzeldir.", + "add-new": "Yeni Belirteรง Ekle", + "add-dialog": { + "title": "{{target}} iรงin bir servis belirteci ekleyin", + "description": "Adฤฑ, ortamฤฑ ve son kullanma sรผresini belirtin. Bir belirteรง oluลŸturulduฤŸunda, onu kaybolmadan รถnce yalnฤฑzca bir kez gรถrebileceksiniz. Bir yere kaydettiฤŸinizden emin olun.", + "name": "Servis Belirteci Adฤฑ", + "add": "Servis Belirteci Ekle", + "copy-service-token": "Service belirtecinizi kopyalayฤฑn", + "copy-service-token-description": "Bu aรงฤฑlฤฑr pencereyi kapattฤฑฤŸฤฑnฤฑzda, servis belirtecinizi bir daha asla gรถremeyeceksiniz" + } +} \ No newline at end of file diff --git a/frontend/public/locales/tr/settings-members.json b/frontend/public/locales/tr/settings-members.json new file mode 100644 index 000000000..c4a7441b7 --- /dev/null +++ b/frontend/public/locales/tr/settings-members.json @@ -0,0 +1,4 @@ +{ + "title": "Proje รœyeleri", + "description": "Bu sayfa seรงilen projenin รผyelerini gรถsterir." +} \ No newline at end of file diff --git a/frontend/public/locales/tr/settings-org.json b/frontend/public/locales/tr/settings-org.json new file mode 100644 index 000000000..3cc5c0d82 --- /dev/null +++ b/frontend/public/locales/tr/settings-org.json @@ -0,0 +1,4 @@ +{ + "title": "KuruluลŸ Ayarlarฤฑ", + "description": "KuruluลŸunuzun รผyelerini yรถnetin. Bu kullanฤฑcฤฑlar daha sonra projelere yรถnlendirilebilir.." +} \ No newline at end of file diff --git a/frontend/public/locales/tr/settings-personal.json b/frontend/public/locales/tr/settings-personal.json new file mode 100644 index 000000000..31c858efb --- /dev/null +++ b/frontend/public/locales/tr/settings-personal.json @@ -0,0 +1,16 @@ +{ + "title": "KiลŸisel Ayarlar", + "description": "KiลŸisel bilgilerinizi burada gรถrรผntรผleyin ve yรถnetin.", + "emergency": { + "name": "Acil Durum Kiti", + "text1": "Acil Durum Kitiniz, Infisical hesabฤฑnฤฑzda oturum aรงmak iรงin ihtiyaรง duyacaฤŸฤฑnฤฑz bilgileri iรงerir.", + "text2": "Yalnฤฑzca en son yayฤฑnlanan Acil Durum Kiti geรงerliliฤŸini korur. Yeni bir Acil Durum Kiti almak iรงin parolanฤฑzฤฑ doฤŸrulayฤฑn.", + "download": "Acil Durum Kitini ฤฐndir" + }, + "change-language": "Dili DeฤŸiลŸtir", + "api-keys": { + "title": "API Anahtarlarฤฑ", + "description": "Infisical API'ye eriลŸmek iรงin kiลŸisel API Anahtarlarฤฑnฤฑzฤฑ yรถnetin", + "add-new": "Ekle yeni" + } +} \ No newline at end of file diff --git a/frontend/public/locales/tr/settings-project.json b/frontend/public/locales/tr/settings-project.json new file mode 100644 index 000000000..41f9f3001 --- /dev/null +++ b/frontend/public/locales/tr/settings-project.json @@ -0,0 +1,13 @@ +{ + "title": "Proje Ayarlarฤฑ", + "description": "Bu ayarlar yalnฤฑzca mevcut seรงili projeye uygulanacak.", + "danger-zone": "Tehlikeli Bรถlge", + "delete-project": "Projeyi Sil", + "project-to-delete": "Silinmek รœzere Olan Proje", + "danger-zone-note": "Bu projeyi sildiฤŸiniz anda geri alamayacaksฤฑnฤฑz. Bu, tรผm anahtarlarฤฑ hemen kaldฤฑracaktฤฑr. Bunu hala yapmak istiyorsanฤฑz, lรผtfen aลŸaฤŸฤฑya projenin adฤฑnฤฑ girin.", + "delete-project-note": "Not: Yalnฤฑzca birden fazla projeniz olmasฤฑ durumunda, bir projeyi silebilirsiniz.", + "project-id-description": "Infisical'ฤฑ kod tabanฤฑnฤฑza entegre etmek ve รงevresel deฤŸiลŸkenlerin otomatik enjeksiyonunu almak iรงin aลŸaฤŸฤฑdaki Proje KimliฤŸini kullanmalฤฑsฤฑnฤฑz.", + "project-id-description2": "ร‡eลŸitli diller ve รงerรงeveler iรงin kod parรงalarฤฑ da dahil olmak รผzere daha fazla rehberlik iรงin bkz.", + "auto-generated": "Bu, projenizin otomatik olarak oluลŸturulan benzersiz tanฤฑmlayฤฑcฤฑsฤฑdฤฑr. DeฤŸiลŸtirilemez..", + "docs": "Infisical Dokรผmanlarฤฑ" +} \ No newline at end of file diff --git a/frontend/public/locales/tr/signup.json b/frontend/public/locales/tr/signup.json new file mode 100644 index 000000000..4a0778335 --- /dev/null +++ b/frontend/public/locales/tr/signup.json @@ -0,0 +1,28 @@ +{ + "title": "Kayฤฑt olun", + "og-title": "Tek satฤฑr kodla .env dosyalarฤฑnฤฑ deฤŸiลŸtirin. 3 dakika iรงerinde Infisical'a kayฤฑt olun.", + "og-description": "Infisical takฤฑmlarฤฑn API anahtarlarฤฑnฤฑ ve ortam deฤŸiลŸkenlerini yรถnetmelerini ve senkronize etmelerini saฤŸlayan basit, uรงtan uca ลŸifrelenmiลŸ bir platformdur. Node.js, Next.js, Gatsby, Nest.js ve daha fazlasฤฑ ile รงalฤฑลŸฤฑr.", + "signup": "Kayฤฑt ol", + "already-have-account": "Hesabฤฑn var mฤฑ? GiriลŸ yap", + "forgot-password": "ลžifreni mi unuttun?", + "verify": "DoฤŸrula", + "step1-start": "Hadi baลŸlayalฤฑm", + "step1-privacy": "Hesap oluลŸturarak, ลžartlarฤฑmฤฑzฤฑ ve Gizlilik Politikasฤฑnฤฑ okuyup kabul etmiลŸ olursunuz.", + "step1-submit": "BaลŸla", + "step2-message": "ลžu adrese bir doฤŸrulama maili yolladฤฑk", + "step2-code-error": "Tรผh. Kodun hatalฤฑ. Lรผtfen tekrar dene.", + "step2-resend-alert": "Mail ulaลŸamadฤฑ mฤฑ?", + "step2-resend-submit": "Tekrar Yolla", + "step2-resend-progress": "Tekrar yollanฤฑyor...", + "step2-spam-alert": "Spam kutunuzu kontrol ettiฤŸinizden emin olun.", + "step3-message": "ร‡ok az kaldฤฑ!", + "step4-message": "Acil Durum Kitinizi kayฤฑt edin", + "step4-description1": "EฤŸer hesabฤฑnฤฑza eriลŸemezseniz, Acil Durum Kitiniz giriลŸ yapmanฤฑn tek yoludur.", + "step4-description2": "Bunu indirmenizi ve gรผvenli bir ortamda saklamanฤฑzฤฑ รถneriyoruz.", + "step4-description3": "Kaybetmeniz durumunda bizim dahi eriลŸemeyeceฤŸimiz veya kurtaramayacaฤŸฤฑmฤฑz Gizli Anahtarฤฑnฤฑzฤฑ barฤฑndฤฑrฤฑr.", + "step4-download": "PDF'yi indir", + "step5-send-invites": "Davetleri yolla", + "step5-invite-team": "Takฤฑmฤฑnฤฑ davet et", + "step5-subtitle": "Infisical takฤฑm arkadaลŸlarฤฑnฤฑz ile kullanฤฑlmak รผzere yapฤฑlmฤฑลŸtฤฑr. Birlikte test etmek iรงin onlarฤฑ davet edin.", + "step5-skip": "Atla" +} \ No newline at end of file diff --git a/frontend/scripts/start.sh b/frontend/scripts/start.sh index 05a1f219a..fea97eb6b 100644 --- a/frontend/scripts/start.sh +++ b/frontend/scripts/start.sh @@ -2,7 +2,7 @@ scripts/replace-variable.sh "$BAKED_NEXT_PUBLIC_POSTHOG_API_KEY" "$NEXT_PUBLIC_POSTHOG_API_KEY" -if [ "$INFISICAL_TELEMETRY_ENABLED" != "false" ]; then +if [ "$TELEMETRY_ENABLED" != "false" ]; then echo "Telemetry is enabled" scripts/set-telemetry.sh true else diff --git a/frontend/components/RouteGuard.js b/frontend/src/components/RouteGuard.tsx similarity index 69% rename from frontend/components/RouteGuard.js rename to frontend/src/components/RouteGuard.tsx index d08972b99..3b755341e 100644 --- a/frontend/components/RouteGuard.js +++ b/frontend/src/components/RouteGuard.tsx @@ -1,17 +1,48 @@ -import { useEffect, useState } from 'react'; -import Image from 'next/image'; +import { ReactNode, useEffect, useState } from 'react'; import { useRouter } from 'next/router'; -import { publicPaths } from '~/const'; -import checkAuth from '~/pages/api/auth/CheckAuth'; +import { publicPaths } from '@app/const'; +import checkAuth from '@app/pages/api/auth/CheckAuth'; // #TODO: finish spinner only when the data loads fully // #TODO: Redirect somewhere if the page does not exist -export default function RouteGuard({ children }) { +type Prop = { + children: ReactNode; +}; + +export default function RouteGuard({ children }: Prop): JSX.Element { const router = useRouter(); + // eslint-disable-next-line @typescript-eslint/no-unused-vars const [authorized, setAuthorized] = useState(false); + /** + * redirect to login page if accessing a private page and not logged in + */ + async function authCheck(url: string) { + // Make sure that we don't redirect when the user is on the following pages. + const path = `/${url.split('?')[0].split('/')[1]}`; + + // Check if the user is authenticated + const response = await checkAuth(); + // #TODO: figure our why sometimes it doesn't output a response + // ANS(akhilmhdh): Because inside the security client the await token() doesn't have try/catch + if (!publicPaths.includes(path)) { + try { + if (response.status !== 200) { + router.push('/login'); + console.log('Unauthorized to access.'); + setAuthorized(false); + } else { + setAuthorized(true); + console.log('Authorized to access.'); + } + } catch (error) { + console.log('Error (probably the authCheck route is stuck again...):', error); + } + } + } + useEffect(() => { // on initial load - run auth check (async () => { @@ -37,48 +68,5 @@ export default function RouteGuard({ children }) { // eslint-disable-next-line react-hooks/exhaustive-deps }, []); - /** - * redirect to login page if accessing a private page and not logged in - * @param {*} url - the url of the page we are trying to go to - */ - async function authCheck(url) { - // Make sure that we don't redirect when the user is on the following pages. - const path = '/' + url.split('?')[0].split('/')[1]; - - // Check if the user is authenticated - const response = await checkAuth(); - // #TODO: figure our why sometimes it doesn't output a response - if (!publicPaths.includes(path)) { - try { - if (response.status !== 200) { - router.push('/login'); - console.log('Unauthorized to access.'); - setAuthorized(false); - } else { - setAuthorized(true); - console.log('Authorized to access.'); - } - } catch (error) { - console.log( - 'Error (probably the authCheck route is stuck again...):', - error - ); - } - } - } - - if (authorized) { - return children; - } else { - return ( -
- google logo -
- ); - } + return children as JSX.Element; } diff --git a/frontend/src/components/analytics/posthog.ts b/frontend/src/components/analytics/posthog.ts new file mode 100644 index 000000000..29208a795 --- /dev/null +++ b/frontend/src/components/analytics/posthog.ts @@ -0,0 +1,26 @@ +/* eslint-disable @typescript-eslint/ban-ts-comment */ +/* eslint-disable no-undef */ +import posthog from 'posthog-js'; + +import { ENV, POSTHOG_API_KEY, POSTHOG_HOST } from '../utilities/config'; + +export const initPostHog = () => { + // @ts-ignore + console.log("Init Infisical") + try { + if (typeof window !== 'undefined') { + // @ts-ignore + if (ENV === 'production' && TELEMETRY_CAPTURING_ENABLED) { + posthog.init(POSTHOG_API_KEY, { + api_host: POSTHOG_HOST + }); + } + } + + return posthog; + } catch (e) { + console.log("posthog err", e) + } + + return undefined; +}; diff --git a/frontend/src/components/basic/Error.tsx b/frontend/src/components/basic/Error.tsx new file mode 100644 index 000000000..ab79fb24d --- /dev/null +++ b/frontend/src/components/basic/Error.tsx @@ -0,0 +1,13 @@ +import { faExclamationTriangle } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; + +const Error = ({ text }: { text: string }): JSX.Element => { + return ( +
+ + {text &&

{text}

} +
+ ); +}; + +export default Error; diff --git a/frontend/src/components/basic/EventFilter.tsx b/frontend/src/components/basic/EventFilter.tsx new file mode 100644 index 000000000..02a6705c6 --- /dev/null +++ b/frontend/src/components/basic/EventFilter.tsx @@ -0,0 +1,94 @@ +import React, { Fragment } from 'react'; +import { useTranslation } from 'next-i18next'; +import { + faAngleDown, + faEye, + faPlus, + faShuffle, + faTrash, + faX +} from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { Listbox, Transition } from '@headlessui/react'; + +interface ListBoxProps { + selected: string; + select: (event: string) => void; +} + +const eventOptions = [ + { + name: 'addSecrets', + icon: faPlus + }, + { + name: 'readSecrets', + icon: faEye + }, + { + name: 'updateSecrets', + icon: faShuffle + }, + { + name: 'deleteSecrets', + icon: faTrash + } +]; + +/** + * This is the component that we use for the event picker in the activity logs tab. + * @param {object} obj + * @param {string} obj.selected - the event that is currently selected + * @param {function} obj.select - an action that happens when an item is selected + */ +const EventFilter = ({ selected, select }: ListBoxProps): JSX.Element => { + const { t } = useTranslation(); + + return ( + +
+ + {selected !== '' ? ( +

{t(`activity:event.${selected}`)}

+ ) : ( +

{String(t('common:select-event'))}

+ )} + {selected !== '' ? ( + select('')} /> + ) : ( + + )} +
+ + + {eventOptions.map((event, id) => ( + + {({ selected: isSelected }) => ( + + {' '} + {t(`activity:event.${event.name}`)} + + )} + + ))} + + +
+
+ ); +}; + +export default EventFilter; diff --git a/frontend/src/components/basic/InputField.tsx b/frontend/src/components/basic/InputField.tsx new file mode 100644 index 000000000..a8ad953a4 --- /dev/null +++ b/frontend/src/components/basic/InputField.tsx @@ -0,0 +1,145 @@ +import { memo, useState } from 'react'; +import { faCircle, faEye, faEyeSlash } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; + +import guidGenerator from '../utilities/randomId'; + +interface InputFieldProps { + isStatic?: boolean; + label: string; + type: string; + value: string; + placeholder?: string; + isRequired: boolean; + error?: boolean; + text?: string; + name?: string; + blurred?: boolean; + errorText?: string; + onChangeHandler: (value: string) => void; +} + +const InputField = ({ + isRequired, + label, + onChangeHandler, + type, + value, + autoComplete, + blurred, + error, + errorText, + id, + name, + placeholder, + isStatic, + text +}: InputFieldProps & Pick) => { + const [passwordVisible, setPasswordVisible] = useState(false); + + if (isStatic === true) { + return ( +
+

{label}

+ {text &&

{text}

} + onChangeHandler(e.target.value)} + type={type} + placeholder={placeholder} + value={value} + required={isRequired} + className="bg-bunker-800 text-gray-400 border border-gray-600 rounded-md text-md p-2 w-full min-w-16 outline-none" + name={name} + readOnly + autoComplete={autoComplete} + id={id} + /> +
+ ); + } + return ( +
+
+

{label}

+ {/* {label === "Password" && router.asPath !== "/login" && ( +
+ + + The password should contain at least 8 + characters including at least 1 lowercase + character, uppercase character, number, and a + special character. + +
+ )} */} +
+
+ onChangeHandler(e.target.value)} + type={passwordVisible === false ? type : 'text'} + placeholder={placeholder} + value={value} + required={isRequired} + className={`${ + blurred + ? 'text-bunker-800 group-hover:text-gray-400 focus:text-gray-400 active:text-gray-400' + : '' + } ${ + error ? 'focus:ring-red/50' : 'focus:ring-primary/50' + } relative peer bg-bunker-800 rounded-md text-gray-400 text-md p-2 w-full min-w-16 outline-none focus:ring-4 duration-200`} + name={name} + spellCheck="false" + autoComplete={autoComplete} + id={id} + /> + {label?.includes('Password') && ( + + )} + {blurred && ( +
+

+ {value + .split('') + .slice(0, 54) + .map(() => ( + + ))} +

+ )} + {/* {error && ( +
+ +
+ )} */} +
+ {error &&

{errorText}

} +
+ ); +}; + +export default memo(InputField); diff --git a/frontend/components/basic/Layout.tsx b/frontend/src/components/basic/Layout.tsx similarity index 54% rename from frontend/components/basic/Layout.tsx rename to frontend/src/components/basic/Layout.tsx index 56a16cb3d..a3d6092a1 100644 --- a/frontend/components/basic/Layout.tsx +++ b/frontend/src/components/basic/Layout.tsx @@ -1,35 +1,37 @@ +/* eslint-disable no-nested-ternary */ /* eslint-disable no-unexpected-multiline */ /* eslint-disable react-hooks/exhaustive-deps */ -import { useEffect, useState } from 'react'; +import crypto from 'crypto'; + +import { useEffect, useMemo, useState } from 'react'; import Link from 'next/link'; import { useRouter } from 'next/router'; +import { useTranslation } from 'next-i18next'; import { faBookOpen, + faFileLines, faGear, faKey, faMobile, faPlug, + faPlus, faUser } from '@fortawesome/free-solid-svg-icons'; -import { faPlus } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import getOrganizations from '~/pages/api/organization/getOrgs'; -import getOrganizationUserProjects from '~/pages/api/organization/GetOrgUserProjects'; -import getOrganizationUsers from '~/pages/api/organization/GetOrgUsers'; -import checkUserAction from '~/pages/api/userActions/checkUserAction'; -import addUserToWorkspace from '~/pages/api/workspace/addUserToWorkspace'; -import createWorkspace from '~/pages/api/workspace/createWorkspace'; -import getWorkspaces from '~/pages/api/workspace/getWorkspaces'; -import uploadKeys from '~/pages/api/workspace/uploadKeys'; +import getOrganizations from '@app/pages/api/organization/getOrgs'; +import getOrganizationUserProjects from '@app/pages/api/organization/GetOrgUserProjects'; +import getOrganizationUsers from '@app/pages/api/organization/GetOrgUsers'; +import getUser from '@app/pages/api/user/getUser'; +import addUserToWorkspace from '@app/pages/api/workspace/addUserToWorkspace'; +import createWorkspace from '@app/pages/api/workspace/createWorkspace'; +import getWorkspaces from '@app/pages/api/workspace/getWorkspaces'; +import uploadKeys from '@app/pages/api/workspace/uploadKeys'; import NavBarDashboard from '../navigation/NavBarDashboard'; import onboardingCheck from '../utilities/checks/OnboardingCheck'; import { tempLocalStorage } from '../utilities/checks/tempLocalStorage'; -import { - decryptAssymmetric, - encryptAssymmetric -} from '../utilities/cryptography/crypto'; +import { decryptAssymmetric, encryptAssymmetric } from '../utilities/cryptography/crypto'; import Button from './buttons/Button'; import AddWorkspaceDialog from './dialog/AddWorkspaceDialog'; import Listbox from './Listbox'; @@ -38,25 +40,25 @@ interface LayoutProps { children: React.ReactNode; } -export default function Layout({ children }: LayoutProps) { +const Layout = ({ children }: LayoutProps) => { const router = useRouter(); - const [workspaceList, setWorkspaceList] = useState([]); - const [workspaceMapping, setWorkspaceMapping] = useState([{ '1': '2' }]); + const [workspaceMapping, setWorkspaceMapping] = useState[]>([]); const [workspaceSelected, setWorkspaceSelected] = useState('โˆž'); const [newWorkspaceName, setNewWorkspaceName] = useState(''); const [isOpen, setIsOpen] = useState(false); const [loading, setLoading] = useState(false); const [error, setError] = useState(false); - const [totalOnboardingActionsDone, setTotalOnboardingActionsDone] = - useState(0); + const [totalOnboardingActionsDone, setTotalOnboardingActionsDone] = useState(0); - function closeModal() { + const { t } = useTranslation(); + + const closeModal = () => { setIsOpen(false); - } + }; - function openModal() { + const openModal = () => { setIsOpen(true); - } + }; // TODO: what to do about the fact that 2ids can have the same name @@ -64,7 +66,7 @@ export default function Layout({ children }: LayoutProps) { * When a user creates a new workspace, redirect them to the page of the new workspace. * @param {*} workspaceName */ - async function submitModal(workspaceName: string, addAllUsers: boolean) { + const submitModal = async (workspaceName: string, addAllUsers: boolean) => { setLoading(true); // timeout code. setTimeout(() => setLoading(false), 1500); @@ -79,44 +81,54 @@ export default function Layout({ children }: LayoutProps) { }); const newWorkspaceId = newWorkspace._id; + const randomBytes = crypto.randomBytes(16).toString('hex'); + const PRIVATE_KEY = String(localStorage.getItem('PRIVATE_KEY')); + + const myUser = await getUser(); + + const { ciphertext, nonce } = encryptAssymmetric({ + plaintext: randomBytes, + publicKey: myUser.publicKey, + privateKey: PRIVATE_KEY + }); + + await uploadKeys(newWorkspaceId, myUser._id, ciphertext, nonce); + if (addAllUsers) { + console.log('adding other users'); const orgUsers = await getOrganizationUsers({ orgId: tempLocalStorage('orgData.id') }); orgUsers.map(async (user: any) => { - if (user.status == 'accepted') { - const result = await addUserToWorkspace( - user.user.email, - newWorkspaceId - ); + if (user.status === 'accepted' && user.email !== myUser.email) { + const result = await addUserToWorkspace(user.user.email, newWorkspaceId); if (result?.invitee && result?.latestKey) { - const PRIVATE_KEY = tempLocalStorage('PRIVATE_KEY'); + const TEMP_PRIVATE_KEY = tempLocalStorage('PRIVATE_KEY'); // assymmetrically decrypt symmetric key with local private key const key = decryptAssymmetric({ ciphertext: result.latestKey.encryptedKey, nonce: result.latestKey.nonce, publicKey: result.latestKey.sender.publicKey, - privateKey: PRIVATE_KEY + privateKey: TEMP_PRIVATE_KEY }); - const { ciphertext, nonce } = encryptAssymmetric({ + const { ciphertext: inviteeCipherText, nonce: inviteeNonce } = encryptAssymmetric({ plaintext: key, publicKey: result.invitee.publicKey, privateKey: PRIVATE_KEY - }) as { ciphertext: string; nonce: string }; + }); - uploadKeys( - newWorkspaceId, - result.invitee._id, - ciphertext, - nonce - ); + uploadKeys(newWorkspaceId, result.invitee._id, inviteeCipherText, inviteeNonce); } } }); } - router.push('/dashboard/' + newWorkspaceId + '?Development'); + setWorkspaceMapping((prevState) => ({ + ...prevState, + [workspaceName]: newWorkspaceId + })); + setWorkspaceSelected(workspaceName); setIsOpen(false); setNewWorkspaceName(''); } else { @@ -129,33 +141,38 @@ export default function Layout({ children }: LayoutProps) { setError(true); setLoading(false); } - } + }; - const menuItems = [ - { - href: - '/dashboard/' + - workspaceMapping[workspaceSelected as any] + - '?Development', - title: 'Secrets', - emoji: - }, - { - href: '/users/' + workspaceMapping[workspaceSelected as any], - title: 'Members', - emoji: - }, - { - href: '/integrations/' + workspaceMapping[workspaceSelected as any], - title: 'Integrations', - emoji: - }, - { - href: '/settings/project/' + workspaceMapping[workspaceSelected as any], - title: 'Project Settings', - emoji: - } - ]; + const menuItems = useMemo( + () => [ + { + href: `/dashboard/${workspaceMapping[workspaceSelected as any]}`, + title: t('nav:menu.secrets'), + emoji: + }, + { + href: `/users/${workspaceMapping[workspaceSelected as any]}`, + title: t('nav:menu.members'), + emoji: + }, + { + href: `/integrations/${workspaceMapping[workspaceSelected as any]}`, + title: t('nav:menu.integrations'), + emoji: + }, + { + href: `/activity/${workspaceMapping[workspaceSelected as any]}`, + title: 'Activity Logs', + emoji: + }, + { + href: `/settings/project/${workspaceMapping[workspaceSelected as any]}`, + title: t('nav:menu.project-settings'), + emoji: + } + ], + [t, workspaceMapping, workspaceSelected] + ); useEffect(() => { // Put a user in a workspace if they're not in one yet @@ -170,85 +187,67 @@ export default function Layout({ children }: LayoutProps) { }); const userWorkspaces = orgUserProjects; if ( - userWorkspaces.length == 0 && - router.asPath != '/noprojects' && - !router.asPath.includes('settings') + userWorkspaces.length === 0 && + router.asPath !== '/noprojects' && + !router.asPath.includes('home') && + !router.asPath.includes('settings') || + router.asPath === '/dashboard/undefined' ) { router.push('/noprojects'); - } else if (router.asPath != '/noprojects') { + } else if (router.asPath !== '/noprojects') { const intendedWorkspaceId = router.asPath .split('/') [router.asPath.split('/').length - 1].split('?')[0]; + + if (!['heroku', 'vercel', 'github', 'netlify'].includes(intendedWorkspaceId)) { + localStorage.setItem('projectData.id', intendedWorkspaceId); + } + // If a user is not a member of a workspace they are trying to access, just push them to one of theirs if ( - intendedWorkspaceId != 'heroku' && + !['heroku', 'vercel', 'github', 'netlify'].includes(intendedWorkspaceId) && !userWorkspaces .map((workspace: { _id: string }) => workspace._id) .includes(intendedWorkspaceId) ) { - router.push('/dashboard/' + userWorkspaces[0]._id + '?Development'); + router.push(`/dashboard/${userWorkspaces[0]._id}`); } else { - setWorkspaceList( - userWorkspaces.map((workspace: any) => workspace.name) - ); setWorkspaceMapping( Object.fromEntries( - userWorkspaces.map((workspace: any) => [ - workspace.name, - workspace._id - ]) + userWorkspaces.map((workspace: any) => [workspace.name, workspace._id]) ) as any ); setWorkspaceSelected( Object.fromEntries( - userWorkspaces.map((workspace: any) => [ - workspace._id, - workspace.name - ]) - )[ - router.asPath - .split('/') - [router.asPath.split('/').length - 1].split('?')[0] - ] + userWorkspaces.map((workspace: any) => [workspace._id, workspace.name]) + )[router.asPath.split('/')[router.asPath.split('/').length - 1].split('?')[0]] ); } } }; putUserInWorkSpace(); onboardingCheck({ setTotalOnboardingActionsDone }); - }, []); + }, [router.query.id]); useEffect(() => { try { if ( workspaceMapping[workspaceSelected as any] && `${workspaceMapping[workspaceSelected as any]}` !== - router.asPath - .split('/') - [router.asPath.split('/').length - 1].split('?')[0] + router.asPath.split('/')[router.asPath.split('/').length - 1].split('?')[0] ) { - router.push( - '/dashboard/' + - workspaceMapping[workspaceSelected as any] + - '?Development' - ); - localStorage.setItem( - 'projectData.id', - `${workspaceMapping[workspaceSelected as any]}` - ); + localStorage.setItem('projectData.id', `${workspaceMapping[workspaceSelected as any]}`); + router.push(`/dashboard/${workspaceMapping[workspaceSelected as any]}`); } - } catch (error) { - console.log(error); + } catch (err) { + console.log(err); } }, [workspaceSelected]); return ( <> -
- +
+ */ diff --git a/frontend/src/pages/activity/[id].tsx b/frontend/src/pages/activity/[id].tsx new file mode 100644 index 000000000..55e5b1924 --- /dev/null +++ b/frontend/src/pages/activity/[id].tsx @@ -0,0 +1,160 @@ +import React, { useEffect, useState } from 'react'; +import { useRouter } from 'next/router'; +import { useTranslation } from 'next-i18next'; + +import Button from '@app/components/basic/buttons/Button'; +import EventFilter from '@app/components/basic/EventFilter'; +import NavHeader from '@app/components/navigation/NavHeader'; +import { getTranslatedServerSideProps } from '@app/components/utilities/withTranslateProps'; +import ActivitySideBar from '@app/ee/components/ActivitySideBar'; + +import getProjectLogs from '../../ee/api/secrets/GetProjectLogs'; +import ActivityTable from '../../ee/components/ActivityTable'; + +interface LogData { + _id: string; + channel: string; + createdAt: string; + ipAddress: string; + user: { + email: string; + }; + actions: { + _id: string; + name: string; + payload: { + secretVersions: string[]; + }; + }[]; +} + +interface PayloadProps { + _id: string; + name: string; + secretVersions: string[]; +} + +interface LogDataPoint { + _id: string; + channel: string; + createdAt: string; + ipAddress: string; + user: string; + payload: PayloadProps[]; +} + +/** + * This is the tab that includes all of the user activity logs + */ +export default function Activity() { + const router = useRouter(); + const [eventChosen, setEventChosen] = useState(''); + const [logsData, setLogsData] = useState([]); + const [isLoading, setIsLoading] = useState(false); + const [currentOffset, setCurrentOffset] = useState(0); + const currentLimit = 10; + const [currentSidebarAction, toggleSidebar] = useState(); + const { t } = useTranslation(); + + // this use effect updates the data in case of a new filter being added + useEffect(() => { + setCurrentOffset(0); + const getLogData = async () => { + setIsLoading(true); + const tempLogsData = await getProjectLogs({ + workspaceId: String(router.query.id), + offset: 0, + limit: currentLimit, + userId: '', + actionNames: eventChosen + }); + setLogsData( + tempLogsData.map((log: LogData) => ({ + _id: log._id, + channel: log.channel, + createdAt: log.createdAt, + ipAddress: log.ipAddress, + user: log.user.email, + payload: log.actions.map((action) => ({ + _id: action._id, + name: action.name, + secretVersions: action.payload.secretVersions + })) + })) + ); + setIsLoading(false); + }; + getLogData(); + }, [eventChosen]); + + // this use effect adds more data in case 'View More' button is clicked + useEffect(() => { + const getLogData = async () => { + setIsLoading(true); + const tempLogsData = await getProjectLogs({ + workspaceId: String(router.query.id), + offset: currentOffset, + limit: currentLimit, + userId: '', + actionNames: eventChosen + }); + setLogsData( + logsData.concat( + tempLogsData.map((log: LogData) => ({ + _id: log._id, + channel: log.channel, + createdAt: log.createdAt, + ipAddress: log.ipAddress, + user: log.user.email, + payload: log.actions.map((action) => ({ + _id: action._id, + name: action.name, + secretVersions: action.payload.secretVersions + })) + })) + ) + ); + setIsLoading(false); + }; + getLogData(); + }, [currentLimit, currentOffset]); + + const loadMoreLogs = () => { + setCurrentOffset(currentOffset + currentLimit); + }; + + return ( +
+ + {currentSidebarAction && ( + + )} +
+
+

{t('activity:title')}

+
+

{t('activity:subtitle')}

+
+
+ +
+ +
+
+
+
+
+ ); +} + +Activity.requireAuth = true; + +export const getServerSideProps = getTranslatedServerSideProps(['activity', 'common']); diff --git a/frontend/src/pages/api/apiKey/addAPIKey.ts b/frontend/src/pages/api/apiKey/addAPIKey.ts new file mode 100644 index 000000000..2b88b380c --- /dev/null +++ b/frontend/src/pages/api/apiKey/addAPIKey.ts @@ -0,0 +1,33 @@ +import SecurityClient from '@app/components/utilities/SecurityClient'; + +interface Props { + name: string; + expiresIn: number; +} + +/** + * This route adds an API key for the user + * @param {object} obj + * @param {string} obj.name - name of the API key + * @param {string} obj.expiresIn - how soon the API key expires in ms + * @returns + */ +const addAPIKey = ({ name, expiresIn }: Props) => + SecurityClient.fetchCall('/api/v2/api-key/', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + name, + expiresIn + }) + }).then(async (res) => { + if (res && res.status === 200) { + return res.json(); + } + console.log('Failed to add API key'); + return undefined; + }); + +export default addAPIKey; diff --git a/frontend/src/pages/api/apiKey/deleteAPIKey.ts b/frontend/src/pages/api/apiKey/deleteAPIKey.ts new file mode 100644 index 000000000..1e242887f --- /dev/null +++ b/frontend/src/pages/api/apiKey/deleteAPIKey.ts @@ -0,0 +1,27 @@ +import SecurityClient from '@app/components/utilities/SecurityClient'; + +interface Props { + apiKeyId: string; +} + +/** + * This route revokes the API key with id [apiKeyId] + * @param {object} obj + * @param {string} obj.apiKeyId - id of the API key to delete + * @returns + */ +const deleteAPIKey = ({ apiKeyId }: Props) => + SecurityClient.fetchCall(`/api/v2/api-key/${apiKeyId}`, { + method: 'DELETE', + headers: { + 'Content-Type': 'application/json' + } + }).then(async (res) => { + if (res && res.status === 200) { + return res.json(); + } + console.log('Failed to delete API key'); + return undefined; + }); + +export default deleteAPIKey; diff --git a/frontend/src/pages/api/apiKey/getAPIKeys.ts b/frontend/src/pages/api/apiKey/getAPIKeys.ts new file mode 100644 index 000000000..66f233d57 --- /dev/null +++ b/frontend/src/pages/api/apiKey/getAPIKeys.ts @@ -0,0 +1,22 @@ +import SecurityClient from '@app/components/utilities/SecurityClient'; + +/** + * This route gets API keys for the user + * @param {*} param0 + * @returns + */ +const getAPIKeys = () => + SecurityClient.fetchCall('/api/v2/api-key', { + method: 'GET', + headers: { + 'Content-Type': 'application/json' + } + }).then(async (res) => { + if (res && res.status === 200) { + return (await res.json()).apiKeyData; + } + console.log('Failed to get API keys'); + return undefined; + }); + +export default getAPIKeys; diff --git a/frontend/src/pages/api/auth/ChangePassword2.ts b/frontend/src/pages/api/auth/ChangePassword2.ts new file mode 100644 index 000000000..71857f8b7 --- /dev/null +++ b/frontend/src/pages/api/auth/ChangePassword2.ts @@ -0,0 +1,39 @@ +import SecurityClient from '@app/components/utilities/SecurityClient'; + +interface Props { + encryptedPrivateKey: string; + iv: string; + tag: string; + salt: string; + verifier: string; + clientProof: string; +} + +/** + * This is the second step of the change password process (pake) + * @param {*} clientPublicKey + * @returns + */ +const changePassword2 = ({ encryptedPrivateKey, iv, tag, salt, verifier, clientProof }: Props) => + SecurityClient.fetchCall('/api/v1/password/change-password', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + clientProof, + encryptedPrivateKey, + iv, + tag, + salt, + verifier + }) + }).then(async (res) => { + if (res && res.status === 200) { + return res; + } + console.log('Failed to change the password'); + return undefined; + }); + +export default changePassword2; diff --git a/frontend/src/pages/api/auth/CheckAuth.ts b/frontend/src/pages/api/auth/CheckAuth.ts new file mode 100644 index 000000000..6b569cfae --- /dev/null +++ b/frontend/src/pages/api/auth/CheckAuth.ts @@ -0,0 +1,15 @@ +import SecurityClient from '@app/components/utilities/SecurityClient'; + +/** + * This function is used to check if the user is authenticated. + * To do that, we get their tokens from cookies, and verify if they are good. + */ +const checkAuth = async () => + SecurityClient.fetchCall('/api/v1/auth/checkAuth', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + } + }).then((res) => res); + +export default checkAuth; diff --git a/frontend/pages/api/auth/CheckEmailVerificationCode.ts b/frontend/src/pages/api/auth/CheckEmailVerificationCode.ts similarity index 72% rename from frontend/pages/api/auth/CheckEmailVerificationCode.ts rename to frontend/src/pages/api/auth/CheckEmailVerificationCode.ts index 0709592a3..6fab91d22 100644 --- a/frontend/pages/api/auth/CheckEmailVerificationCode.ts +++ b/frontend/src/pages/api/auth/CheckEmailVerificationCode.ts @@ -10,17 +10,15 @@ interface Props { * @param {string} obj.code * @returns */ -const checkEmailVerificationCode = ({ email, code }: Props) => { - return fetch('/api/v1/signup/email/verify', { +const checkEmailVerificationCode = ({ email, code }: Props) => fetch('/api/v1/signup/email/verify', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ - email: email, - code: code + email, + code }) }); -}; export default checkEmailVerificationCode; diff --git a/frontend/pages/api/auth/CompleteAccountInformationSignup.ts b/frontend/src/pages/api/auth/CompleteAccountInformationSignup.ts similarity index 92% rename from frontend/pages/api/auth/CompleteAccountInformationSignup.ts rename to frontend/src/pages/api/auth/CompleteAccountInformationSignup.ts index 8057e776a..3fe985cab 100644 --- a/frontend/pages/api/auth/CompleteAccountInformationSignup.ts +++ b/frontend/src/pages/api/auth/CompleteAccountInformationSignup.ts @@ -41,12 +41,11 @@ const completeAccountInformationSignup = ({ salt, verifier, token -}: Props) => { - return fetch('/api/v1/signup/complete-account/signup', { +}: Props) => fetch('/api/v1/signup/complete-account/signup', { method: 'POST', headers: { 'Content-Type': 'application/json', - Authorization: 'Bearer ' + token + Authorization: `Bearer ${ token}` }, body: JSON.stringify({ email, @@ -61,6 +60,5 @@ const completeAccountInformationSignup = ({ verifier }) }); -}; export default completeAccountInformationSignup; diff --git a/frontend/pages/api/auth/CompleteAccountInformationSignupInvite.ts b/frontend/src/pages/api/auth/CompleteAccountInformationSignupInvite.ts similarity index 81% rename from frontend/pages/api/auth/CompleteAccountInformationSignupInvite.ts rename to frontend/src/pages/api/auth/CompleteAccountInformationSignupInvite.ts index 03c11cb67..6fada48ba 100644 --- a/frontend/pages/api/auth/CompleteAccountInformationSignupInvite.ts +++ b/frontend/src/pages/api/auth/CompleteAccountInformationSignupInvite.ts @@ -38,25 +38,23 @@ const completeAccountInformationSignupInvite = ({ salt, verifier, token -}: Props) => { - return fetch('/api/v1/signup/complete-account/invite', { +}: Props) => fetch('/api/v1/signup/complete-account/invite', { method: 'POST', headers: { 'Content-Type': 'application/json', - Authorization: 'Bearer ' + token + Authorization: `Bearer ${ token}` }, body: JSON.stringify({ - email: email, - firstName: firstName, - lastName: lastName, - publicKey: publicKey, + email, + firstName, + lastName, + publicKey, encryptedPrivateKey: ciphertext, - iv: iv, - tag: tag, - salt: salt, - verifier: verifier + iv, + tag, + salt, + verifier }) }); -}; export default completeAccountInformationSignupInvite; diff --git a/frontend/pages/api/auth/EmailVerifyOnPasswordReset.ts b/frontend/src/pages/api/auth/EmailVerifyOnPasswordReset.ts similarity index 96% rename from frontend/pages/api/auth/EmailVerifyOnPasswordReset.ts rename to frontend/src/pages/api/auth/EmailVerifyOnPasswordReset.ts index b3d5e3d55..0ef20ca06 100644 --- a/frontend/pages/api/auth/EmailVerifyOnPasswordReset.ts +++ b/frontend/src/pages/api/auth/EmailVerifyOnPasswordReset.ts @@ -18,8 +18,8 @@ const EmailVerifyOnPasswordReset = async ({ email, code }: Props) => { 'Content-Type': 'application/json' }, body: JSON.stringify({ - email: email, - code: code + email, + code }) }); if (response?.status === 200) { diff --git a/frontend/pages/api/auth/IssueBackupPrivateKey.ts b/frontend/src/pages/api/auth/IssueBackupPrivateKey.ts similarity index 73% rename from frontend/pages/api/auth/IssueBackupPrivateKey.ts rename to frontend/src/pages/api/auth/IssueBackupPrivateKey.ts index e24ac510e..90db8d8dd 100644 --- a/frontend/pages/api/auth/IssueBackupPrivateKey.ts +++ b/frontend/src/pages/api/auth/IssueBackupPrivateKey.ts @@ -1,4 +1,4 @@ -import SecurityClient from '~/utilities/SecurityClient'; +import SecurityClient from '@app/components/utilities/SecurityClient'; interface Props { encryptedPrivateKey: string; @@ -27,19 +27,19 @@ const issueBackupPrivateKey = ({ salt, verifier, clientProof -}: Props) => { - return SecurityClient.fetchCall('/api/v1/password/backup-private-key', { +}: Props) => + SecurityClient.fetchCall('/api/v1/password/backup-private-key', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ - clientProof: clientProof, - encryptedPrivateKey: encryptedPrivateKey, - iv: iv, - tag: tag, - salt: salt, - verifier: verifier + clientProof, + encryptedPrivateKey, + iv, + tag, + salt, + verifier }) }).then((res) => { if (res?.status !== 200) { @@ -47,6 +47,5 @@ const issueBackupPrivateKey = ({ } return res; }); -}; export default issueBackupPrivateKey; diff --git a/frontend/pages/api/auth/Login1.ts b/frontend/src/pages/api/auth/Login1.ts similarity index 97% rename from frontend/pages/api/auth/Login1.ts rename to frontend/src/pages/api/auth/Login1.ts index 818a2d157..94a56866d 100644 --- a/frontend/pages/api/auth/Login1.ts +++ b/frontend/src/pages/api/auth/Login1.ts @@ -16,7 +16,7 @@ const login1 = async (email: string, clientPublicKey: string) => { "Content-Type": "application/json", }, body: JSON.stringify({ - email: email, + email, clientPublicKey, }), }); diff --git a/frontend/pages/api/auth/Login2.ts b/frontend/src/pages/api/auth/Login2.ts similarity index 67% rename from frontend/pages/api/auth/Login2.ts rename to frontend/src/pages/api/auth/Login2.ts index 3adcb695f..6c431cbb8 100644 --- a/frontend/pages/api/auth/Login2.ts +++ b/frontend/src/pages/api/auth/Login2.ts @@ -13,24 +13,24 @@ interface Login2Response { * @returns */ const login2 = async (email: string, clientProof: string) => { - const response = await fetch("/api/v1/auth/login2", { - method: "POST", + const response = await fetch('/api/v1/auth/login2', { + method: 'POST', headers: { - "Content-Type": "application/json", + 'Content-Type': 'application/json' }, body: JSON.stringify({ - email: email, - clientProof, + email, + clientProof }), - credentials: "include", + credentials: 'include' }); // need precise error handling about the status code - if (response.status == 200) { + if (response.status === 200) { const data = (await response.json()) as unknown as Login2Response; return data; } - throw new Error("Password verification failed"); + throw new Error('Password verification failed'); }; export default login2; diff --git a/frontend/pages/api/auth/Logout.ts b/frontend/src/pages/api/auth/Logout.ts similarity index 76% rename from frontend/pages/api/auth/Logout.ts rename to frontend/src/pages/api/auth/Logout.ts index cd4ff9a61..acf04bc1a 100644 --- a/frontend/pages/api/auth/Logout.ts +++ b/frontend/src/pages/api/auth/Logout.ts @@ -1,18 +1,18 @@ -import SecurityClient from '~/utilities/SecurityClient'; +import SecurityClient from '@app/components/utilities/SecurityClient'; /** * This route logs the user out. Note: the user should authorized to do this. * We first try to log out - if the authorization fails (response.status = 401), we refetch the new token, and then retry */ -const logout = async () => { - return SecurityClient.fetchCall('/api/v1/auth/logout', { +const logout = async () => + SecurityClient.fetchCall('/api/v1/auth/logout', { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials: 'include' }).then((res) => { - if (res?.status == 200) { + if (res?.status === 200) { SecurityClient.setToken(''); // Delete the cookie by not setting a value; Alternatively clear the local storage localStorage.setItem('publicKey', ''); @@ -22,10 +22,9 @@ const logout = async () => { localStorage.setItem('PRIVATE_KEY', ''); console.log('User logged out', res); return res; - } else { - console.log('Failed to log out'); } + console.log('Failed to log out'); + return undefined; }); -}; export default logout; diff --git a/frontend/pages/api/auth/SRP1.ts b/frontend/src/pages/api/auth/SRP1.ts similarity index 54% rename from frontend/pages/api/auth/SRP1.ts rename to frontend/src/pages/api/auth/SRP1.ts index cb6386ff2..2316a605c 100644 --- a/frontend/pages/api/auth/SRP1.ts +++ b/frontend/src/pages/api/auth/SRP1.ts @@ -1,4 +1,4 @@ -import SecurityClient from '~/utilities/SecurityClient'; +import SecurityClient from '@app/components/utilities/SecurityClient'; interface Props { clientPublicKey: string; @@ -9,8 +9,8 @@ interface Props { * @param {string} clientPublicKey * @returns */ -const SRP1 = ({ clientPublicKey }: Props) => { - return SecurityClient.fetchCall('/api/v1/password/srp1', { +const SRP1 = ({ clientPublicKey }: Props) => + SecurityClient.fetchCall('/api/v1/password/srp1', { method: 'POST', headers: { 'Content-Type': 'application/json' @@ -19,12 +19,11 @@ const SRP1 = ({ clientPublicKey }: Props) => { clientPublicKey }) }).then(async (res) => { - if (res && res.status == 200) { - return await res.json(); - } else { - console.log('Failed to do the first step of SRP'); + if (res && res.status === 200) { + return res.json(); } + console.log('Failed to do the first step of SRP'); + return undefined; }); -}; export default SRP1; diff --git a/frontend/pages/api/auth/SendEmailOnPasswordReset.ts b/frontend/src/pages/api/auth/SendEmailOnPasswordReset.ts similarity index 97% rename from frontend/pages/api/auth/SendEmailOnPasswordReset.ts rename to frontend/src/pages/api/auth/SendEmailOnPasswordReset.ts index abe610f07..e0f2f0ae3 100644 --- a/frontend/pages/api/auth/SendEmailOnPasswordReset.ts +++ b/frontend/src/pages/api/auth/SendEmailOnPasswordReset.ts @@ -16,7 +16,7 @@ const SendEmailOnPasswordReset = async ({ email }: Props) => { 'Content-Type': 'application/json' }, body: JSON.stringify({ - email: email + email }) }); // need precise error handling about the status code diff --git a/frontend/pages/api/auth/SendVerificationEmail.ts b/frontend/src/pages/api/auth/SendVerificationEmail.ts similarity index 95% rename from frontend/pages/api/auth/SendVerificationEmail.ts rename to frontend/src/pages/api/auth/SendVerificationEmail.ts index 4f3b063c6..dcf7d3db7 100644 --- a/frontend/pages/api/auth/SendVerificationEmail.ts +++ b/frontend/src/pages/api/auth/SendVerificationEmail.ts @@ -9,7 +9,7 @@ const sendVerificationEmail = (email: string) => { 'Content-Type': 'application/json' }, body: JSON.stringify({ - email: email + email }) }); }; diff --git a/frontend/pages/api/auth/Token.ts b/frontend/src/pages/api/auth/Token.ts similarity index 56% rename from frontend/pages/api/auth/Token.ts rename to frontend/src/pages/api/auth/Token.ts index ed347ba4b..75ac906f6 100644 --- a/frontend/pages/api/auth/Token.ts +++ b/frontend/src/pages/api/auth/Token.ts @@ -1,17 +1,16 @@ -const token = async () => { - return fetch('/api/v1/auth/token', { +const token = async () => + fetch('/api/v1/auth/token', { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials: 'include' }).then(async (res) => { - if (res.status == 200) { + if (res.status === 200) { return (await res.json()).token; - } else { - console.log('Getting a new token failed'); } + console.log('Getting a new token failed'); + return undefined; }); -}; export default token; diff --git a/frontend/pages/api/auth/VerifySignupInvite.ts b/frontend/src/pages/api/auth/VerifySignupInvite.ts similarity index 81% rename from frontend/pages/api/auth/VerifySignupInvite.ts rename to frontend/src/pages/api/auth/VerifySignupInvite.ts index 0b6cc7577..71f724654 100644 --- a/frontend/pages/api/auth/VerifySignupInvite.ts +++ b/frontend/src/pages/api/auth/VerifySignupInvite.ts @@ -10,8 +10,7 @@ interface Props { * @param {string} obj.code - code that a user received to the abovementioned email * @returns */ -const verifySignupInvite = ({ email, code }: Props) => { - return fetch('/api/v1/invite-org/verify', { +const verifySignupInvite = ({ email, code }: Props) => fetch('/api/v1/invite-org/verify', { method: 'POST', headers: { 'Content-Type': 'application/json' @@ -21,6 +20,5 @@ const verifySignupInvite = ({ email, code }: Props) => { code }) }); -}; export default verifySignupInvite; diff --git a/frontend/pages/api/auth/getBackupEncryptedPrivateKey.ts b/frontend/src/pages/api/auth/getBackupEncryptedPrivateKey.ts similarity index 84% rename from frontend/pages/api/auth/getBackupEncryptedPrivateKey.ts rename to frontend/src/pages/api/auth/getBackupEncryptedPrivateKey.ts index 826085263..7eca82018 100644 --- a/frontend/pages/api/auth/getBackupEncryptedPrivateKey.ts +++ b/frontend/src/pages/api/auth/getBackupEncryptedPrivateKey.ts @@ -8,12 +8,11 @@ const getBackupEncryptedPrivateKey = ({ verificationToken }: { verificationToken: string; -}) => { - return fetch('/api/v1/password/backup-private-key', { +}) => fetch('/api/v1/password/backup-private-key', { method: 'GET', headers: { 'Content-Type': 'application/json', - Authorization: 'Bearer ' + verificationToken + Authorization: `Bearer ${ verificationToken}` } }).then(async (res) => { if (res?.status !== 200) { @@ -21,6 +20,5 @@ const getBackupEncryptedPrivateKey = ({ } return (await res?.json())?.backupPrivateKey; }); -}; export default getBackupEncryptedPrivateKey; diff --git a/frontend/pages/api/auth/publicKeyInfisical.ts b/frontend/src/pages/api/auth/publicKeyInfisical.ts similarity index 57% rename from frontend/pages/api/auth/publicKeyInfisical.ts rename to frontend/src/pages/api/auth/publicKeyInfisical.ts index d3e0f646c..af8269ee3 100644 --- a/frontend/pages/api/auth/publicKeyInfisical.ts +++ b/frontend/src/pages/api/auth/publicKeyInfisical.ts @@ -1,10 +1,8 @@ -const publicKeyInfisical = () => { - return fetch('/api/v1/key/publicKey/infisical', { +const publicKeyInfisical = () => fetch('/api/v1/key/publicKey/infisical', { method: 'GET', headers: { 'Content-Type': 'application/json' } }); -}; export default publicKeyInfisical; diff --git a/frontend/pages/api/auth/resetPasswordOnAccountRecovery.ts b/frontend/src/pages/api/auth/resetPasswordOnAccountRecovery.ts similarity index 80% rename from frontend/pages/api/auth/resetPasswordOnAccountRecovery.ts rename to frontend/src/pages/api/auth/resetPasswordOnAccountRecovery.ts index f2b5ad98e..77c1a2aa0 100644 --- a/frontend/pages/api/auth/resetPasswordOnAccountRecovery.ts +++ b/frontend/src/pages/api/auth/resetPasswordOnAccountRecovery.ts @@ -25,19 +25,18 @@ const resetPasswordOnAccountRecovery = ({ tag, salt, verifier -}: Props) => { - return fetch('/api/v1/password/password-reset', { +}: Props) => fetch('/api/v1/password/password-reset', { method: 'POST', headers: { 'Content-Type': 'application/json', - Authorization: 'Bearer ' + verificationToken + Authorization: `Bearer ${ verificationToken}` }, body: JSON.stringify({ - encryptedPrivateKey: encryptedPrivateKey, - iv: iv, - tag: tag, - salt: salt, - verifier: verifier + encryptedPrivateKey, + iv, + tag, + salt, + verifier }) }).then(async (res) => { if (res?.status !== 200) { @@ -45,6 +44,5 @@ const resetPasswordOnAccountRecovery = ({ } return res; }); -}; export default resetPasswordOnAccountRecovery; diff --git a/frontend/src/pages/api/bot/getBot.ts b/frontend/src/pages/api/bot/getBot.ts new file mode 100644 index 000000000..5c1d11173 --- /dev/null +++ b/frontend/src/pages/api/bot/getBot.ts @@ -0,0 +1,27 @@ +import SecurityClient from '@app/components/utilities/SecurityClient'; + +interface Props { + workspaceId: string; +} + +/** + * This function fetches the bot for a project + * @param {Object} obj + * @param {String} obj.workspaceId + * @returns + */ +const getBot = async ({ workspaceId }: Props) => + SecurityClient.fetchCall(`/api/v1/bot/${workspaceId}`, { + method: 'GET', + headers: { + 'Content-Type': 'application/json' + } + }).then(async (res) => { + if (res && res.status === 200) { + return (await res.json()).bot; + } + console.log('Failed to get bot for project'); + return undefined; + }); + +export default getBot; diff --git a/frontend/src/pages/api/bot/setBotActiveStatus.ts b/frontend/src/pages/api/bot/setBotActiveStatus.ts new file mode 100644 index 000000000..0cb84081c --- /dev/null +++ b/frontend/src/pages/api/bot/setBotActiveStatus.ts @@ -0,0 +1,42 @@ +import SecurityClient from '@app/components/utilities/SecurityClient'; + +interface BotKey { + encryptedKey: string; + nonce: string; +} + +interface Props { + botId: string; + isActive: boolean; + botKey?: BotKey; +} + +/** + * This function sets the active status of a bot and shares a copy of + * the project key (encrypted under the bot's public key) with the + * project's bot + * @param {Object} obj + * @param {String} obj.botId + * @param {String} obj.isActive + * @param {Object} obj.botKey + * @returns + */ +const setBotActiveStatus = async ({ botId, isActive, botKey }: Props) => + SecurityClient.fetchCall(`/api/v1/bot/${botId}/active`, { + method: 'PATCH', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + isActive, + botKey + }) + }).then(async (res) => { + if (res && res.status === 200) { + return res.json(); + } + console.log('Failed to get bot for project'); + return undefined; + }); + +export default setBotActiveStatus; diff --git a/frontend/src/pages/api/environments/createEnvironment.ts b/frontend/src/pages/api/environments/createEnvironment.ts new file mode 100644 index 000000000..ddeb8effd --- /dev/null +++ b/frontend/src/pages/api/environments/createEnvironment.ts @@ -0,0 +1,28 @@ +import SecurityClient from '@app/components/utilities/SecurityClient'; + +type NewEnvironmentInfo = { + environmentSlug: string; + environmentName: string; +}; + +/** + * This route deletes a specified workspace. + * @param {*} workspaceId + * @returns + */ +const createEnvironment = (workspaceId: string, newEnv: NewEnvironmentInfo) => + SecurityClient.fetchCall(`/api/v2/workspace/${workspaceId}/environments`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(newEnv) + }).then(async (res) => { + if (res && res.status === 200) { + return res; + } + console.log('Failed to create environment'); + return undefined; + }); + +export default createEnvironment; diff --git a/frontend/src/pages/api/environments/deleteEnvironment.ts b/frontend/src/pages/api/environments/deleteEnvironment.ts new file mode 100644 index 000000000..4463ef4a3 --- /dev/null +++ b/frontend/src/pages/api/environments/deleteEnvironment.ts @@ -0,0 +1,22 @@ +import SecurityClient from '@app/components/utilities/SecurityClient'; +/** + * This route deletes a specified env. + * @param {*} workspaceId + * @returns + */ +const deleteEnvironment = (workspaceId: string, environmentSlug: string) => + SecurityClient.fetchCall(`/api/v2/workspace/${workspaceId}/environments`, { + method: 'DELETE', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ environmentSlug }) + }).then(async (res) => { + if (res && res.status === 200) { + return res; + } + console.log('Failed to delete environment'); + return undefined; + }); + +export default deleteEnvironment; diff --git a/frontend/src/pages/api/environments/updateEnvironment.ts b/frontend/src/pages/api/environments/updateEnvironment.ts new file mode 100644 index 000000000..d28517998 --- /dev/null +++ b/frontend/src/pages/api/environments/updateEnvironment.ts @@ -0,0 +1,29 @@ +import SecurityClient from '@app/components/utilities/SecurityClient'; + +type EnvironmentInfo = { + oldEnvironmentSlug: string; + environmentSlug: string; + environmentName: string; +}; + +/** + * This route updates a specified environment. + * @param {*} workspaceId + * @returns + */ +const updateEnvironment = (workspaceId: string, env: EnvironmentInfo) => + SecurityClient.fetchCall(`/api/v2/workspace/${workspaceId}/environments`, { + method: 'PUT', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(env) + }).then(async (res) => { + if (res && res.status === 200) { + return res; + } + console.log('Failed to update environment'); + return undefined; + }); + +export default updateEnvironment; diff --git a/frontend/src/pages/api/files/AddSecrets.ts b/frontend/src/pages/api/files/AddSecrets.ts new file mode 100644 index 000000000..46d454a04 --- /dev/null +++ b/frontend/src/pages/api/files/AddSecrets.ts @@ -0,0 +1,54 @@ +import SecurityClient from '@app/components/utilities/SecurityClient'; + +interface EncryptedSecretProps { + id: string; + createdAt: string; + environment: string; + secretCommentCiphertext: string; + secretCommentIV: string; + secretCommentTag: string; + secretKeyCiphertext: string; + secretKeyIV: string; + secretKeyTag: string; + secretValueCiphertext: string; + secretValueIV: string; + secretValueTag: string; + type: 'personal' | 'shared'; +} + +/** + * This function adds secrets to a certain project + * @param {object} obj + * @param {EncryptedSecretProps} obj.secrets - the ids of secrets that we want to add + * @param {string} obj.env - the environment to which we are adding secrets + * @param {string} obj.workspaceId - the project to which we are adding secrets + * @returns + */ +const addSecrets = async ({ + secrets, + env, + workspaceId +}: { + secrets: EncryptedSecretProps[]; + env: string; + workspaceId: string; +}) => + SecurityClient.fetchCall('/api/v2/secrets', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + environment: env, + workspaceId, + secrets + }) + }).then(async (res) => { + if (res && res.status === 200) { + return res.json(); + } + console.log('Failed to add certain project secrets'); + return undefined; + }); + +export default addSecrets; diff --git a/frontend/src/pages/api/files/DeleteSecrets.ts b/frontend/src/pages/api/files/DeleteSecrets.ts new file mode 100644 index 000000000..76dd19da3 --- /dev/null +++ b/frontend/src/pages/api/files/DeleteSecrets.ts @@ -0,0 +1,25 @@ +import SecurityClient from '@app/components/utilities/SecurityClient'; + +/** + * This function deletes certain secrets from a certain project + * @param {string[]} secretIds - the ids of secrets that we want to be deleted + * @returns + */ +const deleteSecrets = async ({ secretIds }: { secretIds: string[] }) => + SecurityClient.fetchCall('/api/v2/secrets', { + method: 'DELETE', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + secretIds + }) + }).then(async (res) => { + if (res && res.status === 200) { + return res.json(); + } + console.log('Failed to delete certain project secrets'); + return undefined; + }); + +export default deleteSecrets; diff --git a/frontend/src/pages/api/files/GetSecrets.ts b/frontend/src/pages/api/files/GetSecrets.ts new file mode 100644 index 000000000..fb980a433 --- /dev/null +++ b/frontend/src/pages/api/files/GetSecrets.ts @@ -0,0 +1,29 @@ +import SecurityClient from '@app/components/utilities/SecurityClient'; + +/** + * This function fetches the encrypted secrets for a certain project + * @param {string} workspaceId - project is for which a user is trying to get secrets + * @param {string} env - environment of a project for which a user is trying ot get secrets + * @returns + */ +const getSecrets = async (workspaceId: string, env: string) => + SecurityClient.fetchCall( + `/api/v2/secrets?${new URLSearchParams({ + environment: env, + workspaceId + })}`, + { + method: 'GET', + headers: { + 'Content-Type': 'application/json' + } + } + ).then(async (res) => { + if (res && res.status === 200) { + return (await res.json()).secrets; + } + console.log('Failed to get project secrets'); + return undefined; + }); + +export default getSecrets; diff --git a/frontend/src/pages/api/files/UpdateSecrets.ts b/frontend/src/pages/api/files/UpdateSecrets.ts new file mode 100644 index 000000000..b42d653c9 --- /dev/null +++ b/frontend/src/pages/api/files/UpdateSecrets.ts @@ -0,0 +1,42 @@ +import SecurityClient from '@app/components/utilities/SecurityClient'; + +interface EncryptedSecretProps { + id: string; + createdAt: string; + environment: string; + secretCommentCiphertext: string; + secretCommentIV: string; + secretCommentTag: string; + secretKeyCiphertext: string; + secretKeyIV: string; + secretKeyTag: string; + secretValueCiphertext: string; + secretValueIV: string; + secretValueTag: string; + type: 'personal' | 'shared'; +} + +/** + * This function updates certain secrets in a certain project + * @param {object} obj + * @param {EncryptedSecretProps[]} obj.secrets - the ids of secrets that we want to update + * @returns + */ +const updateSecrets = async ({ secrets }: { secrets: EncryptedSecretProps[] }) => + SecurityClient.fetchCall('/api/v2/secrets', { + method: 'PATCH', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + secrets + }) + }).then(async (res) => { + if (res && res.status === 200) { + return res.json(); + } + console.log('Failed to update certain project secrets'); + return undefined; + }); + +export default updateSecrets; diff --git a/frontend/pages/api/files/UploadSecrets.ts b/frontend/src/pages/api/files/UploadSecrets.ts similarity index 63% rename from frontend/pages/api/files/UploadSecrets.ts rename to frontend/src/pages/api/files/UploadSecrets.ts index 04fcb78b5..4fc0ff0e8 100644 --- a/frontend/pages/api/files/UploadSecrets.ts +++ b/frontend/src/pages/api/files/UploadSecrets.ts @@ -1,4 +1,4 @@ -import SecurityClient from '~/utilities/SecurityClient'; +import SecurityClient from '@app/components/utilities/SecurityClient'; interface Props { workspaceId: string; @@ -16,13 +16,8 @@ interface Props { * @param {string} obj.environment * @returns */ -const uploadSecrets = async ({ - workspaceId, - secrets, - keys, - environment -}: Props) => { - return SecurityClient.fetchCall('/api/v1/secret/' + workspaceId, { +const uploadSecrets = async ({ workspaceId, secrets, keys, environment }: Props) => + SecurityClient.fetchCall(`/api/v2/workspace/${workspaceId}/secrets`, { method: 'POST', headers: { 'Content-Type': 'application/json' @@ -34,12 +29,11 @@ const uploadSecrets = async ({ channel: 'web' }) }).then(async (res) => { - if (res && res.status == 200) { + if (res && res.status === 200) { return res; - } else { - console.log('Failed to push secrets'); } + console.log('Failed to push secrets'); + return undefined; }); -}; export default uploadSecrets; diff --git a/frontend/src/pages/api/integrations/ChangeHerokuConfigVars.ts b/frontend/src/pages/api/integrations/ChangeHerokuConfigVars.ts new file mode 100644 index 000000000..27e36a33d --- /dev/null +++ b/frontend/src/pages/api/integrations/ChangeHerokuConfigVars.ts @@ -0,0 +1,37 @@ +import SecurityClient from '@app/components/utilities/SecurityClient'; + +interface Props { + integrationId: string; + key: { encryptedKey: any; nonce: any }; + secrets: { + ciphertextKey: any; + ivKey: any; + tagKey: any; + hashKey: any; + ciphertextValue: any; + ivValue: any; + tagValue: any; + hashValue: any; + type: string; + }[]; +} + +const changeHerokuConfigVars = ({ integrationId, key, secrets }: Props) => + SecurityClient.fetchCall(`/api/v1/integration/${integrationId}/sync`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + key, + secrets + }) + }).then(async (res) => { + if (res && res.status === 200) { + return res; + } + console.log('Failed to sync secrets to Heroku'); + return undefined; + }); + +export default changeHerokuConfigVars; diff --git a/frontend/src/pages/api/integrations/DeleteIntegration.ts b/frontend/src/pages/api/integrations/DeleteIntegration.ts new file mode 100644 index 000000000..a16c629a3 --- /dev/null +++ b/frontend/src/pages/api/integrations/DeleteIntegration.ts @@ -0,0 +1,26 @@ +import SecurityClient from '@app/components/utilities/SecurityClient'; + +interface Props { + integrationId: string; +} + +/** + * This route deletes an integration from a certain project + * @param {*} integrationId + * @returns + */ +const deleteIntegration = ({ integrationId }: Props) => + SecurityClient.fetchCall(`/api/v1/integration/${integrationId}`, { + method: 'DELETE', + headers: { + 'Content-Type': 'application/json' + } + }).then(async (res) => { + if (res && res.status === 200) { + return (await res.json()).integration; + } + console.log('Failed to delete an integration'); + return undefined; + }); + +export default deleteIntegration; diff --git a/frontend/src/pages/api/integrations/DeleteIntegrationAuth.ts b/frontend/src/pages/api/integrations/DeleteIntegrationAuth.ts new file mode 100644 index 000000000..091c615cf --- /dev/null +++ b/frontend/src/pages/api/integrations/DeleteIntegrationAuth.ts @@ -0,0 +1,26 @@ +import SecurityClient from '@app/components/utilities/SecurityClient'; + +interface Props { + integrationAuthId: string; +} + +/** + * This route deletes an integration authorization from a certain project + * @param {*} integrationAuthId + * @returns + */ +const deleteIntegrationAuth = ({ integrationAuthId }: Props) => + SecurityClient.fetchCall(`/api/v1/integration-auth/${integrationAuthId}`, { + method: 'DELETE', + headers: { + 'Content-Type': 'application/json' + } + }).then(async (res) => { + if (res && res.status === 200) { + return (await res.json()).integrationAuth; + } + console.log('Failed to delete an integration authorization'); + return undefined; + }); + +export default deleteIntegrationAuth; diff --git a/frontend/src/pages/api/integrations/GetIntegrationApps.ts b/frontend/src/pages/api/integrations/GetIntegrationApps.ts new file mode 100644 index 000000000..cf49882b4 --- /dev/null +++ b/frontend/src/pages/api/integrations/GetIntegrationApps.ts @@ -0,0 +1,21 @@ +import SecurityClient from '@app/components/utilities/SecurityClient'; + +interface Props { + integrationAuthId: string; +} + +const getIntegrationApps = ({ integrationAuthId }: Props) => + SecurityClient.fetchCall(`/api/v1/integration-auth/${integrationAuthId}/apps`, { + method: 'GET', + headers: { + 'Content-Type': 'application/json' + } + }).then(async (res) => { + if (res && res.status === 200) { + return (await res.json()).apps; + } + console.log('Failed to get available apps for an integration'); + return undefined; + }); + +export default getIntegrationApps; diff --git a/frontend/src/pages/api/integrations/GetIntegrationOptions.ts b/frontend/src/pages/api/integrations/GetIntegrationOptions.ts new file mode 100644 index 000000000..b00ff3fd5 --- /dev/null +++ b/frontend/src/pages/api/integrations/GetIntegrationOptions.ts @@ -0,0 +1,17 @@ +import SecurityClient from '@app/components/utilities/SecurityClient'; + +const getIntegrationOptions = () => + SecurityClient.fetchCall('/api/v1/integration-auth/integration-options', { + method: 'GET', + headers: { + 'Content-Type': 'application/json' + } + }).then(async (res) => { + if (res && res.status === 200) { + return (await res.json()).integrationOptions; + } + console.log('Failed to get (cloud) integration options'); + return undefined; + }); + +export default getIntegrationOptions; diff --git a/frontend/pages/api/integrations/StartIntegration.ts b/frontend/src/pages/api/integrations/StartIntegration.ts similarity index 68% rename from frontend/pages/api/integrations/StartIntegration.ts rename to frontend/src/pages/api/integrations/StartIntegration.ts index bef82e7e1..199462206 100644 --- a/frontend/pages/api/integrations/StartIntegration.ts +++ b/frontend/src/pages/api/integrations/StartIntegration.ts @@ -1,4 +1,4 @@ -import SecurityClient from '~/utilities/SecurityClient'; +import SecurityClient from '@app/components/utilities/SecurityClient'; interface Props { integrationId: string; @@ -11,8 +11,8 @@ interface Props { * @param {*} integrationId * @returns */ -const startIntegration = ({ integrationId, appName, environment }: Props) => { - return SecurityClient.fetchCall('/api/v1/integration/' + integrationId, { +const startIntegration = ({ integrationId, appName, environment }: Props) => + SecurityClient.fetchCall(`/api/v1/integration/${integrationId}`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' @@ -25,12 +25,11 @@ const startIntegration = ({ integrationId, appName, environment }: Props) => { } }) }).then(async (res) => { - if (res && res.status == 200) { + if (res && res.status === 200) { return res; - } else { - console.log('Failed to start an integration'); } + console.log('Failed to start an integration'); + return undefined; }); -}; export default startIntegration; diff --git a/frontend/pages/api/integrations/authorizeIntegration.ts b/frontend/src/pages/api/integrations/authorizeIntegration.ts similarity index 72% rename from frontend/pages/api/integrations/authorizeIntegration.ts rename to frontend/src/pages/api/integrations/authorizeIntegration.ts index 1454bde4d..94f1d54f5 100644 --- a/frontend/pages/api/integrations/authorizeIntegration.ts +++ b/frontend/src/pages/api/integrations/authorizeIntegration.ts @@ -1,4 +1,4 @@ -import SecurityClient from '~/utilities/SecurityClient'; +import SecurityClient from '@app/components/utilities/SecurityClient'; interface Props { workspaceId: string; @@ -13,8 +13,8 @@ interface Props { * @param {object} obj.integration - integration which a user is trying to turn on * @returns */ -const AuthorizeIntegration = ({ workspaceId, code, integration }: Props) => { - return SecurityClient.fetchCall('/api/v1/integration-auth/oauth-token', { +const AuthorizeIntegration = ({ workspaceId, code, integration }: Props) => + SecurityClient.fetchCall('/api/v1/integration-auth/oauth-token', { method: 'POST', headers: { 'Content-Type': 'application/json' @@ -25,12 +25,11 @@ const AuthorizeIntegration = ({ workspaceId, code, integration }: Props) => { integration }) }).then(async (res) => { - if (res && res.status == 200) { + if (res && res.status === 200) { return res; - } else { - console.log('Failed to authorize the integration'); } + console.log('Failed to authorize the integration'); + return undefined; }); -}; export default AuthorizeIntegration; diff --git a/frontend/src/pages/api/integrations/createIntegration.ts b/frontend/src/pages/api/integrations/createIntegration.ts new file mode 100644 index 000000000..6b37f1281 --- /dev/null +++ b/frontend/src/pages/api/integrations/createIntegration.ts @@ -0,0 +1,31 @@ +import SecurityClient from '@app/components/utilities/SecurityClient'; + +interface Props { + integrationAuthId: string; +} +/** + * This route creates a new integration based on the integration authorization with id [integrationAuthId] + * @param {Object} obj + * @param {String} obj.accessToken - id of integration authorization for which to create the integration + * @returns + */ +const createIntegration = ({ + integrationAuthId +}: Props) => + SecurityClient.fetchCall('/api/v1/integration', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + integrationAuthId + }) + }).then(async (res) => { + if (res && res.status === 200) { + return (await res.json()).integration; + } + console.log('Failed to create integration'); + return undefined; + }); + +export default createIntegration; \ No newline at end of file diff --git a/frontend/src/pages/api/integrations/getWorkspaceAuthorizations.ts b/frontend/src/pages/api/integrations/getWorkspaceAuthorizations.ts new file mode 100644 index 000000000..e6b287554 --- /dev/null +++ b/frontend/src/pages/api/integrations/getWorkspaceAuthorizations.ts @@ -0,0 +1,26 @@ +import SecurityClient from '@app/components/utilities/SecurityClient'; + +interface Props { + workspaceId: string; +} + +/** + * This route gets authorizations of a certain project (Heroku, etc.) + * @param {*} workspaceId + * @returns + */ +const getWorkspaceAuthorizations = ({ workspaceId }: Props) => + SecurityClient.fetchCall(`/api/v1/workspace/${workspaceId}/authorizations`, { + method: 'GET', + headers: { + 'Content-Type': 'application/json' + } + }).then(async (res) => { + if (res && res.status === 200) { + return (await res.json()).authorizations; + } + console.log('Failed to get project authorizations'); + return undefined; + }); + +export default getWorkspaceAuthorizations; diff --git a/frontend/src/pages/api/integrations/getWorkspaceIntegrations.ts b/frontend/src/pages/api/integrations/getWorkspaceIntegrations.ts new file mode 100644 index 000000000..1a518f0eb --- /dev/null +++ b/frontend/src/pages/api/integrations/getWorkspaceIntegrations.ts @@ -0,0 +1,26 @@ +import SecurityClient from '@app/components/utilities/SecurityClient'; + +interface Props { + workspaceId: string; +} + +/** + * This route gets integrations of a certain project (Heroku, etc.) + * @param {*} workspaceId + * @returns + */ +const getWorkspaceIntegrations = ({ workspaceId }: Props) => + SecurityClient.fetchCall(`/api/v1/workspace/${workspaceId}/integrations`, { + method: 'GET', + headers: { + 'Content-Type': 'application/json' + } + }).then(async (res) => { + if (res && res.status === 200) { + return (await res.json()).integrations; + } + console.log('Failed to get the project integrations'); + return undefined; + }); + +export default getWorkspaceIntegrations; diff --git a/frontend/src/pages/api/integrations/saveIntegrationAccessToken.ts b/frontend/src/pages/api/integrations/saveIntegrationAccessToken.ts new file mode 100644 index 000000000..184780dca --- /dev/null +++ b/frontend/src/pages/api/integrations/saveIntegrationAccessToken.ts @@ -0,0 +1,42 @@ +import SecurityClient from '@app/components/utilities/SecurityClient'; + +interface Props { + workspaceId: string | null; + integration: string | undefined; + accessToken: string; +} +/** + * This route creates a new integration authorization for integration [integration] + * that requires the user to input their access token manually (e.g. Render). It + * saves access token [accessToken] under that integration for workspace with id + * [workspaceId]. + * @param {Object} obj + * @param {String} obj.workspaceId - id of workspace to authorize integration for + * @param {String} obj.integration - integration + * @param {String} obj.accessToken - access token to save + * @returns + */ +const saveIntegrationAccessToken = ({ + workspaceId, + integration, + accessToken +}: Props) => + SecurityClient.fetchCall(`/api/v1/integration-auth/access-token`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + workspaceId, + integration, + accessToken + }) + }).then(async (res) => { + if (res && res.status === 200) { + return (await res.json()).integrationAuth; + } + console.log('Failed to save integration access token'); + return undefined; + }); + +export default saveIntegrationAccessToken; diff --git a/frontend/src/pages/api/integrations/updateIntegration.ts b/frontend/src/pages/api/integrations/updateIntegration.ts new file mode 100644 index 000000000..53f944114 --- /dev/null +++ b/frontend/src/pages/api/integrations/updateIntegration.ts @@ -0,0 +1,55 @@ +import SecurityClient from '@app/components/utilities/SecurityClient'; + +/** + * This route starts the integration after teh default one if gonna set up. + * Update integration with id [integrationId] to sync envars from the project's + * [environment] to the integration [app] with active state [isActive] + * @param {Object} obj + * @param {String} obj.integrationId - id of integration + * @param {Boolean} obj.isActive - active state + * @param {String} obj.environment - project environment to push secrets from + * @param {String} obj.app - name of app + * @param {String} obj.appId - (optional) app ID for integration + * @param {String} obj.targetEnvironment - target environment for integration + * @param {String} obj.owner - (optional) owner login of repo for GitHub integration + * @returns + */ +const updateIntegration = ({ + integrationId, + isActive, + environment, + app, + appId, + targetEnvironment, + owner +}: { + integrationId: string; + isActive: boolean; + environment: string; + app: string; + appId: string | null; + targetEnvironment: string | null; + owner: string | null; +}) => + SecurityClient.fetchCall(`/api/v1/integration/${integrationId}`, { + method: 'PATCH', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + app, + environment, + isActive, + appId, + targetEnvironment, + owner + }) + }).then(async (res) => { + if (res && res.status === 200) { + return (await res.json()).integration; + } + console.log('Failed to start an integration'); + return undefined; + }); + +export default updateIntegration; diff --git a/frontend/pages/api/organization/GetOrg.ts b/frontend/src/pages/api/organization/GetOrg.ts similarity index 52% rename from frontend/pages/api/organization/GetOrg.ts rename to frontend/src/pages/api/organization/GetOrg.ts index 5e56e5c72..64af7a4c9 100644 --- a/frontend/pages/api/organization/GetOrg.ts +++ b/frontend/src/pages/api/organization/GetOrg.ts @@ -1,23 +1,22 @@ -import SecurityClient from '~/utilities/SecurityClient'; +import SecurityClient from '@app/components/utilities/SecurityClient'; /** * This route lets us get info about a certain org * @param {string} orgId - the organization ID * @returns */ -const getOrganization = ({ orgId }: { orgId: string }) => { - return SecurityClient.fetchCall('/api/v1/organization/' + orgId, { +const getOrganization = ({ orgId }: { orgId: string }) => + SecurityClient.fetchCall(`/api/v1/organization/${orgId}`, { method: 'GET', headers: { 'Content-Type': 'application/json' } }).then(async (res) => { - if (res?.status == 200) { + if (res?.status === 200) { return (await res.json()).organization; - } else { - console.log('Failed to get org info'); } + console.log('Failed to get org info'); + return undefined; }); -}; export default getOrganization; diff --git a/frontend/src/pages/api/organization/GetOrgProjects.ts b/frontend/src/pages/api/organization/GetOrgProjects.ts new file mode 100644 index 000000000..7066772eb --- /dev/null +++ b/frontend/src/pages/api/organization/GetOrgProjects.ts @@ -0,0 +1,25 @@ +import SecurityClient from '@app/components/utilities/SecurityClient'; + +/** + * This route lets us get all the users in an org. + * @param {*} req + * @param {*} res + * @returns + */ + +// TODO: this file is not used anywhere +const getOrganizationProjects = (req: { orgId: string }) => + SecurityClient.fetchCall(`/api/organization/${req.orgId}/workspaces`, { + method: 'GET', + headers: { + 'Content-Type': 'application/json' + } + }).then(async (res) => { + if (res && res.status === 200) { + return (await res.json()).workspaces; + } + console.log('Failed to get projects for an org'); + return undefined; + }); + +export default getOrganizationProjects; diff --git a/frontend/src/pages/api/organization/GetOrgSubscription.ts b/frontend/src/pages/api/organization/GetOrgSubscription.ts new file mode 100644 index 000000000..5004ef078 --- /dev/null +++ b/frontend/src/pages/api/organization/GetOrgSubscription.ts @@ -0,0 +1,23 @@ +import SecurityClient from '@app/components/utilities/SecurityClient'; + +/** + * This route lets us get the current subscription of an org. + * @param {*} req + * @param {*} res + * @returns + */ +const getOrganizationSubscriptions = (req: { orgId: string }) => + SecurityClient.fetchCall(`/api/v1/organization/${req.orgId}/subscriptions`, { + method: 'GET', + headers: { + 'Content-Type': 'application/json' + } + }).then(async (res) => { + if (res && res.status === 200) { + return (await res.json()).subscriptions; + } + console.log('Failed to get org subscriptions'); + return undefined; + }); + +export default getOrganizationSubscriptions; diff --git a/frontend/src/pages/api/organization/GetOrgUserProjects.ts b/frontend/src/pages/api/organization/GetOrgUserProjects.ts new file mode 100644 index 000000000..9e0634f87 --- /dev/null +++ b/frontend/src/pages/api/organization/GetOrgUserProjects.ts @@ -0,0 +1,23 @@ +import SecurityClient from '@app/components/utilities/SecurityClient'; + +/** + * This route lets us get all the projects of a certain user in an org. + * @param {*} req + * @param {*} res + * @returns + */ +const getOrganizationUserProjects = (req: { orgId: string }) => + SecurityClient.fetchCall(`/api/v1/organization/${req.orgId}/my-workspaces`, { + method: 'GET', + headers: { + 'Content-Type': 'application/json' + } + }).then(async (res) => { + if (res && res.status === 200) { + return (await res.json()).workspaces; + } + console.log('Failed to get projects of a user in an org'); + return undefined; + }); + +export default getOrganizationUserProjects; diff --git a/frontend/src/pages/api/organization/GetOrgUsers.ts b/frontend/src/pages/api/organization/GetOrgUsers.ts new file mode 100644 index 000000000..611ea1fec --- /dev/null +++ b/frontend/src/pages/api/organization/GetOrgUsers.ts @@ -0,0 +1,38 @@ +import SecurityClient from '@app/components/utilities/SecurityClient'; + +export interface IMembershipOrg { + _id: string; + user: { + email: string; + firstName: string; + lastName: string; + _id: string; + publicKey: string; + }; + inviteEmail: string; + organization: string; + role: 'owner' | 'admin' | 'member'; + status: 'invited' | 'accepted'; + deniedPermissions: any[]; +} +/** + * This route lets us get all the users in an org. + * @param {object} obj + * @param {string} obj.orgId - organization Id + * @returns + */ +const getOrganizationUsers = ({ orgId }: { orgId: string }): Promise => + SecurityClient.fetchCall(`/api/v1/organization/${orgId}/users`, { + method: 'GET', + headers: { + 'Content-Type': 'application/json' + } + }).then(async (res) => { + if (res?.status === 200) { + return (await res.json()).users; + } + console.log('Failed to get org users'); + return undefined; + }); + +export default getOrganizationUsers; diff --git a/frontend/src/pages/api/organization/StripeRedirect.ts b/frontend/src/pages/api/organization/StripeRedirect.ts new file mode 100644 index 000000000..7a7e93522 --- /dev/null +++ b/frontend/src/pages/api/organization/StripeRedirect.ts @@ -0,0 +1,23 @@ +import SecurityClient from '@app/components/utilities/SecurityClient'; + +/** + * This route redirects the user to the right stripe billing page. + * @param {*} req + * @param {*} res + * @returns + */ +const StripeRedirect = ({ orgId }: { orgId: string }) => + SecurityClient.fetchCall(`/api/v1/organization/${orgId}/customer-portal-session`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + } + }).then(async (res) => { + if (res && res.status === 200) { + window.location.href = (await res.json()).url; + return; + } + console.log('Failed to redirect to Stripe'); + }); + +export default StripeRedirect; diff --git a/frontend/src/pages/api/organization/addIncidentContact.ts b/frontend/src/pages/api/organization/addIncidentContact.ts new file mode 100644 index 000000000..d3cd93fe1 --- /dev/null +++ b/frontend/src/pages/api/organization/addIncidentContact.ts @@ -0,0 +1,25 @@ +import SecurityClient from '@app/components/utilities/SecurityClient'; + +/** + * This route add an incident contact email to a certain organization + * @param {*} param0 + * @returns + */ +const addIncidentContact = (organizationId: string, email: string) => + SecurityClient.fetchCall(`/api/v1/organization/${organizationId}/incidentContactOrg`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + email + }) + }).then(async (res) => { + if (res && res.status === 200) { + return res; + } + console.log('Failed to add an incident contact'); + return undefined; + }); + +export default addIncidentContact; diff --git a/frontend/pages/api/organization/addUserToOrg.ts b/frontend/src/pages/api/organization/addUserToOrg.ts similarity index 56% rename from frontend/pages/api/organization/addUserToOrg.ts rename to frontend/src/pages/api/organization/addUserToOrg.ts index 70dbad56c..8736e6f60 100644 --- a/frontend/pages/api/organization/addUserToOrg.ts +++ b/frontend/src/pages/api/organization/addUserToOrg.ts @@ -1,4 +1,4 @@ -import SecurityClient from '~/utilities/SecurityClient'; +import SecurityClient from '@app/components/utilities/SecurityClient'; /** * This function sends an email invite to a user to join an org @@ -6,8 +6,8 @@ import SecurityClient from '~/utilities/SecurityClient'; * @param {*} orgId * @returns */ -const addUserToOrg = (email: string, orgId: string) => { - return SecurityClient.fetchCall('/api/v1/invite-org/signup', { +const addUserToOrg = (email: string, orgId: string) => + SecurityClient.fetchCall('/api/v1/invite-org/signup', { method: 'POST', headers: { 'Content-Type': 'application/json' @@ -17,12 +17,11 @@ const addUserToOrg = (email: string, orgId: string) => { organizationId: orgId }) }).then(async (res) => { - if (res && res.status == 200) { + if (res && res.status === 200) { return res; - } else { - console.log('Failed to add a user to an org'); } + console.log('Failed to add a user to an org'); + return undefined; }); -}; export default addUserToOrg; diff --git a/frontend/src/pages/api/organization/changeUserRoleInOrganization.ts b/frontend/src/pages/api/organization/changeUserRoleInOrganization.ts new file mode 100644 index 000000000..6bbe966c4 --- /dev/null +++ b/frontend/src/pages/api/organization/changeUserRoleInOrganization.ts @@ -0,0 +1,27 @@ +import SecurityClient from '@app/components/utilities/SecurityClient'; + +/** + * This function change the access of a user in a certain organization + * @param {string} organizationId + * @param {string} membershipId + * @param {string} role + * @returns + */ +const changeUserRoleInOrganization = (organizationId: string, membershipId: string, role: string) => + SecurityClient.fetchCall(`/api/v2/organizations/${organizationId}/memberships/${membershipId}`, { + method: 'PATCH', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + role + }) + }).then(async (res) => { + if (res && res.status === 200) { + return res; + } + console.log('Failed to change the user role in an org'); + return undefined; + }); + +export default changeUserRoleInOrganization; diff --git a/frontend/src/pages/api/organization/deleteIncidentContact.ts b/frontend/src/pages/api/organization/deleteIncidentContact.ts new file mode 100644 index 000000000..be418f530 --- /dev/null +++ b/frontend/src/pages/api/organization/deleteIncidentContact.ts @@ -0,0 +1,25 @@ +import SecurityClient from '@app/components/utilities/SecurityClient'; + +/** + * This route deletes an incident Contact from a certain organization + * @param {*} param0 + * @returns + */ +const deleteIncidentContact = (organizationId: string, email: string) => + SecurityClient.fetchCall(`/api/v1/organization/${organizationId}/incidentContactOrg`, { + method: 'DELETE', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + email + }) + }).then(async (res) => { + if (res && res.status === 200) { + return res; + } + console.log('Failed to delete an incident contact'); + return undefined; + }); + +export default deleteIncidentContact; diff --git a/frontend/src/pages/api/organization/deleteUserFromOrganization.ts b/frontend/src/pages/api/organization/deleteUserFromOrganization.ts new file mode 100644 index 000000000..594c5cbdd --- /dev/null +++ b/frontend/src/pages/api/organization/deleteUserFromOrganization.ts @@ -0,0 +1,22 @@ +import SecurityClient from '@app/components/utilities/SecurityClient'; + +/** + * This function removes a certain member from a certain organization + * @param {*} membershipId + * @returns + */ +const deleteUserFromOrganization = (membershipId: string) => + SecurityClient.fetchCall(`/api/v1/membership-org/${membershipId}`, { + method: 'DELETE', + headers: { + 'Content-Type': 'application/json' + } + }).then(async (res) => { + if (res && res.status === 200) { + return res; + } + console.log('Failed to delete a user from an org'); + return undefined; + }); + +export default deleteUserFromOrganization; diff --git a/frontend/src/pages/api/organization/getIncidentContacts.ts b/frontend/src/pages/api/organization/getIncidentContacts.ts new file mode 100644 index 000000000..df5ab083e --- /dev/null +++ b/frontend/src/pages/api/organization/getIncidentContacts.ts @@ -0,0 +1,27 @@ +import SecurityClient from '@app/components/utilities/SecurityClient'; + +export interface IIncidentContactOrg { + _id: string; + email: string; + organization: string; +} +/** + * This routes gets all the incident contacts of a certain organization + * @param {*} workspaceId + * @returns + */ +const getIncidentContacts = (organizationId: string): Promise => + SecurityClient.fetchCall(`/api/v1/organization/${organizationId}/incidentContactOrg`, { + method: 'GET', + headers: { + 'Content-Type': 'application/json' + } + }).then(async (res) => { + if (res && res.status === 200) { + return (await res.json()).incidentContactsOrg; + } + console.log('Failed to get incident contacts'); + return undefined; + }); + +export default getIncidentContacts; diff --git a/frontend/pages/api/organization/getOrgs.ts b/frontend/src/pages/api/organization/getOrgs.ts similarity index 52% rename from frontend/pages/api/organization/getOrgs.ts rename to frontend/src/pages/api/organization/getOrgs.ts index 5f01bc4d1..84d43187a 100644 --- a/frontend/pages/api/organization/getOrgs.ts +++ b/frontend/src/pages/api/organization/getOrgs.ts @@ -1,22 +1,21 @@ -import SecurityClient from '~/utilities/SecurityClient'; +import SecurityClient from '@app/components/utilities/SecurityClient'; /** * This route lets us get the all the orgs of a certain user. * @returns */ -const getOrganizations = () => { - return SecurityClient.fetchCall('/api/v1/organization', { +const getOrganizations = () => + SecurityClient.fetchCall('/api/v1/organization', { method: 'GET', headers: { 'Content-Type': 'application/json' } }).then(async (res) => { - if (res?.status == 200) { + if (res?.status === 200) { return (await res.json()).organizations; - } else { - console.log('Failed to get orgs of a user'); } + console.log('Failed to get orgs of a user'); + return undefined; }); -}; export default getOrganizations; diff --git a/frontend/pages/api/organization/renameOrg.ts b/frontend/src/pages/api/organization/renameOrg.ts similarity index 51% rename from frontend/pages/api/organization/renameOrg.ts rename to frontend/src/pages/api/organization/renameOrg.ts index c5c0b4d65..c97255d26 100644 --- a/frontend/pages/api/organization/renameOrg.ts +++ b/frontend/src/pages/api/organization/renameOrg.ts @@ -1,4 +1,4 @@ -import SecurityClient from '~/utilities/SecurityClient'; +import SecurityClient from '@app/components/utilities/SecurityClient'; /** * This route lets us rename a certain org. @@ -6,8 +6,8 @@ import SecurityClient from '~/utilities/SecurityClient'; * @param {*} res * @returns */ -const renameOrg = (orgId: string, newOrgName: string) => { - return SecurityClient.fetchCall('/api/v1/organization/' + orgId + '/name', { +const renameOrg = (orgId: string, newOrgName: string) => + SecurityClient.fetchCall(`/api/v1/organization/${orgId}/name`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' @@ -16,12 +16,11 @@ const renameOrg = (orgId: string, newOrgName: string) => { name: newOrgName }) }).then(async (res) => { - if (res && res.status == 200) { + if (res && res.status === 200) { return res; - } else { - console.log('Failed to rename an organization'); } + console.log('Failed to rename an organization'); + return undefined; }); -}; export default renameOrg; diff --git a/frontend/src/pages/api/serviceToken/addServiceToken.ts b/frontend/src/pages/api/serviceToken/addServiceToken.ts new file mode 100644 index 000000000..8dc0cca5d --- /dev/null +++ b/frontend/src/pages/api/serviceToken/addServiceToken.ts @@ -0,0 +1,56 @@ +import SecurityClient from '@app/components/utilities/SecurityClient'; + +interface Props { + name: string; + workspaceId: string; + environment: string; + expiresIn: number; + encryptedKey: string; + iv: string; + tag: string; +} + +/** + * This route adds a service token for a specific user in a project + * @param {object} obj + * @param {string} obj.name - name of the service token + * @param {string} obj.workspaceId - workspace for which we are issuing the token + * @param {string} obj.environment - environment for which we are issuing the token + * @param {string} obj.expiresIn - how soon the service token expires in ms + * @param {string} obj.encryptedKey - encrypted project key through random symmetric encryption + * @param {string} obj.iv - obtained through symmetric encryption + * @param {string} obj.tag - obtained through symmetric encryption + * @returns + */ +const addServiceToken = ({ + name, + workspaceId, + environment, + expiresIn, + encryptedKey, + iv, + tag +}: Props) => + SecurityClient.fetchCall('/api/v2/service-token/', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + name, + workspaceId, + environment, + expiresIn, + encryptedKey, + iv, + tag + }) + }).then(async (res) => { + if (res && res.status === 200) { + return res.json(); + } + console.log('Failed to add service tokens'); + return undefined; + }); + +export default addServiceToken; diff --git a/frontend/src/pages/api/serviceToken/deleteServiceToken.ts b/frontend/src/pages/api/serviceToken/deleteServiceToken.ts new file mode 100644 index 000000000..077f7a4bc --- /dev/null +++ b/frontend/src/pages/api/serviceToken/deleteServiceToken.ts @@ -0,0 +1,27 @@ +import SecurityClient from '@app/components/utilities/SecurityClient'; + +interface Props { + serviceTokenId: string; +} + +/** + * This route revokes a specific service token + * @param {object} obj + * @param {string} obj.serviceTokenId - id of a cervice token that we want to delete + * @returns + */ +const deleteServiceToken = ({ serviceTokenId }: Props) => + SecurityClient.fetchCall(`/api/v2/service-token/${serviceTokenId}`, { + method: 'DELETE', + headers: { + 'Content-Type': 'application/json' + } + }).then(async (res) => { + if (res && res.status === 200) { + return res.json(); + } + console.log('Failed to delete a service token'); + return undefined; + }); + +export default deleteServiceToken; diff --git a/frontend/src/pages/api/serviceToken/getServiceTokens.ts b/frontend/src/pages/api/serviceToken/getServiceTokens.ts new file mode 100644 index 000000000..3d4d32274 --- /dev/null +++ b/frontend/src/pages/api/serviceToken/getServiceTokens.ts @@ -0,0 +1,22 @@ +import SecurityClient from '@app/components/utilities/SecurityClient'; + +/** + * This route gets service tokens for a specific user in a project + * @param {*} param0 + * @returns + */ +const getServiceTokens = ({ workspaceId }: { workspaceId: string }) => + SecurityClient.fetchCall(`/api/v2/workspace/${workspaceId}/service-token-data`, { + method: 'GET', + headers: { + 'Content-Type': 'application/json' + } + }).then(async (res) => { + if (res && res.status === 200) { + return (await res.json()).serviceTokenData; + } + console.log('Failed to get service tokens'); + return undefined; + }); + +export default getServiceTokens; diff --git a/frontend/pages/api/user/getUser.ts b/frontend/src/pages/api/user/getUser.ts similarity index 51% rename from frontend/pages/api/user/getUser.ts rename to frontend/src/pages/api/user/getUser.ts index 7562b0f3b..50f9fc5d3 100644 --- a/frontend/pages/api/user/getUser.ts +++ b/frontend/src/pages/api/user/getUser.ts @@ -1,21 +1,20 @@ -import SecurityClient from '~/utilities/SecurityClient'; +import SecurityClient from '@app/components/utilities/SecurityClient'; /** * This route gets the information about a specific user. */ -const getUser = () => { - return SecurityClient.fetchCall('/api/v1/user', { +const getUser = () => + SecurityClient.fetchCall('/api/v1/user', { method: 'GET', headers: { 'Content-Type': 'application/json' } }).then(async (res) => { - if (res?.status == 200) { + if (res?.status === 200) { return (await res.json()).user; - } else { - console.log('Failed to get user info'); } + console.log('Failed to get user info'); + return undefined; }); -}; export default getUser; diff --git a/frontend/pages/api/userActions/checkUserAction.ts b/frontend/src/pages/api/userActions/checkUserAction.ts similarity index 50% rename from frontend/pages/api/userActions/checkUserAction.ts rename to frontend/src/pages/api/userActions/checkUserAction.ts index 9941ae85a..80f291886 100644 --- a/frontend/pages/api/userActions/checkUserAction.ts +++ b/frontend/src/pages/api/userActions/checkUserAction.ts @@ -1,4 +1,4 @@ -import SecurityClient from '~/utilities/SecurityClient'; +import SecurityClient from '@app/components/utilities/SecurityClient'; /** * This route registers a certain action for a user @@ -6,13 +6,12 @@ import SecurityClient from '~/utilities/SecurityClient'; * @param {*} workspaceId * @returns */ -const checkUserAction = ({ action }: { action: string }) => { - return SecurityClient.fetchCall( - '/api/v1/user-action' + - '?' + - new URLSearchParams({ +const checkUserAction = ({ action }: { action: string }) => + SecurityClient.fetchCall( + `/api/v1/user-action` + + `?${new URLSearchParams({ action - }), + })}`, { method: 'GET', headers: { @@ -20,12 +19,11 @@ const checkUserAction = ({ action }: { action: string }) => { } } ).then(async (res) => { - if (res && res.status == 200) { + if (res && res.status === 200) { return (await res.json()).userAction; - } else { - console.log('Failed to check a user action'); } + console.log('Failed to check a user action'); + return undefined; }); -}; export default checkUserAction; diff --git a/frontend/pages/api/userActions/registerUserAction.ts b/frontend/src/pages/api/userActions/registerUserAction.ts similarity index 51% rename from frontend/pages/api/userActions/registerUserAction.ts rename to frontend/src/pages/api/userActions/registerUserAction.ts index d8f4d41e6..669ccc887 100644 --- a/frontend/pages/api/userActions/registerUserAction.ts +++ b/frontend/src/pages/api/userActions/registerUserAction.ts @@ -1,12 +1,12 @@ -import SecurityClient from '~/utilities/SecurityClient'; +import SecurityClient from '@app/components/utilities/SecurityClient'; /** * This route registers a certain action for a user * @param {*} action * @returns */ -const registerUserAction = ({ action }: { action: string }) => { - return SecurityClient.fetchCall('/api/v1/user-action', { +const registerUserAction = ({ action }: { action: string }) => + SecurityClient.fetchCall('/api/v1/user-action', { method: 'POST', headers: { 'Content-Type': 'application/json' @@ -15,12 +15,11 @@ const registerUserAction = ({ action }: { action: string }) => { action }) }).then(async (res) => { - if (res && res.status == 200) { + if (res && res.status === 200) { return res; - } else { - console.log('Failed to register a user action'); } + console.log('Failed to register a user action'); + return undefined; }); -}; export default registerUserAction; diff --git a/frontend/src/pages/api/workspace/addUserToWorkspace.ts b/frontend/src/pages/api/workspace/addUserToWorkspace.ts new file mode 100644 index 000000000..20a5fa029 --- /dev/null +++ b/frontend/src/pages/api/workspace/addUserToWorkspace.ts @@ -0,0 +1,26 @@ +import SecurityClient from '@app/components/utilities/SecurityClient'; + +/** + * This function adds a user to a project + * @param {*} email + * @param {*} workspaceId + * @returns + */ +const addUserToWorkspace = (email: string, workspaceId: string) => + SecurityClient.fetchCall(`/api/v1/workspace/${workspaceId}/invite-signup`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + email + }) + }).then(async (res) => { + if (res && res.status === 200) { + return res.json(); + } + console.log('Failed to add a user to project'); + return undefined; + }); + +export default addUserToWorkspace; diff --git a/frontend/src/pages/api/workspace/changeUserRoleInWorkspace.ts b/frontend/src/pages/api/workspace/changeUserRoleInWorkspace.ts new file mode 100644 index 000000000..6436b2bb4 --- /dev/null +++ b/frontend/src/pages/api/workspace/changeUserRoleInWorkspace.ts @@ -0,0 +1,26 @@ +import SecurityClient from '@app/components/utilities/SecurityClient'; + +/** + * This function change the access of a user in a certain workspace + * @param {*} membershipId + * @param {*} role + * @returns + */ +const changeUserRoleInWorkspace = (membershipId: string, role: string) => + SecurityClient.fetchCall(`/api/v1/membership/${membershipId}/change-role`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + role + }) + }).then(async (res) => { + if (res && res.status === 200) { + return res; + } + console.log('Failed to change the user role in a project'); + return undefined; + }); + +export default changeUserRoleInWorkspace; diff --git a/frontend/pages/api/workspace/createWorkspace.ts b/frontend/src/pages/api/workspace/createWorkspace.ts similarity index 65% rename from frontend/pages/api/workspace/createWorkspace.ts rename to frontend/src/pages/api/workspace/createWorkspace.ts index 877ef7567..0aee4643b 100644 --- a/frontend/pages/api/workspace/createWorkspace.ts +++ b/frontend/src/pages/api/workspace/createWorkspace.ts @@ -1,4 +1,4 @@ -import SecurityClient from '~/utilities/SecurityClient'; +import SecurityClient from '@app/components/utilities/SecurityClient'; /** * This route creates a new workspace for a user within a certain organization. @@ -12,23 +12,22 @@ const createWorkspace = ({ }: { workspaceName: string; organizationId: string; -}) => { - return SecurityClient.fetchCall('/api/v1/workspace', { +}) => + SecurityClient.fetchCall('/api/v1/workspace', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ - workspaceName: workspaceName, - organizationId: organizationId + workspaceName, + organizationId }) }).then(async (res) => { - if (res?.status == 200) { + if (res?.status === 200) { return (await res.json()).workspace; - } else { - console.log('Failed to create a project'); } + console.log('Failed to create a project'); + return undefined; }); -}; export default createWorkspace; diff --git a/frontend/src/pages/api/workspace/deleteUserFromWorkspace.ts b/frontend/src/pages/api/workspace/deleteUserFromWorkspace.ts new file mode 100644 index 000000000..10cbeb2c6 --- /dev/null +++ b/frontend/src/pages/api/workspace/deleteUserFromWorkspace.ts @@ -0,0 +1,22 @@ +import SecurityClient from '@app/components/utilities/SecurityClient'; + +/** + * This function removes a certain member from a certain workspace + * @param {*} membershipId + * @returns + */ +const deleteUserFromWorkspace = (membershipId: string) => + SecurityClient.fetchCall(`/api/v1/membership/${membershipId}`, { + method: 'DELETE', + headers: { + 'Content-Type': 'application/json' + } + }).then(async (res) => { + if (res && res.status === 200) { + return res; + } + console.log('Failed to delete a user from a project'); + return undefined; + }); + +export default deleteUserFromWorkspace; diff --git a/frontend/src/pages/api/workspace/deleteWorkspace.ts b/frontend/src/pages/api/workspace/deleteWorkspace.ts new file mode 100644 index 000000000..0961bdf26 --- /dev/null +++ b/frontend/src/pages/api/workspace/deleteWorkspace.ts @@ -0,0 +1,22 @@ +import SecurityClient from '@app/components/utilities/SecurityClient'; + +/** + * This route deletes a specified workspace. + * @param {*} workspaceId + * @returns + */ +const deleteWorkspace = (workspaceId: string) => + SecurityClient.fetchCall(`/api/v1/workspace/${workspaceId}`, { + method: 'DELETE', + headers: { + 'Content-Type': 'application/json' + } + }).then(async (res) => { + if (res && res.status === 200) { + return res; + } + console.log('Failed to delete a project'); + return undefined; + }); + +export default deleteWorkspace; diff --git a/frontend/src/pages/api/workspace/getAWorkspace.ts b/frontend/src/pages/api/workspace/getAWorkspace.ts new file mode 100644 index 000000000..69c178ae9 --- /dev/null +++ b/frontend/src/pages/api/workspace/getAWorkspace.ts @@ -0,0 +1,30 @@ +import SecurityClient from '@app/components/utilities/SecurityClient'; + +interface Workspace { + __v: number; + _id: string; + name: string; + organization: string; + environments: Array<{ name: string; slug: string }>; +} + +/** + * This route lets us get the workspaces of a certain user + * @returns + */ +const getAWorkspace = (workspaceID: string) => + SecurityClient.fetchCall(`/api/v1/workspace/${workspaceID}`, { + method: 'GET', + headers: { + 'Content-Type': 'application/json' + } + }).then(async (res) => { + if (res?.status === 200) { + const data = (await res.json()) as unknown as { workspace: Workspace }; + return data.workspace; + } + + throw new Error('Failed to get workspace'); + }); + +export default getAWorkspace; diff --git a/frontend/pages/api/workspace/getLatestFileKey.ts b/frontend/src/pages/api/workspace/getLatestFileKey.ts similarity index 51% rename from frontend/pages/api/workspace/getLatestFileKey.ts rename to frontend/src/pages/api/workspace/getLatestFileKey.ts index 1ecd2035d..576fcf943 100644 --- a/frontend/pages/api/workspace/getLatestFileKey.ts +++ b/frontend/src/pages/api/workspace/getLatestFileKey.ts @@ -1,23 +1,22 @@ -import SecurityClient from '~/utilities/SecurityClient'; +import SecurityClient from '@app/components/utilities/SecurityClient'; /** * Get the latest key pairs from a certain workspace * @param {string} workspaceId * @returns */ -const getLatestFileKey = ({ workspaceId }: { workspaceId: string }) => { - return SecurityClient.fetchCall('/api/v1/key/' + workspaceId + '/latest', { +const getLatestFileKey = ({ workspaceId }: { workspaceId: string }) => + SecurityClient.fetchCall(`/api/v1/key/${workspaceId}/latest`, { method: 'GET', headers: { 'Content-Type': 'application/json' } }).then(async (res) => { - if (res?.status == 200) { - return await res.json(); - } else { - console.log('Failed to get the latest key pairs for a certain project'); + if (res?.status === 200) { + return res.json(); } + console.log('Failed to get the latest key pairs for a certain project'); + return undefined; }); -}; export default getLatestFileKey; diff --git a/frontend/pages/api/workspace/getProjectInfo.ts b/frontend/src/pages/api/workspace/getProjectInfo.ts similarity index 64% rename from frontend/pages/api/workspace/getProjectInfo.ts rename to frontend/src/pages/api/workspace/getProjectInfo.ts index a1ab0438c..f6d364c18 100644 --- a/frontend/pages/api/workspace/getProjectInfo.ts +++ b/frontend/src/pages/api/workspace/getProjectInfo.ts @@ -1,23 +1,22 @@ -import SecurityClient from '~/utilities/SecurityClient'; +import SecurityClient from '@app/components/utilities/SecurityClient'; /** * This route lets us get the information of a certain project. * @param {*} projectId - project ID (we renamed workspaces to projects in the app) * @returns */ -const getProjectInfo = ({ projectId }: { projectId: string }) => { - return SecurityClient.fetchCall('/api/v1/workspace/' + projectId, { +const getProjectInfo = ({ projectId }: { projectId: string }) => + SecurityClient.fetchCall(`/api/v1/workspace/${projectId}`, { method: 'GET', headers: { 'Content-Type': 'application/json' } }).then(async (res) => { - if (res?.status == 200) { + if (res?.status === 200) { return (await res.json()).workspace; - } else { - console.log('Failed to get project info'); } + console.log('Failed to get project info'); + return undefined; }); -}; export default getProjectInfo; diff --git a/frontend/src/pages/api/workspace/getWorkspaceEnvironments.ts b/frontend/src/pages/api/workspace/getWorkspaceEnvironments.ts new file mode 100644 index 000000000..845936cb9 --- /dev/null +++ b/frontend/src/pages/api/workspace/getWorkspaceEnvironments.ts @@ -0,0 +1,22 @@ +import SecurityClient from '@app/components/utilities/SecurityClient'; + +/** + * This route lets us get the environments that a certain user has acess to in a certain project + * @param {string} workspaceId + * @returns + */ +const getWorkspaceEnvironments = ({ workspaceId }: { workspaceId: string }) => + SecurityClient.fetchCall(`/api/v2/workspace/${workspaceId}/environments`, { + method: 'GET', + headers: { + 'Content-Type': 'application/json' + } + }).then(async (res) => { + if (res?.status === 200) { + return (await res.json()).accessibleEnvironments; + } + console.log('Failed to get accessible environments'); + return undefined; + }); + +export default getWorkspaceEnvironments; diff --git a/frontend/src/pages/api/workspace/getWorkspaceKeys.ts b/frontend/src/pages/api/workspace/getWorkspaceKeys.ts new file mode 100644 index 000000000..636b2fc42 --- /dev/null +++ b/frontend/src/pages/api/workspace/getWorkspaceKeys.ts @@ -0,0 +1,22 @@ +import SecurityClient from '@app/components/utilities/SecurityClient'; + +/** + * This route lets us get the public keys of everyone in your workspace. + * @param {string} workspaceId + * @returns + */ +const getWorkspaceKeys = ({ workspaceId }: { workspaceId: string }) => + SecurityClient.fetchCall(`/api/v1/workspace/${workspaceId}/keys`, { + method: 'GET', + headers: { + 'Content-Type': 'application/json' + } + }).then(async (res) => { + if (res?.status === 200) { + return (await res.json()).publicKeys; + } + console.log('Failed to get the public keys of everyone in the workspace'); + return undefined; + }); + +export default getWorkspaceKeys; diff --git a/frontend/src/pages/api/workspace/getWorkspaceUsers.ts b/frontend/src/pages/api/workspace/getWorkspaceUsers.ts new file mode 100644 index 000000000..d49868581 --- /dev/null +++ b/frontend/src/pages/api/workspace/getWorkspaceUsers.ts @@ -0,0 +1,22 @@ +import SecurityClient from '@app/components/utilities/SecurityClient'; + +/** + * This route lets us get all the users in the workspace. + * @param {string} workspaceId - workspace ID + * @returns + */ +const getWorkspaceUsers = ({ workspaceId }: { workspaceId: string }) => + SecurityClient.fetchCall(`/api/v1/workspace/${workspaceId}/users`, { + method: 'GET', + headers: { + 'Content-Type': 'application/json' + } + }).then(async (res) => { + if (res?.status === 200) { + return (await res.json()).users; + } + console.log('Failed to get Project Users'); + return undefined; + }); + +export default getWorkspaceUsers; diff --git a/frontend/pages/api/workspace/getWorkspaces.ts b/frontend/src/pages/api/workspace/getWorkspaces.ts similarity index 67% rename from frontend/pages/api/workspace/getWorkspaces.ts rename to frontend/src/pages/api/workspace/getWorkspaces.ts index 1bbb42c7a..95c977008 100644 --- a/frontend/pages/api/workspace/getWorkspaces.ts +++ b/frontend/src/pages/api/workspace/getWorkspaces.ts @@ -1,30 +1,30 @@ -import SecurityClient from '~/utilities/SecurityClient'; +import SecurityClient from '@app/components/utilities/SecurityClient'; interface Workspace { __v: number; _id: string; name: string; organization: string; + environments: Array<{ name: string; slug: string }>; } /** * This route lets us get the workspaces of a certain user * @returns */ -const getWorkspaces = () => { - return SecurityClient.fetchCall('/api/v1/workspace', { +const getWorkspaces = () => + SecurityClient.fetchCall('/api/v1/workspace', { method: 'GET', headers: { 'Content-Type': 'application/json' } }).then(async (res) => { - if (res?.status == 200) { + if (res?.status === 200) { const data = (await res.json()) as unknown as { workspaces: Workspace[] }; return data.workspaces; } throw new Error('Failed to get projects'); }); -}; export default getWorkspaces; diff --git a/frontend/src/pages/api/workspace/renameWorkspace.ts b/frontend/src/pages/api/workspace/renameWorkspace.ts new file mode 100644 index 000000000..5c7238b40 --- /dev/null +++ b/frontend/src/pages/api/workspace/renameWorkspace.ts @@ -0,0 +1,26 @@ +import SecurityClient from '@app/components/utilities/SecurityClient'; + +/** + * This route lets us rename a certain workspace. + * @param {*} req + * @param {*} res + * @returns + */ +const renameWorkspace = (workspaceId: string, newWorkspaceName: string) => + SecurityClient.fetchCall(`/api/v1/workspace/${workspaceId}/name`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + name: newWorkspaceName + }) + }).then(async (res) => { + if (res && res.status === 200) { + return res; + } + console.log('Failed to rename a project'); + return undefined; + }); + +export default renameWorkspace; diff --git a/frontend/src/pages/api/workspace/uploadKeys.ts b/frontend/src/pages/api/workspace/uploadKeys.ts new file mode 100644 index 000000000..7d05fa9ed --- /dev/null +++ b/frontend/src/pages/api/workspace/uploadKeys.ts @@ -0,0 +1,32 @@ +import SecurityClient from '@app/components/utilities/SecurityClient'; + +/** + * This route uplods the keys in an encrypted format. + * @param {*} workspaceId + * @param {*} userId + * @param {*} encryptedKey + * @param {*} nonce + * @returns + */ +const uploadKeys = (workspaceId: string, userId: string, encryptedKey: string, nonce: string) => + SecurityClient.fetchCall(`/api/v1/key/${workspaceId}`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + key: { + userId, + encryptedKey, + nonce + } + }) + }).then(async (res) => { + if (res && res.status === 200) { + return res; + } + console.log('Failed to upload keys for a new user'); + return undefined; + }); + +export default uploadKeys; diff --git a/frontend/src/pages/dashboard.tsx b/frontend/src/pages/dashboard.tsx new file mode 100644 index 000000000..60fda6cf2 --- /dev/null +++ b/frontend/src/pages/dashboard.tsx @@ -0,0 +1,34 @@ +import { useEffect } from 'react'; +import { useRouter } from 'next/router'; + +import getWorkspaces from './api/workspace/getWorkspaces'; + +export default function DashboardRedirect() { + const router = useRouter(); + + /** + * Here we forward to the default workspace if a user opens this url + */ + // eslint-disable-next-line react-hooks/exhaustive-deps + useEffect(() => { + (async () => { + let userWorkspace; + try { + if (localStorage.getItem('projectData.id')) { + router.push(`/dashboard/${ localStorage.getItem('projectData.id')}`); + } else { + const userWorkspaces = await getWorkspaces(); + userWorkspace = userWorkspaces[0]._id; + router.push(`/dashboard/${ userWorkspace}`); + } + } catch (error) { + console.log('Error - Not logged in yet'); + } + })(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + return
; +} + +DashboardRedirect.requireAuth = true; diff --git a/frontend/src/pages/dashboard/[id].tsx b/frontend/src/pages/dashboard/[id].tsx new file mode 100644 index 000000000..b199790a9 --- /dev/null +++ b/frontend/src/pages/dashboard/[id].tsx @@ -0,0 +1,881 @@ +/* eslint-disable no-nested-ternary */ +import { UIEvent, useCallback, useEffect, useRef, useState } from 'react'; +import Head from 'next/head'; +import Image from 'next/image'; +import { useRouter } from 'next/router'; +import { useTranslation } from 'next-i18next'; +import { + faArrowDownAZ, + faArrowDownZA, + faArrowLeft, + faCheck, + faClockRotateLeft, + faEye, + faEyeSlash, + faFolderOpen, + faMagnifyingGlass, + faPlus +} from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; + +import Button from '@app/components/basic/buttons/Button'; +import ListBox from '@app/components/basic/Listbox'; +import BottonRightPopup from '@app/components/basic/popups/BottomRightPopup'; +import { useNotificationContext } from '@app/components/context/Notifications/NotificationProvider'; +import DownloadSecretMenu from '@app/components/dashboard/DownloadSecretsMenu'; +import DropZone from '@app/components/dashboard/DropZone'; +import KeyPair from '@app/components/dashboard/KeyPair'; +import SideBar from '@app/components/dashboard/SideBar'; +import NavHeader from '@app/components/navigation/NavHeader'; +import guidGenerator from '@app/components/utilities/randomId'; +import encryptSecrets from '@app/components/utilities/secrets/encryptSecrets'; +import getSecretsForProject from '@app/components/utilities/secrets/getSecretsForProject'; +import { getTranslatedServerSideProps } from '@app/components/utilities/withTranslateProps'; +import getProjectSercetSnapshotsCount from '@app/ee/api/secrets/GetProjectSercetSnapshotsCount'; +import performSecretRollback from '@app/ee/api/secrets/PerformSecretRollback'; +import PITRecoverySidebar from '@app/ee/components/PITRecoverySidebar'; + +import addSecrets from '../api/files/AddSecrets'; +import deleteSecrets from '../api/files/DeleteSecrets'; +import updateSecrets from '../api/files/UpdateSecrets'; +import getUser from '../api/user/getUser'; +import checkUserAction from '../api/userActions/checkUserAction'; +import registerUserAction from '../api/userActions/registerUserAction'; +import getWorkspaceEnvironments from '../api/workspace/getWorkspaceEnvironments'; +import getWorkspaces from '../api/workspace/getWorkspaces'; + +type WorkspaceEnv = { + name: string; + slug: string; + isWriteDenied: boolean; +}; + +interface SecretDataProps { + pos: number; + key: string; + value: string; + valueOverride: string | undefined; + id: string; + idOverride: string | undefined; + comment: string; +} + +// eslint-disable-next-line @typescript-eslint/no-unused-vars +interface OverrideProps { + id: string; + keyName: string; + value: string; + pos: number; + comment: string; +} + +interface SnapshotProps { + id: string; + createdAt: string; + version: number; + secretVersions: { + id: string; + pos: number; + environment: string; + key: string; + value: string; + valueOverride: string; + comment: string; + }[]; +} + +/** + * this function finds the teh duplicates in an array + * @param arr - array of anything (e.g., with secret keys and types (personal/shared)) + * @returns - a list with duplicates + */ +function findDuplicates(arr: any[]) { + const map = new Map(); + return arr.filter((item) => { + if (map.has(item)) { + map.set(item, false); + return true; + } + map.set(item, true); + return false; + }); +} + +/** + * This is the main component for the dashboard (aka the screen with all the encironemnt variable & secrets) + * @returns + */ +export default function Dashboard() { + const [data, setData] = useState(); + const [initialData, setInitialData] = useState([]); + const [buttonReady, setButtonReady] = useState(false); + const router = useRouter(); + const [blurred, setBlurred] = useState(true); + const [isKeyAvailable, setIsKeyAvailable] = useState(true); + const [isNew, setIsNew] = useState(false); + const [isLoading, setIsLoading] = useState(false); + const [searchKeys, setSearchKeys] = useState(''); + const [errorDragAndDrop, setErrorDragAndDrop] = useState(false); + const [sortMethod, setSortMethod] = useState('alphabetical'); + const [checkDocsPopUpVisible, setCheckDocsPopUpVisible] = useState(false); + const [hasUserEverPushed, setHasUserEverPushed] = useState(false); + const [sidebarSecretId, toggleSidebar] = useState('None'); + const [PITSidebarOpen, togglePITSidebar] = useState(false); + const [sharedToHide, setSharedToHide] = useState([]); + const [snapshotData, setSnapshotData] = useState(); + const [numSnapshots, setNumSnapshots] = useState(); + const [saveLoading, setSaveLoading] = useState(false); + + const { t } = useTranslation(); + const { createNotification } = useNotificationContext(); + + const workspaceId = router.query.id as string; + const [workspaceEnvs, setWorkspaceEnvs] = useState([]); + + const [selectedSnapshotEnv, setSelectedSnapshotEnv] = useState(); + const [selectedEnv, setSelectedEnv] = useState({ + name: '', + slug: '', + isWriteDenied: false + }); + const [atSecretAreaTop, setAtSecretsAreaTop] = useState(true); + const secretsTop = useRef(null); + + const onSecretsAreaScroll = (event: UIEvent) => { + if (event.currentTarget.scrollTop !== 0) { + setAtSecretsAreaTop(false); + } + }; + // #TODO: fix save message for changing reroutes + // const beforeRouteHandler = (url) => { + // const warningText = + // "Do you want to save your results bfore leaving this page?"; + // if (!buttonReady) return; + // if (router.asPath !== url && !confirm(warningText)) { + // // router.events.emit('routeChangeError'); + // // setData(data) + // savePush(); + // throw `Route change to "${url}" was aborted (this error can be safely ignored).`; + // } else { + // setButtonReady(false); + // } + // }; + + // prompt the user if they try and leave with unsaved changes + useEffect(() => { + const warningText = 'Do you want to save your results before leaving this page?'; + const handleWindowClose = (e: any) => { + if (!buttonReady) return; + e.preventDefault(); + e.returnValue = warningText; + }; + window.addEventListener('beforeunload', handleWindowClose); + // router.events.on('routeChangeStart', beforeRouteHandler); + return () => { + window.removeEventListener('beforeunload', handleWindowClose); + // router.events.off('routeChangeStart', beforeRouteHandler); + }; + }, [buttonReady]); + + // TODO(akhilmhdh): change to FP + const sortValuesHandler = ( + dataToSort: SecretDataProps[] | 1, + specificSortMethod?: 'alphabetical' | '-alphabetical' + ) => { + const howToSort = specificSortMethod === undefined ? sortMethod : specificSortMethod; + const sortedData = (dataToSort !== 1 ? dataToSort : data)! + .sort((a, b) => + howToSort === 'alphabetical' ? a.key.localeCompare(b.key) : b.key.localeCompare(a.key) + ) + .map((item: SecretDataProps, index: number) => ({ + ...item, + pos: index + })); + + setData(sortedData); + }; + + /** + * Reorder rows alphabetically or in the opprosite order + */ + const reorderRows = (dataToReorder: SecretDataProps[] | 1) => { + setSortMethod((prevSort) => (prevSort === 'alphabetical' ? '-alphabetical' : 'alphabetical')); + + sortValuesHandler(dataToReorder, undefined); + }; + + useEffect(() => { + (async () => { + try { + const tempNumSnapshots = await getProjectSercetSnapshotsCount({ + workspaceId + }); + setNumSnapshots(tempNumSnapshots); + const userWorkspaces = await getWorkspaces(); + const workspace = userWorkspaces.find((wp) => wp._id === workspaceId); + if (!workspace) { + router.push(`/dashboard/${userWorkspaces?.[0]?._id}`); + } + + const accessibleEnvironments = await getWorkspaceEnvironments({ workspaceId }); + setWorkspaceEnvs(accessibleEnvironments || []); + // set env + const env = accessibleEnvironments?.[0] || { + name: 'unknown', + slug: 'unkown' + }; + setSelectedEnv(env); + setSelectedSnapshotEnv(env); + const user = await getUser(); + setIsNew((Date.parse(String(new Date())) - Date.parse(user.createdAt)) / 60000 < 3); + + const userAction = await checkUserAction({ + action: 'first_time_secrets_pushed' + }); + setHasUserEverPushed(!!userAction); + } catch (error) { + console.log('Error', error); + setData(undefined); + } + })(); + }, [workspaceId]); + + useEffect(() => { + (async () => { + try { + setIsLoading(true); + setBlurred(true); + // ENV + const dataToSort = await getSecretsForProject({ + env: selectedEnv.slug, + setIsKeyAvailable, + setData, + workspaceId + }); + setInitialData(dataToSort); + reorderRows(dataToSort); + + setTimeout(() => setIsLoading(false), 700); + } catch (error) { + console.log('Error', error); + setData(undefined); + } + })(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [selectedEnv]); + + const addRow = () => { + setIsNew(false); + setData([ + { + id: guidGenerator(), + idOverride: guidGenerator(), + pos: data!.length, + key: '', + value: '', + valueOverride: undefined, + comment: '' + }, + ...data! + ]); + if (!atSecretAreaTop) { + secretsTop.current?.scrollIntoView({ behavior: 'smooth' }); + } + }; + + const deleteRow = ({ ids, secretName }: { ids: string[]; secretName: string }) => { + setButtonReady(true); + toggleSidebar('None'); + createNotification({ + text: `${secretName} has been deleted. Remember to save changes.`, + type: 'error' + }); + sortValuesHandler( + data!.filter((row: SecretDataProps) => !ids.includes(row.id)), + sortMethod === 'alhpabetical' ? '-alphabetical' : 'alphabetical' + ); + }; + + const modifyValue = (value: string, pos: number) => { + setData((oldData) => oldData?.map((e) => (e.pos === pos ? { ...e, value } : e))); + setButtonReady(true); + }; + + const modifyValueOverride = (valueOverride: string | undefined, pos: number) => { + setData((oldData) => oldData?.map((e) => (e.pos === pos ? { ...e, valueOverride } : e))); + setButtonReady(true); + }; + + const modifyKey = (key: string, pos: number) => { + setData((oldData) => oldData?.map((e) => (e.pos === pos ? { ...e, key } : e))); + setButtonReady(true); + }; + + const modifyComment = (comment: string, pos: number) => { + setData((oldData) => oldData?.map((e) => (e.pos === pos ? { ...e, comment } : e))); + setButtonReady(true); + }; + + // For speed purposes and better perforamance, we are using useCallback + const listenChangeValue = useCallback((value: string, pos: number) => { + modifyValue(value, pos); + }, []); + + const listenChangeValueOverride = useCallback((value: string | undefined, pos: number) => { + modifyValueOverride(value, pos); + }, []); + + const listenChangeKey = useCallback((value: string, pos: number) => { + modifyKey(value, pos); + }, []); + + const listenChangeComment = useCallback((value: string, pos: number) => { + modifyComment(value, pos); + }, []); + + /** + * Save the changes of environment variables and push them to the database + */ + // TODO(akhilmhdh): split and make it small + const savePush = async (dataToPush?: SecretDataProps[]) => { + setSaveLoading(true); + let newData: SecretDataProps[] | null | undefined; + // dataToPush is mostly used for rollbacks, otherwise we always take the current state data + if ((dataToPush ?? [])?.length > 0) { + newData = dataToPush; + } else { + newData = data; + } + + // Checking if any of the secret keys start with a number - if so, don't do anything + const nameErrors = !newData! + .map((secret) => !Number.isNaN(Number(secret.key.charAt(0)))) + .every((v) => v === false); + const duplicatesExist = + findDuplicates(data!.map((item: SecretDataProps) => item.key)).length > 0; + + if (nameErrors) { + setSaveLoading(false); + return createNotification({ + text: 'Solve all name errors before saving secrets.', + type: 'error' + }); + } + + if (duplicatesExist) { + setSaveLoading(false); + return createNotification({ + text: 'Remove duplicated secret names before saving.', + type: 'error' + }); + } + + if (selectedEnv.isWriteDenied) { + setSaveLoading(false); + return createNotification({ + text: 'You are not allowed to edit this environment', + type: 'error' + }); + } + + // Once "Save changes" is clicked, disable that button + setButtonReady(false); + + const secretsToBeDeleted = initialData! + .filter( + (initDataPoint) => + !newData!.map((newDataPoint) => newDataPoint.id).includes(initDataPoint.id) + ) + .map((secret) => secret.id); + console.log('delete', secretsToBeDeleted.length); + + const secretsToBeAdded = newData!.filter( + (newDataPoint) => + !initialData!.map((initDataPoint) => initDataPoint.id).includes(newDataPoint.id) + ); + console.log('add', secretsToBeAdded.length); + + const secretsToBeUpdated = newData!.filter((newDataPoint) => + initialData! + .filter( + (initDataPoint) => + newData!.map((dataPoint) => dataPoint.id).includes(initDataPoint.id) && + (newData!.filter((dataPoint) => dataPoint.id === initDataPoint.id)[0].value !== + initDataPoint.value || + newData!.filter((dataPoint) => dataPoint.id === initDataPoint.id)[0].key !== + initDataPoint.key || + newData!.filter((dataPoint) => dataPoint.id === initDataPoint.id)[0].comment !== + initDataPoint.comment) + ) + .map((secret) => secret.id) + .includes(newDataPoint.id) + ); + console.log('update', secretsToBeUpdated.length); + + const newOverrides = newData!.filter( + (newDataPoint) => newDataPoint.valueOverride !== undefined + ); + const initOverrides = initialData!.filter( + (initDataPoint) => initDataPoint.valueOverride !== undefined + ); + + const overridesToBeDeleted = initOverrides + .filter( + (initDataPoint) => + !newOverrides!.map((newDataPoint) => newDataPoint.id).includes(initDataPoint.id) + ) + .map((secret) => String(secret.idOverride)); + console.log('override delete', overridesToBeDeleted.length); + + const overridesToBeAdded = newOverrides! + .filter( + (newDataPoint) => + !initOverrides.map((initDataPoint) => initDataPoint.id).includes(newDataPoint.id) + ) + .map((override) => ({ + pos: override.pos, + key: override.key, + value: String(override.valueOverride), + valueOverride: override.valueOverride, + comment: '', + id: String(override.idOverride), + idOverride: String(override.idOverride) + })); + console.log('override add', overridesToBeAdded.length); + + const overridesToBeUpdated = newOverrides! + .filter((newDataPoint) => + initOverrides + .filter( + (initDataPoint) => + newOverrides!.map((dataPoint) => dataPoint.id).includes(initDataPoint.id) && + (newOverrides!.filter((dataPoint) => dataPoint.id === initDataPoint.id)[0] + .valueOverride !== initDataPoint.valueOverride || + newOverrides!.filter((dataPoint) => dataPoint.id === initDataPoint.id)[0].key !== + initDataPoint.key || + newOverrides!.filter((dataPoint) => dataPoint.id === initDataPoint.id)[0] + .comment !== initDataPoint.comment) + ) + .map((secret) => secret.id) + .includes(newDataPoint.id) + ) + .map((override) => ({ + pos: override.pos, + key: override.key, + value: String(override.valueOverride), + valueOverride: override.valueOverride, + comment: '', + id: String(override.idOverride), + idOverride: String(override.idOverride) + })); + console.log('override update', overridesToBeUpdated.length); + + if (secretsToBeDeleted.concat(overridesToBeDeleted).length > 0) { + await deleteSecrets({ secretIds: secretsToBeDeleted.concat(overridesToBeDeleted) }); + } + if (secretsToBeAdded.concat(overridesToBeAdded).length > 0) { + const secrets = await encryptSecrets({ + secretsToEncrypt: secretsToBeAdded.concat(overridesToBeAdded), + workspaceId, + env: selectedEnv.slug + }); + if (secrets) await addSecrets({ secrets, env: selectedEnv.slug, workspaceId }); + } + if (secretsToBeUpdated.concat(overridesToBeUpdated).length > 0) { + const secrets = await encryptSecrets({ + secretsToEncrypt: secretsToBeUpdated.concat(overridesToBeUpdated), + workspaceId, + env: selectedEnv.slug + }); + if (secrets) await updateSecrets({ secrets }); + } + + setInitialData(structuredClone(newData)); + + // If this user has never saved environment variables before, show them a prompt to read docs + if (!hasUserEverPushed) { + setCheckDocsPopUpVisible(true); + await registerUserAction({ action: 'first_time_secrets_pushed' }); + } + + // increasing the number of project commits + setNumSnapshots((numSnapshots ?? 0) + 1); + setSaveLoading(false); + return undefined; + }; + + const addData = (newData: SecretDataProps[]) => { + setData(data!.concat(newData)); + setButtonReady(true); + }; + + const changeBlurred = () => { + setBlurred(!blurred); + }; + + const deleteCertainRow = ({ ids, secretName }: { ids: string[]; secretName: string }) => { + deleteRow({ ids, secretName }); + }; + + return data ? ( +
+ + {t('common:head-title', { title: t('dashboard:title') })} + + + + + +
+ {sidebarSecretId !== 'None' && ( + + row.key === data.filter((r) => r.id === sidebarSecretId)[0]?.key + )} + modifyKey={listenChangeKey} + modifyValue={listenChangeValue} + modifyValueOverride={listenChangeValueOverride} + modifyComment={listenChangeComment} + buttonReady={buttonReady} + savePush={savePush} + sharedToHide={sharedToHide} + setSharedToHide={setSharedToHide} + deleteRow={deleteCertainRow} + /> + )} + {PITSidebarOpen && ( + + )} +
+ + {checkDocsPopUpVisible && ( + + )} +
+ {snapshotData && ( +
+
+ )} +
+
+

{snapshotData ? 'Secret Snapshot' : t('dashboard:title')}

+ {snapshotData && ( + + {new Date(snapshotData.createdAt).toLocaleString()} + + )} +
+ {!snapshotData && data?.length === 0 && ( + name)} + onChange={(envName) => + setSelectedEnv( + workspaceEnvs.find(({ name }) => envName === name) || { + name: 'unknown', + slug: 'unknown', + isWriteDenied: false + } + ) + } + /> + )} +
+
+
+
+ {(data?.length !== 0 || buttonReady) && !snapshotData && ( +
+
+ )} + {snapshotData && ( +
+
+ )} +
+
+
+
+
+ {(snapshotData || data?.length !== 0) && ( + <> + {!snapshotData ? ( + name)} + onChange={(envName) => + setSelectedEnv( + workspaceEnvs.find(({ name }) => envName === name) || { + name: 'unknown', + slug: 'unknown', + isWriteDenied: false + } + ) + } + /> + ) : ( + name)} + onChange={(envName) => + setSelectedSnapshotEnv( + workspaceEnvs.find(({ name }) => envName === name) || { + name: 'unknown', + slug: 'unknown', + isWriteDenied: false + } + ) + } + /> + )} +
+ + setSearchKeys(e.target.value)} + placeholder={String(t('dashboard:search-keys'))} + /> +
+ {!snapshotData && ( +
+
+ )} + {!snapshotData && ( +
+ +
+ )} +
+
+ {!snapshotData && ( +
+
+ )} + + )} +
+
+ {isLoading ? ( +
+ infisical loading indicator +
+ ) : data?.length !== 0 ? ( +
+
+
+
+ {!snapshotData && + data + ?.filter((row) => row.key?.toUpperCase().includes(searchKeys.toUpperCase())) + .filter((row) => !sharedToHide.includes(row.id)) + .map((keyPair) => ( + item.key))?.includes( + keyPair.key + )} + toggleSidebar={toggleSidebar} + sidebarSecretId={sidebarSecretId} + isSnapshot={false} + /> + ))} + {snapshotData && + snapshotData.secretVersions + ?.sort((a, b) => a.key.localeCompare(b.key)) + .filter((row) => row.environment === selectedSnapshotEnv?.slug) + .filter((row) => row.key.toUpperCase().includes(searchKeys.toUpperCase())) + .filter( + (row) => + !snapshotData.secretVersions + ?.filter((secretVersion) => + snapshotData.secretVersions + ?.map((item) => item.key) + .filter( + (item, index) => + index !== + snapshotData.secretVersions?.map((i) => i.key).indexOf(item) + ) + .includes(secretVersion.key) + ) + ?.map((item) => item.id) + .includes(row.id) + ) + .map((keyPair) => ( + item.key))?.includes( + keyPair.key + )} + toggleSidebar={toggleSidebar} + sidebarSecretId={sidebarSecretId} + isSnapshot + /> + ))} +
+ {!snapshotData && ( +
+ +
+ )} +
+
+ ) : ( +
+ {isKeyAvailable && !snapshotData && ( + + )} + {!isKeyAvailable && ( + <> + +

To view this file, contact your administrator for permission.

+

They need to grant you access in the team tab.

+ + )} +
+ )} +
+
+
+
+ ) : ( +
+
+ loading animation +
+ ); +} + +Dashboard.requireAuth = true; + +export const getServerSideProps = getTranslatedServerSideProps(['dashboard']); diff --git a/frontend/pages/email-not-verified.js b/frontend/src/pages/email-not-verified.tsx similarity index 81% rename from frontend/pages/email-not-verified.js rename to frontend/src/pages/email-not-verified.tsx index 11aec70bd..cac631e30 100644 --- a/frontend/pages/email-not-verified.js +++ b/frontend/src/pages/email-not-verified.tsx @@ -1,7 +1,7 @@ import React from 'react'; import Head from 'next/head'; -export default function Activity() { +export default function EmailNotFeriviedPage() { return (
@@ -13,8 +13,7 @@ export default function Activity() {

Your email was not verified.

Please try again.

- Note: If it still {"doesn't work"}, please reach out to us at - support@infisical.com + Note: If it still doesn't work, please reach out to us at support@infisical.com

diff --git a/frontend/src/pages/github.tsx b/frontend/src/pages/github.tsx new file mode 100644 index 000000000..897027246 --- /dev/null +++ b/frontend/src/pages/github.tsx @@ -0,0 +1,41 @@ +import { useEffect } from 'react'; +import { useRouter } from 'next/router'; +import queryString from 'query-string'; + +import AuthorizeIntegration from './api/integrations/authorizeIntegration'; + +export default function Github() { + const router = useRouter(); + const parsedUrl = queryString.parse(router.asPath.split('?')[1]); + const {code} = parsedUrl; + const {state} = parsedUrl; + + /** + * Here we forward to the default workspace if a user opens this url + */ + // eslint-disable-next-line react-hooks/exhaustive-deps + useEffect(() => { + (async () => { + try { + if (state === localStorage.getItem('latestCSRFToken')) { + localStorage.removeItem('latestCSRFToken'); + await AuthorizeIntegration({ + workspaceId: localStorage.getItem('projectData.id') as string, + code: code as string, + integration: 'github', + }); + router.push( + `/integrations/${ localStorage.getItem('projectData.id')}` + ); + } + } catch (error) { + console.error('Github integration error: ', error); + } + })(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + return
; +} + +Github.requireAuth = true; diff --git a/frontend/src/pages/heroku.tsx b/frontend/src/pages/heroku.tsx new file mode 100644 index 000000000..ff4f2263e --- /dev/null +++ b/frontend/src/pages/heroku.tsx @@ -0,0 +1,41 @@ +import { useEffect } from 'react'; +import { useRouter } from 'next/router'; +import queryString from 'query-string'; + +import AuthorizeIntegration from './api/integrations/authorizeIntegration'; + +export default function Heroku() { + const router = useRouter(); + const parsedUrl = queryString.parse(router.asPath.split('?')[1]); + const {code} = parsedUrl; + const {state} = parsedUrl; + + /** + * Here we forward to the default workspace if a user opens this url + */ + // eslint-disable-next-line react-hooks/exhaustive-deps + useEffect(() => { + (async () => { + try { + if (state === localStorage.getItem('latestCSRFToken')) { + localStorage.removeItem('latestCSRFToken'); + await AuthorizeIntegration({ + workspaceId: localStorage.getItem('projectData.id') as string, + code: code as string, + integration: 'heroku', + }); + router.push( + `/integrations/${ localStorage.getItem('projectData.id')}` + ); + } + } catch (error) { + console.error('Heroku integration error: ', error); + } + })(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + return
; +} + +Heroku.requireAuth = true; diff --git a/frontend/pages/home/[id].tsx b/frontend/src/pages/home/[id].tsx similarity index 52% rename from frontend/pages/home/[id].tsx rename to frontend/src/pages/home/[id].tsx index d433600d3..fef9397c4 100644 --- a/frontend/pages/home/[id].tsx +++ b/frontend/src/pages/home/[id].tsx @@ -1,5 +1,4 @@ -import React, { useEffect, useState } from 'react'; -import Link from 'next/link'; +import { useEffect, useState } from 'react'; import { useRouter } from 'next/router'; import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { faSlack } from '@fortawesome/free-brands-svg-icons'; @@ -14,7 +13,8 @@ import { } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import onboardingCheck from '~/components/utilities/checks/OnboardingCheck'; +import onboardingCheck from '@app/components/utilities/checks/OnboardingCheck'; +import { getTranslatedServerSideProps } from '@app/components/utilities/withTranslateProps'; import registerUserAction from '../api/userActions/registerUserAction'; @@ -39,91 +39,82 @@ const learningItem = ({ }: ItemProps): JSX.Element => { if (link) { return ( - - -
{ - if (userAction && userAction != 'first_time_secrets_pushed') { - await registerUserAction({ - action: userAction - }); - } - }} - className="relative bg-bunker-700 hover:bg-bunker-500 shadow-xl duration-200 rounded-md border border-dashed border-bunker-400 pl-2 pr-6 py-2 h-[5.5rem] w-full flex items-center justify-between overflow-hidden my-1.5 cursor-pointer" - > -
- - {complete && ( -
- -
- )} -
-
{text}
-
{subText}
-
-
-
- {complete ? 'Complete!' : 'About ' + time} -
- {complete && ( -
- )} -
-
- - ); - } else { - return ( -
{ - if (userAction) { - await registerUserAction({ - action: userAction - }); - } - }} - className="relative bg-bunker-700 hover:bg-bunker-500 shadow-xl duration-200 rounded-md border border-dashed border-bunker-400 pl-2 pr-6 py-2 h-[5.5rem] w-full flex items-center justify-between overflow-hidden my-1.5 cursor-pointer" + -
- - {complete && ( -
- -
- )} -
-
{text}
-
{subText}
-
-
null} + role="button" + tabIndex={0} + onClick={async () => { + if (userAction && userAction !== 'first_time_secrets_pushed') { + await registerUserAction({ + action: userAction + }); + } + }} + className="relative bg-bunker-700 hover:bg-bunker-500 shadow-xl duration-200 rounded-md border border-dashed border-bunker-400 pl-2 pr-6 py-2 h-[5.5rem] w-full flex items-center justify-between overflow-hidden my-1.5 cursor-pointer" > - {complete ? 'Complete!' : 'About ' + time} +
+ + {complete && ( +
+ +
+ )} +
+
{text}
+
{subText}
+
+
+
+ {complete ? 'Complete!' : `About ${time}`} +
+ {complete &&
}
- {complete && ( -
- )} -
+
); } + return ( +
null} + role="button" + tabIndex={0} + onClick={async () => { + if (userAction) { + await registerUserAction({ + action: userAction + }); + } + }} + className="relative bg-bunker-700 hover:bg-bunker-500 shadow-xl duration-200 rounded-md border border-dashed border-bunker-400 pl-2 pr-6 py-2 h-[5.5rem] w-full flex items-center justify-between overflow-hidden my-1.5 cursor-pointer" + > +
+ + {complete && ( +
+ +
+ )} +
+
{text}
+
{subText}
+
+
+
+ {complete ? 'Complete!' : `About ${time}`} +
+ {complete &&
} +
+ ); }; /** @@ -152,9 +143,7 @@ export default function Home() { return (
-
- Your quick start guide -
+
Your quick start guide
Click on the items below and follow the instructions.
@@ -165,7 +154,7 @@ export default function Home() { icon: faHandPeace, time: '3 min', userAction: 'intro_cta_clicked', - link: 'https://www.youtube.com/watch?v=JS3OKYU2078' + link: 'https://www.youtube.com/watch?v=3F7FNYX94zA' })} {learningItem({ text: 'Add your secrets', @@ -174,12 +163,11 @@ export default function Home() { icon: faPlus, time: '2 min', userAction: 'first_time_secrets_pushed', - link: '/dashboard/' + router.query.id + link: `/dashboard/${router.query.id}` })} {learningItem({ text: 'Inject secrets locally', - subText: - 'Replace .env files with a more secure an efficient alternative.', + subText: 'Replace .env files with a more secure and efficient alternative.', complete: false, icon: faNetworkWired, time: '8 min', @@ -187,8 +175,7 @@ export default function Home() { })} {learningItem({ text: 'Integrate Infisical with your infrastructure', - subText: - 'Only a few integrations are currently available. Many more coming soon!', + subText: 'Only a few integrations are currently available. Many more coming soon!', complete: false, icon: faPlug, time: '15 min', @@ -200,7 +187,7 @@ export default function Home() { complete: usersInOrg, icon: faUserPlus, time: '2 min', - link: '/settings/org/' + router.query.id + '?invite' + link: `/settings/org/${router.query.id}?invite` })} {learningItem({ text: 'Join Infisical Slack', @@ -226,3 +213,5 @@ export default function Home() { } Home.requireAuth = true; + +export const getServerSideProps = getTranslatedServerSideProps(['home']); diff --git a/frontend/pages/index.js b/frontend/src/pages/index.tsx similarity index 69% rename from frontend/pages/index.js rename to frontend/src/pages/index.tsx index 5fc3aab22..615393cbd 100644 --- a/frontend/pages/index.js +++ b/frontend/src/pages/index.tsx @@ -1,4 +1,4 @@ -import React, { useEffect } from "react"; +import { useEffect } from "react"; import { useRouter } from "next/router"; export default function Home() { @@ -9,5 +9,5 @@ export default function Home() { // eslint-disable-next-line react-hooks/exhaustive-deps }, []); - return
; + return
; } diff --git a/frontend/src/pages/integrations/[id].tsx b/frontend/src/pages/integrations/[id].tsx new file mode 100644 index 000000000..a4bf83a89 --- /dev/null +++ b/frontend/src/pages/integrations/[id].tsx @@ -0,0 +1,403 @@ +import crypto from 'crypto'; + +import { useEffect, useState } from 'react'; +import Head from 'next/head'; +import { useRouter } from 'next/router'; +import { useTranslation } from 'next-i18next'; +import frameworkIntegrationOptions from 'public/json/frameworkIntegrations.json'; + +import ActivateBotDialog from '@app/components/basic/dialog/ActivateBotDialog'; +import IntegrationAccessTokenDialog from '@app/components/basic/dialog/IntegrationAccessTokenDialog'; +import CloudIntegrationSection from '@app/components/integrations/CloudIntegrationSection'; +import FrameworkIntegrationSection from '@app/components/integrations/FrameworkIntegrationSection'; +import IntegrationSection from '@app/components/integrations/IntegrationSection'; +import NavHeader from '@app/components/navigation/NavHeader'; +import { getTranslatedServerSideProps } from '@app/components/utilities/withTranslateProps'; + +import { + decryptAssymmetric, + encryptAssymmetric +} from '../../components/utilities/cryptography/crypto'; +import getBot from '../api/bot/getBot'; +import setBotActiveStatus from '../api/bot/setBotActiveStatus'; +import createIntegration from '../api/integrations/createIntegration'; +import deleteIntegration from '../api/integrations/DeleteIntegration'; +import getIntegrationOptions from '../api/integrations/GetIntegrationOptions'; +import getWorkspaceAuthorizations from '../api/integrations/getWorkspaceAuthorizations'; +import getWorkspaceIntegrations from '../api/integrations/getWorkspaceIntegrations'; +import saveIntegrationAccessToken from '../api/integrations/saveIntegrationAccessToken'; +import getAWorkspace from '../api/workspace/getAWorkspace'; +import getLatestFileKey from '../api/workspace/getLatestFileKey'; + +interface IntegrationAuth { + _id: string; + integration: string; + workspace: string; + createdAt: string; + updatedAt: string; +} + +interface Integration { + _id: string; + isActive: boolean; + app: string | null; + appId: string | null; + createdAt: string; + updatedAt: string; + environment: string; + integration: string; + targetEnvironment: string; + workspace: string; + integrationAuth: string; +} + +interface IntegrationOption { + clientId: string; + clientSlug?: string; // vercel-integration specific + docsLink: string; + image: string; + isAvailable: boolean; + name: string; + slug: string; + type: string; +} + +export default function Integrations() { + const [cloudIntegrationOptions, setCloudIntegrationOptions] = useState([]); + const [integrationAuths, setIntegrationAuths] = useState([]); + const [environments, setEnvironments] = useState< + { + name: string; + slug: string; + }[] + >([]); + const [integrations, setIntegrations] = useState([]); + // TODO: These will have its type when migratiing towards react-query + const [bot, setBot] = useState(null); + const [isActivateBotDialogOpen, setIsActivateBotDialogOpen] = useState(false); + const [isIntegrationAccessTokenDialogOpen, setIntegrationAccessTokenDialogOpen] = useState(false); + const [selectedIntegrationOption, setSelectedIntegrationOption] = useState(null); + + const router = useRouter(); + const workspaceId = router.query.id as string; + + const { t } = useTranslation(); + + useEffect(() => { + (async () => { + try { + const workspace = await getAWorkspace(workspaceId); + setEnvironments(workspace.environments); + + // get cloud integration options + setCloudIntegrationOptions(await getIntegrationOptions()); + + // get project integration authorizations + setIntegrationAuths( + await getWorkspaceAuthorizations({ + workspaceId + }) + ); + + // get project integrations + setIntegrations( + await getWorkspaceIntegrations({ + workspaceId + }) + ); + + // get project bot + setBot(await getBot({ workspaceId })); + } catch (err) { + console.error(err); + } + })(); + }, []); + + /** + * Activate bot for project by performing the following steps: + * 1. Get the (encrypted) project key + * 2. Decrypt project key with user's private key + * 3. Encrypt project key with bot's public key + * 4. Send encrypted project key to backend and set bot status to active + */ + const handleBotActivate = async () => { + let botKey; + try { + if (bot) { + // case: there is a bot + const key = await getLatestFileKey({ workspaceId }); + const PRIVATE_KEY = localStorage.getItem('PRIVATE_KEY'); + + if (!PRIVATE_KEY) { + throw new Error('Private Key missing'); + } + + const WORKSPACE_KEY = decryptAssymmetric({ + ciphertext: key.latestKey.encryptedKey, + nonce: key.latestKey.nonce, + publicKey: key.latestKey.sender.publicKey, + privateKey: PRIVATE_KEY + }); + + const { ciphertext, nonce } = encryptAssymmetric({ + plaintext: WORKSPACE_KEY, + publicKey: bot.publicKey, + privateKey: PRIVATE_KEY + }); + + botKey = { + encryptedKey: ciphertext, + nonce + }; + + setBot( + ( + await setBotActiveStatus({ + botId: bot._id, + isActive: true, + botKey + }) + ).bot + ); + } + } catch (err) { + console.error(err); + } + }; + + /** + * Handle integration option authorization for a given integration option [integrationOption] + * @param {Object} obj + * @param {Object} obj.integrationOption - an integration option + * @param {String} obj.name + * @param {String} obj.type + * @param {String} obj.docsLink + * @returns + */ + const handleIntegrationOption = async ({ + integrationOption, + accessToken + }: { + integrationOption: IntegrationOption, + accessToken?: string; + }) => { + try { + if (!bot.isActive) { + await handleBotActivate(); + } + + if (integrationOption.type === 'oauth') { + // integration is of type OAuth + + // generate CSRF token for OAuth2 code-token exchange integrations + const state = crypto.randomBytes(16).toString('hex'); + localStorage.setItem('latestCSRFToken', state); + + switch (integrationOption.slug) { + case 'heroku': + window.location.assign( + `https://id.heroku.com/oauth/authorize?client_id=${integrationOption.clientId}&response_type=code&scope=write-protected&state=${state}` + ); + break; + case 'vercel': + window.location.assign( + `https://vercel.com/integrations/${integrationOption.clientSlug}/new?state=${state}` + ); + break; + case 'netlify': + window.location.assign( + `https://app.netlify.com/authorize?client_id=${integrationOption.clientId}&response_type=code&state=${state}&redirect_uri=${window.location.origin}/netlify` + ); + break; + case 'github': + window.location.assign( + `https://github.com/login/oauth/authorize?client_id=${integrationOption.clientId}&response_type=code&scope=repo&redirect_uri=${window.location.origin}/github&state=${state}` + ); + break; + default: + break; + } + return; + } if (integrationOption.type === 'pat') { + // integration is of type personal access token + const integrationAuth = await saveIntegrationAccessToken({ + workspaceId: localStorage.getItem('projectData.id'), + integration: integrationOption.slug, + accessToken: accessToken ?? '' + }); + + setIntegrationAuths([...integrationAuths, integrationAuth]) + + const integration = await createIntegration({ + integrationAuthId: integrationAuth._id + }); + + setIntegrations([...integrations, integration]); + return; + } + } catch (err) { + console.error(err); + } + }; + + /** + * Open dialog to activate bot if bot is not active. + * Otherwise, start integration [integrationOption] + * @param {Object} integrationOption - an integration option + * @param {String} integrationOption.name + * @param {String} integrationOption.type + * @param {String} integrationOption.docsLink + * @returns + */ + const integrationOptionPress = async (integrationOption: IntegrationOption) => { + // consider: don't start integration until at [handleIntegrationOption] step + try { + const integrationAuthX = integrationAuths.find((integrationAuth) => integrationAuth.integration === integrationOption.slug); + + if (!integrationAuthX) { + // case: integration has not been authorized before + + if (integrationOption.type === 'pat') { + // case: integration requires user to input their personal access token for that integration + setIntegrationAccessTokenDialogOpen(true); + return; + } + + // case: integration does not require user to input their personal access token (i.e. it's an OAuth2 integration) + handleIntegrationOption({ integrationOption }); + return; + } + + if (!bot.isActive) { + await handleBotActivate(); + } + + // case: integration has been authorized before + // -> create new integration + const integration = await createIntegration({ + integrationAuthId: integrationAuthX._id + }); + setIntegrations([...integrations, integration]); + } catch (err) { + console.error(err); + } + }; + + /** + * Handle deleting integration authorization [integrationAuth] and corresponding integrations from state where applicable + * @param {Object} obj + * @param {IntegrationAuth} obj.integrationAuth - integrationAuth to delete + */ + const handleDeleteIntegrationAuth = async ({ integrationAuth: deletedIntegrationAuth }: { integrationAuth: IntegrationAuth }) => { + try { + const newIntegrations = integrations.filter((integration) => integration.integrationAuth !== deletedIntegrationAuth._id); + setIntegrationAuths(integrationAuths.filter((integrationAuth) => integrationAuth._id !== deletedIntegrationAuth._id)); + setIntegrations(newIntegrations); + + // handle updating bot + if (newIntegrations.length < 1) { + // case: no integrations left + setBot( + ( + await setBotActiveStatus({ + botId: bot._id, + isActive: false + }) + ).bot + ); + } + } catch (err) { + console.error(err); + } + } + + /** + * Handle deleting integration [integration] + * @param {Object} obj + * @param {Integration} obj.integration - integration to delete + */ + const handleDeleteIntegration = async ({ integration }: { integration: Integration }) => { + try { + const deletedIntegration = await deleteIntegration({ + integrationId: integration._id + }); + + const newIntegrations = integrations.filter((i) => i._id !== deletedIntegration._id); + setIntegrations(newIntegrations); + + // handle updating bot + if (newIntegrations.length < 1) { + // case: no integrations left + setBot( + ( + await setBotActiveStatus({ + botId: bot._id, + isActive: false + }) + ).bot + ); + } + } catch (err) { + console.error(err); + } + } + + return ( +
+ + {t('common:head-title', { title: t('integrations:title') })} + + + + + +
+ + setIsActivateBotDialogOpen(false)} + selectedIntegrationOption={selectedIntegrationOption} + integrationOptionPress={integrationOptionPress} + /> + setIntegrationAccessTokenDialogOpen(false)} + selectedIntegrationOption={selectedIntegrationOption} + handleIntegrationOption={handleIntegrationOption} + /> + + {cloudIntegrationOptions.length > 0 && bot ? ( + { + if (!bot.isActive) { + // case: bot is not active -> open modal to activate bot + setIsActivateBotDialogOpen(true); + return; + } + integrationOptionPress(integrationOption) + }} + integrationAuths={integrationAuths} + handleDeleteIntegrationAuth={handleDeleteIntegrationAuth} + /> + ) : ( +
+ )} + +
+
+ ); +} + +Integrations.requireAuth = true; + +export const getServerSideProps = getTranslatedServerSideProps(['integrations']); diff --git a/frontend/src/pages/login.tsx b/frontend/src/pages/login.tsx new file mode 100644 index 000000000..c32c4bd4f --- /dev/null +++ b/frontend/src/pages/login.tsx @@ -0,0 +1,170 @@ +import { useEffect, useState } from 'react'; +import Head from 'next/head'; +import Image from 'next/image'; +import Link from 'next/link'; +import { useRouter } from 'next/router'; +import { useTranslation } from 'next-i18next'; +import { faWarning } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; + +import Button from '@app/components/basic/buttons/Button'; +import Error from '@app/components/basic/Error'; +import InputField from '@app/components/basic/InputField'; +import ListBox from '@app/components/basic/Listbox'; +import attemptLogin from '@app/components/utilities/attemptLogin'; +import { getTranslatedStaticProps } from '@app/components/utilities/withTranslateProps'; +import { isLoggedIn } from '@app/reactQuery'; + +import getWorkspaces from './api/workspace/getWorkspaces'; + +export default function Login() { + const [email, setEmail] = useState(''); + const [password, setPassword] = useState(''); + const [errorLogin, setErrorLogin] = useState(false); + const [isLoading, setIsLoading] = useState(false); + const router = useRouter(); + const { t } = useTranslation(); + const lang = router.locale ?? 'en'; + + const setLanguage = async (to: string) => { + router.push('/login', '/login', { locale: to }); + localStorage.setItem('lang', to); + }; + + useEffect(() => { + // TODO(akhilmhdh): workspace will be controlled by a workspace context + const redirectToDashboard = async () => { + let userWorkspace; + try { + const userWorkspaces = await getWorkspaces(); + userWorkspace = userWorkspaces[0]._id; + router.push(`/dashboard/${userWorkspace}`); + } catch (error) { + console.log('Error - Not logged in yet'); + } + }; + if (isLoggedIn()) { + redirectToDashboard(); + } + }, []); + + /** + * This function check if the user entered the correct credentials and should be allowed to log in. + */ + const loginCheck = async () => { + if (!email || !password) { + return; + } + + setIsLoading(true); + await attemptLogin(email, password, setErrorLogin, router, false, true).then(() => { + setTimeout(() => { + setIsLoading(false); + }, 2000); + }); + }; + + return ( +
+ + {t('common:head-title', { title: t('login:title') })} + + + + + + +
+ long logo +
+ +
setErrorLogin(false)} onSubmit={(e) => e.preventDefault()}> +
+

+ {t('login:login')} +

+
+ +
+
+ +
+ + + +
+
+ {!isLoading && errorLogin && } +
+
+
+
+ {/*
+

I may have forgotten my password.

+
*/} +
+ {false && ( +
+ + {t('common:maintenance-alert')} +
+ )} +
+

+ {t('login:need-account')} +

+ + + +
+
+
+
+ +
+
+
+ ); +} + +export const getStaticProps = getTranslatedStaticProps(['auth', 'login']); diff --git a/frontend/src/pages/netlify.tsx b/frontend/src/pages/netlify.tsx new file mode 100644 index 000000000..532d6044a --- /dev/null +++ b/frontend/src/pages/netlify.tsx @@ -0,0 +1,46 @@ +import { useEffect } from 'react'; +import { useRouter } from 'next/router'; +import queryString from 'query-string'; + +import AuthorizeIntegration from './api/integrations/authorizeIntegration'; + +export default function Netlify() { + const router = useRouter(); + const parsedUrl = queryString.parse(router.asPath.split('?')[1]); + const {code} = parsedUrl; + const {state} = parsedUrl; + // modify comment here + + /** + * Here we forward to the default workspace if a user opens this url + */ + // eslint-disable-next-line react-hooks/exhaustive-deps + useEffect(() => { + (async () => { + try { + if (!code) throw new Error('Code not found'); + + if (state === localStorage.getItem('latestCSRFToken')) { + localStorage.removeItem('latestCSRFToken'); + + await AuthorizeIntegration({ + workspaceId: localStorage.getItem('projectData.id') as string, + code: code as string, + integration: 'netlify', + }); + + router.push( + `/integrations/${ localStorage.getItem('projectData.id')}` + ); + } + } catch (err) { + console.error('Netlify integration error: ', err); + } + })(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + return
; +} + +Netlify.requireAuth = true; diff --git a/frontend/src/pages/noprojects.tsx b/frontend/src/pages/noprojects.tsx new file mode 100644 index 000000000..a08c1b8ee --- /dev/null +++ b/frontend/src/pages/noprojects.tsx @@ -0,0 +1,51 @@ +import { useEffect } from 'react'; +import Image from 'next/image'; +import { useRouter } from 'next/router'; + +import Button from '@app/components/basic/buttons/Button'; +import { getTranslatedServerSideProps } from '@app/components/utilities/withTranslateProps'; + +import getOrganizationUserProjects from './api/organization/GetOrgUserProjects'; + +export default function NoProjects() { + const router = useRouter(); + + const redirectUser = async () => { + const workspaces = await getOrganizationUserProjects({ orgId: String(localStorage.getItem("orgData.id")) }); + if (workspaces.length > 0) { + router.push(`/dashboard/${workspaces[0]._id}`); + } + }; + + useEffect(() => { + // on initial load - run auth check + (async () => { + await redirectUser(); + })(); + }, []); + + return ( +
+
+ google logo +
+
+
+ You are not part of any projects in this organization yet. When you are, they will appear + here. +
+
+ Create a new project, or ask other organization members to give you neccessary + permissions. +
+
+
+
+
+ ); +} + +NoProjects.requireAuth = true; + +export const getServerSideProps = getTranslatedServerSideProps(['noprojects']); diff --git a/frontend/pages/password-reset.tsx b/frontend/src/pages/password-reset.tsx similarity index 70% rename from frontend/pages/password-reset.tsx rename to frontend/src/pages/password-reset.tsx index a09b85ab0..7da1778ea 100644 --- a/frontend/pages/password-reset.tsx +++ b/frontend/src/pages/password-reset.tsx @@ -1,29 +1,25 @@ -import React, { useState } from 'react'; +import { useState } from 'react'; import Image from 'next/image'; import { useRouter } from 'next/router'; import { faCheck, faX } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import jsrp from 'jsrp'; +import queryString from 'query-string'; -import Button from '~/components/basic/buttons/Button'; -import InputField from '~/components/basic/InputField'; -import passwordCheck from '~/components/utilities/checks/PasswordCheck'; -import Aes256Gcm from '~/components/utilities/cryptography/aes-256-gcm'; +import Button from '@app/components/basic/buttons/Button'; +import InputField from '@app/components/basic/InputField'; +import passwordCheck from '@app/components/utilities/checks/PasswordCheck'; +import Aes256Gcm from '@app/components/utilities/cryptography/aes-256-gcm'; +import { getTranslatedStaticProps } from '@app/components/utilities/withTranslateProps'; import EmailVerifyOnPasswordReset from './api/auth/EmailVerifyOnPasswordReset'; import getBackupEncryptedPrivateKey from './api/auth/getBackupEncryptedPrivateKey'; import resetPasswordOnAccountRecovery from './api/auth/resetPasswordOnAccountRecovery'; -const queryString = require('query-string'); -const nacl = require('tweetnacl'); -const jsrp = require('jsrp'); -nacl.util = require('tweetnacl-util'); +// eslint-disable-next-line new-cap const client = new jsrp.client(); export default function PasswordReset() { - const router = useRouter(); - const parsedUrl = queryString.parse(router.asPath.split('?')[1]); - const token = parsedUrl.token; - const email = parsedUrl.to?.replace(' ', '+').trim(); const [verificationToken, setVerificationToken] = useState(''); const [step, setStep] = useState(1); const [backupKey, setBackupKey] = useState(''); @@ -34,6 +30,11 @@ export default function PasswordReset() { const [passwordErrorNumber, setPasswordErrorNumber] = useState(false); const [passwordErrorLowerCase, setPasswordErrorLowerCase] = useState(false); + const router = useRouter(); + const parsedUrl = queryString.parse(router.asPath.split('?')[1]); + const token = parsedUrl.token as string; + const email = (parsedUrl.to as string)?.replace(' ', '+').trim(); + // Unencrypt the private key with a backup key const getEncryptedKeyHandler = async () => { try { @@ -54,13 +55,12 @@ export default function PasswordReset() { // If everything is correct, reset the password const resetPasswordHandler = async () => { - let errorCheck = false; - errorCheck = passwordCheck({ + const errorCheck = passwordCheck({ password: newPassword, setPasswordErrorLength, setPasswordErrorNumber, setPasswordErrorLowerCase, - currentErrorCheck: errorCheck + errorCheck: false }); if (!errorCheck) { @@ -69,11 +69,7 @@ export default function PasswordReset() { text: privateKey, secret: newPassword .slice(0, 32) - .padStart( - 32 + - (newPassword.slice(0, 32).length - new Blob([newPassword]).size), - '0' - ) + .padStart(32 + (newPassword.slice(0, 32).length - new Blob([newPassword]).size), '0') }) as { ciphertext: string; iv: string; tag: string }; client.init( @@ -82,23 +78,21 @@ export default function PasswordReset() { password: newPassword }, async () => { - client.createVerifier( - async (err: any, result: { salt: string; verifier: string }) => { - const response = await resetPasswordOnAccountRecovery({ - verificationToken, - encryptedPrivateKey: ciphertext, - iv, - tag, - salt: result.salt, - verifier: result.verifier - }); + client.createVerifier(async (err: any, result: { salt: string; verifier: string }) => { + const response = await resetPasswordOnAccountRecovery({ + verificationToken, + encryptedPrivateKey: ciphertext, + iv, + tag, + salt: result.salt, + verifier: result.verifier + }); - // if everything works, go the main dashboard page. - if (response?.status === 200) { - router.push('/login'); - } + // if everything works, go the main dashboard page. + if (response?.status === 200) { + router.push('/login'); } - ); + }); } ); } @@ -106,17 +100,12 @@ export default function PasswordReset() { // Click a button to confirm email const stepConfirmEmail = ( -
+

Confirm your email

- verify email -
+ verify email +
-
+

- Organization Members + {t('section-members:org-members')}

- Manage members of your organization. These users could - afterwards be formed into projects. + {t('section-members:org-members-description')}

+ = 5 && currentPlan === plans.starter && host === 'https://app.infisical.com'} + onClose={closeAddUserModal} + text="You can add more members if you switch to Infisical's Team plan." + /> {/* */}
-
+
setSearchUsers(e.target.value)} - placeholder={'Search members...'} + placeholder={t('section-members:search-members') as string} />
)}
-
+

- Incident Contacts + {t('section-incident:incident-contacts')}

- These contacts will be notified in the unlikely event of a - severe incident. + {t('section-incident:incident-contacts-description')}

-
+
-
+
setSearchIncidentContact(e.target.value)} - placeholder={'Search...'} + placeholder={t('common:search') as string} />
- {incidentContacts?.filter((email) => - email.includes(searchIncidentContact) + {incidentContacts?.filter((incidentEmail) => + incidentEmail.includes(searchIncidentContact) ).length > 0 ? ( incidentContacts - .filter((email) => email.includes(searchIncidentContact)) + .filter((incidentEmail) => incidentEmail.includes(searchIncidentContact)) .map((contact) => (
{contact}

@@ -378,3 +374,10 @@ export default function SettingsOrg() { } SettingsOrg.requireAuth = true; + +export const getServerSideProps = getTranslatedServerSideProps([ + 'settings', + 'settings-org', + 'section-incident', + 'section-members' +]); diff --git a/frontend/src/pages/settings/personal/[id].tsx b/frontend/src/pages/settings/personal/[id].tsx new file mode 100644 index 000000000..7d015ca40 --- /dev/null +++ b/frontend/src/pages/settings/personal/[id].tsx @@ -0,0 +1,322 @@ +import { useEffect, useState } from 'react'; +import Head from 'next/head'; +import { useRouter } from 'next/router'; +import { useTranslation } from 'next-i18next'; +import { faCheck, faPlus, faX } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; + +import Button from '@app/components/basic/buttons/Button'; +import InputField from '@app/components/basic/InputField'; +import ListBox from '@app/components/basic/Listbox'; +import ApiKeyTable from '@app/components/basic/table/ApiKeyTable'; +import NavHeader from '@app/components/navigation/NavHeader'; +import passwordCheck from '@app/components/utilities/checks/PasswordCheck'; +import changePassword from '@app/components/utilities/cryptography/changePassword'; +import issueBackupKey from '@app/components/utilities/cryptography/issueBackupKey'; +import { getTranslatedServerSideProps } from '@app/components/utilities/withTranslateProps'; + +import AddApiKeyDialog from '../../../components/basic/dialog/AddApiKeyDialog'; +import getAPIKeys from '../../api/apiKey/getAPIKeys'; +import getUser from '../../api/user/getUser'; + +export default function PersonalSettings() { + const [personalEmail, setPersonalEmail] = useState(''); + const [personalName, setPersonalName] = useState(''); + const [passwordErrorLength, setPasswordErrorLength] = useState(false); + const [passwordErrorNumber, setPasswordErrorNumber] = useState(false); + const [passwordErrorLowerCase, setPasswordErrorLowerCase] = useState(false); + const [currentPasswordError, setCurrentPasswordError] = useState(false); + const [currentPassword, setCurrentPassword] = useState(''); + const [newPassword, setNewPassword] = useState(''); + const [backupPassword, setBackupPassword] = useState(''); + const [passwordChanged, setPasswordChanged] = useState(false); + const [backupKeyIssued, setBackupKeyIssued] = useState(false); + const [backupKeyError, setBackupKeyError] = useState(false); + const [isAddApiKeyDialogOpen, setIsAddApiKeyDialogOpen] = useState(false); + const [apiKeys, setApiKeys] = useState([]); + + const { t } = useTranslation(); + const router = useRouter(); + const lang = router.locale ?? 'en'; + + const setLanguage = async (to: string) => { + router.push(router.asPath, router.asPath, { locale: to }); + localStorage.setItem('lang', to); + }; + + useEffect(() => { + const load = async () => { + try { + const user = await getUser(); + setApiKeys(await getAPIKeys()); + setPersonalEmail(user.email); + setPersonalName(`${user.firstName} ${user.lastName}`); + } catch (err) { + console.error(err); + } + }; + + load(); + }, []); + + const closeAddApiKeyModal = () => { + setIsAddApiKeyDialogOpen(false); + }; + + return ( +
+ + {t('common:head-title', { title: t('settings-personal:title') })} + + + +
+
+ +
+
+

{t('settings-personal:title')}

+

+ {t('settings-personal:description')} +

+
+
+
+
+

+ {t('settings-personal:change-language')} +

+
+ +
+
+
+
+
+

+ {t('settings-personal:api-keys.title')} +

+

+ {t('settings-personal:api-keys.description')} +

+
+
+
+
+ +
+ +
+
+
+

+ {t('section-password:change')} +

+
+
+
+ { + setCurrentPassword(password); + }} + type="password" + value={currentPassword} + isRequired + error={currentPasswordError} + errorText={t('section-password:current-wrong') as string} + autoComplete="current-password" + id="current-password" + /> +
+ { + setNewPassword(password); + passwordCheck({ + password, + setPasswordErrorLength, + setPasswordErrorNumber, + setPasswordErrorLowerCase, + errorCheck: false + }); + }} + type="password" + value={newPassword} + isRequired + error={passwordErrorLength && passwordErrorLowerCase && passwordErrorNumber} + autoComplete="new-password" + id="new-password" + /> +
+ {passwordErrorLength || passwordErrorLowerCase || passwordErrorNumber ? ( +
+
+ {t('section-password:validate-base')} +
+
+ {passwordErrorLength ? ( + + ) : ( + + )} +
+ {t('section-password:validate-length')} +
+
+
+ {passwordErrorLowerCase ? ( + + ) : ( + + )} +
+ {t('section-password:validate-case')} +
+
+
+ {passwordErrorNumber ? ( + + ) : ( + + )} +
+ {t('section-password:validate-number')} +
+
+
+ ) : ( +
+ )} +
+
+
+ +
+
+
+

+ {t('settings-personal:emergency.name')} +

+

+ {t('settings-personal:emergency.text1')} +

+

+ {t('settings-personal:emergency.text2')} +

+
+
+
+ +
+
+
+
+
+
+
+
+ ); +} + +PersonalSettings.requireAuth = true; + +export const getServerSideProps = getTranslatedServerSideProps([ + 'settings', + 'settings-personal', + 'section-password', + 'section-api-key' +]); diff --git a/frontend/src/pages/settings/project/[id].tsx b/frontend/src/pages/settings/project/[id].tsx new file mode 100644 index 000000000..14b2a3785 --- /dev/null +++ b/frontend/src/pages/settings/project/[id].tsx @@ -0,0 +1,333 @@ +import { useEffect, useState } from 'react'; +import Head from 'next/head'; +import { useRouter } from 'next/router'; +import { useTranslation } from 'next-i18next'; +import { faCheck, faCopy, faPlus } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; + +import Button from '@app/components/basic/buttons/Button'; +import AddServiceTokenDialog from '@app/components/basic/dialog/AddServiceTokenDialog'; +import InputField from '@app/components/basic/InputField'; +import EnvironmentTable from '@app/components/basic/table/EnvironmentsTable'; +import ServiceTokenTable from '@app/components/basic/table/ServiceTokenTable'; +import NavHeader from '@app/components/navigation/NavHeader'; +import { getTranslatedServerSideProps } from '@app/components/utilities/withTranslateProps'; +import deleteEnvironment from '@app/pages/api/environments/deleteEnvironment'; +import updateEnvironment from '@app/pages/api/environments/updateEnvironment'; + +import createEnvironment from '../../api/environments/createEnvironment'; +import getServiceTokens from '../../api/serviceToken/getServiceTokens'; +import deleteWorkspace from '../../api/workspace/deleteWorkspace'; +import getWorkspaces from '../../api/workspace/getWorkspaces'; +import renameWorkspace from '../../api/workspace/renameWorkspace'; + +type EnvData = { + name: string; + slug: string; +}; + +export default function SettingsBasic() { + const [buttonReady, setButtonReady] = useState(false); + const router = useRouter(); + const [workspaceName, setWorkspaceName] = useState(''); + const [serviceTokens, setServiceTokens] = useState([]); + const [environments, setEnvironments] = useState>([]); + const [workspaceToBeDeletedName, setWorkspaceToBeDeletedName] = useState(''); + // const [isAddOpen, setIsAddOpen] = useState(false); + const [isAddServiceTokenDialogOpen, setIsAddServiceTokenDialogOpen] = useState(false); + const [projectIdCopied, setProjectIdCopied] = useState(false); + const workspaceId = router.query.id as string; + + const { t } = useTranslation(); + + /** + * This function copies the project id to the clipboard + */ + function copyToClipboard() { + const copyText = document.getElementById('myInput') as HTMLInputElement; + + if (copyText) { + copyText.select(); + copyText.setSelectionRange(0, 99999); // For mobile devices + + navigator.clipboard.writeText(copyText.value); + + setProjectIdCopied(true); + setTimeout(() => setProjectIdCopied(false), 2000); + } + } + + useEffect(() => { + const load = async () => { + const userWorkspaces = await getWorkspaces(); + userWorkspaces.forEach((userWorkspace) => { + if (userWorkspace._id === workspaceId) { + setWorkspaceName(userWorkspace.name); + setEnvironments(userWorkspace.environments); + } + }); + const tempServiceTokens = await getServiceTokens({ + workspaceId + }); + setServiceTokens(tempServiceTokens); + }; + + load(); + }, []); + + const modifyWorkspaceName = (newName: string) => { + setButtonReady(true); + setWorkspaceName(newName); + }; + + const submitChanges = (newWorkspaceName: string) => { + renameWorkspace(workspaceId, newWorkspaceName); + setButtonReady(false); + }; + + const closeAddServiceTokenModal = () => { + setIsAddServiceTokenDialogOpen(false); + }; + + /** + * This function deleted a workspace. + * It first checks if there is more than one workspace aviable. Otherwise, it doesn't delete + * It then checks if the name of the workspace to be deleted is correct. Otherwise, it doesn't delete. + * It then deletes the workspace and forwards the user to another aviable workspace. + */ + const executeDeletingWorkspace = async () => { + const userWorkspaces = await getWorkspaces(); + + if (userWorkspaces.length > 1) { + if ( + userWorkspaces.filter((workspace) => workspace._id === workspaceId)[0].name === + workspaceToBeDeletedName + ) { + await deleteWorkspace(workspaceId); + const ws = await getWorkspaces(); + router.push(`/dashboard/${ws[0]._id}`); + } + } + }; + + const onCreateEnvironment = async ({ name, slug }: EnvData) => { + const res = await createEnvironment(workspaceId, { + environmentName: name, + environmentSlug: slug + }); + if (res) { + // TODO: on react-query migration do an api call to resync + setEnvironments((env) => [...env, { name, slug }]); + } + }; + + const onUpdateEnvironment = async (oldSlug: string, { name, slug }: EnvData) => { + const res = await updateEnvironment(workspaceId, { + oldEnvironmentSlug: oldSlug, + environmentName: name, + environmentSlug: slug + }); + // TODO: on react-query migration do an api call to resync + if (res) { + setEnvironments((env) => env.map((el) => (el.slug === oldSlug ? { name, slug } : el))); + } + }; + + const onDeleteEnvironment = async (slugToBeDelete: string) => { + const res = await deleteEnvironment(workspaceId, slugToBeDelete); + // TODO: on react-query migration do an api call to resync + if (res) { + setEnvironments((env) => env.filter(({ slug }) => slug !== slugToBeDelete)); + } + }; + + return ( +
+ + {t('common:head-title', { title: t('settings-project:title') })} + + + +
+
+ +
+
+

{t('settings-project:title')}

+

+ {t('settings-project:description')} +

+
+
+
+
+
+
+

{t('common:display-name')}

+
+ +
+
+
+
+
+
+
+

{t('common:project-id')}

+

+ {t('settings-project:project-id-description')} +

+

+ {t('settings-project:project-id-description2')} + {/* eslint-disable-next-line react/jsx-no-target-blank */} + + {t('settings-project:docs')} + +

+

+ {t('settings-project:auto-generated')} +

+
+

{`${t('common:project-id')}:`}

+ +
+ + + {t('common:click-to-copy')} + +
+
+
+
+ +
+
+
+
+

+ {t('section-token:service-tokens')} +

+

+ {t('section-token:service-tokens-description')} +

+

+ Please, make sure you are on the + + latest version of CLI + + . +

+
+
+
+
+ +
+
+
+
+

{t('settings-project:danger-zone')}

+

{t('settings-project:danger-zone-note')}

+
+ +
+ +

+ {t('settings-project:delete-project-note')} +

+
+
+
+
+
+ ); +} + +SettingsBasic.requireAuth = true; + +export const getServerSideProps = getTranslatedServerSideProps([ + 'settings', + 'settings-project', + 'section-token' +]); diff --git a/frontend/src/pages/signup.tsx b/frontend/src/pages/signup.tsx new file mode 100644 index 000000000..ae93d97d0 --- /dev/null +++ b/frontend/src/pages/signup.tsx @@ -0,0 +1,123 @@ +/* eslint-disable no-nested-ternary */ +import { useEffect, useState } from 'react'; +import Head from 'next/head'; +import Image from 'next/image'; +import Link from 'next/link'; +import { useRouter } from 'next/router'; +import { useTranslation } from 'next-i18next'; + +import CodeInputStep from '@app/components/signup/CodeInputStep'; +import DownloadBackupPDF from '@app/components/signup/DonwloadBackupPDFStep'; +import EnterEmailStep from '@app/components/signup/EnterEmailStep'; +import TeamInviteStep from '@app/components/signup/TeamInviteStep'; +import UserInfoStep from '@app/components/signup/UserInfoStep'; +import { getTranslatedStaticProps } from '@app/components/utilities/withTranslateProps'; + +import checkEmailVerificationCode from './api/auth/CheckEmailVerificationCode'; +import getWorkspaces from './api/workspace/getWorkspaces'; + +/** + * @returns the signup page + */ +export default function SignUp() { + const [email, setEmail] = useState(''); + const [password, setPassword] = useState(''); + const [firstName, setFirstName] = useState(''); + const [lastName, setLastName] = useState(''); + const [code, setCode] = useState(''); + const [codeError, setCodeError] = useState(false); + const [step, setStep] = useState(1); + const router = useRouter(); + const [verificationToken, setVerificationToken] = useState(''); + + const { t } = useTranslation(); + + useEffect(() => { + const tryAuth = async () => { + try { + const userWorkspaces = await getWorkspaces(); + router.push(`/dashboard/${userWorkspaces[0]._id}`); + } catch (error) { + console.log('Error - Not logged in yet'); + } + }; + tryAuth(); + }, []); + + /** + * Goes to the following step (out of 5) of the signup process. + * Step 1 is submitting your email + * Step 2 is Verifying your email with the code that you received + * Step 3 is asking the final info. + * Step 4 is downloading a backup pdf + * Step 5 is inviting users + */ + const incrementStep = async () => { + if (step === 1 || step === 3 || step === 4) { + setStep(step + 1); + } else if (step === 2) { + // Checking if the code matches the email. + const response = await checkEmailVerificationCode({ email, code }); + if (response.status === 200) { + setVerificationToken((await response.json()).token); + setStep(3); + } else { + setCodeError(true); + } + } + }; + + return ( +
+ + {t('common:head-title', { title: t('signup:title') })} + + + + + +
+ +
+ Infisical Wide Logo +
+ +
e.preventDefault()}> + {step === 1 ? ( + + ) : step === 2 ? ( + + ) : step === 3 ? ( + + ) : step === 4 ? ( + + ) : ( + + )} + +
+
+ ); +} + +export const getStaticProps = getTranslatedStaticProps(['auth', 'signup', 'section-password']); diff --git a/frontend/pages/signupinvite.js b/frontend/src/pages/signupinvite.tsx similarity index 67% rename from frontend/pages/signupinvite.js rename to frontend/src/pages/signupinvite.tsx index a41010aea..ce8db9afe 100644 --- a/frontend/pages/signupinvite.js +++ b/frontend/src/pages/signupinvite.tsx @@ -1,26 +1,29 @@ -import React, { useState } from 'react'; +/* eslint-disable no-nested-ternary */ +/* eslint-disable @typescript-eslint/no-unused-vars */ +import { useState } from 'react'; import Head from 'next/head'; import Image from 'next/image'; import Link from 'next/link'; import { useRouter } from 'next/router'; import { faCheck, faWarning, faX } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import jsrp from 'jsrp'; +import queryString from 'query-string'; +import nacl from 'tweetnacl'; +import { encodeBase64 } from 'tweetnacl-util'; -import Button from '~/components/basic/buttons/Button'; -import InputField from '~/components/basic/InputField'; -import Aes256Gcm from '~/components/utilities/cryptography/aes-256-gcm'; -import issueBackupKey from '~/components/utilities/cryptography/issueBackupKey'; -import attemptLogin from '~/utilities/attemptLogin'; -import passwordCheck from '~/utilities/checks/PasswordCheck'; +import Button from '@app/components/basic/buttons/Button'; +import InputField from '@app/components/basic/InputField'; +import attemptLogin from '@app/components/utilities/attemptLogin'; +import passwordCheck from '@app/components/utilities/checks/PasswordCheck'; +import Aes256Gcm from '@app/components/utilities/cryptography/aes-256-gcm'; +import issueBackupKey from '@app/components/utilities/cryptography/issueBackupKey'; import completeAccountInformationSignupInvite from './api/auth/CompleteAccountInformationSignupInvite'; import verifySignupInvite from './api/auth/VerifySignupInvite'; -const nacl = require('tweetnacl'); -const jsrp = require('jsrp'); -nacl.util = require('tweetnacl-util'); +// eslint-disable-next-line new-cap const client = new jsrp.client(); -const queryString = require('query-string'); export default function SignupInvite() { const [password, setPassword] = useState(''); @@ -31,21 +34,22 @@ export default function SignupInvite() { const [passwordErrorLength, setPasswordErrorLength] = useState(false); const [passwordErrorNumber, setPasswordErrorNumber] = useState(false); const [passwordErrorLowerCase, setPasswordErrorLowerCase] = useState(false); - const router = useRouter(); - const parsedUrl = queryString.parse(router.asPath.split('?')[1]); - const [email, setEmail] = useState(parsedUrl.to?.replace(' ', '+').trim()); - const token = parsedUrl.token; const [errorLogin, setErrorLogin] = useState(false); const [isLoading, setIsLoading] = useState(false); const [step, setStep] = useState(1); const [backupKeyError, setBackupKeyError] = useState(false); - const [verificationToken, setVerificationToken] = useState(); + const [verificationToken, setVerificationToken] = useState(''); const [backupKeyIssued, setBackupKeyIssued] = useState(false); + const router = useRouter(); + const parsedUrl = queryString.parse(router.asPath.split('?')[1]); + const token = parsedUrl.token as string; + const email = (parsedUrl.to as string)?.replace(' ', '+').trim(); + // Verifies if the information that the users entered (name, workspace) is there, and if the password matched the criteria. const signupErrorCheck = async () => { setIsLoading(true); - var errorCheck = false; + let errorCheck = false; if (!firstName) { setFirstNameError(true); errorCheck = true; @@ -71,17 +75,14 @@ export default function SignupInvite() { const pair = nacl.box.keyPair(); const secretKeyUint8Array = pair.secretKey; const publicKeyUint8Array = pair.publicKey; - const PRIVATE_KEY = nacl.util.encodeBase64(secretKeyUint8Array); - const PUBLIC_KEY = nacl.util.encodeBase64(publicKeyUint8Array); + const PRIVATE_KEY = encodeBase64(secretKeyUint8Array); + const PUBLIC_KEY = encodeBase64(publicKeyUint8Array); const { ciphertext, iv, tag } = Aes256Gcm.encrypt({ text: PRIVATE_KEY, secret: password .slice(0, 32) - .padStart( - 32 + (password.slice(0, 32).length - new Blob([password]).size), - '0' - ) + .padStart(32 + (password.slice(0, 32).length - new Blob([password]).size), '0') }); localStorage.setItem('PRIVATE_KEY', PRIVATE_KEY); @@ -89,7 +90,7 @@ export default function SignupInvite() { client.init( { username: email, - password: password + password }, async () => { client.createVerifier(async (err, result) => { @@ -107,7 +108,7 @@ export default function SignupInvite() { }); // if everything works, go the main dashboard page. - if (!errorCheck && response.status == '200') { + if (!errorCheck && response.status === 200) { response = await response.json(); localStorage.setItem('publicKey', PUBLIC_KEY); @@ -116,14 +117,7 @@ export default function SignupInvite() { localStorage.setItem('tag', tag); try { - await attemptLogin( - email, - password, - setErrorLogin, - router, - false, - false - ); + await attemptLogin(email, password, setErrorLogin, router, false, false); setStep(3); } catch (error) { setIsLoading(false); @@ -140,17 +134,12 @@ export default function SignupInvite() { // Step 4 of the sign up process (download the emergency kit pdf) const stepConfirmEmail = ( -
-

+

+

Confirm your email

- verify email -
+ verify email +
); } diff --git a/frontend/src/pages/users/[id].tsx b/frontend/src/pages/users/[id].tsx new file mode 100644 index 000000000..abd1cfc6f --- /dev/null +++ b/frontend/src/pages/users/[id].tsx @@ -0,0 +1,222 @@ +import { useEffect, useState } from 'react'; +import Head from 'next/head'; +import Image from 'next/image'; +import { useRouter } from 'next/router'; +import { useTranslation } from 'next-i18next'; +import { faMagnifyingGlass, faPlus } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; + +import Button from '@app/components/basic/buttons/Button'; +import AddProjectMemberDialog from '@app/components/basic/dialog/AddProjectMemberDialog'; +import ProjectUsersTable from '@app/components/basic/table/ProjectUsersTable'; +import NavHeader from '@app/components/navigation/NavHeader'; +import guidGenerator from '@app/components/utilities/randomId'; +import { getTranslatedServerSideProps } from '@app/components/utilities/withTranslateProps'; + +import { + decryptAssymmetric, + encryptAssymmetric +} from '../../components/utilities/cryptography/crypto'; +import getOrganizationUsers from '../api/organization/GetOrgUsers'; +import getUser from '../api/user/getUser'; +// import DeleteUserDialog from '@app/components/basic/dialog/DeleteUserDialog'; +import addUserToWorkspace from '../api/workspace/addUserToWorkspace'; +import getWorkspaceUsers from '../api/workspace/getWorkspaceUsers'; +import uploadKeys from '../api/workspace/uploadKeys'; + +interface UserProps { + firstName: string; + lastName: string; + email: string; + _id: string; + publicKey: string; +} + +interface MembershipProps { + deniedPermissions: any[]; + user: UserProps; + inviteEmail: string; + role: string; + status: string; + _id: string; +} + +// #TODO: Update all the workspaceIds + +export default function Users() { + const [isAddOpen, setIsAddOpen] = useState(false); + // let [isDeleteOpen, setIsDeleteOpen] = useState(false); + // let [userIdToBeDeleted, setUserIdToBeDeleted] = useState(false); + const [email, setEmail] = useState(''); + const [personalEmail, setPersonalEmail] = useState(''); + const [searchUsers, setSearchUsers] = useState(''); + + const { t } = useTranslation(); + + const router = useRouter(); + const workspaceId = router.query.id as string; + + const [userList, setUserList] = useState([]); + const [orgUserList, setOrgUserList] = useState([]); + + useEffect(() => { + (async () => { + const user = await getUser(); + setPersonalEmail(user.email); + + // This part quiries the current users of a project + const workspaceUsers = await getWorkspaceUsers({ + workspaceId + }); + const tempUserList = workspaceUsers.map((membership: MembershipProps) => ({ + key: guidGenerator(), + firstName: membership.user?.firstName, + lastName: membership.user?.lastName, + email: membership.user?.email === null ? membership.inviteEmail : membership.user?.email, + role: membership?.role, + status: membership?.status, + userId: membership.user?._id, + membershipId: membership._id, + deniedPermissions: membership.deniedPermissions, + publicKey: membership.user?.publicKey + })); + setUserList(tempUserList); + + // This is needed to know wha users from an org (if any), we are able to add to a certain project + const orgUsers = await getOrganizationUsers({ + orgId: String(localStorage.getItem('orgData.id')) + }); + setOrgUserList(orgUsers); + setEmail( + orgUsers + ?.filter((membership: MembershipProps) => membership.status === 'accepted') + .map((membership: MembershipProps) => membership.user.email) + .filter( + (usEmail: string) => + !tempUserList?.map((user1: UserProps) => user1.email).includes(usEmail) + )[0] + ); + })(); + }, []); + + const closeAddModal = () => { + setIsAddOpen(false); + }; + + const openAddModal = () => { + setIsAddOpen(true); + }; + + // function closeDeleteModal() { + // setIsDeleteOpen(false); + // } + + // function deleteMembership(userId) { + // deleteUserFromWorkspace(userId, router.query.id) + // } + + // function openDeleteModal() { + // setIsDeleteOpen(true); + // } + + const submitAddModal = async () => { + const result = await addUserToWorkspace(email, workspaceId); + if (result?.invitee && result?.latestKey) { + const PRIVATE_KEY = localStorage.getItem('PRIVATE_KEY') as string; + + // assymmetrically decrypt symmetric key with local private key + const key = decryptAssymmetric({ + ciphertext: result.latestKey.encryptedKey, + nonce: result.latestKey.nonce, + publicKey: result.latestKey.sender.publicKey, + privateKey: PRIVATE_KEY + }); + + const { ciphertext, nonce } = encryptAssymmetric({ + plaintext: key, + publicKey: result.invitee.publicKey, + privateKey: PRIVATE_KEY + }); + + uploadKeys(workspaceId, result.invitee._id, ciphertext, nonce); + } + setEmail(''); + setIsAddOpen(false); + router.reload(); + }; + + return userList ? ( +
+ + {t('common:head-title', { title: t('settings-members:title') })} + + + +
+

{t('settings-members:title')}

+

{t('settings-members:description')}

+
+ membership.status === 'accepted') + .map((membership: MembershipProps) => membership.user.email) + .filter( + (orgEmail) => !userList?.map((user1: UserProps) => user1.email).includes(orgEmail) + )} + setEmail={setEmail} + /> + {/* */} +
+
+ + setSearchUsers(e.target.value)} + placeholder={String(t('section-members:search-members'))} + /> +
+
+
+
+
+ +
+
+ ) : ( +
+
+ loading animation +
+ ); +} + +Users.requireAuth = true; + +export const getServerSideProps = getTranslatedServerSideProps([ + 'settings', + 'settings-members', + 'section-members' +]); diff --git a/frontend/src/pages/vercel.tsx b/frontend/src/pages/vercel.tsx new file mode 100644 index 000000000..8e8245736 --- /dev/null +++ b/frontend/src/pages/vercel.tsx @@ -0,0 +1,46 @@ +import { useEffect } from 'react'; +import { useRouter } from 'next/router'; +import queryString from 'query-string'; + +import AuthorizeIntegration from './api/integrations/authorizeIntegration'; + +export default function Vercel() { + const router = useRouter(); + const parsedUrl = queryString.parse(router.asPath.split('?')[1]); + const {code} = parsedUrl; + const {state} = parsedUrl; + + /** + * Here we forward to the default workspace if a user opens this url + */ + // eslint-disable-next-line react-hooks/exhaustive-deps + useEffect(() => { + (async () => { + try { + // type check + if (!code) throw new Error('Code not found'); + + if (state === localStorage.getItem('latestCSRFToken')) { + localStorage.removeItem('latestCSRFToken'); + + await AuthorizeIntegration({ + workspaceId: localStorage.getItem('projectData.id') as string, + code: code as string, + integration: 'vercel', + }); + + router.push( + `/integrations/${ localStorage.getItem('projectData.id')}` + ); + } + } catch (err) { + console.error('Vercel integration error: ', err); + } + })(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + return
; +} + +Vercel.requireAuth = true; diff --git a/frontend/pages/verify-email.tsx b/frontend/src/pages/verify-email.tsx similarity index 81% rename from frontend/pages/verify-email.tsx rename to frontend/src/pages/verify-email.tsx index 7dfc1427e..3b7e1c8d5 100644 --- a/frontend/pages/verify-email.tsx +++ b/frontend/src/pages/verify-email.tsx @@ -1,10 +1,11 @@ -import React, { useState } from 'react'; +import { useState } from 'react'; import Head from 'next/head'; import Image from 'next/image'; import Link from 'next/link'; -import Button from '~/components/basic/buttons/Button'; -import InputField from '~/components/basic/InputField'; +import Button from '@app/components/basic/buttons/Button'; +import InputField from '@app/components/basic/InputField'; +import { getTranslatedStaticProps } from '@app/components/utilities/withTranslateProps'; import SendEmailOnPasswordReset from './api/auth/SendEmailOnPasswordReset'; @@ -28,7 +29,7 @@ export default function VerifyEmail() { Login - +
- long logo + long logo
- {step == 1 && ( + {step === 1 && (

Forgot your password?

- You will need your emergency kit. Enter your email to start - account recovery. + You will need your emergency kit. Enter your email to start account recovery.

@@ -68,16 +63,12 @@ export default function VerifyEmail() {
-
)} - {step == 2 && ( + {step === 2 && (

Look for an email in your inbox. @@ -92,3 +83,5 @@ export default function VerifyEmail() {

); } + +export const getServerSideProps = getTranslatedStaticProps([]); diff --git a/frontend/src/reactQuery.ts b/frontend/src/reactQuery.ts new file mode 100644 index 000000000..c28dc39b1 --- /dev/null +++ b/frontend/src/reactQuery.ts @@ -0,0 +1,21 @@ +import { QueryClient } from '@tanstack/react-query'; + +// this is saved in react-query cache +export const AUTH_TOKEN_CACHE_KEY = ['infisical__auth-token']; + +export const queryClient = new QueryClient({ + defaultOptions: { + queries: { + refetchOnWindowFocus: false, + retry: 1 + } + } +}); + +// set token in memory cache +export const setAuthToken = (token: string) => + queryClient.setQueryData(AUTH_TOKEN_CACHE_KEY, token); + +export const getAuthToken = () => queryClient.getQueryData(AUTH_TOKEN_CACHE_KEY) as string; + +export const isLoggedIn = () => Boolean(getAuthToken()); diff --git a/frontend/src/styles/globals.css b/frontend/src/styles/globals.css new file mode 100644 index 000000000..df32da8d0 --- /dev/null +++ b/frontend/src/styles/globals.css @@ -0,0 +1,7 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +@import '@fontsource/inter/400.css'; +@import '@fontsource/inter/500.css'; +@import '@fontsource/inter/700.css'; \ No newline at end of file diff --git a/frontend/styles/globals.css b/frontend/styles/globals.css deleted file mode 100644 index b5c61c956..000000000 --- a/frontend/styles/globals.css +++ /dev/null @@ -1,3 +0,0 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; diff --git a/frontend/tailwind.config.js b/frontend/tailwind.config.js index 6f3d038cf..f2c832acc 100644 --- a/frontend/tailwind.config.js +++ b/frontend/tailwind.config.js @@ -1,12 +1,13 @@ -const colors = require("tailwindcss/colors"); +const colors = require('tailwindcss/colors'); const round = (num) => num .toFixed(7) - .replace(/(\.[0-9]+?)0+$/, "$1") - .replace(/\.0$/, ""); + .replace(/(\.[0-9]+?)0+$/, '$1') + .replace(/\.0$/, ''); const rem = (px) => `${round(px / 16)}rem`; const em = (px, base) => `${round(px / base)}em`; +// TODO(akhilmhdh): Clean up this later let defaultModifiers = { sm: { css: [ @@ -15,71 +16,71 @@ let defaultModifiers = { lineHeight: round(24 / 14), p: { marginTop: em(16, 14), - marginBottom: em(16, 14), + marginBottom: em(16, 14) }, '[class~="lead"]': { fontSize: em(18, 14), lineHeight: round(28 / 18), marginTop: em(16, 18), - marginBottom: em(16, 18), + marginBottom: em(16, 18) }, blockquote: { marginTop: em(24, 18), marginBottom: em(24, 18), - paddingLeft: em(20, 18), + paddingLeft: em(20, 18) }, h1: { fontSize: em(30, 14), - marginTop: "0", + marginTop: '0', marginBottom: em(24, 30), - lineHeight: round(36 / 30), + lineHeight: round(36 / 30) }, h2: { fontSize: em(20, 14), marginTop: em(32, 20), marginBottom: em(16, 20), - lineHeight: round(28 / 20), + lineHeight: round(28 / 20) }, h3: { fontSize: em(18, 14), marginTop: em(28, 18), marginBottom: em(8, 18), - lineHeight: round(28 / 18), + lineHeight: round(28 / 18) }, h4: { marginTop: em(20, 14), marginBottom: em(8, 14), - lineHeight: round(20 / 14), + lineHeight: round(20 / 14) }, img: { marginTop: em(24, 14), - marginBottom: em(24, 14), + marginBottom: em(24, 14) }, video: { marginTop: em(24, 14), - marginBottom: em(24, 14), + marginBottom: em(24, 14) }, figure: { marginTop: em(24, 14), - marginBottom: em(24, 14), + marginBottom: em(24, 14) }, - "figure > *": { - marginTop: "0", - marginBottom: "0", + 'figure > *': { + marginTop: '0', + marginBottom: '0' }, figcaption: { fontSize: em(12, 14), lineHeight: round(16 / 12), - marginTop: em(8, 12), + marginTop: em(8, 12) }, code: { - fontSize: em(12, 14), + fontSize: em(12, 14) }, - "h2 code": { - fontSize: em(18, 20), + 'h2 code': { + fontSize: em(18, 20) }, - "h3 code": { - fontSize: em(16, 18), + 'h3 code': { + fontSize: em(16, 18) }, pre: { fontSize: em(12, 14), @@ -90,101 +91,101 @@ let defaultModifiers = { paddingTop: em(8, 12), paddingRight: em(12, 12), paddingBottom: em(8, 12), - paddingLeft: em(12, 12), + paddingLeft: em(12, 12) }, ol: { marginTop: em(16, 14), marginBottom: em(16, 14), - paddingLeft: em(22, 14), + paddingLeft: em(22, 14) }, ul: { marginTop: em(16, 14), marginBottom: em(16, 14), - paddingLeft: em(22, 14), + paddingLeft: em(22, 14) }, li: { marginTop: em(4, 14), - marginBottom: em(4, 14), + marginBottom: em(4, 14) }, - "ol > li": { - paddingLeft: em(6, 14), + 'ol > li': { + paddingLeft: em(6, 14) }, - "ul > li": { - paddingLeft: em(6, 14), + 'ul > li': { + paddingLeft: em(6, 14) }, - "> ul > li p": { + '> ul > li p': { marginTop: em(8, 14), - marginBottom: em(8, 14), + marginBottom: em(8, 14) }, - "> ul > li > *:first-child": { - marginTop: em(16, 14), + '> ul > li > *:first-child': { + marginTop: em(16, 14) }, - "> ul > li > *:last-child": { - marginBottom: em(16, 14), + '> ul > li > *:last-child': { + marginBottom: em(16, 14) }, - "> ol > li > *:first-child": { - marginTop: em(16, 14), + '> ol > li > *:first-child': { + marginTop: em(16, 14) }, - "> ol > li > *:last-child": { - marginBottom: em(16, 14), + '> ol > li > *:last-child': { + marginBottom: em(16, 14) }, - "ul ul, ul ol, ol ul, ol ol": { + 'ul ul, ul ol, ol ul, ol ol': { marginTop: em(8, 14), - marginBottom: em(8, 14), + marginBottom: em(8, 14) }, hr: { marginTop: em(40, 14), - marginBottom: em(40, 14), + marginBottom: em(40, 14) }, - "hr + *": { - marginTop: "0", + 'hr + *': { + marginTop: '0' }, - "h2 + *": { - marginTop: "0", + 'h2 + *': { + marginTop: '0' }, - "h3 + *": { - marginTop: "0", + 'h3 + *': { + marginTop: '0' }, - "h4 + *": { - marginTop: "0", + 'h4 + *': { + marginTop: '0' }, table: { fontSize: em(12, 14), - lineHeight: round(18 / 12), + lineHeight: round(18 / 12) }, - "thead th": { + 'thead th': { paddingRight: em(12, 12), paddingBottom: em(8, 12), - paddingLeft: em(12, 12), + paddingLeft: em(12, 12) }, - "thead th:first-child": { - paddingLeft: "0", + 'thead th:first-child': { + paddingLeft: '0' }, - "thead th:last-child": { - paddingRight: "0", + 'thead th:last-child': { + paddingRight: '0' }, - "tbody td, tfoot td": { + 'tbody td, tfoot td': { paddingTop: em(8, 12), paddingRight: em(12, 12), paddingBottom: em(8, 12), - paddingLeft: em(12, 12), + paddingLeft: em(12, 12) }, - "tbody td:first-child, tfoot td:first-child": { - paddingLeft: "0", - }, - "tbody td:last-child, tfoot td:last-child": { - paddingRight: "0", + 'tbody td:first-child, tfoot td:first-child': { + paddingLeft: '0' }, + 'tbody td:last-child, tfoot td:last-child': { + paddingRight: '0' + } }, { - "> :first-child": { - marginTop: "0", + '> :first-child': { + marginTop: '0' }, - "> :last-child": { - marginBottom: "0", - }, - }, - ], + '> :last-child': { + marginBottom: '0' + } + } + ] }, base: { css: [ @@ -193,71 +194,71 @@ let defaultModifiers = { lineHeight: round(28 / 16), p: { marginTop: em(20, 16), - marginBottom: em(20, 16), + marginBottom: em(20, 16) }, '[class~="lead"]': { fontSize: em(20, 16), lineHeight: round(32 / 20), marginTop: em(24, 20), - marginBottom: em(24, 20), + marginBottom: em(24, 20) }, blockquote: { marginTop: em(32, 20), marginBottom: em(32, 20), - paddingLeft: em(20, 20), + paddingLeft: em(20, 20) }, h1: { fontSize: em(36, 16), - marginTop: "0", + marginTop: '0', marginBottom: em(32, 36), - lineHeight: round(40 / 36), + lineHeight: round(40 / 36) }, h2: { fontSize: em(24, 16), marginTop: em(48, 24), marginBottom: em(24, 24), - lineHeight: round(32 / 24), + lineHeight: round(32 / 24) }, h3: { fontSize: em(20, 16), marginTop: em(32, 20), marginBottom: em(12, 20), - lineHeight: round(32 / 20), + lineHeight: round(32 / 20) }, h4: { marginTop: em(24, 16), marginBottom: em(8, 16), - lineHeight: round(24 / 16), + lineHeight: round(24 / 16) }, img: { marginTop: em(32, 16), - marginBottom: em(32, 16), + marginBottom: em(32, 16) }, video: { marginTop: em(32, 16), - marginBottom: em(32, 16), + marginBottom: em(32, 16) }, figure: { marginTop: em(32, 16), - marginBottom: em(32, 16), + marginBottom: em(32, 16) }, - "figure > *": { - marginTop: "0", - marginBottom: "0", + 'figure > *': { + marginTop: '0', + marginBottom: '0' }, figcaption: { fontSize: em(14, 16), lineHeight: round(20 / 14), - marginTop: em(12, 14), + marginTop: em(12, 14) }, code: { - fontSize: em(14, 16), + fontSize: em(14, 16) }, - "h2 code": { - fontSize: em(21, 24), + 'h2 code': { + fontSize: em(21, 24) }, - "h3 code": { - fontSize: em(18, 20), + 'h3 code': { + fontSize: em(18, 20) }, pre: { fontSize: em(14, 16), @@ -268,101 +269,101 @@ let defaultModifiers = { paddingTop: em(12, 14), paddingRight: em(16, 14), paddingBottom: em(12, 14), - paddingLeft: em(16, 14), + paddingLeft: em(16, 14) }, ol: { marginTop: em(20, 16), marginBottom: em(20, 16), - paddingLeft: em(26, 16), + paddingLeft: em(26, 16) }, ul: { marginTop: em(20, 16), marginBottom: em(20, 16), - paddingLeft: em(26, 16), + paddingLeft: em(26, 16) }, li: { marginTop: em(8, 16), - marginBottom: em(8, 16), + marginBottom: em(8, 16) }, - "ol > li": { - paddingLeft: em(6, 16), + 'ol > li': { + paddingLeft: em(6, 16) }, - "ul > li": { - paddingLeft: em(6, 16), + 'ul > li': { + paddingLeft: em(6, 16) }, - "> ul > li p": { + '> ul > li p': { marginTop: em(12, 16), - marginBottom: em(12, 16), + marginBottom: em(12, 16) }, - "> ul > li > *:first-child": { - marginTop: em(20, 16), + '> ul > li > *:first-child': { + marginTop: em(20, 16) }, - "> ul > li > *:last-child": { - marginBottom: em(20, 16), + '> ul > li > *:last-child': { + marginBottom: em(20, 16) }, - "> ol > li > *:first-child": { - marginTop: em(20, 16), + '> ol > li > *:first-child': { + marginTop: em(20, 16) }, - "> ol > li > *:last-child": { - marginBottom: em(20, 16), + '> ol > li > *:last-child': { + marginBottom: em(20, 16) }, - "ul ul, ul ol, ol ul, ol ol": { + 'ul ul, ul ol, ol ul, ol ol': { marginTop: em(12, 16), - marginBottom: em(12, 16), + marginBottom: em(12, 16) }, hr: { marginTop: em(48, 16), - marginBottom: em(48, 16), + marginBottom: em(48, 16) }, - "hr + *": { - marginTop: "0", + 'hr + *': { + marginTop: '0' }, - "h2 + *": { - marginTop: "0", + 'h2 + *': { + marginTop: '0' }, - "h3 + *": { - marginTop: "0", + 'h3 + *': { + marginTop: '0' }, - "h4 + *": { - marginTop: "0", + 'h4 + *': { + marginTop: '0' }, table: { fontSize: em(14, 16), - lineHeight: round(24 / 14), + lineHeight: round(24 / 14) }, - "thead th": { + 'thead th': { paddingRight: em(8, 14), paddingBottom: em(8, 14), - paddingLeft: em(8, 14), + paddingLeft: em(8, 14) }, - "thead th:first-child": { - paddingLeft: "0", + 'thead th:first-child': { + paddingLeft: '0' }, - "thead th:last-child": { - paddingRight: "0", + 'thead th:last-child': { + paddingRight: '0' }, - "tbody td, tfoot td": { + 'tbody td, tfoot td': { paddingTop: em(8, 14), paddingRight: em(8, 14), paddingBottom: em(8, 14), - paddingLeft: em(8, 14), + paddingLeft: em(8, 14) }, - "tbody td:first-child, tfoot td:first-child": { - paddingLeft: "0", - }, - "tbody td:last-child, tfoot td:last-child": { - paddingRight: "0", + 'tbody td:first-child, tfoot td:first-child': { + paddingLeft: '0' }, + 'tbody td:last-child, tfoot td:last-child': { + paddingRight: '0' + } }, { - "> :first-child": { - marginTop: "0", + '> :first-child': { + marginTop: '0' }, - "> :last-child": { - marginBottom: "0", - }, - }, - ], + '> :last-child': { + marginBottom: '0' + } + } + ] }, lg: { css: [ @@ -371,71 +372,71 @@ let defaultModifiers = { lineHeight: round(32 / 18), p: { marginTop: em(24, 18), - marginBottom: em(24, 18), + marginBottom: em(24, 18) }, '[class~="lead"]': { fontSize: em(22, 18), lineHeight: round(32 / 22), marginTop: em(24, 22), - marginBottom: em(24, 22), + marginBottom: em(24, 22) }, blockquote: { marginTop: em(40, 24), marginBottom: em(40, 24), - paddingLeft: em(24, 24), + paddingLeft: em(24, 24) }, h1: { fontSize: em(48, 18), - marginTop: "0", + marginTop: '0', marginBottom: em(40, 48), - lineHeight: round(48 / 48), + lineHeight: round(48 / 48) }, h2: { fontSize: em(30, 18), marginTop: em(56, 30), marginBottom: em(32, 30), - lineHeight: round(40 / 30), + lineHeight: round(40 / 30) }, h3: { fontSize: em(24, 18), marginTop: em(40, 24), marginBottom: em(16, 24), - lineHeight: round(36 / 24), + lineHeight: round(36 / 24) }, h4: { marginTop: em(32, 18), marginBottom: em(8, 18), - lineHeight: round(28 / 18), + lineHeight: round(28 / 18) }, img: { marginTop: em(32, 18), - marginBottom: em(32, 18), + marginBottom: em(32, 18) }, video: { marginTop: em(32, 18), - marginBottom: em(32, 18), + marginBottom: em(32, 18) }, figure: { marginTop: em(32, 18), - marginBottom: em(32, 18), + marginBottom: em(32, 18) }, - "figure > *": { - marginTop: "0", - marginBottom: "0", + 'figure > *': { + marginTop: '0', + marginBottom: '0' }, figcaption: { fontSize: em(16, 18), lineHeight: round(24 / 16), - marginTop: em(16, 16), + marginTop: em(16, 16) }, code: { - fontSize: em(16, 18), + fontSize: em(16, 18) }, - "h2 code": { - fontSize: em(26, 30), + 'h2 code': { + fontSize: em(26, 30) }, - "h3 code": { - fontSize: em(21, 24), + 'h3 code': { + fontSize: em(21, 24) }, pre: { fontSize: em(16, 18), @@ -446,101 +447,101 @@ let defaultModifiers = { paddingTop: em(16, 16), paddingRight: em(24, 16), paddingBottom: em(16, 16), - paddingLeft: em(24, 16), + paddingLeft: em(24, 16) }, ol: { marginTop: em(24, 18), marginBottom: em(24, 18), - paddingLeft: em(28, 18), + paddingLeft: em(28, 18) }, ul: { marginTop: em(24, 18), marginBottom: em(24, 18), - paddingLeft: em(28, 18), + paddingLeft: em(28, 18) }, li: { marginTop: em(12, 18), - marginBottom: em(12, 18), + marginBottom: em(12, 18) }, - "ol > li": { - paddingLeft: em(8, 18), + 'ol > li': { + paddingLeft: em(8, 18) }, - "ul > li": { - paddingLeft: em(8, 18), + 'ul > li': { + paddingLeft: em(8, 18) }, - "> ul > li p": { + '> ul > li p': { marginTop: em(16, 18), - marginBottom: em(16, 18), + marginBottom: em(16, 18) }, - "> ul > li > *:first-child": { - marginTop: em(24, 18), + '> ul > li > *:first-child': { + marginTop: em(24, 18) }, - "> ul > li > *:last-child": { - marginBottom: em(24, 18), + '> ul > li > *:last-child': { + marginBottom: em(24, 18) }, - "> ol > li > *:first-child": { - marginTop: em(24, 18), + '> ol > li > *:first-child': { + marginTop: em(24, 18) }, - "> ol > li > *:last-child": { - marginBottom: em(24, 18), + '> ol > li > *:last-child': { + marginBottom: em(24, 18) }, - "ul ul, ul ol, ol ul, ol ol": { + 'ul ul, ul ol, ol ul, ol ol': { marginTop: em(16, 18), - marginBottom: em(16, 18), + marginBottom: em(16, 18) }, hr: { marginTop: em(56, 18), - marginBottom: em(56, 18), + marginBottom: em(56, 18) }, - "hr + *": { - marginTop: "0", + 'hr + *': { + marginTop: '0' }, - "h2 + *": { - marginTop: "0", + 'h2 + *': { + marginTop: '0' }, - "h3 + *": { - marginTop: "0", + 'h3 + *': { + marginTop: '0' }, - "h4 + *": { - marginTop: "0", + 'h4 + *': { + marginTop: '0' }, table: { fontSize: em(16, 18), - lineHeight: round(24 / 16), + lineHeight: round(24 / 16) }, - "thead th": { + 'thead th': { paddingRight: em(12, 16), paddingBottom: em(12, 16), - paddingLeft: em(12, 16), + paddingLeft: em(12, 16) }, - "thead th:first-child": { - paddingLeft: "0", + 'thead th:first-child': { + paddingLeft: '0' }, - "thead th:last-child": { - paddingRight: "0", + 'thead th:last-child': { + paddingRight: '0' }, - "tbody td, tfoot td": { + 'tbody td, tfoot td': { paddingTop: em(12, 16), paddingRight: em(12, 16), paddingBottom: em(12, 16), - paddingLeft: em(12, 16), + paddingLeft: em(12, 16) }, - "tbody td:first-child, tfoot td:first-child": { - paddingLeft: "0", - }, - "tbody td:last-child, tfoot td:last-child": { - paddingRight: "0", + 'tbody td:first-child, tfoot td:first-child': { + paddingLeft: '0' }, + 'tbody td:last-child, tfoot td:last-child': { + paddingRight: '0' + } }, { - "> :first-child": { - marginTop: "0", + '> :first-child': { + marginTop: '0' }, - "> :last-child": { - marginBottom: "0", - }, - }, - ], + '> :last-child': { + marginBottom: '0' + } + } + ] }, xl: { css: [ @@ -549,71 +550,71 @@ let defaultModifiers = { lineHeight: round(36 / 20), p: { marginTop: em(24, 20), - marginBottom: em(24, 20), + marginBottom: em(24, 20) }, '[class~="lead"]': { fontSize: em(24, 20), lineHeight: round(36 / 24), marginTop: em(24, 24), - marginBottom: em(24, 24), + marginBottom: em(24, 24) }, blockquote: { marginTop: em(48, 30), marginBottom: em(48, 30), - paddingLeft: em(32, 30), + paddingLeft: em(32, 30) }, h1: { fontSize: em(56, 20), - marginTop: "0", + marginTop: '0', marginBottom: em(48, 56), - lineHeight: round(56 / 56), + lineHeight: round(56 / 56) }, h2: { fontSize: em(36, 20), marginTop: em(56, 36), marginBottom: em(32, 36), - lineHeight: round(40 / 36), + lineHeight: round(40 / 36) }, h3: { fontSize: em(30, 20), marginTop: em(48, 30), marginBottom: em(20, 30), - lineHeight: round(40 / 30), + lineHeight: round(40 / 30) }, h4: { marginTop: em(36, 20), marginBottom: em(12, 20), - lineHeight: round(32 / 20), + lineHeight: round(32 / 20) }, img: { marginTop: em(40, 20), - marginBottom: em(40, 20), + marginBottom: em(40, 20) }, video: { marginTop: em(40, 20), - marginBottom: em(40, 20), + marginBottom: em(40, 20) }, figure: { marginTop: em(40, 20), - marginBottom: em(40, 20), + marginBottom: em(40, 20) }, - "figure > *": { - marginTop: "0", - marginBottom: "0", + 'figure > *': { + marginTop: '0', + marginBottom: '0' }, figcaption: { fontSize: em(18, 20), lineHeight: round(28 / 18), - marginTop: em(18, 18), + marginTop: em(18, 18) }, code: { - fontSize: em(18, 20), + fontSize: em(18, 20) }, - "h2 code": { - fontSize: em(31, 36), + 'h2 code': { + fontSize: em(31, 36) }, - "h3 code": { - fontSize: em(27, 30), + 'h3 code': { + fontSize: em(27, 30) }, pre: { fontSize: em(18, 20), @@ -624,174 +625,174 @@ let defaultModifiers = { paddingTop: em(20, 18), paddingRight: em(24, 18), paddingBottom: em(20, 18), - paddingLeft: em(24, 18), + paddingLeft: em(24, 18) }, ol: { marginTop: em(24, 20), marginBottom: em(24, 20), - paddingLeft: em(32, 20), + paddingLeft: em(32, 20) }, ul: { marginTop: em(24, 20), marginBottom: em(24, 20), - paddingLeft: em(32, 20), + paddingLeft: em(32, 20) }, li: { marginTop: em(12, 20), - marginBottom: em(12, 20), + marginBottom: em(12, 20) }, - "ol > li": { - paddingLeft: em(8, 20), + 'ol > li': { + paddingLeft: em(8, 20) }, - "ul > li": { - paddingLeft: em(8, 20), + 'ul > li': { + paddingLeft: em(8, 20) }, - "> ul > li p": { + '> ul > li p': { marginTop: em(16, 20), - marginBottom: em(16, 20), + marginBottom: em(16, 20) }, - "> ul > li > *:first-child": { - marginTop: em(24, 20), + '> ul > li > *:first-child': { + marginTop: em(24, 20) }, - "> ul > li > *:last-child": { - marginBottom: em(24, 20), + '> ul > li > *:last-child': { + marginBottom: em(24, 20) }, - "> ol > li > *:first-child": { - marginTop: em(24, 20), + '> ol > li > *:first-child': { + marginTop: em(24, 20) }, - "> ol > li > *:last-child": { - marginBottom: em(24, 20), + '> ol > li > *:last-child': { + marginBottom: em(24, 20) }, - "ul ul, ul ol, ol ul, ol ol": { + 'ul ul, ul ol, ol ul, ol ol': { marginTop: em(16, 20), - marginBottom: em(16, 20), + marginBottom: em(16, 20) }, hr: { marginTop: em(56, 20), - marginBottom: em(56, 20), + marginBottom: em(56, 20) }, - "hr + *": { - marginTop: "0", + 'hr + *': { + marginTop: '0' }, - "h2 + *": { - marginTop: "0", + 'h2 + *': { + marginTop: '0' }, - "h3 + *": { - marginTop: "0", + 'h3 + *': { + marginTop: '0' }, - "h4 + *": { - marginTop: "0", + 'h4 + *': { + marginTop: '0' }, table: { fontSize: em(18, 20), - lineHeight: round(28 / 18), + lineHeight: round(28 / 18) }, - "thead th": { + 'thead th': { paddingRight: em(12, 18), paddingBottom: em(16, 18), - paddingLeft: em(12, 18), + paddingLeft: em(12, 18) }, - "thead th:first-child": { - paddingLeft: "0", + 'thead th:first-child': { + paddingLeft: '0' }, - "thead th:last-child": { - paddingRight: "0", + 'thead th:last-child': { + paddingRight: '0' }, - "tbody td, tfoot td": { + 'tbody td, tfoot td': { paddingTop: em(16, 18), paddingRight: em(12, 18), paddingBottom: em(16, 18), - paddingLeft: em(12, 18), + paddingLeft: em(12, 18) }, - "tbody td:first-child, tfoot td:first-child": { - paddingLeft: "0", - }, - "tbody td:last-child, tfoot td:last-child": { - paddingRight: "0", + 'tbody td:first-child, tfoot td:first-child': { + paddingLeft: '0' }, + 'tbody td:last-child, tfoot td:last-child': { + paddingRight: '0' + } }, { - "> :first-child": { - marginTop: "0", + '> :first-child': { + marginTop: '0' }, - "> :last-child": { - marginBottom: "0", - }, - }, - ], + '> :last-child': { + marginBottom: '0' + } + } + ] }, - "2xl": { + '2xl': { css: [ { fontSize: rem(24), lineHeight: round(40 / 24), p: { marginTop: em(32, 24), - marginBottom: em(32, 24), + marginBottom: em(32, 24) }, '[class~="lead"]': { fontSize: em(30, 24), lineHeight: round(44 / 30), marginTop: em(32, 30), - marginBottom: em(32, 30), + marginBottom: em(32, 30) }, blockquote: { marginTop: em(64, 36), marginBottom: em(64, 36), - paddingLeft: em(40, 36), + paddingLeft: em(40, 36) }, h1: { fontSize: em(64, 24), - marginTop: "0", + marginTop: '0', marginBottom: em(56, 64), - lineHeight: round(64 / 64), + lineHeight: round(64 / 64) }, h2: { fontSize: em(48, 24), marginTop: em(72, 48), marginBottom: em(40, 48), - lineHeight: round(52 / 48), + lineHeight: round(52 / 48) }, h3: { fontSize: em(36, 24), marginTop: em(56, 36), marginBottom: em(24, 36), - lineHeight: round(44 / 36), + lineHeight: round(44 / 36) }, h4: { marginTop: em(40, 24), marginBottom: em(16, 24), - lineHeight: round(36 / 24), + lineHeight: round(36 / 24) }, img: { marginTop: em(48, 24), - marginBottom: em(48, 24), + marginBottom: em(48, 24) }, video: { marginTop: em(48, 24), - marginBottom: em(48, 24), + marginBottom: em(48, 24) }, figure: { marginTop: em(48, 24), - marginBottom: em(48, 24), + marginBottom: em(48, 24) }, - "figure > *": { - marginTop: "0", - marginBottom: "0", + 'figure > *': { + marginTop: '0', + marginBottom: '0' }, figcaption: { fontSize: em(20, 24), lineHeight: round(32 / 20), - marginTop: em(20, 20), + marginTop: em(20, 20) }, code: { - fontSize: em(20, 24), + fontSize: em(20, 24) }, - "h2 code": { - fontSize: em(42, 48), + 'h2 code': { + fontSize: em(42, 48) }, - "h3 code": { - fontSize: em(32, 36), + 'h3 code': { + fontSize: em(32, 36) }, pre: { fontSize: em(20, 24), @@ -802,884 +803,947 @@ let defaultModifiers = { paddingTop: em(24, 20), paddingRight: em(32, 20), paddingBottom: em(24, 20), - paddingLeft: em(32, 20), + paddingLeft: em(32, 20) }, ol: { marginTop: em(32, 24), marginBottom: em(32, 24), - paddingLeft: em(38, 24), + paddingLeft: em(38, 24) }, ul: { marginTop: em(32, 24), marginBottom: em(32, 24), - paddingLeft: em(38, 24), + paddingLeft: em(38, 24) }, li: { marginTop: em(12, 24), - marginBottom: em(12, 24), + marginBottom: em(12, 24) }, - "ol > li": { - paddingLeft: em(10, 24), + 'ol > li': { + paddingLeft: em(10, 24) }, - "ul > li": { - paddingLeft: em(10, 24), + 'ul > li': { + paddingLeft: em(10, 24) }, - "> ul > li p": { + '> ul > li p': { marginTop: em(20, 24), - marginBottom: em(20, 24), + marginBottom: em(20, 24) }, - "> ul > li > *:first-child": { - marginTop: em(32, 24), + '> ul > li > *:first-child': { + marginTop: em(32, 24) }, - "> ul > li > *:last-child": { - marginBottom: em(32, 24), + '> ul > li > *:last-child': { + marginBottom: em(32, 24) }, - "> ol > li > *:first-child": { - marginTop: em(32, 24), + '> ol > li > *:first-child': { + marginTop: em(32, 24) }, - "> ol > li > *:last-child": { - marginBottom: em(32, 24), + '> ol > li > *:last-child': { + marginBottom: em(32, 24) }, - "ul ul, ul ol, ol ul, ol ol": { + 'ul ul, ul ol, ol ul, ol ol': { marginTop: em(16, 24), - marginBottom: em(16, 24), + marginBottom: em(16, 24) }, hr: { marginTop: em(72, 24), - marginBottom: em(72, 24), + marginBottom: em(72, 24) }, - "hr + *": { - marginTop: "0", + 'hr + *': { + marginTop: '0' }, - "h2 + *": { - marginTop: "0", + 'h2 + *': { + marginTop: '0' }, - "h3 + *": { - marginTop: "0", + 'h3 + *': { + marginTop: '0' }, - "h4 + *": { - marginTop: "0", + 'h4 + *': { + marginTop: '0' }, table: { fontSize: em(20, 24), - lineHeight: round(28 / 20), + lineHeight: round(28 / 20) }, - "thead th": { + 'thead th': { paddingRight: em(12, 20), paddingBottom: em(16, 20), - paddingLeft: em(12, 20), + paddingLeft: em(12, 20) }, - "thead th:first-child": { - paddingLeft: "0", + 'thead th:first-child': { + paddingLeft: '0' }, - "thead th:last-child": { - paddingRight: "0", + 'thead th:last-child': { + paddingRight: '0' }, - "tbody td, tfoot td": { + 'tbody td, tfoot td': { paddingTop: em(16, 20), paddingRight: em(12, 20), paddingBottom: em(16, 20), - paddingLeft: em(12, 20), + paddingLeft: em(12, 20) }, - "tbody td:first-child, tfoot td:first-child": { - paddingLeft: "0", - }, - "tbody td:last-child, tfoot td:last-child": { - paddingRight: "0", + 'tbody td:first-child, tfoot td:first-child': { + paddingLeft: '0' }, + 'tbody td:last-child, tfoot td:last-child': { + paddingRight: '0' + } }, { - "> :first-child": { - marginTop: "0", + '> :first-child': { + marginTop: '0' }, - "> :last-child": { - marginBottom: "0", - }, - }, - ], + '> :last-child': { + marginBottom: '0' + } + } + ] }, // Invert (for dark mode) invert: { css: { - "--tw-prose-body": "var(--tw-prose-invert-body)", - "--tw-prose-headings": "var(--tw-prose-invert-headings)", - "--tw-prose-lead": "var(--tw-prose-invert-lead)", - "--tw-prose-links": "var(--tw-prose-invert-links)", - "--tw-prose-bold": "var(--tw-prose-invert-bold)", - "--tw-prose-counters": "var(--tw-prose-invert-counters)", - "--tw-prose-bullets": "var(--tw-prose-invert-bullets)", - "--tw-prose-hr": "var(--tw-prose-invert-hr)", - "--tw-prose-quotes": "var(--tw-prose-invert-quotes)", - "--tw-prose-quote-borders": "var(--tw-prose-invert-quote-borders)", - "--tw-prose-captions": "var(--tw-prose-invert-captions)", - "--tw-prose-code": "var(--tw-prose-invert-code)", - "--tw-prose-pre-code": "var(--tw-prose-invert-pre-code)", - "--tw-prose-pre-bg": "var(--tw-prose-invert-pre-bg)", - "--tw-prose-th-borders": "var(--tw-prose-invert-th-borders)", - "--tw-prose-td-borders": "var(--tw-prose-invert-td-borders)", - }, + '--tw-prose-body': 'var(--tw-prose-invert-body)', + '--tw-prose-headings': 'var(--tw-prose-invert-headings)', + '--tw-prose-lead': 'var(--tw-prose-invert-lead)', + '--tw-prose-links': 'var(--tw-prose-invert-links)', + '--tw-prose-bold': 'var(--tw-prose-invert-bold)', + '--tw-prose-counters': 'var(--tw-prose-invert-counters)', + '--tw-prose-bullets': 'var(--tw-prose-invert-bullets)', + '--tw-prose-hr': 'var(--tw-prose-invert-hr)', + '--tw-prose-quotes': 'var(--tw-prose-invert-quotes)', + '--tw-prose-quote-borders': 'var(--tw-prose-invert-quote-borders)', + '--tw-prose-captions': 'var(--tw-prose-invert-captions)', + '--tw-prose-code': 'var(--tw-prose-invert-code)', + '--tw-prose-pre-code': 'var(--tw-prose-invert-pre-code)', + '--tw-prose-pre-bg': 'var(--tw-prose-invert-pre-bg)', + '--tw-prose-th-borders': 'var(--tw-prose-invert-th-borders)', + '--tw-prose-td-borders': 'var(--tw-prose-invert-td-borders)' + } }, // Gray color themes slate: { css: { - "--tw-prose-body": colors.slate[700], - "--tw-prose-headings": colors.slate[900], - "--tw-prose-lead": colors.slate[600], - "--tw-prose-links": colors.slate[900], - "--tw-prose-bold": colors.slate[900], - "--tw-prose-counters": colors.slate[500], - "--tw-prose-bullets": colors.slate[300], - "--tw-prose-hr": colors.slate[200], - "--tw-prose-quotes": colors.slate[900], - "--tw-prose-quote-borders": colors.slate[200], - "--tw-prose-captions": colors.slate[500], - "--tw-prose-code": colors.slate[900], - "--tw-prose-pre-code": colors.slate[200], - "--tw-prose-pre-bg": colors.slate[800], - "--tw-prose-th-borders": colors.slate[300], - "--tw-prose-td-borders": colors.slate[200], - "--tw-prose-invert-body": colors.slate[300], - "--tw-prose-invert-headings": colors.white, - "--tw-prose-invert-lead": colors.slate[400], - "--tw-prose-invert-links": colors.white, - "--tw-prose-invert-bold": colors.white, - "--tw-prose-invert-counters": colors.slate[400], - "--tw-prose-invert-bullets": colors.slate[600], - "--tw-prose-invert-hr": colors.slate[700], - "--tw-prose-invert-quotes": colors.slate[100], - "--tw-prose-invert-quote-borders": colors.slate[700], - "--tw-prose-invert-captions": colors.slate[400], - "--tw-prose-invert-code": colors.white, - "--tw-prose-invert-pre-code": colors.slate[300], - "--tw-prose-invert-pre-bg": "rgb(0 0 0 / 50%)", - "--tw-prose-invert-th-borders": colors.slate[600], - "--tw-prose-invert-td-borders": colors.slate[700], - }, + '--tw-prose-body': colors.slate[700], + '--tw-prose-headings': colors.slate[900], + '--tw-prose-lead': colors.slate[600], + '--tw-prose-links': colors.slate[900], + '--tw-prose-bold': colors.slate[900], + '--tw-prose-counters': colors.slate[500], + '--tw-prose-bullets': colors.slate[300], + '--tw-prose-hr': colors.slate[200], + '--tw-prose-quotes': colors.slate[900], + '--tw-prose-quote-borders': colors.slate[200], + '--tw-prose-captions': colors.slate[500], + '--tw-prose-code': colors.slate[900], + '--tw-prose-pre-code': colors.slate[200], + '--tw-prose-pre-bg': colors.slate[800], + '--tw-prose-th-borders': colors.slate[300], + '--tw-prose-td-borders': colors.slate[200], + '--tw-prose-invert-body': colors.slate[300], + '--tw-prose-invert-headings': colors.white, + '--tw-prose-invert-lead': colors.slate[400], + '--tw-prose-invert-links': colors.white, + '--tw-prose-invert-bold': colors.white, + '--tw-prose-invert-counters': colors.slate[400], + '--tw-prose-invert-bullets': colors.slate[600], + '--tw-prose-invert-hr': colors.slate[700], + '--tw-prose-invert-quotes': colors.slate[100], + '--tw-prose-invert-quote-borders': colors.slate[700], + '--tw-prose-invert-captions': colors.slate[400], + '--tw-prose-invert-code': colors.white, + '--tw-prose-invert-pre-code': colors.slate[300], + '--tw-prose-invert-pre-bg': 'rgb(0 0 0 / 50%)', + '--tw-prose-invert-th-borders': colors.slate[600], + '--tw-prose-invert-td-borders': colors.slate[700] + } }, gray: { css: { - "--tw-prose-body": colors.gray[700], - "--tw-prose-headings": colors.gray[900], - "--tw-prose-lead": colors.gray[600], - "--tw-prose-links": colors.gray[900], - "--tw-prose-bold": colors.gray[900], - "--tw-prose-counters": colors.gray[500], - "--tw-prose-bullets": colors.gray[300], - "--tw-prose-hr": colors.gray[200], - "--tw-prose-quotes": colors.gray[900], - "--tw-prose-quote-borders": colors.gray[200], - "--tw-prose-captions": colors.gray[500], - "--tw-prose-code": colors.gray[900], - "--tw-prose-pre-code": colors.gray[200], - "--tw-prose-pre-bg": colors.gray[800], - "--tw-prose-th-borders": colors.gray[300], - "--tw-prose-td-borders": colors.gray[200], - "--tw-prose-invert-body": colors.gray[300], - "--tw-prose-invert-headings": colors.white, - "--tw-prose-invert-lead": colors.gray[400], - "--tw-prose-invert-links": colors.white, - "--tw-prose-invert-bold": colors.white, - "--tw-prose-invert-counters": colors.gray[400], - "--tw-prose-invert-bullets": colors.gray[600], - "--tw-prose-invert-hr": colors.gray[700], - "--tw-prose-invert-quotes": colors.gray[100], - "--tw-prose-invert-quote-borders": colors.gray[700], - "--tw-prose-invert-captions": colors.gray[400], - "--tw-prose-invert-code": colors.white, - "--tw-prose-invert-pre-code": colors.gray[300], - "--tw-prose-invert-pre-bg": "rgb(0 0 0 / 50%)", - "--tw-prose-invert-th-borders": colors.gray[600], - "--tw-prose-invert-td-borders": colors.gray[700], - }, + '--tw-prose-body': colors.gray[700], + '--tw-prose-headings': colors.gray[900], + '--tw-prose-lead': colors.gray[600], + '--tw-prose-links': colors.gray[900], + '--tw-prose-bold': colors.gray[900], + '--tw-prose-counters': colors.gray[500], + '--tw-prose-bullets': colors.gray[300], + '--tw-prose-hr': colors.gray[200], + '--tw-prose-quotes': colors.gray[900], + '--tw-prose-quote-borders': colors.gray[200], + '--tw-prose-captions': colors.gray[500], + '--tw-prose-code': colors.gray[900], + '--tw-prose-pre-code': colors.gray[200], + '--tw-prose-pre-bg': colors.gray[800], + '--tw-prose-th-borders': colors.gray[300], + '--tw-prose-td-borders': colors.gray[200], + '--tw-prose-invert-body': colors.gray[300], + '--tw-prose-invert-headings': colors.white, + '--tw-prose-invert-lead': colors.gray[400], + '--tw-prose-invert-links': colors.white, + '--tw-prose-invert-bold': colors.white, + '--tw-prose-invert-counters': colors.gray[400], + '--tw-prose-invert-bullets': colors.gray[600], + '--tw-prose-invert-hr': colors.gray[700], + '--tw-prose-invert-quotes': colors.gray[100], + '--tw-prose-invert-quote-borders': colors.gray[700], + '--tw-prose-invert-captions': colors.gray[400], + '--tw-prose-invert-code': colors.white, + '--tw-prose-invert-pre-code': colors.gray[300], + '--tw-prose-invert-pre-bg': 'rgb(0 0 0 / 50%)', + '--tw-prose-invert-th-borders': colors.gray[600], + '--tw-prose-invert-td-borders': colors.gray[700] + } }, zinc: { css: { - "--tw-prose-body": colors.zinc[700], - "--tw-prose-headings": colors.zinc[900], - "--tw-prose-lead": colors.zinc[600], - "--tw-prose-links": colors.zinc[900], - "--tw-prose-bold": colors.zinc[900], - "--tw-prose-counters": colors.zinc[500], - "--tw-prose-bullets": colors.zinc[300], - "--tw-prose-hr": colors.zinc[200], - "--tw-prose-quotes": colors.zinc[900], - "--tw-prose-quote-borders": colors.zinc[200], - "--tw-prose-captions": colors.zinc[500], - "--tw-prose-code": colors.zinc[900], - "--tw-prose-pre-code": colors.zinc[200], - "--tw-prose-pre-bg": colors.zinc[800], - "--tw-prose-th-borders": colors.zinc[300], - "--tw-prose-td-borders": colors.zinc[200], - "--tw-prose-invert-body": colors.zinc[300], - "--tw-prose-invert-headings": colors.white, - "--tw-prose-invert-lead": colors.zinc[400], - "--tw-prose-invert-links": colors.white, - "--tw-prose-invert-bold": colors.white, - "--tw-prose-invert-counters": colors.zinc[400], - "--tw-prose-invert-bullets": colors.zinc[600], - "--tw-prose-invert-hr": colors.zinc[700], - "--tw-prose-invert-quotes": colors.zinc[100], - "--tw-prose-invert-quote-borders": colors.zinc[700], - "--tw-prose-invert-captions": colors.zinc[400], - "--tw-prose-invert-code": colors.white, - "--tw-prose-invert-pre-code": colors.zinc[300], - "--tw-prose-invert-pre-bg": "rgb(0 0 0 / 50%)", - "--tw-prose-invert-th-borders": colors.zinc[600], - "--tw-prose-invert-td-borders": colors.zinc[700], - }, + '--tw-prose-body': colors.zinc[700], + '--tw-prose-headings': colors.zinc[900], + '--tw-prose-lead': colors.zinc[600], + '--tw-prose-links': colors.zinc[900], + '--tw-prose-bold': colors.zinc[900], + '--tw-prose-counters': colors.zinc[500], + '--tw-prose-bullets': colors.zinc[300], + '--tw-prose-hr': colors.zinc[200], + '--tw-prose-quotes': colors.zinc[900], + '--tw-prose-quote-borders': colors.zinc[200], + '--tw-prose-captions': colors.zinc[500], + '--tw-prose-code': colors.zinc[900], + '--tw-prose-pre-code': colors.zinc[200], + '--tw-prose-pre-bg': colors.zinc[800], + '--tw-prose-th-borders': colors.zinc[300], + '--tw-prose-td-borders': colors.zinc[200], + '--tw-prose-invert-body': colors.zinc[300], + '--tw-prose-invert-headings': colors.white, + '--tw-prose-invert-lead': colors.zinc[400], + '--tw-prose-invert-links': colors.white, + '--tw-prose-invert-bold': colors.white, + '--tw-prose-invert-counters': colors.zinc[400], + '--tw-prose-invert-bullets': colors.zinc[600], + '--tw-prose-invert-hr': colors.zinc[700], + '--tw-prose-invert-quotes': colors.zinc[100], + '--tw-prose-invert-quote-borders': colors.zinc[700], + '--tw-prose-invert-captions': colors.zinc[400], + '--tw-prose-invert-code': colors.white, + '--tw-prose-invert-pre-code': colors.zinc[300], + '--tw-prose-invert-pre-bg': 'rgb(0 0 0 / 50%)', + '--tw-prose-invert-th-borders': colors.zinc[600], + '--tw-prose-invert-td-borders': colors.zinc[700] + } }, neutral: { css: { - "--tw-prose-body": colors.neutral[700], - "--tw-prose-headings": colors.neutral[900], - "--tw-prose-lead": colors.neutral[600], - "--tw-prose-links": colors.neutral[900], - "--tw-prose-bold": colors.neutral[900], - "--tw-prose-counters": colors.neutral[500], - "--tw-prose-bullets": colors.neutral[300], - "--tw-prose-hr": colors.neutral[200], - "--tw-prose-quotes": colors.neutral[900], - "--tw-prose-quote-borders": colors.neutral[200], - "--tw-prose-captions": colors.neutral[500], - "--tw-prose-code": colors.neutral[900], - "--tw-prose-pre-code": colors.neutral[200], - "--tw-prose-pre-bg": colors.neutral[800], - "--tw-prose-th-borders": colors.neutral[300], - "--tw-prose-td-borders": colors.neutral[200], - "--tw-prose-invert-body": colors.neutral[300], - "--tw-prose-invert-headings": colors.white, - "--tw-prose-invert-lead": colors.neutral[400], - "--tw-prose-invert-links": colors.white, - "--tw-prose-invert-bold": colors.white, - "--tw-prose-invert-counters": colors.neutral[400], - "--tw-prose-invert-bullets": colors.neutral[600], - "--tw-prose-invert-hr": colors.neutral[700], - "--tw-prose-invert-quotes": colors.neutral[100], - "--tw-prose-invert-quote-borders": colors.neutral[700], - "--tw-prose-invert-captions": colors.neutral[400], - "--tw-prose-invert-code": colors.white, - "--tw-prose-invert-pre-code": colors.neutral[300], - "--tw-prose-invert-pre-bg": "rgb(0 0 0 / 50%)", - "--tw-prose-invert-th-borders": colors.neutral[600], - "--tw-prose-invert-td-borders": colors.neutral[700], - }, + '--tw-prose-body': colors.neutral[700], + '--tw-prose-headings': colors.neutral[900], + '--tw-prose-lead': colors.neutral[600], + '--tw-prose-links': colors.neutral[900], + '--tw-prose-bold': colors.neutral[900], + '--tw-prose-counters': colors.neutral[500], + '--tw-prose-bullets': colors.neutral[300], + '--tw-prose-hr': colors.neutral[200], + '--tw-prose-quotes': colors.neutral[900], + '--tw-prose-quote-borders': colors.neutral[200], + '--tw-prose-captions': colors.neutral[500], + '--tw-prose-code': colors.neutral[900], + '--tw-prose-pre-code': colors.neutral[200], + '--tw-prose-pre-bg': colors.neutral[800], + '--tw-prose-th-borders': colors.neutral[300], + '--tw-prose-td-borders': colors.neutral[200], + '--tw-prose-invert-body': colors.neutral[300], + '--tw-prose-invert-headings': colors.white, + '--tw-prose-invert-lead': colors.neutral[400], + '--tw-prose-invert-links': colors.white, + '--tw-prose-invert-bold': colors.white, + '--tw-prose-invert-counters': colors.neutral[400], + '--tw-prose-invert-bullets': colors.neutral[600], + '--tw-prose-invert-hr': colors.neutral[700], + '--tw-prose-invert-quotes': colors.neutral[100], + '--tw-prose-invert-quote-borders': colors.neutral[700], + '--tw-prose-invert-captions': colors.neutral[400], + '--tw-prose-invert-code': colors.white, + '--tw-prose-invert-pre-code': colors.neutral[300], + '--tw-prose-invert-pre-bg': 'rgb(0 0 0 / 50%)', + '--tw-prose-invert-th-borders': colors.neutral[600], + '--tw-prose-invert-td-borders': colors.neutral[700] + } }, stone: { css: { - "--tw-prose-body": colors.stone[700], - "--tw-prose-headings": colors.stone[900], - "--tw-prose-lead": colors.stone[600], - "--tw-prose-links": colors.stone[900], - "--tw-prose-bold": colors.stone[900], - "--tw-prose-counters": colors.stone[500], - "--tw-prose-bullets": colors.stone[300], - "--tw-prose-hr": colors.stone[200], - "--tw-prose-quotes": colors.stone[900], - "--tw-prose-quote-borders": colors.stone[200], - "--tw-prose-captions": colors.stone[500], - "--tw-prose-code": colors.stone[900], - "--tw-prose-pre-code": colors.stone[200], - "--tw-prose-pre-bg": colors.stone[800], - "--tw-prose-th-borders": colors.stone[300], - "--tw-prose-td-borders": colors.stone[200], - "--tw-prose-invert-body": colors.stone[300], - "--tw-prose-invert-headings": colors.white, - "--tw-prose-invert-lead": colors.stone[400], - "--tw-prose-invert-links": colors.white, - "--tw-prose-invert-bold": colors.white, - "--tw-prose-invert-counters": colors.stone[400], - "--tw-prose-invert-bullets": colors.stone[600], - "--tw-prose-invert-hr": colors.stone[700], - "--tw-prose-invert-quotes": colors.stone[100], - "--tw-prose-invert-quote-borders": colors.stone[700], - "--tw-prose-invert-captions": colors.stone[400], - "--tw-prose-invert-code": colors.white, - "--tw-prose-invert-pre-code": colors.stone[300], - "--tw-prose-invert-pre-bg": "rgb(0 0 0 / 50%)", - "--tw-prose-invert-th-borders": colors.stone[600], - "--tw-prose-invert-td-borders": colors.stone[700], - }, + '--tw-prose-body': colors.stone[700], + '--tw-prose-headings': colors.stone[900], + '--tw-prose-lead': colors.stone[600], + '--tw-prose-links': colors.stone[900], + '--tw-prose-bold': colors.stone[900], + '--tw-prose-counters': colors.stone[500], + '--tw-prose-bullets': colors.stone[300], + '--tw-prose-hr': colors.stone[200], + '--tw-prose-quotes': colors.stone[900], + '--tw-prose-quote-borders': colors.stone[200], + '--tw-prose-captions': colors.stone[500], + '--tw-prose-code': colors.stone[900], + '--tw-prose-pre-code': colors.stone[200], + '--tw-prose-pre-bg': colors.stone[800], + '--tw-prose-th-borders': colors.stone[300], + '--tw-prose-td-borders': colors.stone[200], + '--tw-prose-invert-body': colors.stone[300], + '--tw-prose-invert-headings': colors.white, + '--tw-prose-invert-lead': colors.stone[400], + '--tw-prose-invert-links': colors.white, + '--tw-prose-invert-bold': colors.white, + '--tw-prose-invert-counters': colors.stone[400], + '--tw-prose-invert-bullets': colors.stone[600], + '--tw-prose-invert-hr': colors.stone[700], + '--tw-prose-invert-quotes': colors.stone[100], + '--tw-prose-invert-quote-borders': colors.stone[700], + '--tw-prose-invert-captions': colors.stone[400], + '--tw-prose-invert-code': colors.white, + '--tw-prose-invert-pre-code': colors.stone[300], + '--tw-prose-invert-pre-bg': 'rgb(0 0 0 / 50%)', + '--tw-prose-invert-th-borders': colors.stone[600], + '--tw-prose-invert-td-borders': colors.stone[700] + } }, // Link-only themes (for backward compatibility) red: { css: { - "--tw-prose-links": colors.red[600], - "--tw-prose-invert-links": colors.red[500], - }, + '--tw-prose-links': colors.red[600], + '--tw-prose-invert-links': colors.red[500] + } }, orange: { css: { - "--tw-prose-links": colors.orange[600], - "--tw-prose-invert-links": colors.orange[500], - }, + '--tw-prose-links': colors.orange[600], + '--tw-prose-invert-links': colors.orange[500] + } }, amber: { css: { - "--tw-prose-links": colors.amber[600], - "--tw-prose-invert-links": colors.amber[500], - }, + '--tw-prose-links': colors.amber[600], + '--tw-prose-invert-links': colors.amber[500] + } }, yellow: { css: { - "--tw-prose-links": colors.yellow[600], - "--tw-prose-invert-links": colors.yellow[500], - }, + '--tw-prose-links': colors.yellow[600], + '--tw-prose-invert-links': colors.yellow[500] + } }, lime: { css: { - "--tw-prose-links": colors.lime[600], - "--tw-prose-invert-links": colors.lime[500], - }, + '--tw-prose-links': colors.lime[600], + '--tw-prose-invert-links': colors.lime[500] + } }, green: { css: { - "--tw-prose-links": colors.green[600], - "--tw-prose-invert-links": colors.green[500], - }, + '--tw-prose-links': colors.green[600], + '--tw-prose-invert-links': colors.green[500] + } }, emerald: { css: { - "--tw-prose-links": colors.emerald[600], - "--tw-prose-invert-links": colors.emerald[500], - }, + '--tw-prose-links': colors.emerald[600], + '--tw-prose-invert-links': colors.emerald[500] + } }, teal: { css: { - "--tw-prose-links": colors.teal[600], - "--tw-prose-invert-links": colors.teal[500], - }, + '--tw-prose-links': colors.teal[600], + '--tw-prose-invert-links': colors.teal[500] + } }, cyan: { css: { - "--tw-prose-links": colors.cyan[600], - "--tw-prose-invert-links": colors.cyan[500], - }, + '--tw-prose-links': colors.cyan[600], + '--tw-prose-invert-links': colors.cyan[500] + } }, sky: { css: { - "--tw-prose-links": colors.sky[600], - "--tw-prose-invert-links": colors.sky[500], - }, + '--tw-prose-links': colors.sky[600], + '--tw-prose-invert-links': colors.sky[500] + } }, blue: { css: { - "--tw-prose-links": colors.blue[600], - "--tw-prose-invert-links": colors.blue[500], - }, + '--tw-prose-links': colors.blue[600], + '--tw-prose-invert-links': colors.blue[500] + } }, indigo: { css: { - "--tw-prose-links": colors.indigo[600], - "--tw-prose-invert-links": colors.indigo[500], - }, + '--tw-prose-links': colors.indigo[600], + '--tw-prose-invert-links': colors.indigo[500] + } }, violet: { css: { - "--tw-prose-links": colors.violet[600], - "--tw-prose-invert-links": colors.violet[500], - }, + '--tw-prose-links': colors.violet[600], + '--tw-prose-invert-links': colors.violet[500] + } }, purple: { css: { - "--tw-prose-links": colors.purple[600], - "--tw-prose-invert-links": colors.purple[500], - }, + '--tw-prose-links': colors.purple[600], + '--tw-prose-invert-links': colors.purple[500] + } }, fuchsia: { css: { - "--tw-prose-links": colors.fuchsia[600], - "--tw-prose-invert-links": colors.fuchsia[500], - }, + '--tw-prose-links': colors.fuchsia[600], + '--tw-prose-invert-links': colors.fuchsia[500] + } }, pink: { css: { - "--tw-prose-links": colors.pink[600], - "--tw-prose-invert-links": colors.pink[500], - }, + '--tw-prose-links': colors.pink[600], + '--tw-prose-invert-links': colors.pink[500] + } }, rose: { css: { - "--tw-prose-links": colors.rose[600], - "--tw-prose-invert-links": colors.rose[500], - }, - }, + '--tw-prose-links': colors.rose[600], + '--tw-prose-invert-links': colors.rose[500] + } + } }; -const plugin = require("tailwindcss/plugin"); +const plugin = require('tailwindcss/plugin'); /** @type {import('tailwindcss').Config} */ module.exports = { - darkMode: "class", - content: [ - "./pages/**/*.{js,ts,jsx,tsx}", - "./components/**/*.{js,ts,jsx,tsx}", - ], + darkMode: 'class', + content: ['./src/**/*.{js,ts,jsx,tsx}'], theme: { extend: { + fontFamily: { + inter: ['Inter'] + }, colors: { // You can generate your own colors with this tool: https://javisperez.github.io/tailwindcolorshades/ primary: { - 50: "#fcfdf7", - 100: "#f8fcee", - 200: "#eef6d5", - 300: "#e3f1bc", - 400: "#cfe78a", - 500: "#badc58", - 600: "#a7c64f", - 700: "#8ca542", - 800: "#708435", - 900: "#5b6c2b", - DEFAULT: "#badc58", + 50: '#fcfdf7', + 100: '#f8fcee', + 200: '#eef6d5', + 300: '#e3f1bc', + 400: '#cfe78a', + 500: '#badc58', + 600: '#a7c64f', + 700: '#8ca542', + 800: '#708435', + 900: '#5b6c2b', + DEFAULT: '#badc58' }, - grey: "#0d1117", + grey: '#0d1117', mineshaft: { - 50: "#f5f5f5", - 100: "#ebebeb", - 200: "#ccccce", - 300: "#adaeb0", - 400: "#707174", - 500: "#323439", - 600: "#2d2f33", - 700: "#26272b", - 800: "#1e1f22", - 900: "#19191c", - DEFAULT: "#323439", + 50: '#f5f5f5', + 100: '#ebebeb', + 200: '#ccccce', + 300: '#adaeb0', + 400: '#707174', + 500: '#323439', + 600: '#2d2f33', + 700: '#26272b', + 800: '#1e1f22', + 900: '#19191c', + DEFAULT: '#323439' }, chicago: { - 50: "#f7f7f7", - 100: "#efefef", - 200: "#d6d6d7", - 300: "#bdbebf", - 400: "#8c8d8e", - 500: "#5b5c5e", - 600: "#525355", - 700: "#444547", - 800: "#373738", - 900: "#2d2d2e", - DEFAULT: "#5b5c5e", + 50: '#f7f7f7', + 100: '#efefef', + 200: '#d6d6d7', + 300: '#bdbebf', + 400: '#8c8d8e', + 500: '#5b5c5e', + 600: '#525355', + 700: '#444547', + 800: '#373738', + 900: '#2d2d2e', + DEFAULT: '#5b5c5e' }, bunker: { - 50: "#f3f4f4", - 100: "#e8e8e9", - 200: "#c5c6c8", - 300: "#a2a4a6", - 400: "#5d5f64", - 500: "#171b21", - 600: "#15181e", - 700: "#111419", - 800: "#0e1014", - 900: "#0b0d10", - DEFAULT: "#171B21", + 50: '#f3f4f4', + 100: '#e8e8e9', + 200: '#c5c6c8', + 300: '#a2a4a6', + 400: '#5d5f64', + 500: '#171b21', + 600: '#15181e', + 700: '#111419', + 800: '#0e1014', + 900: '#0b0d10', + DEFAULT: '#171B21' }, - githubblack: "#020409", - blue2: "#130f40", - blue1: "#3498db", + githubblack: '#020409', + blue2: '#130f40', + blue1: '#3498db', yellow: { - 50: "#fefcf3", - 100: "#fef9e7", - 200: "#fcf0c3", - 300: "#f9e79f", - 400: "#f5d657", - 500: "#f1c40f", - 600: "#d9b00e", - 700: "#b5930b", - 800: "#917609", - 900: "#766007", - DEFAULT: "#f1c40f", + 50: '#fefcf3', + 100: '#fef9e7', + 200: '#fcf0c3', + 300: '#f9e79f', + 400: '#f5d657', + 500: '#f1c40f', + 600: '#d9b00e', + 700: '#b5930b', + 800: '#917609', + 900: '#766007', + DEFAULT: '#f1c40f' }, red: { - 50: "#fef6f5", - 100: "#fdedec", - 200: "#f9d2ce", - 300: "#f5b7b1", - 400: "#ee8277", - 500: "#e74c3c", - 600: "#d04436", - 700: "#ad392d", - 800: "#8b2e24", - 900: "#71251d", - DEFAULT: "#e74c3c", + 50: '#fef6f5', + 100: '#fdedec', + 200: '#f9d2ce', + 300: '#f5b7b1', + 400: '#ee8277', + 500: '#e74c3c', + 600: '#d04436', + 700: '#ad392d', + 800: '#8b2e24', + 900: '#71251d', + DEFAULT: '#e74c3c' }, - orange: "#f39c12", + orange: '#f39c12', green: { - 50: "#f5fcf8", - 100: "#eafaf1", - 200: "#cbf2dc", - 300: "#abebc6", - 400: "#6ddb9c", - 500: "#2ecc71", - 600: "#29b866", - 700: "#239955", - 800: "#1c7a44", - 900: "#176437", - DEFAULT: "#2ecc71", - }, - }, + 50: '#f5fcf8', + 100: '#eafaf1', + 200: '#cbf2dc', + 300: '#abebc6', + 400: '#6ddb9c', + 500: '#2ecc71', + 600: '#29b866', + 700: '#239955', + 800: '#1c7a44', + 900: '#176437', + DEFAULT: '#2ecc71' + } + } }, keyframes: { type: { - "0%": { transform: "translateX(0ch)" }, - "5%, 10%": { transform: "translateX(1ch)" }, - "15%, 20%": { transform: "translateX(2ch)" }, - "25%, 30%": { transform: "translateX(3ch)" }, - "35%, 40%": { transform: "translateX(4ch)" }, - "45%, 50%": { transform: "translateX(5ch)" }, - "55%, 60%": { transform: "translateX(6ch)" }, - "65%, 70%": { transform: "translateX(7ch)" }, - "75%, 80%": { transform: "translateX(8ch)" }, - "85%, 90%": { transform: "translateX(9ch)" }, - "95%, 100%": { transform: "translateX(11ch)" }, + '0%': { transform: 'translateX(0ch)' }, + '5%, 10%': { transform: 'translateX(1ch)' }, + '15%, 20%': { transform: 'translateX(2ch)' }, + '25%, 30%': { transform: 'translateX(3ch)' }, + '35%, 40%': { transform: 'translateX(4ch)' }, + '45%, 50%': { transform: 'translateX(5ch)' }, + '55%, 60%': { transform: 'translateX(6ch)' }, + '65%, 70%': { transform: 'translateX(7ch)' }, + '75%, 80%': { transform: 'translateX(8ch)' }, + '85%, 90%': { transform: 'translateX(9ch)' }, + '95%, 100%': { transform: 'translateX(11ch)' } }, + // REQUIRED BY DEISGN COMPONENT + // MODAL fadeIn: { - "0%": { opacity: 0 }, - "100%": { opacity: 1 }, + '0%': { opacity: 0 }, + '100%': { opacity: 1 } }, + popIn: { + from: { + opacity: 0, + transform: 'translate(-50%, -48%) scale(0.96)' + }, + to: { + opacity: 1, + transform: 'translate(-50%, -50%) scale(1)' + } + }, + // Dropdown + slideUpAndFade: { + from: { + opacity: 0, + transform: ' translateY(2px)' + }, + to: { + opacity: 1, + transform: ' translateY(0)' + } + }, + slideRightAndFade: { + from: { + opacity: 0, + transform: ' translateX(-2px)' + }, + to: { + opacity: 1, + transform: ' translateX(0)' + } + }, + slideDownAndFade: { + from: { + opacity: 0, + transform: ' translateY(-2px)' + }, + to: { + opacity: 1, + transform: ' translateY(0)' + } + }, + slideLeftAndFade: { + from: { + opacity: 0, + transform: ' translateX(2px)' + }, + to: { + opacity: 1, + transform: ' translateX(0)' + } + }, + // END spin: { - "0%": { transform: "rotate(0deg)" }, - "40%": { transform: "rotate(360deg)" }, - "100%": { transform: "rotate(360deg)" }, + '0%': { transform: 'rotate(0deg)' }, + '40%': { transform: 'rotate(360deg)' }, + '100%': { transform: 'rotate(360deg)' } }, bounce: { - "0%": { transform: "translateY(-90%)" }, - "100%": { transform: "translateY(-100%)" }, + '0%': { transform: 'translateY(-90%)' }, + '100%': { transform: 'translateY(-100%)' } }, wiggle: { - "0%, 100%": { transform: "rotate(-3deg)" }, - "50%": { transform: "rotate(3deg)" }, + '0%, 100%': { transform: 'rotate(-3deg)' }, + '50%': { transform: 'rotate(3deg)' } }, ping: { - "75%, 100%": { - transform: "scale(2)", - opacity: 0, - }, + '75%, 100%': { + transform: 'scale(2)', + opacity: 0 + } }, popup: { - "0%": { - transform: "scale(0.2)", - opacity: 0, - transform: "translateY(120%)", - }, - "100%": { - transform: "scale(1)", - opacity: 1, - transform: "translateY(100%)", + '0%': { + transform: 'scale(0.2)', + opacity: 0 + // transform: "translateY(120%)", }, + '100%': { + transform: 'scale(1)', + opacity: 1 + // transform: "translateY(100%)", + } }, popright: { - "0%": { - transform: "translateX(-100%)", - }, - "100%": { - transform: "translateX(0%)", + '0%': { + transform: 'translateX(-100%)' }, + '100%': { + transform: 'translateX(0%)' + } }, popleft: { - "0%": { - transform: "translateX(100%)", - }, - "100%": { - transform: "translateX(0%)", + '0%': { + transform: 'translateX(100%)' }, + '100%': { + transform: 'translateX(0%)' + } }, popdown: { - "0%": { - transform: "scale(0.2)", - opacity: 0, - transform: "translateY(80%)", + '0%': { + transform: 'scale(0.2)', + opacity: 0 + // transform: "translateY(80%)", }, - "100%": { - transform: "scale(1)", - opacity: 1, - transform: "translateY(100%)", - }, - }, + '100%': { + transform: 'scale(1)', + opacity: 1 + // transform: "translateY(100%)", + } + } }, animation: { - fadeIn: "fadeIn 1000ms ease-in-out", - bounce: "bounce 1000ms ease-in-out infinite", - spin: "spin 4000ms ease-in-out infinite", - cursor: "cursor .6s linear infinite alternate", - type: "type 2.7s ease-out .8s infinite alternate both", - "type-reverse": "type 1.8s ease-out 0s infinite alternate-reverse both", - wiggle: "wiggle 200ms ease-in-out", - ping: "ping 1000ms ease-in-out infinite", - popup: "popup 300ms ease-in-out", - popdown: "popdown 300ms ease-in-out", - popright: "popright 100ms ease-in-out", - popleft: "popleft 100ms ease-in-out", + // Design Lib + // MODAL + fadeIn: 'fadeIn 100ms cubic-bezier(0.16, 1, 0.3, 1)', + popIn: 'popIn 150ms cubic-bezier(0.16, 1, 0.3, 1);', + // Dropdown + slideDownAndFade: 'slideDownAndFade 400ms cubic-bezier(0.16, 1, 0.3, 1)', + slideLeftAndFade: 'slideLeftAndFade 400ms cubic-bezier(0.16, 1, 0.3, 1)', + slideUpAndFade: 'slideUpAndFade 400ms cubic-bezier(0.16, 1, 0.3, 1)', + slideRightAndFade: 'slideRightAndFade 400ms cubic-bezier(0.16, 1, 0.3, 1)', + // END + bounce: 'bounce 1000ms ease-in-out infinite', + spin: 'spin 4000ms ease-in-out infinite', + cursor: 'cursor .6s linear infinite alternate', + type: 'type 2.7s ease-out .8s infinite alternate both', + 'type-reverse': 'type 1.8s ease-out 0s infinite alternate-reverse both', + wiggle: 'wiggle 200ms ease-in-out', + ping: 'ping 1000ms ease-in-out infinite', + popup: 'popup 300ms ease-in-out', + popdown: 'popdown 300ms ease-in-out', + popright: 'popright 100ms ease-in-out', + popleft: 'popleft 100ms ease-in-out' }, fontSize: { - xxxs: ".23rem", - xxs: ".5rem", - xs: ".75rem", - sm: ".875rem", - base: "1rem", - lg: "1.125rem", - xl: "1.25rem", - "2xl": "1.5rem", - "3xl": "1.875rem", - "4xl": "2.25rem", - "5xl": "3rem", - "6xl": "4rem", - "7xl": "5rem", - "8xl": "6rem", - "9xl": "7rem", + xxxs: '.23rem', + xxs: '.5rem', + xs: '.75rem', + sm: '.875rem', + base: '1rem', + lg: '1.125rem', + xl: '1.25rem', + '2xl': '1.5rem', + '3xl': '1.875rem', + '4xl': '2.25rem', + '5xl': '3rem', + '6xl': '4rem', + '7xl': '5rem', + '8xl': '6rem', + '9xl': '7rem' }, typography: (theme) => ({ DEFAULT: { css: [ { - color: "var(--tw-prose-body)", - maxWidth: "65ch", + color: 'var(--tw-prose-body)', + maxWidth: '65ch', '[class~="lead"]': { - color: "var(--tw-prose-lead)", + color: 'var(--tw-prose-lead)' }, a: { color: colors.gray[200], - textDecoration: "underline", - fontWeight: "500", + textDecoration: 'underline', + fontWeight: '500' }, strong: { color: colors.gray[200], - fontWeight: "600", + fontWeight: '600' }, - "a strong": { - color: "inherit", + 'a strong': { + color: 'inherit' }, - "blockquote strong": { - color: "inherit", + 'blockquote strong': { + color: 'inherit' }, - "thead th strong": { - color: "inherit", + 'thead th strong': { + color: 'inherit' }, ol: { - listStyleType: "decimal", + listStyleType: 'decimal' }, 'ol[type="A"]': { - listStyleType: "upper-alpha", + listStyleType: 'upper-alpha' }, 'ol[type="a"]': { - listStyleType: "lower-alpha", + listStyleType: 'lower-alpha' }, 'ol[type="A" s]': { - listStyleType: "upper-alpha", + listStyleType: 'upper-alpha' }, 'ol[type="a" s]': { - listStyleType: "lower-alpha", + listStyleType: 'lower-alpha' }, 'ol[type="I"]': { - listStyleType: "upper-roman", + listStyleType: 'upper-roman' }, 'ol[type="i"]': { - listStyleType: "lower-roman", + listStyleType: 'lower-roman' }, 'ol[type="I" s]': { - listStyleType: "upper-roman", + listStyleType: 'upper-roman' }, 'ol[type="i" s]': { - listStyleType: "lower-roman", + listStyleType: 'lower-roman' }, 'ol[type="1"]': { - listStyleType: "decimal", + listStyleType: 'decimal' }, ul: { - listStyleType: "disc", + listStyleType: 'disc' }, - "ol > li::marker": { - fontWeight: "400", - color: "var(--tw-prose-counters)", + 'ol > li::marker': { + fontWeight: '400', + color: 'var(--tw-prose-counters)' }, - "ul > li::marker": { - color: "var(--tw-prose-bullets)", + 'ul > li::marker': { + color: 'var(--tw-prose-bullets)' }, hr: { - borderColor: "var(--tw-prose-hr)", - borderTopWidth: 1, + borderColor: 'var(--tw-prose-hr)', + borderTopWidth: 1 }, blockquote: { - fontWeight: "500", - fontStyle: "italic", - color: "var(--tw-prose-quotes)", - borderLeftWidth: "0.25rem", - borderLeftColor: "var(--tw-prose-quote-borders)", - quotes: '"\\201C""\\201D""\\2018""\\2019"', + fontWeight: '500', + fontStyle: 'italic', + color: 'var(--tw-prose-quotes)', + borderLeftWidth: '0.25rem', + borderLeftColor: 'var(--tw-prose-quote-borders)', + quotes: '"\\201C""\\201D""\\2018""\\2019"' }, - "blockquote p:first-of-type::before": { - content: "open-quote", + 'blockquote p:first-of-type::before': { + content: 'open-quote' }, - "blockquote p:last-of-type::after": { - content: "close-quote", + 'blockquote p:last-of-type::after': { + content: 'close-quote' }, h1: { color: colors.gray[200], - fontWeight: "800", + fontWeight: '800' }, - "h1 strong": { - fontWeight: "900", - color: "inherit", + 'h1 strong': { + fontWeight: '900', + color: 'inherit' }, h2: { color: colors.gray[200], - fontWeight: "700", + fontWeight: '700' }, - "h2 strong": { - fontWeight: "800", - color: "inherit", + 'h2 strong': { + fontWeight: '800', + color: 'inherit' }, h3: { color: colors.gray[300], - fontWeight: "600", + fontWeight: '600' }, - "h3 strong": { - fontWeight: "700", - color: "inherit", + 'h3 strong': { + fontWeight: '700', + color: 'inherit' }, h4: { color: colors.gray[400], - fontWeight: "600", + fontWeight: '600' }, - "h4 strong": { - fontWeight: "700", - color: "inherit", + 'h4 strong': { + fontWeight: '700', + color: 'inherit' }, // TODO: Figure out how to not need these, it's a merging issue img: {}, - "figure > *": {}, + 'figure > *': {}, figcaption: { - color: "var(--tw-prose-captions)", + color: 'var(--tw-prose-captions)' }, code: { - color: "var(--tw-prose-code)", - fontWeight: "600", + color: 'var(--tw-prose-code)', + fontWeight: '600' }, - "code::before": { - content: '"`"', + 'code::before': { + content: '"`"' }, - "code::after": { - content: '"`"', + 'code::after': { + content: '"`"' }, - "a code": { - color: "inherit", + 'a code': { + color: 'inherit' }, - "h1 code": { - color: "inherit", + 'h1 code': { + color: 'inherit' }, - "h2 code": { - color: "inherit", + 'h2 code': { + color: 'inherit' }, - "h3 code": { - color: "inherit", + 'h3 code': { + color: 'inherit' }, - "h4 code": { - color: "inherit", + 'h4 code': { + color: 'inherit' }, - "blockquote code": { - color: "inherit", + 'blockquote code': { + color: 'inherit' }, - "thead th code": { - color: "inherit", + 'thead th code': { + color: 'inherit' }, pre: { - color: "var(--tw-prose-pre-code)", + color: 'var(--tw-prose-pre-code)', backgroundColor: colors.gray[800], - overflowX: "auto", - fontWeight: "400", + overflowX: 'auto', + fontWeight: '400' }, - "pre code": { - backgroundColor: "transparent", - borderWidth: "0", - borderRadius: "0", - padding: "0", - fontWeight: "inherit", - color: "inherit", - fontSize: "inherit", - fontFamily: "inherit", - lineHeight: "inherit", + 'pre code': { + backgroundColor: 'transparent', + borderWidth: '0', + borderRadius: '0', + padding: '0', + fontWeight: 'inherit', + color: 'inherit', + fontSize: 'inherit', + fontFamily: 'inherit', + lineHeight: 'inherit' }, - "pre code::before": { - content: "none", + 'pre code::before': { + content: 'none' }, - "pre code::after": { - content: "none", + 'pre code::after': { + content: 'none' }, table: { - width: "100%", - tableLayout: "auto", - textAlign: "left", + width: '100%', + tableLayout: 'auto', + textAlign: 'left', marginTop: em(32, 16), - marginBottom: em(32, 16), + marginBottom: em(32, 16) }, thead: { - borderBottomWidth: "1px", - borderBottomColor: "var(--tw-prose-th-borders)", + borderBottomWidth: '1px', + borderBottomColor: 'var(--tw-prose-th-borders)' }, - "thead th": { - color: "var(--tw-prose-headings)", - fontWeight: "600", - verticalAlign: "bottom", + 'thead th': { + color: 'var(--tw-prose-headings)', + fontWeight: '600', + verticalAlign: 'bottom' }, - "tbody tr": { - borderBottomWidth: "1px", - borderBottomColor: "var(--tw-prose-td-borders)", + 'tbody tr': { + borderBottomWidth: '1px', + borderBottomColor: 'var(--tw-prose-td-borders)' }, - "tbody tr:last-child": { - borderBottomWidth: "0", + 'tbody tr:last-child': { + borderBottomWidth: '0' }, - "tbody td": { - verticalAlign: "baseline", + 'tbody td': { + verticalAlign: 'baseline' }, tfoot: { - borderTopWidth: "1px", - borderTopColor: "var(--tw-prose-th-borders)", - }, - "tfoot td": { - verticalAlign: "top", + borderTopWidth: '1px', + borderTopColor: 'var(--tw-prose-th-borders)' }, + 'tfoot td': { + verticalAlign: 'top' + } }, defaultModifiers.gray.css, - ...defaultModifiers.base.css, - ], + ...defaultModifiers.base.css + ] }, - ...defaultModifiers, - }), + ...defaultModifiers + }) }, plugins: [ plugin(function ({ addUtilities }) { addUtilities({ - ".no-scrollbar::-webkit-scrollbar": { - display: "none", - }, - ".no-scrollbar": { - "-ms-overflow-style": "none", - "scrollbar-width": "none", + '.no-scrollbar::-webkit-scrollbar': { + display: 'none' }, + '.no-scrollbar': { + '-ms-overflow-style': 'none', + 'scrollbar-width': 'none' + } }); }), - require("@tailwindcss/typography"), - ], + require('@tailwindcss/typography') + ] }; diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json index e936a69a2..70fc385b9 100644 --- a/frontend/tsconfig.json +++ b/frontend/tsconfig.json @@ -2,10 +2,12 @@ "compilerOptions": { "baseUrl": ".", "paths": { - "~/components/*": ["components/*"], - "~/utilities/*": ["components/utilities/*"], - "~/*": ["const"], - "~/pages/*": ["pages/*"] + "~/components/*": ["./src/components/*"], + "~/hooks/*": ["./src/hooks/*"], + "~/utilities/*": ["./src/components/utilities/*"], + "~/*": ["./src/const"], + "~/pages/*": ["./src/pages/*"], + "@app/*": ["./src/*"] }, "target": "ESNext", "lib": ["dom", "dom.iterable", "esnext"], @@ -23,6 +25,6 @@ "jsx": "preserve", "incremental": true }, - "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], + "include": ["next-env.d.ts", "./src/**/*.ts", "./src/**/*.tsx", "./.eslintrc.js"], "exclude": ["node_modules"] } diff --git a/helm-charts/README.md b/helm-charts/README.md index 097464028..468275e3f 100644 --- a/helm-charts/README.md +++ b/helm-charts/README.md @@ -14,3 +14,4 @@ helm install infisical-helm-charts/ #### Available chart names - infisical +- secrets-operator diff --git a/helm-charts/infisical/Chart.yaml b/helm-charts/infisical/Chart.yaml index a9297b385..fe65e3b11 100644 --- a/helm-charts/infisical/Chart.yaml +++ b/helm-charts/infisical/Chart.yaml @@ -7,10 +7,10 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.1.3 +version: 0.1.13 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -appVersion: "1.16.0" +appVersion: "1.17.0" diff --git a/helm-charts/infisical/templates/_helpers.tpl b/helm-charts/infisical/templates/_helpers.tpl new file mode 100644 index 000000000..d0ceb0641 --- /dev/null +++ b/helm-charts/infisical/templates/_helpers.tpl @@ -0,0 +1,128 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "infisical.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "infisical.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create unified labels for infisical components +*/}} +{{- define "infisical.common.matchLabels" -}} +app: {{ template "infisical.name" . }} +release: {{ .Release.Name }} +{{- end -}} + +{{- define "infisical.common.metaLabels" -}} +chart: {{ template "infisical.chart" . }} +heritage: {{ .Release.Service }} +{{- end -}} + +{{- define "infisical.common.labels" -}} +{{ include "infisical.common.matchLabels" . }} +{{ include "infisical.common.metaLabels" . }} +{{- end -}} + + +{{- define "infisical.backend.labels" -}} +{{ include "infisical.backend.matchLabels" . }} +{{ include "infisical.common.metaLabels" . }} +{{- end -}} + +{{- define "infisical.backend.matchLabels" -}} +component: {{ .Values.backend.name | quote }} +{{ include "infisical.common.matchLabels" . }} +{{- end -}} + +{{- define "infisical.frontend.labels" -}} +{{ include "infisical.frontend.matchLabels" . }} +{{ include "infisical.common.metaLabels" . }} +{{- end -}} + +{{- define "infisical.frontend.matchLabels" -}} +component: {{ .Values.frontend.name | quote }} +{{ include "infisical.common.matchLabels" . }} +{{- end -}} + +{{- define "infisical.mongodb.labels" -}} +{{ include "infisical.mongodb.matchLabels" . }} +{{ include "infisical.common.metaLabels" . }} +{{- end -}} + +{{- define "infisical.mongodb.matchLabels" -}} +component: {{ .Values.mongodb.name | quote }} +{{ include "infisical.common.matchLabels" . }} +{{- end -}} + +{{/* +Create a fully qualified backend name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +*/}} +{{- define "infisical.backend.fullname" -}} +{{- if .Values.backend.fullnameOverride -}} +{{- .Values.backend.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- printf "%s-%s" .Release.Name .Values.backend.name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s-%s" .Release.Name $name .Values.backend.name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create a fully qualified frontend name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +*/}} +{{- define "infisical.frontend.fullname" -}} +{{- if .Values.frontend.fullnameOverride -}} +{{- .Values.frontend.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- printf "%s-%s" .Release.Name .Values.frontend.name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s-%s" .Release.Name $name .Values.frontend.name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create a fully qualified mongodb name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +*/}} +{{- define "infisical.mongodb.fullname" -}} +{{- if .Values.mongodb.fullnameOverride -}} +{{- .Values.mongodb.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- printf "%s-%s" .Release.Name .Values.mongodb.name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s-%s" .Release.Name $name .Values.mongodb.name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create the mongodb connection string. +*/}} +{{- define "infisical.mongodb.connectionString" -}} +{{- $host := include "infisical.mongodb.fullname" . -}} +{{- $port := 27017 -}} +{{- $user := "root" -}} +{{- $pass := "root" -}} +{{- $connectionString := printf "mongodb://%s:%s@%s:%d/" $user $pass $host $port -}} +{{- if .Values.mongodbConnection.externalMongoDBConnectionString -}} +{{- $connectionString = .Values.mongodbConnection.externalMongoDBConnectionString -}} +{{- end -}} +{{- printf "%s" $connectionString -}} +{{- end -}} diff --git a/helm-charts/infisical/templates/backend-deployment.yaml b/helm-charts/infisical/templates/backend-deployment.yaml index 6a2faa688..7a366d390 100644 --- a/helm-charts/infisical/templates/backend-deployment.yaml +++ b/helm-charts/infisical/templates/backend-deployment.yaml @@ -1,26 +1,48 @@ apiVersion: apps/v1 kind: Deployment metadata: - name: {{ .Release.Name }}-backend-deployment + name: {{ include "infisical.backend.fullname" . }} + {{- with .Values.backend.deploymentAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} labels: - app: backend + {{- include "infisical.backend.labels" . | nindent 4 }} spec: replicas: {{ .Values.backend.replicaCount }} selector: matchLabels: - app: backend + {{- include "infisical.backend.matchLabels" . | nindent 6 }} template: metadata: labels: - app: backend + {{- include "infisical.backend.matchLabels" . | nindent 8 }} + {{- with .Values.backend.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} spec: containers: - - name: backend - image: infisical/backend + - name: {{ template "infisical.name" . }}-{{ .Values.backend.name }} + image: "{{ .Values.backend.image.repository }}:{{ .Values.backend.image.tag | default .Chart.AppVersion }}" imagePullPolicy: {{ .Values.backend.image.pullPolicy }} + readinessProbe: + httpGet: + path: /api/status + port: 4000 + initialDelaySeconds: 10 + periodSeconds: 10 ports: - containerPort: 4000 + {{- if .Values.backend.kubeSecretRef }} + envFrom: + - secretRef: + name: {{ .Values.backend.kubeSecretRef }} + {{- end }} env: + - name: MONGO_URL + value: {{ include "infisical.mongodb.connectionString" . | quote }} + {{- if .Values.backendEnvironmentVariables }} {{- range $key, $value := .Values.backendEnvironmentVariables }} {{- if $value | quote | eq "MUST_REPLACE" }} {{ fail "Environment variables are not set. Please set all environment variables to continue." }} @@ -28,15 +50,22 @@ spec: - name: {{ $key }} value: {{ quote $value }} {{- end }} + {{- end }} --- apiVersion: v1 kind: Service metadata: - name: infisical-backend-service + name: {{ include "infisical.backend.fullname" . }} + labels: + {{- include "infisical.backend.labels" . | nindent 4 }} + {{- with .Values.backend.service.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} spec: selector: - app: backend + {{- include "infisical.backend.matchLabels" . | nindent 8 }} ports: - protocol: TCP port: 4000 diff --git a/helm-charts/infisical/templates/frontend-deployment.yaml b/helm-charts/infisical/templates/frontend-deployment.yaml index 3cd29f326..d396e5628 100644 --- a/helm-charts/infisical/templates/frontend-deployment.yaml +++ b/helm-charts/infisical/templates/frontend-deployment.yaml @@ -1,23 +1,43 @@ apiVersion: apps/v1 kind: Deployment metadata: - name: {{ .Release.Name }}-frontend-deployment + name: {{ include "infisical.frontend.fullname" . }} + {{- with .Values.frontend.deploymentAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} labels: - app: frontend + {{- include "infisical.frontend.labels" . | nindent 4 }} spec: replicas: {{ .Values.frontend.replicaCount }} selector: matchLabels: - app: frontend + {{- include "infisical.frontend.matchLabels" . | nindent 6 }} template: metadata: labels: - app: frontend + {{- include "infisical.frontend.matchLabels" . | nindent 8 }} + {{- with .Values.frontend.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} spec: containers: - - name: frontend - image: infisical/frontend + - name: {{ template "infisical.name" . }}-{{ .Values.frontend.name }} + image: "{{ .Values.frontend.image.repository }}:{{ .Values.frontend.image.tag | default .Chart.AppVersion }}" imagePullPolicy: {{ .Values.frontend.image.pullPolicy }} + readinessProbe: + httpGet: + path: / + port: 3000 + initialDelaySeconds: 10 + periodSeconds: 10 + {{- if .Values.frontend.kubeSecretRef }} + envFrom: + - secretRef: + name: {{ .Values.frontend.kubeSecretRef }} + {{- end }} + {{- if .Values.frontendEnvironmentVariables }} env: {{- range $key, $value := .Values.frontendEnvironmentVariables }} {{- if $value | quote | eq "MUST_REPLACE" }} @@ -26,17 +46,28 @@ spec: - name: {{ $key }} value: {{ quote $value }} {{- end }} + {{- end }} ports: - - containerPort: 4000 + - containerPort: 3000 --- apiVersion: v1 kind: Service metadata: - name: infisical-frontend-service + name: {{ include "infisical.frontend.fullname" . }} + labels: + {{- include "infisical.frontend.labels" . | nindent 4 }} + {{- with .Values.frontend.service.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} spec: + type: {{ .Values.frontend.service.type }} selector: - app: frontend + {{- include "infisical.frontend.matchLabels" . | nindent 8 }} ports: - protocol: TCP port: 3000 # service targetPort: 3000 # container port + {{- if eq .Values.frontend.service.type "NodePort" }} + nodePort: {{ .Values.frontend.service.nodePort }} + {{- end }} \ No newline at end of file diff --git a/helm-charts/infisical/templates/ingress.yaml b/helm-charts/infisical/templates/ingress.yaml index a987627f4..cf9952ea3 100644 --- a/helm-charts/infisical/templates/ingress.yaml +++ b/helm-charts/infisical/templates/ingress.yaml @@ -26,14 +26,14 @@ spec: pathType: {{ .Values.ingress.frontend.pathType }} backend: service: - name: infisical-frontend-service + name: {{ include "infisical.frontend.fullname" . }} port: number: 3000 - path: {{ .Values.ingress.backend.path }} pathType: {{ .Values.ingress.backend.pathType }} backend: service: - name: infisical-backend-service + name: {{ include "infisical.backend.fullname" . }} port: number: 4000 {{ end }} \ No newline at end of file diff --git a/helm-charts/infisical/templates/mongodb-deployment.yaml b/helm-charts/infisical/templates/mongodb-deployment.yaml index 90b755ad3..c9a4b13a8 100644 --- a/helm-charts/infisical/templates/mongodb-deployment.yaml +++ b/helm-charts/infisical/templates/mongodb-deployment.yaml @@ -1,22 +1,27 @@ apiVersion: apps/v1 kind: Deployment metadata: - name: mongodb-deployment + name: {{ include "infisical.mongodb.fullname" . }} labels: - app: mongodb + {{- include "infisical.mongodb.labels" . | nindent 4 }} spec: replicas: 1 # Cannot be scaled. To scale, you must set up Stateful Set selector: matchLabels: - app: mongodb + {{- include "infisical.mongodb.matchLabels" . | nindent 6 }} template: metadata: labels: - app: mongodb + {{- include "infisical.mongodb.matchLabels" . | nindent 8 }} + {{- with .Values.mongodb.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} spec: containers: - - name: mongodb - image: mongo + - name: {{ template "infisical.name" . }}-{{ .Values.mongodb.name }} + image: "{{ .Values.mongodb.image.repository }}:{{ .Values.mongodb.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.mongodb.image.pullPolicy }} ports: - containerPort: 27017 env: @@ -28,10 +33,16 @@ spec: apiVersion: v1 kind: Service metadata: - name: mongodb-service + name: {{ include "infisical.mongodb.fullname" . }} + labels: + {{- include "infisical.mongodb.labels" . | nindent 4 }} + {{- with .Values.mongodb.service.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} spec: selector: - app: mongodb + {{- include "infisical.mongodb.matchLabels" . | nindent 8 }} ports: - protocol: TCP port: 27017 diff --git a/helm-charts/infisical/values.yaml b/helm-charts/infisical/values.yaml index a93a4769d..9ed7ef9dc 100644 --- a/helm-charts/infisical/values.yaml +++ b/helm-charts/infisical/values.yaml @@ -1,28 +1,61 @@ ##### -# INFISICAL K8 DEFAULT VALUES FIL +# INFISICAL K8 DEFAULT VALUES FILE # PLEASE REPLACE VALUES/EDIT AS REQUIRED ##### -namespace: infisical +nameOverride: "" frontend: - replicaCount: 1 + name: frontend + podAnnotations: {} + deploymentAnnotations: {} + replicaCount: 2 image: - repository: + repository: infisical/frontend pullPolicy: IfNotPresent tag: "latest" + # kubeSecretRef: some-kube-secret-name + service: + # type of the frontend service + type: ClusterIP + # define the nodePort if service type is NodePort + # nodePort: + annotations: {} backend: - replicaCount: 1 + name: backend + podAnnotations: {} + deploymentAnnotations: {} + replicaCount: 2 image: - repository: + repository: infisical/backend pullPolicy: IfNotPresent tag: "latest" + # kubeSecretRef: some-kube-secret-name + service: + annotations: {} + +mongodb: + name: mongodb + podAnnotations: {} + image: + repository: mongo + pullPolicy: IfNotPresent + tag: "latest" + service: + annotations: {} + +# By default the backend will be connected to a Mongo instance in the cluster. +# However, it is recommended to add a managed document DB connection string because the DB instance in the cluster does not have persistence yet ( data will be deleted on next deploy). +# Learn about connection string type here https://www.mongodb.com/docs/manual/reference/connection-string/ +mongodbConnection: {} + # externalMongoDBConnectionString: <> ingress: enabled: true - annotations: {} - hostName: example.com + annotations: + kubernetes.io/ingress.class: "nginx" + hostName: example.com # replace with your domain frontend: path: / pathType: Prefix @@ -31,6 +64,7 @@ ingress: pathType: Prefix tls: [] + ## Complete Ingress example # ingress: # enabled: true @@ -49,31 +83,6 @@ ingress: # hosts: # - k8.infisical.com -### -### YOU MUST FILL IN ALL SECRETS BELOW -### -backendEnvironmentVariables: - # Required keys for platform encryption/decryption ops. Replace with nacl sk keys - PRIVATE_KEY: MUST_REPLACE - PUBLIC_KEY: MUST_REPLACE - ENCRYPTION_KEY: MUST_REPLACE +frontendEnvironmentVariables: {} - # JWT - # Required secrets to sign JWT tokens - JWT_SIGNUP_SECRET: MUST_REPLACE - JWT_REFRESH_SECRET: MUST_REPLACE - JWT_AUTH_SECRET: MUST_REPLACE - - # Mail/SMTP - # Required to send emails - SMTP_HOST: MUST_REPLACE - SMTP_NAME: MUST_REPLACE - SMTP_USERNAME: MUST_REPLACE - SMTP_PASSWORD: MUST_REPLACE - - # You may replace with Mongo Cloud URI - MONGO_URL: mongodb://root:root@mongodb-service:27017/ - -# frontendEnvironmentVariables: -# INFISICAL_TELEMETRY_ENABLED: true - \ No newline at end of file +backendEnvironmentVariables: {} diff --git a/helm-charts/secrets-operator/.helmignore b/helm-charts/secrets-operator/.helmignore new file mode 100644 index 000000000..0e8a0eb36 --- /dev/null +++ b/helm-charts/secrets-operator/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/helm-charts/secrets-operator/Chart.yaml b/helm-charts/secrets-operator/Chart.yaml new file mode 100644 index 000000000..21480085b --- /dev/null +++ b/helm-charts/secrets-operator/Chart.yaml @@ -0,0 +1,21 @@ +apiVersion: v2 +name: secrets-operator +description: A Helm chart for Infisical secrets +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.2 +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "0.1.2" diff --git a/helm-charts/secrets-operator/templates/_helpers.tpl b/helm-charts/secrets-operator/templates/_helpers.tpl new file mode 100644 index 000000000..44e464d93 --- /dev/null +++ b/helm-charts/secrets-operator/templates/_helpers.tpl @@ -0,0 +1,62 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "secrets-operator.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "secrets-operator.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "secrets-operator.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "secrets-operator.labels" -}} +helm.sh/chart: {{ include "secrets-operator.chart" . }} +{{ include "secrets-operator.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "secrets-operator.selectorLabels" -}} +app.kubernetes.io/name: {{ include "secrets-operator.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "secrets-operator.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "secrets-operator.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/helm-charts/secrets-operator/templates/deployment.yaml b/helm-charts/secrets-operator/templates/deployment.yaml new file mode 100644 index 000000000..026728bfa --- /dev/null +++ b/helm-charts/secrets-operator/templates/deployment.yaml @@ -0,0 +1,108 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "secrets-operator.fullname" . }}-controller-manager + labels: + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: k8-operator + app.kubernetes.io/part-of: k8-operator + {{- include "secrets-operator.labels" . | nindent 4 }} +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "secrets-operator.fullname" . }}-controller-manager + labels: + app.kubernetes.io/component: manager + app.kubernetes.io/created-by: k8-operator + app.kubernetes.io/part-of: k8-operator + control-plane: controller-manager + {{- include "secrets-operator.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.controllerManager.replicas }} + selector: + matchLabels: + control-plane: controller-manager + {{- include "secrets-operator.selectorLabels" . | nindent 6 }} + template: + metadata: + labels: + control-plane: controller-manager + {{- include "secrets-operator.selectorLabels" . | nindent 8 }} + annotations: + kubectl.kubernetes.io/default-container: manager + spec: + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/arch + operator: In + values: + - amd64 + - arm64 + - ppc64le + - s390x + - key: kubernetes.io/os + operator: In + values: + - linux + containers: + - args: + - --secure-listen-address=0.0.0.0:8443 + - --upstream=http://127.0.0.1:8080/ + - --logtostderr=true + - --v=0 + env: + - name: KUBERNETES_CLUSTER_DOMAIN + value: {{ .Values.kubernetesClusterDomain }} + image: {{ .Values.controllerManager.kubeRbacProxy.image.repository }}:{{ .Values.controllerManager.kubeRbacProxy.image.tag + | default .Chart.AppVersion }} + name: kube-rbac-proxy + ports: + - containerPort: 8443 + name: https + protocol: TCP + resources: {{- toYaml .Values.controllerManager.kubeRbacProxy.resources | nindent + 10 }} + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + - args: + - --health-probe-bind-address=:8081 + - --metrics-bind-address=127.0.0.1:8080 + - --leader-elect + command: + - /manager + env: + - name: KUBERNETES_CLUSTER_DOMAIN + value: {{ .Values.kubernetesClusterDomain }} + image: {{ .Values.controllerManager.manager.image.repository }}:{{ .Values.controllerManager.manager.image.tag + | default .Chart.AppVersion }} + livenessProbe: + httpGet: + path: /healthz + port: 8081 + initialDelaySeconds: 15 + periodSeconds: 20 + name: manager + readinessProbe: + httpGet: + path: /readyz + port: 8081 + initialDelaySeconds: 5 + periodSeconds: 10 + resources: {{- toYaml .Values.controllerManager.manager.resources | nindent 10 + }} + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + securityContext: + runAsNonRoot: true + serviceAccountName: {{ include "secrets-operator.fullname" . }}-controller-manager + terminationGracePeriodSeconds: 10 \ No newline at end of file diff --git a/helm-charts/secrets-operator/templates/infisicalsecret-crd.yaml b/helm-charts/secrets-operator/templates/infisicalsecret-crd.yaml new file mode 100644 index 000000000..e3e3517d5 --- /dev/null +++ b/helm-charts/secrets-operator/templates/infisicalsecret-crd.yaml @@ -0,0 +1,151 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: infisicalsecrets.secrets.infisical.com + annotations: + controller-gen.kubebuilder.io/version: v0.10.0 + labels: + {{- include "secrets-operator.labels" . | nindent 4 }} +spec: + group: secrets.infisical.com + names: + kind: InfisicalSecret + listKind: InfisicalSecretList + plural: infisicalsecrets + singular: infisicalsecret + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: InfisicalSecret is the Schema for the infisicalsecrets API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: InfisicalSecretSpec defines the desired state of InfisicalSecret + properties: + hostAPI: + default: https://app.infisical.com/api + description: Infisical host to pull secrets from + type: string + managedSecretReference: + properties: + secretName: + description: The name of the Kubernetes Secret + type: string + secretNamespace: + description: The name space where the Kubernetes Secret is located + type: string + required: + - secretName + - secretNamespace + type: object + tokenSecretReference: + properties: + secretName: + description: The name of the Kubernetes Secret + type: string + secretNamespace: + description: The name space where the Kubernetes Secret is located + type: string + required: + - secretName + - secretNamespace + type: object + type: object + status: + description: InfisicalSecretStatus defines the observed state of InfisicalSecret + properties: + conditions: + items: + description: "Condition contains details for one aspect of the current + state of this API Resource. --- This struct is intended for direct + use as an array at the field path .status.conditions. For example, + \n type FooStatus struct{ // Represents the observations of a foo's + current state. // Known .status.conditions.type are: \"Available\", + \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge + // +listType=map // +listMapKey=type Conditions []metav1.Condition + `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" + protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" + properties: + lastTransitionTime: + description: lastTransitionTime is the last time the condition + transitioned from one status to another. This should be when + the underlying condition changed. If that is not known, then + using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: message is a human readable message indicating details + about the transition. This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: observedGeneration represents the .metadata.generation + that the condition was set based upon. For instance, if .metadata.generation + is currently 12, but the .status.conditions[x].observedGeneration + is 9, the condition is out of date with respect to the current + state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: reason contains a programmatic identifier indicating + the reason for the condition's last transition. Producers of + specific condition types may define expected values and meanings + for this field, and whether the values are considered a guaranteed + API. The value should be a CamelCase string. This field may + not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + --- Many .condition.type values are consistent across resources + like Available, but because arbitrary conditions can be useful + (see .node.status.conditions), the ability to deconflict is + important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + required: + - conditions + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] \ No newline at end of file diff --git a/helm-charts/secrets-operator/templates/leader-election-rbac.yaml b/helm-charts/secrets-operator/templates/leader-election-rbac.yaml new file mode 100644 index 000000000..dc41acf14 --- /dev/null +++ b/helm-charts/secrets-operator/templates/leader-election-rbac.yaml @@ -0,0 +1,59 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ include "secrets-operator.fullname" . }}-leader-election-role + labels: + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: k8-operator + app.kubernetes.io/part-of: k8-operator + {{- include "secrets-operator.labels" . | nindent 4 }} +rules: +- apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +- apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +- apiGroups: + - "" + resources: + - events + verbs: + - create + - patch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ include "secrets-operator.fullname" . }}-leader-election-rolebinding + labels: + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: k8-operator + app.kubernetes.io/part-of: k8-operator + {{- include "secrets-operator.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: '{{ include "secrets-operator.fullname" . }}-leader-election-role' +subjects: +- kind: ServiceAccount + name: '{{ include "secrets-operator.fullname" . }}-controller-manager' + namespace: '{{ .Release.Namespace }}' \ No newline at end of file diff --git a/helm-charts/secrets-operator/templates/manager-rbac.yaml b/helm-charts/secrets-operator/templates/manager-rbac.yaml new file mode 100644 index 000000000..a560790f6 --- /dev/null +++ b/helm-charts/secrets-operator/templates/manager-rbac.yaml @@ -0,0 +1,71 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "secrets-operator.fullname" . }}-manager-role + labels: + {{- include "secrets-operator.labels" . | nindent 4 }} +rules: +- apiGroups: + - "" + resources: + - secrets + verbs: + - create + - delete + - get + - list + - update + - watch +- apiGroups: + - apps + resources: + - deployments + verbs: + - get + - list + - update + - watch +- apiGroups: + - secrets.infisical.com + resources: + - infisicalsecrets + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - secrets.infisical.com + resources: + - infisicalsecrets/finalizers + verbs: + - update +- apiGroups: + - secrets.infisical.com + resources: + - infisicalsecrets/status + verbs: + - get + - patch + - update +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "secrets-operator.fullname" . }}-manager-rolebinding + labels: + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: k8-operator + app.kubernetes.io/part-of: k8-operator + {{- include "secrets-operator.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: '{{ include "secrets-operator.fullname" . }}-manager-role' +subjects: +- kind: ServiceAccount + name: '{{ include "secrets-operator.fullname" . }}-controller-manager' + namespace: '{{ .Release.Namespace }}' \ No newline at end of file diff --git a/helm-charts/secrets-operator/templates/metrics-reader-rbac.yaml b/helm-charts/secrets-operator/templates/metrics-reader-rbac.yaml new file mode 100644 index 000000000..7d7ceba46 --- /dev/null +++ b/helm-charts/secrets-operator/templates/metrics-reader-rbac.yaml @@ -0,0 +1,14 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "secrets-operator.fullname" . }}-metrics-reader + labels: + app.kubernetes.io/component: kube-rbac-proxy + app.kubernetes.io/created-by: k8-operator + app.kubernetes.io/part-of: k8-operator + {{- include "secrets-operator.labels" . | nindent 4 }} +rules: +- nonResourceURLs: + - /metrics + verbs: + - get \ No newline at end of file diff --git a/helm-charts/secrets-operator/templates/metrics-service.yaml b/helm-charts/secrets-operator/templates/metrics-service.yaml new file mode 100644 index 000000000..ebf7ce549 --- /dev/null +++ b/helm-charts/secrets-operator/templates/metrics-service.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "secrets-operator.fullname" . }}-controller-manager-metrics-service + labels: + app.kubernetes.io/component: kube-rbac-proxy + app.kubernetes.io/created-by: k8-operator + app.kubernetes.io/part-of: k8-operator + control-plane: controller-manager + {{- include "secrets-operator.labels" . | nindent 4 }} +spec: + type: {{ .Values.metricsService.type }} + selector: + control-plane: controller-manager + {{- include "secrets-operator.selectorLabels" . | nindent 4 }} + ports: + {{- .Values.metricsService.ports | toYaml | nindent 2 -}} \ No newline at end of file diff --git a/helm-charts/secrets-operator/templates/proxy-rbac.yaml b/helm-charts/secrets-operator/templates/proxy-rbac.yaml new file mode 100644 index 000000000..5f07e2908 --- /dev/null +++ b/helm-charts/secrets-operator/templates/proxy-rbac.yaml @@ -0,0 +1,40 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "secrets-operator.fullname" . }}-proxy-role + labels: + app.kubernetes.io/component: kube-rbac-proxy + app.kubernetes.io/created-by: k8-operator + app.kubernetes.io/part-of: k8-operator + {{- include "secrets-operator.labels" . | nindent 4 }} +rules: +- apiGroups: + - authentication.k8s.io + resources: + - tokenreviews + verbs: + - create +- apiGroups: + - authorization.k8s.io + resources: + - subjectaccessreviews + verbs: + - create +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "secrets-operator.fullname" . }}-proxy-rolebinding + labels: + app.kubernetes.io/component: kube-rbac-proxy + app.kubernetes.io/created-by: k8-operator + app.kubernetes.io/part-of: k8-operator + {{- include "secrets-operator.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: '{{ include "secrets-operator.fullname" . }}-proxy-role' +subjects: +- kind: ServiceAccount + name: '{{ include "secrets-operator.fullname" . }}-controller-manager' + namespace: '{{ .Release.Namespace }}' \ No newline at end of file diff --git a/helm-charts/secrets-operator/values.yaml b/helm-charts/secrets-operator/values.yaml new file mode 100644 index 000000000..32ae2f789 --- /dev/null +++ b/helm-charts/secrets-operator/values.yaml @@ -0,0 +1,32 @@ +controllerManager: + kubeRbacProxy: + image: + repository: gcr.io/kubebuilder/kube-rbac-proxy + tag: v0.13.1 + resources: + limits: + cpu: 500m + memory: 128Mi + requests: + cpu: 5m + memory: 64Mi + manager: + image: + repository: infisical/kubernetes-operator + tag: latest + resources: + limits: + cpu: 500m + memory: 128Mi + requests: + cpu: 10m + memory: 64Mi + replicas: 1 +kubernetesClusterDomain: cluster.local +metricsService: + ports: + - name: https + port: 8443 + protocol: TCP + targetPort: https + type: ClusterIP diff --git a/i18n/README.en.md b/i18n/README.en.md new file mode 100644 index 000000000..1ec8cff50 --- /dev/null +++ b/i18n/README.en.md @@ -0,0 +1,365 @@ +

+ infisical + infisical +

+

+

Open-source, E2EE, simple tool to manage secrets and configs across your team and infrastructure.

+

+ +

+ Slack | + Infisical Cloud | + Self-Hosting | + Docs | + Website +

+ +

+ + Medusa is released under the MIT license. + + + PRs welcome! + + + git commit activity + + + Cloudsmith downloads + + + Slack community channel + + + Infisical Twitter + +

+ +Dashboard + + +**Read this in other languages**: [English language](i18n/README.en.md) +[Spanish language](i18n/README.es.md) +[Korean language](i18n/README.ko.md) +[Turkish language](i18n/README.tr.md) + +**[Infisical](https://infisical.com)** is an open source, E2EE tool to help teams manage and sync secrets and configs across their development workflow and infrastructure. It's designed to be simple and take minutes to get going. + +- **[User-Friendly Dashboard](https://infisical.com/docs/getting-started/dashboard/project)** to manage your team's secrets and configs within projects +- **[Language-Agnostic CLI](https://infisical.com/docs/cli/overview)** that pulls and injects esecrets and configs into your local workflow +- **[Complete control over your data](https://infisical.com/docs/self-hosting/overview)** - host it yourself on any infrastructure +- **Navigate Multiple Environments** per project (e.g. development, staging, production, etc.) +- **Personal overrides** for secrets and configs +- **[Integrations](https://infisical.com/docs/integrations/overview)** with CI/CD and production infrastructure +- **[Infisical API](https://infisical.com/docs/api-reference/overview/introduction)** - manage secrets via HTTPS requests to the platform +- **[Secret Versioning](https://infisical.com/docs/getting-started/dashboard/versioning)** to view the change history for any secret +- **[Activity Logs](https://infisical.com/docs/getting-started/dashboard/audit-logs)** to record every action taken in a project +- **[Point-in-time Secrets Recovery](https://infisical.com/docs/getting-started/dashboard/pit-recovery)** for rolling back to any snapshot of your secrets +- **Role-based Access Controls** per environment +- ๐Ÿ”œ **2FA** (next week) +- ๐Ÿ”œ **1-Click Deploy** to Digital Ocean and Heroku +- ๐Ÿ”œ **Automatic Secret Rotation** +- ๐Ÿ”œ **Slack & MS Teams** integrations + +And more. + +## ๐Ÿš€ Get started + +To quickly get started, visit our [get started guide](https://infisical.com/docs/getting-started/introduction). + +

+ + + +

+ +## ๐Ÿ”ฅ What's cool about this? + +Infisical makes secret management simple and end-to-end encrypted by default. We're on a mission to make it more accessible to all developers, not just security teams. + +According to a [report](https://www.ekransystem.com/en/blog/secrets-management), only 10% of organizations use secret management solutions despite all using digital secrets to some extent. + +If you care about efficiency and security, then Infisical is right for you. + +We are currently working hard to make Infisical more extensive. Need any integrations or want a new feature? Feel free to [create an issue](https://github.com/Infisical/infisical/issues) or [contribute](https://infisical.com/docs/contributing/overview) directly to the repository. + +## ๐ŸŒฑ Contributing + +Whether it's big or small, we love contributions โค๏ธ Check out our guide to see how to [get started](https://infisical.com/docs/contributing/overview). + +Not sure where to get started? You can: + +- [Book a free, non-pressure pairing sessions with one of our teammates](mailto:tony@infisical.com?subject=Pairing%20session&body=I'd%20like%20to%20do%20a%20pairing%20session!)! +- Join our Slack, and ask us any questions there. + +## ๐Ÿ’š Community & Support + +- [Slack](https://join.slack.com/t/infisical-users/shared_invite/zt-1kdbk07ro-RtoyEt_9E~fyzGo_xQYP6g) (For live discussion with the community and the Infisical team) +- [GitHub Discussions](https://github.com/Infisical/infisical/discussions) (For help with building and deeper conversations about features) +- [GitHub Issues](https://github.com/Infisical/infisical-cli/issues) (For any bugs and errors you encounter using Infisical) +- [Twitter](https://twitter.com/infisical) (Get news fast) + +## ๐ŸŒ„ Status + +- [x] Public Alpha: Anyone can sign up over at [infisical.com](https://infisical.com) but there are some minor kinks. +- [ ] Public Beta: Stable enough for most non-enterprise use-cases. +- [ ] Public: Production-ready. + +## ๏ฟฝ๐Ÿ”Œ Integrations + +We're currently setting the foundation and building [integrations](https://infisical.com/docs/integrations/overview) so secrets can be synced everywhere. Any help is welcome! :) + + + + + + + + + + +
Platforms Frameworks
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + โœ”๏ธ Docker + + + + โœ”๏ธ Docker Compose + + + + โœ”๏ธ Heroku + +
+ + โœ”๏ธ Vercel + + + + โœ”๏ธ Kubernetes + + + + โœ”๏ธ Fly.io + +
+ ๐Ÿ”œ AWS PS (https://github.com/Infisical/infisical/issues/286) + + + โœ”๏ธ GitHub Actions + + + ๐Ÿ”œ Railway (https://github.com/Infisical/infisical/issues/271) +
+ ๐Ÿ”œ GCP SM (https://github.com/Infisical/infisical/issues/285) + + ๐Ÿ”œ GitLab CI/CD (https://github.com/Infisical/infisical/issues/134) + + ๐Ÿ”œ CircleCI (https://github.com/Infisical/infisical/issues/91) +
+ ๐Ÿ”œ Jenkins + + ๐Ÿ”œ Digital Ocean + + ๐Ÿ”œ Azure +
+ ๐Ÿ”œ TravisCI + + + โœ”๏ธ Netlify + + + ๐Ÿ”œ Forge +
+ ๐Ÿ”œ Bitbucket + + ๐Ÿ”œ Supabase + + + โœ”๏ธ Render + +
+ ๐Ÿ”œ BuddyCI + + ๐Ÿ”œ Serverless + + ๐Ÿ”œ AWS Lambda +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + โœ”๏ธ React + + + + โœ”๏ธ Express + +
+ + โœ”๏ธ Gatsby + + + + โœ”๏ธ Flask + +
+ + โœ”๏ธ Django + + + + โœ”๏ธ Laravel + +
+ + โœ”๏ธ NestJS + + + + โœ”๏ธ Remix + +
+ + โœ”๏ธ Next.js + + + + โœ”๏ธ Vite + +
+ + โœ”๏ธ Vue + + + + โœ”๏ธ Ruby on Rails + +
+ + โœ”๏ธ Fiber + + + + โœ”๏ธ Nuxt + +
+ + โœ”๏ธ .NET + + + And more... +
+ +
+ +## ๐Ÿ˜ Open-source vs. paid + +This repo is entirely MIT licensed, with the exception of the `ee` directory which will contain premium enterprise features requiring a Infisical license in the future. We're currently focused on developing non-enterprise offerings first that should suit most use-cases. + +## ๐Ÿ›ก Security + +Looking to report a security vulnerability? Please don't post about it in GitHub issue. Instead, refer to our [SECURITY.md](./SECURITY.md) file. + +## ๐Ÿšจ Stay Up-to-Date + +Infisical officially launched as v.1.0 on November 21st, 2022. There are a lot of new features coming very frequently. Watch **releases** of this repository to be notified about future updates: + +![infisical-star-github](https://github.com/Infisical/infisical/blob/main/.github/images/star-infisical.gif?raw=true) + +## ๐Ÿฆธ Contributors + +[//]: contributor-faces + + + + + + + +## ๐ŸŒŽ Translations + +Infisical is currently available in English, Korean, French, and Portuguese (Brazil). Help us translate Infisical to your language! + +You can find all the info in [this issue](https://github.com/Infisical/infisical/issues/181). diff --git a/i18n/README.es.md b/i18n/README.es.md new file mode 100644 index 000000000..d579bfa1c --- /dev/null +++ b/i18n/README.es.md @@ -0,0 +1,361 @@ +

+ infisical + infisical +

+

+

Herramienta simple de cรณdigo abierto cifrado de extremo a extremo (E2EE) para gestionar secretos y configuraciones dentro de su equipo e infraestructura.

+

+ +

+ Slack | + Infisical Cloud | + Self-Hosting | + Documentaciรณn | + Sitio web +

+ +

+ + Medusa is released under the MIT license. + + + PRs welcome! + + + git commit activity + + + Cloudsmith downloads + + + Slack community channel + + + Infisical Twitter + +

+ +Dashboard + +**[Infisical](https://infisical.com)** es una herramienta de cรณdigo abierto que busca ayudar a equipos a gestionar y sincronizar secretos y configuraciones dentro de su flujo de trabajo e infraestructura. Estรก diseรฑada para ser simple y solo tomar minutos para implementar. + +- **[Tablero fรกcil de usar](https://infisical.com/docs/getting-started/dashboard/project)** para gestionar los secretos y configuraciones de su equipo dentro de proyectos +- **[Infraestructura de lenguaje comรบn (CLI) independiente del lenguaje](https://infisical.com/docs/cli/overview)** que extrae e inyecta secretos y configuraciones a su flujo de trabajo local +- **[Control total sobre sus datos:](https://infisical.com/docs/self-hosting/overview)** alรณjelos en cualquier infraestructura +- **Navega mรบltiples entornos** por proyecto (ej. Desarrollo, evaluaciรณn, producciรณn, etc.) +- **Mando manual** para secretos y configuraciones +- **[Integraciones](https://infisical.com/docs/integrations/overview)** con CI/CD e infraestructura de producciรณn +- **[API de Infisical:](https://infisical.com/docs/api-reference/overview/introduction)** administra secretos a travรฉs de solicitudes HTTPS a la plataforma +- **[Control de versiones ](https://infisical.com/docs/getting-started/dashboard/versioning)** para ver el historial de cambios de cualquier secreto +- **[Registros de actividad](https://infisical.com/docs/getting-started/dashboard/audit-logs)** para documentar cada acciรณn tomada en el proyecto +- **[Recuperaciรณn de secretos en el momento](https://infisical.com/docs/getting-started/dashboard/pit-recovery)** para retroceder a cualquier instancia de alguno +- ๐Ÿ”œ **Implementaciรณn de 1 clic** para Digital Ocean y Heroku +- ๐Ÿ”œ **Autenticaciรณn/Autorizaciรณn** para proyectos (controles de lectura/escritura prรณximamente) +- ๐Ÿ”œ **Rotaciรณn automรกtica de secretos** +- ๐Ÿ”œ **Autenticaciรณn de dos factores** +- ๐Ÿ”œ **Integraciones con Slack y MS Teams** + +Y mรกs. + +## ๐Ÿš€ Para empezar + +Para empezar rรกpidamente visita nuestra [guรญa de inicio](https://infisical.com/docs/getting-started/introduction). + +

+ + + +

+ +## ๐Ÿ”ฅ ยฟEn quรฉ es bueno? + +Infisical hace la gestiรณn de secretos simple y estรก cifrada de extremo a extremo de manera predeterminada. Tenemos la misiรณn de hacerla mรกs accesible a todos los desarrolladores, no solo los equipos de seguridad. + +Segรบn un [reporte](https://www.ekransystem.com/en/blog/secrets-management), solo el 10% de las organizaciones utilizan soluciones para gestionar secretos a pesar de que todas usan secretos digitales en cierta medida. + +Si estรก interesado en la eficiencia y la seguridad, Infisical es para ti. + +Actualmente estamos trabajando duro para hacer Infisical mรกs extenso. ยฟNecesitas una integraciรณn o quieres una nueva funciรณn? Siente libre de [crear un issue](https://github.com/Infisical/infisical/issues) o [contribuir](https://infisical.com/docs/contributing/overview) directamente al repositorio. + +## ๐ŸŒฑ Contribuir + +Sea de manera pequeรฑa o grande, nos encantan las contribuciones โค๏ธ Cheque nuestra guรญa de [cรณmo empezar](https://infisical.com/docs/contributing/overview). + +ยฟNo estรก seguro de dรณnde empezar? Usted puede: + +- ยก[Agendar una sesiรณn gratis, sin presiรณn con uno de nuestros integrantes](mailto:tony@infisical.com?subject=Pairing%20session&body=I'd%20like%20to%20do%20a%20pairing%20session!)! (inglรฉs) +- Unesรฉ a nuestro Slack y preguntenos ahรญ (inglรฉs) + +## ๐Ÿ’š Soporte y comunidad + +- [Slack](https://join.slack.com/t/infisical-users/shared_invite/zt-1kdbk07ro-RtoyEt_9E~fyzGo_xQYP6g) (Para discusiones en vivo con la comunidad y el equipo de Infisical) +- [GitHub Discussions](https://github.com/Infisical/infisical/discussions) (Para ayudar en construir y profundizar conversaciones acerca de funciones) +- [GitHub Issues](https://github.com/Infisical/infisical-cli/issues) (Para cualquier bug o error que encuentre usando Infisical) +- [Twitter](https://twitter.com/infisical) (Obtรฉn las noticias rรกpidamente) + +## ๐Ÿฅ Estatus + +- [x] Alpha pรบblico: Cualquiera puede registrarse en [infisical.com](https://infisical.com) pero tรฉnganos paciencia, hay problemas y apenas estamos comenzando. +- [ ] Beta pรบblico: Suficientemente estable para la mayorรญa de los casos de uso no empresariales. +- [ ] Pรบblico: Listo para producciรณn. + +Estamos actualmente en Alpha pรบblico. + +## ๐Ÿ”Œ Integraciones + +Actualmente estamos sentando bases y construyendo [integraciones](https://infisical.com/docs/integrations/overview) para que los secretos se puedan sincronizar en todas partes. ยกCualquier ayuda es bienvenida! :) + + + + + + + + + + +
Plataformas Marcos
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + โœ”๏ธ Docker + + + + โœ”๏ธ Docker Compose + + + + โœ”๏ธ Heroku + +
+ + โœ”๏ธ Vercel + + + + โœ”๏ธ Kubernetes + + + + โœ”๏ธ Fly.io + +
+ ๐Ÿ”œ AWS PS (https://github.com/Infisical/infisical/issues/286) + + + โœ”๏ธ GitHub Actions + + + ๐Ÿ”œ Railway (https://github.com/Infisical/infisical/issues/271) +
+ ๐Ÿ”œ GCP SM (https://github.com/Infisical/infisical/issues/285) + + ๐Ÿ”œ GitLab CI/CD (https://github.com/Infisical/infisical/issues/134) + + ๐Ÿ”œ CircleCI (https://github.com/Infisical/infisical/issues/91) +
+ ๐Ÿ”œ Jenkins + + ๐Ÿ”œ Digital Ocean + + ๐Ÿ”œ Azure +
+ ๐Ÿ”œ TravisCI + + + โœ”๏ธ Netlify + + + ๐Ÿ”œ Forge +
+ ๐Ÿ”œ Bitbucket + + ๐Ÿ”œ Supabase + + + โœ”๏ธ Render + +
+ ๐Ÿ”œ BuddyCI + + ๐Ÿ”œ Serverless + + ๐Ÿ”œ AWS Lambda +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + โœ”๏ธ React + + + + โœ”๏ธ Express + +
+ + โœ”๏ธ Gatsby + + + + โœ”๏ธ Flask + +
+ + โœ”๏ธ Django + + + + โœ”๏ธ Laravel + +
+ + โœ”๏ธ NestJS + + + + โœ”๏ธ Remix + +
+ + โœ”๏ธ Next.js + + + + โœ”๏ธ Vite + +
+ + โœ”๏ธ Vue + + + + โœ”๏ธ Ruby on Rails + +
+ + โœ”๏ธ Fiber + + + + โœ”๏ธ Nuxt + +
+ + โœ”๏ธ .NET + + + And more... +
+ +
+ +## ๐Ÿ˜ Cรณdigo abierto vs pagado + +Este repositorio es enteramente licenciado con MIT, con la excepciรณn del directorio `ee` que contendrรก funciones empresariales premium que requerirรกn una licencia de Infisical en el futuro. Actualmente estamos enfocados en desarrollar primero ofertas no empresariales que deberรญan adaptarse a la mayorรญa de los casos de uso. + +## ๐Ÿ›ก Seguridad + +ยฟQuiere reportar alguna vulnerabilidad en seguridad? Por favor, no lo publique en Github issues. En su lugar consulte nuestro archivo de [SECURITY.md](./SECURITY.md). + +## ๐Ÿšจ Mantรฉngase al tanto + +Infisical se lanzรณ oficialmente como v.1.0 el 21 de noviembre de 2022. Hay muchas funciones nuevas que llegan con mucha frecuencia. Mire los **lanzamientos** de este repositorio para recibir notificaciones sobre futuras actualizaciones: + +![infisical-star-github](https://github.com/Infisical/infisical/blob/main/.github/images/star-infisical.gif?raw=true) + +## ๐Ÿฆธ Contribuyentes + +[//]: contributor-faces + + + + + + + +## ๐ŸŒŽ Traducciones + +Infisical estรก actualmente disponible en inglรฉs, coreano, francรฉs y portuguรฉs (Brasil). ยกAyรบdanos a traducir Infisical a tu idioma! + +Puedes encontrar toda la informaciรณn en [este issue](https://github.com/Infisical/infisical/issues/181). \ No newline at end of file diff --git a/i18n/README.ko.md b/i18n/README.ko.md new file mode 100644 index 000000000..bab9e4d49 --- /dev/null +++ b/i18n/README.ko.md @@ -0,0 +1,362 @@ +

+ infisical + infisical +

+

+

ํŒ€ ๋ฉค๋ฒ„์™€ ์ธํ”„๋ผ ์ „๋ฐ˜์—์„œ ์‹œํฌ๋ฆฟ๊ณผ ์„ค์ •์„ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ„๋‹จํ•œ ์˜คํ”ˆ์†Œ์Šค E2EE ํˆด.

+

+ +

+ Slack | + Infisical Cloud | + ์ง์ ‘ ํ˜ธ์ŠคํŒ… | + ๋ฌธ์„œ | + ์›น์‚ฌ์ดํŠธ +

+ +

+ + Infisical is released under the MIT license. + + + PRs welcome! + + + git commit activity + + + Cloudsmith downloads + + + Slack community channel + + + Infisical Twitter + +

+ +Dashboard + +**[Infisical](https://infisical.com)** ์€ ํŒ€์ด ๊ฐœ๋ฐœ ์›Œํฌํ”Œ๋กœ์šฐ์™€ ์ธํ”„๋ผ ์ „๋ฐ˜์—์„œ ์‹œํฌ๋ฆฟ๊ณผ ๊ตฌ์„ฑ์„ ๊ด€๋ฆฌํ•˜๊ณ  ๋™๊ธฐํ™”ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋„์™€์ฃผ๋Š” ์˜คํ”ˆ์†Œ์Šค E2EE ํˆด์ž…๋‹ˆ๋‹ค. ๋ช‡ ๋ถ„ ์•ˆ์— ๋น ๋ฅด๊ฒŒ ์‹œ์ž‘ํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค๊ณ„๋˜์—ˆ์–ด์š”. + +- ์—ฌ๋Ÿฌ ํ”„๋กœ์ ํŠธ์—์„œ ํŒ€์˜ ์‹œํฌ๋ฆฟ๊ณผ ๊ตฌ์„ฑ์„ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ์‚ฌ์šฉ์ž ์นœํ™”์  **[๋Œ€์‹œ๋ณด๋“œ](https://infisical.com/docs/getting-started/dashboard/project)** +- ์–ด๋–ค ์–ธ์–ด๋“ ์ง€ ์ƒ๊ด€์—†์ด ์‹œํฌ๋ฆฟ๊ณผ ๊ตฌ์„ฑ์„ ๋กœ์ปฌ ์›Œํฌํ”Œ๋กœ์šฐ์— ๊ฐ€์ ธ์™€์ฃผ๋Š” **[CLI](https://infisical.com/docs/cli/overview)** +- **[์ง์ ‘ ํ˜ธ์ŠคํŒ…](https://infisical.com/docs/self-hosting/overview)** - ์–ด๋–ค ์ธํ”„๋ผ๋“ ์ง€ ์ง์ ‘ ํ˜ธ์ŠคํŒ…ํ•  ์ˆ˜ ์žˆ์–ด์š” +- ํ•œ ํ”„๋กœ์ ํŠธ์— **์—ฌ๋Ÿฌ ํ™˜๊ฒฝ**์„ ์‚ฌ์šฉํ•˜์„ธ์š” (์˜ˆ: development, staging, production, etc) +- ์‹œํฌ๋ฆฟ๊ณผ ๊ตฌ์„ฑ์— ๋Œ€ํ•œ **๊ฐœ์ธ ์˜ค๋ฒ„๋ผ์ด๋“œ** +- CI/CD, ํ”„๋กœ๋•์…˜ ์ธํ”„๋ผ์™€์˜ ๋†’์€ **[์—ฐ๋™์„ฑ](https://infisical.com/docs/integrations/overview)** +- **[Infisical API](https://infisical.com/docs/api-reference/overview/introduction)** - HTTPS ์š”์ฒญ์„ ํ†ตํ•ด ์‹œํฌ๋ฆฟ์„ ๊ด€๋ฆฌํ•˜์„ธ์š” +- **[์‹œํฌ๋ฆฟ ๋ฒ„์ „ ๊ธฐ๋ก](https://infisical.com/docs/getting-started/dashboard/versioning)** ์„ ํ†ตํ•ด ์–ด๋–ค ์‹œํฌ๋ฆฟ์ด๋“  ๋ฒ„์ „ ๊ธฐ๋ก์„ ๋ณผ ์ˆ˜ ์žˆ์–ด์š” +- **[ํ™œ๋™ ๋กœ๊ทธ](https://infisical.com/docs/getting-started/dashboard/audit-logs)** ๋ฅผ ํ†ตํ•ด ํ”„๋กœ์ ํŠธ์˜ ๋ชจ๋“  ํ™œ๋™์„ ๋ณผ ์ˆ˜ ์žˆ์–ด์š” +- **[์ง€์ • ์‹œ์ ์œผ๋กœ ์‹œํฌ๋ฆฟ ๋ณต๊ตฌ](https://infisical.com/docs/getting-started/dashboard/pit-recovery)** ๋ฅผ ์‚ฌ์šฉํ•ด ํŠน์ •ํ•œ ์‹œ์ ์œผ๋กœ ์‹œํฌ๋ฆฟ์„ ๋ณต๊ตฌํ•  ์ˆ˜ ์žˆ์–ด์š” +- ๐Ÿ”œ Digital Ocean ๋ฐ Heroku๋กœ **์›ํด๋ฆญ ๋ฐฐํฌ** +- ๐Ÿ”œ **ํ”„๋กœ์ ํŠธ ๋ณ„ ์ธ์ฆ** (read/write ์ปจํŠธ๋กค๋„ ๊ณง ์ฐพ์•„์˜ต๋‹ˆ๋‹ค) +- ๐Ÿ”œ **์ž๋™ ์‹œํฌ๋ฆฟ ๋กœํ…Œ์ด์…˜** +- ๐Ÿ”œ **2๋‹จ๊ณ„ ์ธ์ฆ** +- ๐Ÿ”œ **Slack & MS Teams** ์—ฐ๋™ + +๊ทธ ์™ธ์— ๋” ๋งŽ์€ ๊ธฐ๋Šฅ๋“ค์ด ์žˆ์–ด์š”. + +## ๐Ÿš€ ์‹œ์ž‘ํ•˜๊ธฐ + +[๋น ๋ฅธ ์‹œ์ž‘ ๊ฐ€์ด๋“œ](https://infisical.com/docs/getting-started/introduction)์— ๋ฐฉ๋ฌธํ•˜์„ธ์š”. + +

+ + + +

+ +## ๐Ÿ”ฅ ์ด๊ฒŒ ๋ญ”๋ฐ์š”? ์ข‹์€๊ฑด๊ฐ€์š”? + +Infisical์€ ์‹œํฌ๋ฆฟ ๊ด€๋ฆฌ๋ฅผ ๊ฐ„๋‹จํ•˜๊ฒŒ, ๊ทธ๋ฆฌ๊ณ  E2EE๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์•ˆ์ „ํ•˜๊ฒŒ ํ•ด์ค๋‹ˆ๋‹ค. ๋ณด์•ˆ ํŒ€๋ฟ๋งŒ ์•„๋‹ˆ๋ผ, **๋ชจ๋“  ๊ฐœ๋ฐœ์ž๋“ค์ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก** ํ•˜๋Š”๊ฒŒ ์ €ํฌ์˜ ๋ชฉํ‘œ์—์š”. + + +[๋ณด๊ณ ์„œ](https://www.ekransystem.com/en/blog/secrets-management)์— ๋”ฐ๋ฅด๋ฉด, ์˜ค์ง 10%์˜ ์กฐ์ง์ด ๋””์ง€ํ„ธ ์‹œํฌ๋ฆฟ ๊ด€๋ฆฌ ์†”๋ฃจ์…˜์„ ์‚ฌ์šฉํ•œ๋‹ค๊ณ  ํ•ด์š”. + +ํšจ์œจ์„ฑ๊ณผ ๋ณด์•ˆ์„ ๋”ฐ์ง„๋‹ค๋ฉด, Infisical์„ ์‚ฌ์šฉํ•ด๋ณด์„ธ์š”. + +์ €ํฌ๋Š” Infisical์„ ๋” ์ข‹๊ฒŒ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด ๋…ธ๋ ฅํ•˜๊ณ  ์žˆ์–ด์š”. ์ƒˆ๋กœ์šด ์—ฐ๋™์ด๋‚˜ ๊ธฐ๋Šฅ์ด ํ•„์š”ํ•œ๊ฐ€์š”? [์ด์Šˆ](https://github.com/Infisical/infisical/issues)๋ฅผ ๋งŒ๋“ค๊ฑฐ๋‚˜ [์ง์ ‘ ๊ธฐ์—ฌ](https://infisical.com/docs/contributing/overview)ํ•  ์ˆ˜ ์žˆ์–ด์š”. + +## ๐ŸŒฑ ๊ธฐ์—ฌํ•˜๊ธฐ + +์ž‘๋“  ํฌ๋“ , ์šฐ๋ฆฌ๋Š” ๋ชจ๋“  ๊ธฐ์—ฌ๋ฅผ ํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค โค๏ธ [๊ธฐ์—ฌํ•˜๋Š” ๋ฐฉ๋ฒ•](https://infisical.com/docs/contributing/overview)์— ๋Œ€ํ•ด ์ž์„ธํžˆ ์•Œ์•„๋ณด์„ธ์š”. + +์–ด๋””์„œ๋ถ€ํ„ฐ ์‹œ์ž‘ํ• ์ง€ ๋ชจ๋ฅด๊ฒ ๋‚˜์š”? ๊ทธ๋ ‡๋‹ค๋ฉด: + +- [Infisical ํŒ€์› ํ•œ๋ช…๊ณผ ํŽ˜์–ด๋ง ์„ธ์…˜์„ ํ•ด๋ณด์„ธ์š”](mailto:tony@infisical.com?subject=Pairing%20session&body=I'd%20like%20to%20do%20a%20pairing%20session!)! +- Slack์— ์ฐธ๊ฐ€ํ•ด์„œ, ์•„๋ฌด ์งˆ๋ฌธ์ด๋‚˜ ๋ฌผ์–ด๋ณด์„ธ์š”. + +## ๐Ÿ’š ์ปค๋ฎค๋‹ˆํ‹ฐ์™€ ์ง€์› + +- [Slack](https://join.slack.com/t/infisical-users/shared_invite/zt-1kdbk07ro-RtoyEt_9E~fyzGo_xQYP6g) (์ปค๋ฎค๋‹ˆํ‹ฐ ๊ทธ๋ฆฌ๊ณ  Infisical ํŒ€์›๊ณผ ์†Œํ†ตํ•˜๋Š” ๊ณณ) +- [GitHub Discussions](https://github.com/Infisical/infisical/discussions) (๊ธฐ๋Šฅ์— ๋Œ€ํ•œ ๊นŠ์€ ํ† ๋ก ์„ ๋‚˜๋ˆ„๊ธฐ ์œ„ํ•œ ๊ณณ) +- [GitHub Issues](https://github.com/Infisical/infisical-cli/issues) (Infisical์„ ์‚ฌ์šฉํ•˜๋˜ ์ค‘ ๋ฐœ์ƒํ•œ ์˜ค๋ฅ˜์— ๋Œ€ํ•ด ์ œ๋ณดํ•˜๋Š” ๊ณณ) +- [Twitter](https://twitter.com/infisical) (Infisical์— ๋Œ€ํ•œ ์†Œ์‹์„ ๋น ๋ฅด๊ฒŒ ๋ฐ›์•„๋ณด์„ธ์š”) + +## ๐Ÿฅ ์ƒํƒœ + +- [x] ๊ณต๊ฐœ ์•ŒํŒŒ: [infisical.com](https://infisical.com)์—์„œ ์•„๋ฌด๋‚˜ ๊ฐ€์ž…ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ์—ฌ๋Ÿฌ๊ฐ€์ง€ ๊ฒฐํ•จ์ด ์žˆ์„ ์ˆ˜ ์žˆ์–ด์š”. +- [ ] ๊ณต๊ฐœ ๋ฒ ํƒ€: ์ผ๋ฐ˜์ ์ธ ์‚ฌ์šฉ์—๋Š” ๋ฌธ์ œ ์—†์Œ +- [ ] ๊ณต๊ฐœ: ํ”„๋กœ๋•์…˜์— ์‚ฌ์šฉํ•  ์ค€๋น„ ์™„๋ฃŒ + +Infisical์€ ํ˜„์žฌ ๊ณต๊ฐœ ์•ŒํŒŒ ์ƒํƒœ์—์š”. + +## ๐Ÿ”Œ ์—ฐ๋™ + +์ €ํฌ๋Š” ์‹œํฌ๋ฆฟ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์—ฌ๋Ÿฌ๊ฐ€์ง€ [์—ฐ๋™](https://infisical.com/docs/integrations/overview)์„ ๊ฐœ๋ฐœํ•˜๊ณ  ์žˆ์–ด์š”. ๋ชจ๋“  ๋„์›€์€ ํ™˜์˜ํ•ด์š”! :) + + + + + + + + + + +
ํ”Œ๋žซํผ ํ”„๋ ˆ์ž„์›Œํฌ
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + โœ”๏ธ Docker + + + + โœ”๏ธ Docker Compose + + + + โœ”๏ธ Heroku + +
+ + โœ”๏ธ Vercel + + + + โœ”๏ธ Kubernetes + + + + โœ”๏ธ Fly.io + +
+ ๐Ÿ”œ AWS PS (https://github.com/Infisical/infisical/issues/286) + + + โœ”๏ธ GitHub Actions + + + ๐Ÿ”œ Railway (https://github.com/Infisical/infisical/issues/271) +
+ ๐Ÿ”œ GCP SM (https://github.com/Infisical/infisical/issues/285) + + ๐Ÿ”œ GitLab CI/CD (https://github.com/Infisical/infisical/issues/134) + + ๐Ÿ”œ CircleCI (https://github.com/Infisical/infisical/issues/91) +
+ ๐Ÿ”œ Jenkins + + ๐Ÿ”œ Digital Ocean + + ๐Ÿ”œ Azure +
+ ๐Ÿ”œ TravisCI + + + โœ”๏ธ Netlify + + + ๐Ÿ”œ Forge +
+ ๐Ÿ”œ Bitbucket + + ๐Ÿ”œ Supabase + + + โœ”๏ธ Render + +
+ ๐Ÿ”œ BuddyCI + + ๐Ÿ”œ Serverless + + ๐Ÿ”œ AWS Lambda +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + โœ”๏ธ React + + + + โœ”๏ธ Express + +
+ + โœ”๏ธ Gatsby + + + + โœ”๏ธ Flask + +
+ + โœ”๏ธ Django + + + + โœ”๏ธ Laravel + +
+ + โœ”๏ธ NestJS + + + + โœ”๏ธ Remix + +
+ + โœ”๏ธ Next.js + + + + โœ”๏ธ Vite + +
+ + โœ”๏ธ Vue + + + + โœ”๏ธ Ruby on Rails + +
+ + โœ”๏ธ Fiber + + + + โœ”๏ธ Nuxt + +
+ + โœ”๏ธ .NET + + + And more... +
+ +
+ +## ๐Ÿ˜ ์˜คํ”ˆ์†Œ์Šค vs ์œ ๋ฃŒ ๋ฒ„์ „ + +์ด ์ €์žฅ์†Œ๋Š” ์ถ”ํ›„ ์œ ๋ฃŒ ํ”„๋ฆฌ๋ฏธ์—„ ์—”ํ„ฐํ”„๋ผ์ด์ฆˆ ๊ธฐ๋Šฅ๋“ค์„ ํฌํ•จํ•  `ee` ํด๋”๋ฅผ ์ œ์™ธํ•˜๊ณ  ๋ชจ๋‘ MIT ๋ผ์ด์„ ์Šค์—์š”. + +## ๐Ÿ›ก ๋ณด์•ˆ + +๋ณด์•ˆ ์ทจ์•ฝ์ ์„ ๋ฐœ๊ฒฌํ–ˆ๋‚˜์š”? GitHub ์ด์Šˆ์— ์˜ฌ๋ฆฌ์ง€ ๋งˆ์‹œ๊ณ , [SECURITY.md](./SECURITY.md) ํŒŒ์ผ์„ ์ฐธ๊ณ ํ•ด์ฃผ์„ธ์š”. + +## ๐Ÿšจ ์ตœ์‹  ์†Œ์‹ ๋ฐ›๊ธฐ + +Infisical์€ 2022๋…„ 11์›” 21์ผ์— v1.0 ๋ฒ„์ „์„ ์ถœ์‹œํ–ˆ์–ด์š”. ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ๋“ค์ด ์ž์ฃผ ์ถ”๊ฐ€๋˜๋‹ˆ, ์ด ์ €์žฅ์†Œ์˜ **Releases**๋ฅผ ๋ˆˆ์—ฌ๊ฒจ๋ด์ฃผ์„ธ์š”! + +![infisical-star-github](https://github.com/Infisical/infisical/blob/main/.github/images/star-infisical.gif?raw=true) + +## ๐Ÿฆธ ๊ธฐ์—ฌ์ž + +[//]: contributor-faces + + + + + + + +## ๐ŸŒŽ ๋ฒˆ์—ญ + +Infisical์€ ํ˜„์žฌ ์˜์–ด, ํ•œ๊ตญ์–ด, ํ”„๋ž‘์Šค์–ด, ํฌ๋ฅดํˆฌ๊ฐˆ์–ด (๋ธŒ๋ผ์งˆ)๋กœ ๋ฒˆ์—ญ๋˜์–ด ์žˆ์–ด์š”. ๋‹น์‹ ์˜ ์–ธ์–ด๋กœ Infisical์„ ๋ฒˆ์—ญํ•˜๋„๋ก ๋„์™€์ฃผ์„ธ์š”! + +[์ด ์ด์Šˆ](https://github.com/Infisical/infisical/issues/181)์—์„œ ๋ฒˆ์—ญ์— ๊ด€ํ•œ ์ •๋ณด๋ฅผ ์ฐพ์•„๋ณผ ์ˆ˜ ์žˆ์–ด์š”. diff --git a/i18n/README.tr.md b/i18n/README.tr.md new file mode 100644 index 000000000..bef6aa6b8 --- /dev/null +++ b/i18n/README.tr.md @@ -0,0 +1,360 @@ +

+ infisical + infisical +

+

+

Aรงฤฑk kaynak kodlu, uรงtan uca ลŸifrelenmiลŸ(E2EE), ekibiniz ile altyapฤฑnฤฑz arasฤฑnda ortam deฤŸiลŸkenlerini yรถnetmeniz ve senkronize etmeniz iรงin basit bir araรง.

+

+ +

+ Slack | + Infisical Cloud | + Self-Hosting | + Docs | + Website +

+ +

+ + Medusa is released under the MIT license. + + + PRs welcome! + + + git commit activity + + + Slack community channel + + + Infisical Twitter + +

+ +Dashboard + +**[Infisical](https://infisical.com)** takฤฑmlarฤฑn geliลŸtirme sรผreรงleri ile altapฤฑlarฤฑ arasฤฑnda ortam deฤŸiลŸkenlerini yรถnetmelerine ve senkronize etmelerine yardฤฑmcฤฑ olan aรงฤฑk kaynak kodlu, uรงtan uca ลŸifrelenmiลŸ(E2EE) bir araรงtฤฑr. +Basit olmasฤฑ iรงin tasarlandฤฑ, sadece birkaรง dakika iรงerisinde harekete geรงin. + +- **[Kullanฤฑcฤฑ Dostu Gรถsterge Paneli](https://infisical.com/docs/getting-started/dashboard/project)** projeler arasฤฑnda takฤฑmฤฑnฤฑzฤฑn ortam deฤŸiลŸkenlerini yรถnetmenize yardฤฑmcฤฑ olur. +- **[Dillerden BaฤŸฤฑmsฤฑz CLI](https://infisical.com/docs/cli/overview)** - ortam deฤŸiลŸkenlerini รงeker ve yerel iลŸ akฤฑลŸฤฑnฤฑza enjekte eder. +- **[Kontrol Sizde](https://infisical.com/docs/self-hosting/overview)** - herhangi bir altyapฤฑda kendiniz hostlayarak verileriniz รผzerinde tam kontrol saฤŸlayฤฑn. +- **ร‡oklu ortamlar arasฤฑ gezinin** - herbir proje iรงin ortamlarฤฑnฤฑz arasฤฑnda geรงiลŸ saฤŸlayฤฑn(รถr. development, staging, production, vb.) +- **KiลŸisel yada PaylaลŸฤฑlabilen** alan - ortam deฤŸiลŸkenleriniz iรงin. +- **[Entegrasyonlar](https://infisical.com/docs/integrations/overview)** - CI/CD production altyapฤฑsฤฑ ile. +- **[Infisical API](https://infisical.com/docs/api-reference/overview/introduction)** - HTTPS istekleri ile sฤฑrlarฤฑ yรถnetin. +- **[Sฤฑrlar ฤฐรงin Versiyon Kontrol](https://infisical.com/docs/getting-started/dashboard/versioning)** - herhangi bir sฤฑr iรงin deฤŸiลŸiklik geรงmiลŸini gรถrรผntรผleyin. +- **[Aktivite Gรผnlรผkleri](https://infisical.com/docs/getting-started/dashboard/audit-logs)** - projedeki tรผm deฤŸiลŸikleri kayฤฑt altฤฑna almak iรงin. +- **[Anฤฑnda Geri Yรผkleme](https://infisical.com/docs/getting-started/dashboard/pit-recovery)** - sฤฑrlarฤฑnฤฑzฤฑn herhangi bir snapshotฤฑna geri yรผkleme yapmanฤฑz iรงin. +- ๐Ÿ”œ **Tek tฤฑkla Deploy** edin, Digital Ocean ve Heroku'ya. +- ๐Ÿ”œ **Kimlik DoฤŸrulama/Yetkilendirme** projeleriniz iรงin okuma/yazma kontrolleri (pek yakฤฑnda) +- ๐Ÿ”œ **Otomatik Sฤฑr Rotasyonu** +- ๐Ÿ”œ **2 Faktรถr Kimlik DoฤŸrulama** +- ๐Ÿ”œ **EriลŸim Gรผnlรผkleri** +- ๐Ÿ”œ **Slack & MS Teams** entegrasyonlarฤฑ + +Ve daha fazlasฤฑ. + +## ๐Ÿš€ Hadi baลŸlayalฤฑm + +Hฤฑzlฤฑca baลŸlamak iรงin [baลŸlangฤฑรง rehberimizi](https://infisical.com/docs/getting-started/introduction) ziyaret edin. + +

+ + + +

+ +## ๐Ÿ”ฅ Peki bunun nesi havalฤฑ? + +Infisical sฤฑr yรถnetimini varsayฤฑlan olarak uรงtan uca ลŸifreleyerek basitleลŸtirir. Infisical'ฤฑ sadece gรผvenlik takฤฑmlarฤฑ iรงin deฤŸil tรผm geliลŸtiriciler iรงin daha รงok eriลŸilebilir hale getirmek รผzere gรถrevdeyiz. + +2019'daki bir [rapora](https://www.ekransystem.com/en/blog/secrets-management) gรถre, dijital sฤฑrlarฤฑ kullanan kuruluลŸlarฤฑn sadece %10 kadarฤฑ sฤฑr yรถnetim รงรถzรผmlerini kullanฤฑyor. + +EฤŸer gรผvenlik ve verimliliฤŸe รถnem veriyorsanฤฑz Infisical tam size gรถre. + +Infisical'ฤฑ daha yaygฤฑn hale getirmek iรงin sฤฑkฤฑ รงalฤฑลŸฤฑyoruz. ฤฐstediฤŸiniz herhangi bir entegrasyon mu var yada yeni bir รถzellik mi istiyorsunuz? Lรผtfen [yeni bir issue oluลŸturun](https://github.com/Infisical/infisical/issues) yada repositoriye direkt [katkฤฑda bulunun](https://infisical.com/docs/contributing/overview). + +## ๐ŸŒฑ Katkฤฑlar + +Bรผyรผk yada kรผรงรผk farketmeksizin katkฤฑlara bayฤฑlฤฑyoruz โค๏ธ Nasฤฑl baลŸlayacaฤŸฤฑnฤฑzฤฑ gรถrmek iรงin [baลŸlangฤฑรง](https://infisical.com/docs/contributing/overview) rehberimize gรถz atฤฑn. + +Nereden baลŸlayacaฤŸฤฑnฤฑzdan emin deฤŸil misiniz? O zaman; + +- [Ekip arkadaลŸlarฤฑmฤฑzdan biriyle รผcretsiz, baskฤฑ iรงermeyen bir yรถnlendirme seansฤฑnฤฑ rezerve edin](mailto:tony@infisical.com?subject=Pairing%20session&body=I'd%20like%20to%20do%20a%20pairing%20session!)! +- Bizim Slack'imize katฤฑlฤฑn, ve bize herhangi bir soru sorun. + +## ๐Ÿ’š Topluluk & Destek + +- [Slack](https://join.slack.com/t/infisical-users/shared_invite/zt-1kdbk07ro-RtoyEt_9E~fyzGo_xQYP6g) (Toplulukla ve Infisical team ile canlฤฑ tartฤฑลŸma iรงin) +- [GitHub Discussions](https://github.com/Infisical/infisical/discussions) (ร–zellikler hakkฤฑnda daha derin tartฤฑลŸmalar oluลŸturma ve geliลŸtirme konusunda yardฤฑm iรงin) +- [GitHub Issues](https://github.com/Infisical/infisical-cli/issues) (Infisical'ฤฑ kullanฤฑrken karลŸฤฑlaลŸtฤฑฤŸฤฑnฤฑz herhangi bir bug iรงin) +- [Twitter](https://twitter.com/infisical) (Haberleri kaรงฤฑrmayฤฑn) + +## ๐Ÿฅ Durum + +- [x] Public Alpha: Herkes [infisical.com](https://infisical.com) รผzerinden katฤฑlabilir (ama รผzerimize fazla gelmeyin), bazฤฑ karmaลŸalar sรถz konusu ve biz daha yeni baลŸlฤฑyoruz. +- [ ] Public Beta: Kurumsal olmayan รงoฤŸu kullanฤฑm iรงin yeterince kararlฤฑ. +- [ ] Public: Production-ready. + +ลžuan Public Alpha'dayฤฑz. + +## ๐Ÿ”Œ Entegrasyonlar + +ลžu anda sฤฑrlarฤฑn herhangi bir yerde senkron olabilmesi iรงin [entegrasyonlar](https://infisical.com/docs/integrations/overview) รผzerinde sฤฑkฤฑ รงalฤฑลŸฤฑyoruz. Her tรผrlรผ yardฤฑmฤฑ gรถzlรผyoruz! :) + + + + + + + + + + +
Platforms Frameworks
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + โœ”๏ธ Docker + + + + โœ”๏ธ Docker Compose + + + + โœ”๏ธ Heroku + +
+ + โœ”๏ธ Vercel + + + + โœ”๏ธ Kubernetes + + + + โœ”๏ธ Fly.io + +
+ ๐Ÿ”œ AWS PS (https://github.com/Infisical/infisical/issues/286) + + + โœ”๏ธ GitHub Actions + + + ๐Ÿ”œ Railway (https://github.com/Infisical/infisical/issues/271) +
+ ๐Ÿ”œ GCP SM (https://github.com/Infisical/infisical/issues/285) + + ๐Ÿ”œ GitLab CI/CD (https://github.com/Infisical/infisical/issues/134) + + ๐Ÿ”œ CircleCI (https://github.com/Infisical/infisical/issues/91) +
+ ๐Ÿ”œ Jenkins + + ๐Ÿ”œ Digital Ocean + + ๐Ÿ”œ Azure +
+ ๐Ÿ”œ TravisCI + + + โœ”๏ธ Netlify + + + ๐Ÿ”œ Forge +
+ ๐Ÿ”œ Bitbucket + + ๐Ÿ”œ Supabase + + + โœ”๏ธ Render + +
+ ๐Ÿ”œ BuddyCI + + ๐Ÿ”œ Serverless + + ๐Ÿ”œ AWS Lambda +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + โœ”๏ธ React + + + + โœ”๏ธ Express + +
+ + โœ”๏ธ Gatsby + + + + โœ”๏ธ Flask + +
+ + โœ”๏ธ Django + + + + โœ”๏ธ Laravel + +
+ + โœ”๏ธ NestJS + + + + โœ”๏ธ Remix + +
+ + โœ”๏ธ Next.js + + + + โœ”๏ธ Vite + +
+ + โœ”๏ธ Vue + + + + โœ”๏ธ Ruby on Rails + +
+ + โœ”๏ธ Fiber + + + + โœ”๏ธ Nuxt + +
+ + โœ”๏ธ .NET + + + And more... +
+ +
+ +## ๐Ÿ˜ Aรงฤฑk kaynak mฤฑ yoksa รผcretlimi + +Bu repository premium kurumsal รงรถzรผmler iรงeren, gelecekte Infisical lisansฤฑ gerektirecek `ee` dizini hariรง tamamen MIT lisansฤฑ altฤฑndadฤฑr. ลžu anda รถncelikli olarak kurumsal olmayan ancak bir รงok kullanฤฑm senaryosuna รงรถzรผm sunacak teklifler รผzerine yoฤŸunlaลŸฤฑyoruz. + +## ๐Ÿ›ก Gรผvenlik + +Bir gรผvenlik aรงฤฑฤŸฤฑnฤฑ bildirmek mi istiyorsunuz? Lรผtfen Github'da herhangi bir ลŸekilde paylaลŸmayฤฑn. Bunun yerine, [SECURITY.md](./SECURITY.md) dosyamฤฑza yรถnlendirin. + +## ๐Ÿšจ Gรผncel kalฤฑn + +Infisical 21 Kasฤฑm 2022 de v.1.0 resmi olarak olarak yayฤฑnlandฤฑ. Buna raฤŸmen yeni รถzellikler hฤฑzlฤฑ bir ลŸekilde gelmekte. Gelecekteki gรผncellemeler hakkฤฑnda bilgilenmek iรงin, bu repositorynin **releases** bรถlรผmรผnรผ takipte kalฤฑn: + +![infisical-star-github](https://github.com/Infisical/infisical/blob/main/.github/images/star-infisical.gif?raw=true) + +## ๐Ÿฆธ Katkฤฑda bulunanlar + +[//]: contributor-faces + + + + + + + +## ๐ŸŒŽ ร‡eviriler + +Infisical ลŸu anda ฤฐngilizce, Korece ve Tรผrkรงe dillerinde mevcut. Infisical' ฤฑ dilinize รงevirmemize yardฤฑm edin! + +[Bu issue](https://github.com/Infisical/infisical/issues/181)'dan gerekli tรผm bilgilere eriลŸebilirsiniz. diff --git a/img/infisical_github_repo.png b/img/infisical_github_repo.png index ed763aad7..f2a328d7d 100644 Binary files a/img/infisical_github_repo.png and b/img/infisical_github_repo.png differ diff --git a/k8-operator/Makefile b/k8-operator/Makefile index 9116f8522..a8b056376 100644 --- a/k8-operator/Makefile +++ b/k8-operator/Makefile @@ -1,6 +1,6 @@ # Image URL to use all building/pushing image targets -IMG ?= controller:latest +IMG ?= infisical/kubernetes-operator:latest # ENVTEST_K8S_VERSION refers to the version of kubebuilder assets to be downloaded by envtest binary. ENVTEST_K8S_VERSION = 1.25.0 @@ -36,6 +36,17 @@ all: build help: ## Display this help. @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST) + +## Chart +helm-chart: + $(KUSTOMIZE) build config/default | helmify ../helm-charts/secrets-operator + +## Yaml for Kubectl +kubectl-install: manifests kustomize + mkdir -p kubectl-install + cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG} + $(KUSTOMIZE) build config/default > kubectl-install/install-secrets-operator.yaml + ##@ Development .PHONY: manifests diff --git a/k8-operator/README.md b/k8-operator/README.md index 6d953997e..807476c0c 100644 --- a/k8-operator/README.md +++ b/k8-operator/README.md @@ -1,8 +1,8 @@ # k8-operator -// TODO(user): Add simple overview of use/purpose +// TODO ## Description -// TODO(user): An in-depth paragraph about your project and overview of use +// TODO ## Getting Started Youโ€™ll need a Kubernetes cluster to run against. You can use [KIND](https://sigs.k8s.io/kind) to get a local cluster for testing, or run against a remote cluster. @@ -42,7 +42,7 @@ make undeploy ``` ## Contributing -// TODO(user): Add detailed information on how you would like others to contribute to this project +// TODO ### How it works This project aims to follow the Kubernetes [Operator pattern](https://kubernetes.io/docs/concepts/extend-kubernetes/operator/) @@ -76,19 +76,3 @@ make manifests More information can be found via the [Kubebuilder Documentation](https://book.kubebuilder.io/introduction.html) -## License - -Copyright 2022. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. - diff --git a/k8-operator/api/v1alpha1/infisicalsecret_types.go b/k8-operator/api/v1alpha1/infisicalsecret_types.go index 74e3f9788..8f8fbbed9 100644 --- a/k8-operator/api/v1alpha1/infisicalsecret_types.go +++ b/k8-operator/api/v1alpha1/infisicalsecret_types.go @@ -16,16 +16,14 @@ type KubeSecretReference struct { // InfisicalSecretSpec defines the desired state of InfisicalSecret type InfisicalSecretSpec struct { - InfisicalToken KubeSecretReference `json:"infisicalToken,omitempty"` - ManagedSecret KubeSecretReference `json:"managedSecret,omitempty"` - - // The Infisical project id // +kubebuilder:validation:Required - ProjectId string `json:"projectId"` - - // The Infisical environment such as dev, prod, testing + TokenSecretReference KubeSecretReference `json:"tokenSecretReference,omitempty"` // +kubebuilder:validation:Required - Environment string `json:"environment"` + ManagedSecretReference KubeSecretReference `json:"managedSecretReference,omitempty"` + + // Infisical host to pull secrets from + // +kubebuilder:default="https://app.infisical.com/api" + HostAPI string `json:"hostAPI,omitempty"` } // InfisicalSecretStatus defines the observed state of InfisicalSecret diff --git a/k8-operator/api/v1alpha1/zz_generated.deepcopy.go b/k8-operator/api/v1alpha1/zz_generated.deepcopy.go index e6053ba74..af9eff318 100644 --- a/k8-operator/api/v1alpha1/zz_generated.deepcopy.go +++ b/k8-operator/api/v1alpha1/zz_generated.deepcopy.go @@ -88,8 +88,8 @@ func (in *InfisicalSecretList) DeepCopyObject() runtime.Object { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *InfisicalSecretSpec) DeepCopyInto(out *InfisicalSecretSpec) { *out = *in - out.InfisicalToken = in.InfisicalToken - out.ManagedSecret = in.ManagedSecret + out.TokenSecretReference = in.TokenSecretReference + out.ManagedSecretReference = in.ManagedSecretReference } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfisicalSecretSpec. diff --git a/k8-operator/config/crd/bases/secrets.infisical.com_infisicalsecrets.yaml b/k8-operator/config/crd/bases/secrets.infisical.com_infisicalsecrets.yaml index ca00676b4..2f99ef443 100644 --- a/k8-operator/config/crd/bases/secrets.infisical.com_infisicalsecrets.yaml +++ b/k8-operator/config/crd/bases/secrets.infisical.com_infisicalsecrets.yaml @@ -35,10 +35,11 @@ spec: spec: description: InfisicalSecretSpec defines the desired state of InfisicalSecret properties: - environment: - description: The Infisical environment such as dev, prod, testing + hostAPI: + default: https://app.infisical.com/api + description: Infisical host to pull secrets from type: string - infisicalToken: + managedSecretReference: properties: secretName: description: The name of the Kubernetes Secret @@ -50,7 +51,7 @@ spec: - secretName - secretNamespace type: object - managedSecret: + tokenSecretReference: properties: secretName: description: The name of the Kubernetes Secret @@ -62,12 +63,6 @@ spec: - secretName - secretNamespace type: object - projectId: - description: The Infisical project id - type: string - required: - - environment - - projectId type: object status: description: InfisicalSecretStatus defines the observed state of InfisicalSecret diff --git a/k8-operator/config/default/kustomization.yaml b/k8-operator/config/default/kustomization.yaml index 4cab9014c..1237b893d 100644 --- a/k8-operator/config/default/kustomization.yaml +++ b/k8-operator/config/default/kustomization.yaml @@ -1,12 +1,12 @@ # Adds namespace to all resources. -namespace: k8-operator-system +namespace: infisical-operator-system # Value of this field is prepended to the # names of all resources, e.g. a deployment named # "wordpress" becomes "alices-wordpress". # Note that it should also match with the prefix (text before '-') of the namespace # field above. -namePrefix: k8-operator- +namePrefix: infisical-operator- # Labels to add to all resources and selectors. #commonLabels: diff --git a/k8-operator/config/manager/kustomization.yaml b/k8-operator/config/manager/kustomization.yaml index 5c5f0b84c..96ea36924 100644 --- a/k8-operator/config/manager/kustomization.yaml +++ b/k8-operator/config/manager/kustomization.yaml @@ -1,2 +1,8 @@ resources: - manager.yaml +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +images: +- name: controller + newName: infisical/kubernetes-operator + newTag: latest diff --git a/k8-operator/config/samples/deployment.yaml b/k8-operator/config/samples/deployment.yaml new file mode 100644 index 000000000..78de44032 --- /dev/null +++ b/k8-operator/config/samples/deployment.yaml @@ -0,0 +1,26 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-deployment + labels: + app: nginx + annotations: + secrets.infisical.com/auto-reload: "true" +spec: + replicas: 3 + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: nginx:1.14.2 + envFrom: + - secretRef: + name: managed-secret + ports: + - containerPort: 80 \ No newline at end of file diff --git a/k8-operator/config/samples/sample.yaml b/k8-operator/config/samples/sample.yaml new file mode 100644 index 000000000..236e55baf --- /dev/null +++ b/k8-operator/config/samples/sample.yaml @@ -0,0 +1,12 @@ +apiVersion: secrets.infisical.com/v1alpha1 +kind: InfisicalSecret +metadata: + name: infisicalsecret-sample +spec: + hostAPI: https://app.infisical.com/api + tokenSecretReference: + secretName: service-token + secretNamespace: default + managedSecretReference: + secretName: managed-secret + secretNamespace: default diff --git a/k8-operator/config/samples/secrets_v1alpha1_infisicalsecret.yaml b/k8-operator/config/samples/secrets_v1alpha1_infisicalsecret.yaml deleted file mode 100644 index 7ab08e9cd..000000000 --- a/k8-operator/config/samples/secrets_v1alpha1_infisicalsecret.yaml +++ /dev/null @@ -1,19 +0,0 @@ -apiVersion: secrets.infisical.com/v1alpha1 -kind: InfisicalSecret -metadata: - labels: - app.kubernetes.io/name: infisicalsecret - app.kubernetes.io/instance: infisicalsecret-sample - app.kubernetes.io/part-of: k8-operator - app.kubernetes.io/managed-by: kustomize - app.kubernetes.io/created-by: k8-operator - name: infisicalsecret-sample -spec: - projectId: 62faf98ae0b05e8529b5da46 - environment: dev - infisicalToken: - secretName: service-token - secretNamespace: default - managedSecret: - secretName: managed-secret - secretNamespace: default diff --git a/k8-operator/config/samples/serviceTokenSecret.yaml b/k8-operator/config/samples/serviceTokenSecret.yaml new file mode 100644 index 000000000..3fd2e1b8a --- /dev/null +++ b/k8-operator/config/samples/serviceTokenSecret.yaml @@ -0,0 +1,7 @@ +apiVersion: v1 +kind: Secret +metadata: + name: service-token +type: Opaque +data: + infisicalToken: \ No newline at end of file diff --git a/k8-operator/controllers/auto_redeployment.go b/k8-operator/controllers/auto_redeployment.go new file mode 100644 index 000000000..e4fa6d00f --- /dev/null +++ b/k8-operator/controllers/auto_redeployment.go @@ -0,0 +1,105 @@ +package controllers + +import ( + "context" + "fmt" + "sync" + + "github.com/Infisical/infisical/k8-operator/api/v1alpha1" + v1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +const DEPLOYMENT_SECRET_NAME_ANNOTATION_PREFIX = "secrets.infisical.com/managed-secret" +const AUTO_RELOAD_DEPLOYMENT_ANNOTATION = "secrets.infisical.com/auto-reload" // needs to be set to true for a deployment to start auto redeploying + +func (r *InfisicalSecretReconciler) ReconcileDeploymentsWithManagedSecrets(ctx context.Context, infisicalSecret v1alpha1.InfisicalSecret) (int, error) { + listOfDeployments := &v1.DeploymentList{} + err := r.Client.List(ctx, listOfDeployments, &client.ListOptions{Namespace: infisicalSecret.Spec.ManagedSecretReference.SecretNamespace}) + if err != nil { + return 0, fmt.Errorf("unable to get deployments in the [namespace=%v] [err=%v]", infisicalSecret.Spec.ManagedSecretReference.SecretNamespace, err) + } + + managedKubeSecretNameAndNamespace := types.NamespacedName{ + Namespace: infisicalSecret.Spec.ManagedSecretReference.SecretNamespace, + Name: infisicalSecret.Spec.ManagedSecretReference.SecretName, + } + + managedKubeSecret := &corev1.Secret{} + err = r.Client.Get(ctx, managedKubeSecretNameAndNamespace, managedKubeSecret) + if err != nil { + return 0, fmt.Errorf("unable to fetch Kubernetes secret to update deployment: %v", err) + } + + var wg sync.WaitGroup + // Iterate over the deployments and check if they use the managed secret + for _, deployment := range listOfDeployments.Items { + if deployment.Annotations[AUTO_RELOAD_DEPLOYMENT_ANNOTATION] == "true" && r.IsDeploymentUsingManagedSecret(deployment, infisicalSecret) { + // Start a goroutine to reconcile the deployment + wg.Add(1) + go func(d v1.Deployment, s corev1.Secret) { + defer wg.Done() + if err := r.ReconcileDeployment(ctx, d, s); err != nil { + fmt.Printf("unable to reconcile deployment with [name=%v]. Will try next requeue", deployment.ObjectMeta.Name) + } + }(deployment, *managedKubeSecret) + } + } + + wg.Wait() + + return 0, nil +} + +// Check if the deployment uses managed secrets +func (r *InfisicalSecretReconciler) IsDeploymentUsingManagedSecret(deployment v1.Deployment, infisicalSecret v1alpha1.InfisicalSecret) bool { + managedSecretName := infisicalSecret.Spec.ManagedSecretReference.SecretName + for _, container := range deployment.Spec.Template.Spec.Containers { + for _, envFrom := range container.EnvFrom { + if envFrom.SecretRef != nil && envFrom.SecretRef.LocalObjectReference.Name == managedSecretName { + return true + } + } + for _, env := range container.Env { + if env.ValueFrom != nil && env.ValueFrom.SecretKeyRef != nil && env.ValueFrom.SecretKeyRef.LocalObjectReference.Name == managedSecretName { + return true + } + } + } + for _, volume := range deployment.Spec.Template.Spec.Volumes { + if volume.Secret != nil && volume.Secret.SecretName == managedSecretName { + return true + } + } + + return false +} + +// This function ensures that a deployment is in sync with a Kubernetes secret by comparing their versions. +// If the version of the secret is different from the version annotation on the deployment, the annotation is updated to trigger a restart of the deployment. +func (r *InfisicalSecretReconciler) ReconcileDeployment(ctx context.Context, deployment v1.Deployment, secret corev1.Secret) error { + annotationKey := fmt.Sprintf("%s.%s", DEPLOYMENT_SECRET_NAME_ANNOTATION_PREFIX, secret.Name) + annotationValue := secret.Annotations[SECRET_VERSION_ANNOTATION] + + if deployment.Annotations[annotationKey] == annotationValue && + deployment.Spec.Template.Annotations[annotationKey] == annotationValue { + fmt.Printf("The [deploymentName=%v] is already using the most up to date managed secrets. No action required.\n", deployment.ObjectMeta.Name) + return nil + } + + fmt.Printf("deployment is using outdated managed secret. Starting re-deployment [deploymentName=%v]\n", deployment.ObjectMeta.Name) + + if deployment.Spec.Template.Annotations == nil { + deployment.Spec.Template.Annotations = make(map[string]string) + } + + deployment.Annotations[annotationKey] = annotationValue + deployment.Spec.Template.Annotations[annotationKey] = annotationValue + + if err := r.Client.Update(ctx, &deployment); err != nil { + return fmt.Errorf("failed to update deployment annotation: %v", err) + } + return nil +} diff --git a/k8-operator/controllers/conditions.go b/k8-operator/controllers/conditions.go new file mode 100644 index 000000000..dea822088 --- /dev/null +++ b/k8-operator/controllers/conditions.go @@ -0,0 +1,95 @@ +package controllers + +import ( + "context" + "fmt" + + "github.com/Infisical/infisical/k8-operator/api/v1alpha1" + "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func (r *InfisicalSecretReconciler) SetReadyToSyncSecretsConditions(ctx context.Context, infisicalSecret *v1alpha1.InfisicalSecret, errorToConditionOn error) error { + if infisicalSecret.Status.Conditions == nil { + infisicalSecret.Status.Conditions = []metav1.Condition{} + } + + if errorToConditionOn != nil { + meta.SetStatusCondition(&infisicalSecret.Status.Conditions, metav1.Condition{ + Type: "secrets.infisical.com/ReadyToSyncSecrets", + Status: metav1.ConditionFalse, + Reason: "Error", + Message: "Failed to sync secrets. This can be caused by invalid service token or an invalid API host that is set. Check operator logs for more info", + }) + + meta.SetStatusCondition(&infisicalSecret.Status.Conditions, metav1.Condition{ + Type: "secrets.infisical.com/AutoRedeployReady", + Status: metav1.ConditionFalse, + Reason: "Stopped", + Message: "Auto redeployment has been stopped because the operator failed to sync secrets", + }) + } else { + meta.SetStatusCondition(&infisicalSecret.Status.Conditions, metav1.Condition{ + Type: "secrets.infisical.com/ReadyToSyncSecrets", + Status: metav1.ConditionTrue, + Reason: "OK", + Message: "Infisical controller has started syncing your secrets", + }) + } + + return r.Client.Status().Update(ctx, infisicalSecret) +} + +func (r *InfisicalSecretReconciler) SetInfisicalTokenLoadCondition(ctx context.Context, infisicalSecret *v1alpha1.InfisicalSecret, errorToConditionOn error) { + if infisicalSecret.Status.Conditions == nil { + infisicalSecret.Status.Conditions = []metav1.Condition{} + } + + if errorToConditionOn == nil { + meta.SetStatusCondition(&infisicalSecret.Status.Conditions, metav1.Condition{ + Type: "secrets.infisical.com/LoadedInfisicalToken", + Status: metav1.ConditionTrue, + Reason: "OK", + Message: "Infisical controller has located the Infisical token in provided Kubernetes secret", + }) + } else { + meta.SetStatusCondition(&infisicalSecret.Status.Conditions, metav1.Condition{ + Type: "secrets.infisical.com/LoadedInfisicalToken", + Status: metav1.ConditionFalse, + Reason: "Error", + Message: fmt.Sprintf("Failed to load Infisical Token from the provided Kubernetes secret because: %v", errorToConditionOn), + }) + } + + err := r.Client.Status().Update(ctx, infisicalSecret) + if err != nil { + fmt.Println("Could not set condition for LoadedInfisicalToken") + } +} + +func (r *InfisicalSecretReconciler) SetInfisicalAutoRedeploymentReady(ctx context.Context, infisicalSecret *v1alpha1.InfisicalSecret, numDeployments int, errorToConditionOn error) { + if infisicalSecret.Status.Conditions == nil { + infisicalSecret.Status.Conditions = []metav1.Condition{} + } + + if errorToConditionOn == nil { + meta.SetStatusCondition(&infisicalSecret.Status.Conditions, metav1.Condition{ + Type: "secrets.infisical.com/AutoRedeployReady", + Status: metav1.ConditionTrue, + Reason: "OK", + Message: fmt.Sprintf("Infisical has found %v deployments which are ready to be auto redeployed when secrets change", numDeployments), + }) + } else { + meta.SetStatusCondition(&infisicalSecret.Status.Conditions, metav1.Condition{ + Type: "secrets.infisical.com/AutoRedeployReady", + Status: metav1.ConditionFalse, + Reason: "Error", + Message: fmt.Sprintf("Failed reconcile deployments because: %v", errorToConditionOn), + }) + } + + err := r.Client.Status().Update(ctx, infisicalSecret) + if err != nil { + fmt.Println("Could not set condition for AutoRedeployReady") + } +} diff --git a/k8-operator/controllers/infisicalsecret_controller.go b/k8-operator/controllers/infisicalsecret_controller.go index 297e29bfb..ba2f6a17b 100644 --- a/k8-operator/controllers/infisicalsecret_controller.go +++ b/k8-operator/controllers/infisicalsecret_controller.go @@ -2,16 +2,17 @@ package controllers import ( "context" + "fmt" "time" "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/runtime" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/log" "github.com/Infisical/infisical/k8-operator/api/v1alpha1" secretsv1alpha1 "github.com/Infisical/infisical/k8-operator/api/v1alpha1" + "github.com/Infisical/infisical/k8-operator/packages/api" ) // InfisicalSecretReconciler reconciles a InfisicalSecret object @@ -31,46 +32,63 @@ type InfisicalSecretReconciler struct { // For more details, check Reconcile and its Result here: // - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.13.1/pkg/reconcile func (r *InfisicalSecretReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - log := log.FromContext(ctx) - + requeueTime := time.Minute * 1 var infisicalSecretCR v1alpha1.InfisicalSecret - err := r.Get(ctx, req.NamespacedName, &infisicalSecretCR) + err := r.Get(ctx, req.NamespacedName, &infisicalSecretCR) if err != nil { if errors.IsNotFound(err) { - log.Info("Infisical Secret not found") - return ctrl.Result{}, nil - } else { - log.Error(err, "Unable to fetch Infisical Secret from cluster. Will retry") + fmt.Printf("Infisical Secret CRD not found [err=%v]", err) return ctrl.Result{ - RequeueAfter: time.Minute, + Requeue: false, + }, nil + } else { + fmt.Printf("Unable to fetch Infisical Secret CRD from cluster because [err=%v]", err) + return ctrl.Result{ + RequeueAfter: requeueTime, }, nil } } // Check if the resource is already marked for deletion if infisicalSecretCR.GetDeletionTimestamp() != nil { - return ctrl.Result{}, nil + return ctrl.Result{ + Requeue: false, + }, nil } + // set the api url based on the CRD + api.API_HOST_URL = infisicalSecretCR.Spec.HostAPI + err = r.ReconcileInfisicalSecret(ctx, infisicalSecretCR) r.SetReadyToSyncSecretsConditions(ctx, &infisicalSecretCR, err) + if err != nil { - log.Error(err, "Unable to reconcile Infisical Secret and will try again") + fmt.Printf("unable to reconcile Infisical Secret because [err=%v]. Will requeue after [requeueTime=%v]\n", err, requeueTime) return ctrl.Result{ - RequeueAfter: time.Minute, + RequeueAfter: requeueTime, + }, nil + } + + numDeployments, err := r.ReconcileDeploymentsWithManagedSecrets(ctx, infisicalSecretCR) + r.SetInfisicalAutoRedeploymentReady(ctx, &infisicalSecretCR, numDeployments, err) + if err != nil { + fmt.Printf("unable to reconcile auto redeployment because [err=%v]", err) + return ctrl.Result{ + RequeueAfter: requeueTime, }, nil } // Sync again after the specified time + fmt.Printf("Operator will requeue after [%v] \n", requeueTime) return ctrl.Result{ - RequeueAfter: time.Minute, + RequeueAfter: requeueTime, }, nil } // SetupWithManager sets up the controller with the Manager. func (r *InfisicalSecretReconciler) SetupWithManager(mgr ctrl.Manager) error { return ctrl.NewControllerManagedBy(mgr). - For(&secretsv1alpha1.InfisicalSecret{}). // TODO we should also be watching secrets with the name specifed + For(&secretsv1alpha1.InfisicalSecret{}). Complete(r) } diff --git a/k8-operator/controllers/infisicalsecret_helper.go b/k8-operator/controllers/infisicalsecret_helper.go index fbcacadea..8428cbec1 100644 --- a/k8-operator/controllers/infisicalsecret_helper.go +++ b/k8-operator/controllers/infisicalsecret_helper.go @@ -6,16 +6,16 @@ import ( "strings" "github.com/Infisical/infisical/k8-operator/api/v1alpha1" - api "github.com/Infisical/infisical/k8-operator/packages/api" - models "github.com/Infisical/infisical/k8-operator/packages/models" + "github.com/Infisical/infisical/k8-operator/packages/api" + "github.com/Infisical/infisical/k8-operator/packages/util" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" ) const INFISICAL_TOKEN_SECRET_KEY_NAME = "infisicalToken" +const SECRET_VERSION_ANNOTATION = "secrets.infisical.com/version" // used to set the version of secrets via Etag func (r *InfisicalSecretReconciler) GetKubeSecretByNamespacedName(ctx context.Context, namespacedName types.NamespacedName) (*corev1.Secret, error) { kubeSecret := &corev1.Secret{} @@ -27,14 +27,14 @@ func (r *InfisicalSecretReconciler) GetKubeSecretByNamespacedName(ctx context.Co return kubeSecret, err } -func (r *InfisicalSecretReconciler) GetInfisicalToken(ctx context.Context, infisicalSecret v1alpha1.InfisicalSecret) (string, error) { +func (r *InfisicalSecretReconciler) GetInfisicalTokenFromKubeSecret(ctx context.Context, infisicalSecret v1alpha1.InfisicalSecret) (string, error) { tokenSecret, err := r.GetKubeSecretByNamespacedName(ctx, types.NamespacedName{ - Namespace: infisicalSecret.Spec.InfisicalToken.SecretNamespace, - Name: infisicalSecret.Spec.InfisicalToken.SecretName, + Namespace: infisicalSecret.Spec.TokenSecretReference.SecretNamespace, + Name: infisicalSecret.Spec.TokenSecretReference.SecretName, }) if err != nil { - return "", fmt.Errorf("failed to read Infisical token secret from secret named [%s] in namespace [%s]: with error [%w]", infisicalSecret.Spec.ManagedSecret.SecretName, infisicalSecret.Spec.ManagedSecret.SecretNamespace, err) + return "", fmt.Errorf("failed to read Infisical token secret from secret named [%s] in namespace [%s]: with error [%w]", infisicalSecret.Spec.TokenSecretReference.SecretName, infisicalSecret.Spec.TokenSecretReference.SecretNamespace, err) } infisicalServiceToken := tokenSecret.Data[INFISICAL_TOKEN_SECRET_KEY_NAME] @@ -45,7 +45,7 @@ func (r *InfisicalSecretReconciler) GetInfisicalToken(ctx context.Context, infis return strings.Replace(string(infisicalServiceToken), " ", "", -1), nil } -func (r *InfisicalSecretReconciler) CreateInfisicalManagedKubeSecret(ctx context.Context, infisicalSecret v1alpha1.InfisicalSecret, secretsFromAPI []models.SingleEnvironmentVariable) error { +func (r *InfisicalSecretReconciler) CreateInfisicalManagedKubeSecret(ctx context.Context, infisicalSecret v1alpha1.InfisicalSecret, secretsFromAPI []util.SingleEnvironmentVariable, encryptedSecretsResponse api.GetEncryptedSecretsV2Response) error { plainProcessedSecrets := make(map[string][]byte) for _, secret := range secretsFromAPI { plainProcessedSecrets[secret.Key] = []byte(secret.Value) // plain process @@ -54,8 +54,11 @@ func (r *InfisicalSecretReconciler) CreateInfisicalManagedKubeSecret(ctx context // create a new secret as specified by the managed secret spec of CRD newKubeSecretInstance := &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ - Name: infisicalSecret.Spec.ManagedSecret.SecretName, - Namespace: infisicalSecret.Spec.ManagedSecret.SecretNamespace, + Name: infisicalSecret.Spec.ManagedSecretReference.SecretName, + Namespace: infisicalSecret.Spec.ManagedSecretReference.SecretNamespace, + Annotations: map[string]string{ + SECRET_VERSION_ANNOTATION: encryptedSecretsResponse.ETag, + }, }, Type: "Opaque", Data: plainProcessedSecrets, @@ -70,13 +73,17 @@ func (r *InfisicalSecretReconciler) CreateInfisicalManagedKubeSecret(ctx context return nil } -func (r *InfisicalSecretReconciler) UpdateInfisicalManagedKubeSecret(ctx context.Context, managedKubeSecret corev1.Secret, secretsFromAPI []models.SingleEnvironmentVariable) error { +func (r *InfisicalSecretReconciler) UpdateInfisicalManagedKubeSecret(ctx context.Context, managedKubeSecret corev1.Secret, secretsFromAPI []util.SingleEnvironmentVariable, encryptedSecretsResponse api.GetEncryptedSecretsV2Response) error { plainProcessedSecrets := make(map[string][]byte) for _, secret := range secretsFromAPI { plainProcessedSecrets[secret.Key] = []byte(secret.Value) } managedKubeSecret.Data = plainProcessedSecrets + managedKubeSecret.ObjectMeta.Annotations = map[string]string{ + SECRET_VERSION_ANNOTATION: encryptedSecretsResponse.ETag, + } + err := r.Client.Update(ctx, &managedKubeSecret) if err != nil { return fmt.Errorf("unable to update Kubernetes secret because [%w]", err) @@ -87,87 +94,44 @@ func (r *InfisicalSecretReconciler) UpdateInfisicalManagedKubeSecret(ctx context } func (r *InfisicalSecretReconciler) ReconcileInfisicalSecret(ctx context.Context, infisicalSecret v1alpha1.InfisicalSecret) error { - infisicalToken, err := r.GetInfisicalToken(ctx, infisicalSecret) + infisicalToken, err := r.GetInfisicalTokenFromKubeSecret(ctx, infisicalSecret) r.SetInfisicalTokenLoadCondition(ctx, &infisicalSecret, err) if err != nil { return fmt.Errorf("unable to load Infisical Token from the specified Kubernetes secret with error [%w]", err) } + // Look for managed secret by name and namespace managedKubeSecret, err := r.GetKubeSecretByNamespacedName(ctx, types.NamespacedName{ - Name: infisicalSecret.Spec.ManagedSecret.SecretName, - Namespace: infisicalSecret.Spec.ManagedSecret.SecretNamespace, + Name: infisicalSecret.Spec.ManagedSecretReference.SecretName, + Namespace: infisicalSecret.Spec.ManagedSecretReference.SecretNamespace, }) if err != nil && !errors.IsNotFound(err) { return fmt.Errorf("something went wrong when fetching the managed Kubernetes secret [%w]", err) } - secretsFromApi, err := api.GetAllEnvironmentVariables(infisicalSecret.Spec.ProjectId, infisicalSecret.Spec.Environment, infisicalToken) + secretVersionBasedOnETag := "" - if err != nil { - return err + if managedKubeSecret != nil { + secretVersionBasedOnETag = managedKubeSecret.Annotations[SECRET_VERSION_ANNOTATION] } + plainTextSecretsFromApi, fullEncryptedSecretsResponse, err := util.GetPlainTextSecretsViaServiceToken(infisicalToken, secretVersionBasedOnETag) + if err != nil { + return fmt.Errorf("failed to get secrets because [err=%v]\n", err) + } + + if !fullEncryptedSecretsResponse.Modified { + fmt.Println("No secrets modified so reconcile not needed", "Etag:", fullEncryptedSecretsResponse.ETag, "Modified:", fullEncryptedSecretsResponse.Modified) + return nil + } + + fmt.Println("secret is modified so it needs to be created or updated") + if managedKubeSecret == nil { - return r.CreateInfisicalManagedKubeSecret(ctx, infisicalSecret, secretsFromApi) + return r.CreateInfisicalManagedKubeSecret(ctx, infisicalSecret, plainTextSecretsFromApi, fullEncryptedSecretsResponse) } else { - return r.UpdateInfisicalManagedKubeSecret(ctx, *managedKubeSecret, secretsFromApi) + return r.UpdateInfisicalManagedKubeSecret(ctx, *managedKubeSecret, plainTextSecretsFromApi, fullEncryptedSecretsResponse) } } - -// Conditions - -func (r *InfisicalSecretReconciler) SetReadyToSyncSecretsConditions(ctx context.Context, infisicalSecret *v1alpha1.InfisicalSecret, errorToConditionOn error) { - if infisicalSecret.Status.Conditions == nil { - infisicalSecret.Status.Conditions = []metav1.Condition{} - } - - if errorToConditionOn == nil { - meta.SetStatusCondition(&infisicalSecret.Status.Conditions, metav1.Condition{ - Type: "secrets.infisical.com/ReadyToSyncSecrets", - Status: metav1.ConditionTrue, - Reason: "OK", - Message: "Infisical controller has started syncing your secrets", - }) - } else { - meta.SetStatusCondition(&infisicalSecret.Status.Conditions, metav1.Condition{ - Type: "secrets.infisical.com/ReadyToSyncSecrets", - Status: metav1.ConditionFalse, - Reason: "Error", - Message: fmt.Sprintf("Failed to update secret because: %v", errorToConditionOn), - }) - } - - err := r.Client.Status().Update(ctx, infisicalSecret) - if err != nil { - fmt.Println("Could not set condition", err) - } -} - -func (r *InfisicalSecretReconciler) SetInfisicalTokenLoadCondition(ctx context.Context, infisicalSecret *v1alpha1.InfisicalSecret, errorToConditionOn error) { - if infisicalSecret.Status.Conditions == nil { - infisicalSecret.Status.Conditions = []metav1.Condition{} - } - - if errorToConditionOn == nil { - meta.SetStatusCondition(&infisicalSecret.Status.Conditions, metav1.Condition{ - Type: "secrets.infisical.com/LoadedInfisicalToken", - Status: metav1.ConditionTrue, - Reason: "OK", - Message: "Infisical controller has located the Infisical token in provided Kubernetes secret", - }) - } else { - meta.SetStatusCondition(&infisicalSecret.Status.Conditions, metav1.Condition{ - Type: "secrets.infisical.com/LoadedInfisicalToken", - Status: metav1.ConditionFalse, - Reason: "Error", - Message: fmt.Sprintf("Failed to load Infisical Token because: %v", errorToConditionOn), - }) - } - - err := r.Client.Status().Update(ctx, infisicalSecret) - if err != nil { - fmt.Println("Could not set condition for LoadedInfisicalToken") - } -} diff --git a/k8-operator/kubectl-install/install-secrets-operator.yaml b/k8-operator/kubectl-install/install-secrets-operator.yaml new file mode 100644 index 000000000..7862fe7c3 --- /dev/null +++ b/k8-operator/kubectl-install/install-secrets-operator.yaml @@ -0,0 +1,466 @@ +apiVersion: v1 +kind: Namespace +metadata: + labels: + app.kubernetes.io/component: manager + app.kubernetes.io/created-by: k8-operator + app.kubernetes.io/instance: system + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: namespace + app.kubernetes.io/part-of: k8-operator + control-plane: controller-manager + name: infisical-operator-system +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.10.0 + creationTimestamp: null + name: infisicalsecrets.secrets.infisical.com +spec: + group: secrets.infisical.com + names: + kind: InfisicalSecret + listKind: InfisicalSecretList + plural: infisicalsecrets + singular: infisicalsecret + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: InfisicalSecret is the Schema for the infisicalsecrets API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: InfisicalSecretSpec defines the desired state of InfisicalSecret + properties: + hostAPI: + default: https://app.infisical.com/api + description: Infisical host to pull secrets from + type: string + managedSecretReference: + properties: + secretName: + description: The name of the Kubernetes Secret + type: string + secretNamespace: + description: The name space where the Kubernetes Secret is located + type: string + required: + - secretName + - secretNamespace + type: object + tokenSecretReference: + properties: + secretName: + description: The name of the Kubernetes Secret + type: string + secretNamespace: + description: The name space where the Kubernetes Secret is located + type: string + required: + - secretName + - secretNamespace + type: object + type: object + status: + description: InfisicalSecretStatus defines the observed state of InfisicalSecret + properties: + conditions: + items: + description: "Condition contains details for one aspect of the current state of this API Resource. --- This struct is intended for direct use as an array at the field path .status.conditions. For example, \n type FooStatus struct{ // Represents the observations of a foo's current state. // Known .status.conditions.type are: \"Available\", \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge // +listType=map // +listMapKey=type Conditions []metav1.Condition `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" + properties: + lastTransitionTime: + description: lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: message is a human readable message indicating details about the transition. This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: reason contains a programmatic identifier indicating the reason for the condition's last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. --- Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be useful (see .node.status.conditions), the ability to deconflict is important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + required: + - conditions + type: object + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + labels: + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: k8-operator + app.kubernetes.io/instance: controller-manager + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: serviceaccount + app.kubernetes.io/part-of: k8-operator + name: infisical-operator-controller-manager + namespace: infisical-operator-system +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + labels: + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: k8-operator + app.kubernetes.io/instance: leader-election-role + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: role + app.kubernetes.io/part-of: k8-operator + name: infisical-operator-leader-election-role + namespace: infisical-operator-system +rules: +- apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +- apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +- apiGroups: + - "" + resources: + - events + verbs: + - create + - patch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + creationTimestamp: null + name: infisical-operator-manager-role +rules: +- apiGroups: + - "" + resources: + - secrets + verbs: + - create + - delete + - get + - list + - update + - watch +- apiGroups: + - apps + resources: + - deployments + verbs: + - get + - list + - update + - watch +- apiGroups: + - secrets.infisical.com + resources: + - infisicalsecrets + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - secrets.infisical.com + resources: + - infisicalsecrets/finalizers + verbs: + - update +- apiGroups: + - secrets.infisical.com + resources: + - infisicalsecrets/status + verbs: + - get + - patch + - update +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/component: kube-rbac-proxy + app.kubernetes.io/created-by: k8-operator + app.kubernetes.io/instance: metrics-reader + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: clusterrole + app.kubernetes.io/part-of: k8-operator + name: infisical-operator-metrics-reader +rules: +- nonResourceURLs: + - /metrics + verbs: + - get +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/component: kube-rbac-proxy + app.kubernetes.io/created-by: k8-operator + app.kubernetes.io/instance: proxy-role + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: clusterrole + app.kubernetes.io/part-of: k8-operator + name: infisical-operator-proxy-role +rules: +- apiGroups: + - authentication.k8s.io + resources: + - tokenreviews + verbs: + - create +- apiGroups: + - authorization.k8s.io + resources: + - subjectaccessreviews + verbs: + - create +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + labels: + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: k8-operator + app.kubernetes.io/instance: leader-election-rolebinding + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: rolebinding + app.kubernetes.io/part-of: k8-operator + name: infisical-operator-leader-election-rolebinding + namespace: infisical-operator-system +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: infisical-operator-leader-election-role +subjects: +- kind: ServiceAccount + name: infisical-operator-controller-manager + namespace: infisical-operator-system +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: k8-operator + app.kubernetes.io/instance: manager-rolebinding + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: clusterrolebinding + app.kubernetes.io/part-of: k8-operator + name: infisical-operator-manager-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: infisical-operator-manager-role +subjects: +- kind: ServiceAccount + name: infisical-operator-controller-manager + namespace: infisical-operator-system +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: + app.kubernetes.io/component: kube-rbac-proxy + app.kubernetes.io/created-by: k8-operator + app.kubernetes.io/instance: proxy-rolebinding + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: clusterrolebinding + app.kubernetes.io/part-of: k8-operator + name: infisical-operator-proxy-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: infisical-operator-proxy-role +subjects: +- kind: ServiceAccount + name: infisical-operator-controller-manager + namespace: infisical-operator-system +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app.kubernetes.io/component: kube-rbac-proxy + app.kubernetes.io/created-by: k8-operator + app.kubernetes.io/instance: controller-manager-metrics-service + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: service + app.kubernetes.io/part-of: k8-operator + control-plane: controller-manager + name: infisical-operator-controller-manager-metrics-service + namespace: infisical-operator-system +spec: + ports: + - name: https + port: 8443 + protocol: TCP + targetPort: https + selector: + control-plane: controller-manager +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app.kubernetes.io/component: manager + app.kubernetes.io/created-by: k8-operator + app.kubernetes.io/instance: controller-manager + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: deployment + app.kubernetes.io/part-of: k8-operator + control-plane: controller-manager + name: infisical-operator-controller-manager + namespace: infisical-operator-system +spec: + replicas: 1 + selector: + matchLabels: + control-plane: controller-manager + template: + metadata: + annotations: + kubectl.kubernetes.io/default-container: manager + labels: + control-plane: controller-manager + spec: + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/arch + operator: In + values: + - amd64 + - arm64 + - ppc64le + - s390x + - key: kubernetes.io/os + operator: In + values: + - linux + containers: + - args: + - --secure-listen-address=0.0.0.0:8443 + - --upstream=http://127.0.0.1:8080/ + - --logtostderr=true + - --v=0 + image: gcr.io/kubebuilder/kube-rbac-proxy:v0.13.1 + name: kube-rbac-proxy + ports: + - containerPort: 8443 + name: https + protocol: TCP + resources: + limits: + cpu: 500m + memory: 128Mi + requests: + cpu: 5m + memory: 64Mi + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + - args: + - --health-probe-bind-address=:8081 + - --metrics-bind-address=127.0.0.1:8080 + - --leader-elect + command: + - /manager + image: infisical/kubernetes-operator:latest + livenessProbe: + httpGet: + path: /healthz + port: 8081 + initialDelaySeconds: 15 + periodSeconds: 20 + name: manager + readinessProbe: + httpGet: + path: /readyz + port: 8081 + initialDelaySeconds: 5 + periodSeconds: 10 + resources: + limits: + cpu: 500m + memory: 128Mi + requests: + cpu: 10m + memory: 64Mi + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + securityContext: + runAsNonRoot: true + serviceAccountName: infisical-operator-controller-manager + terminationGracePeriodSeconds: 10 diff --git a/k8-operator/packages/api/api.go b/k8-operator/packages/api/api.go index ac2cc5b25..ac7c47d6d 100644 --- a/k8-operator/packages/api/api.go +++ b/k8-operator/packages/api/api.go @@ -1,179 +1,80 @@ package api import ( - "encoding/base64" - "errors" "fmt" - "regexp" - "strings" - "github.com/Infisical/infisical/k8-operator/packages/crypto" - "github.com/Infisical/infisical/k8-operator/packages/models" "github.com/go-resty/resty/v2" - "golang.org/x/crypto/nacl/box" ) -const INFISICAL_URL = "https://app.infisical.com/api" +const USER_AGENT_NAME = "k8-operator" -func GetAllEnvironmentVariables(projectId string, envName string, infisicalToken string) ([]models.SingleEnvironmentVariable, error) { - envsFromApi, err := GetSecretsFromAPIUsingInfisicalToken(infisicalToken, envName, projectId) - if err != nil { - return nil, err - } - - return SubstituteSecrets(envsFromApi), nil -} - -func GetSecretsFromAPIUsingInfisicalToken(infisicalToken string, envName string, projectId string) ([]models.SingleEnvironmentVariable, error) { - if infisicalToken == "" || projectId == "" || envName == "" { - return nil, errors.New("infisical token, project id and or environment name cannot be empty") - } - - splitToken := strings.Split(infisicalToken, ",") - JTWToken := splitToken[0] - temPrivateKey := splitToken[1] - - // create http client - httpClient := resty.New(). - SetAuthToken(JTWToken). - SetHeader("Accept", "application/json") - - var pullSecretsByInfisicalTokenResponse models.PullSecretsByInfisicalTokenResponse +func CallGetEncryptedWorkspaceKey(httpClient *resty.Client, request GetEncryptedWorkspaceKeyRequest) (GetEncryptedWorkspaceKeyResponse, error) { + endpoint := fmt.Sprintf("%v/v2/workspace/%v/encrypted-key", API_HOST_URL, request.WorkspaceId) + var result GetEncryptedWorkspaceKeyResponse response, err := httpClient. R(). - SetQueryParam("environment", envName). - SetQueryParam("channel", "cli"). - SetResult(&pullSecretsByInfisicalTokenResponse). - Get(fmt.Sprintf("%v/v1/secret/%v/service-token", INFISICAL_URL, projectId)) + SetResult(&result). + SetHeader("User-Agent", USER_AGENT_NAME). + Get(endpoint) if err != nil { - return nil, err + return GetEncryptedWorkspaceKeyResponse{}, fmt.Errorf("CallGetEncryptedWorkspaceKey: Unable to complete api request [err=%s]", err) } - if response.StatusCode() > 299 { - return nil, fmt.Errorf(response.Status()) + if response.IsError() { + return GetEncryptedWorkspaceKeyResponse{}, fmt.Errorf("CallGetEncryptedWorkspaceKey: Unsuccessful response: [response=%s]", response) } - // Get workspace key - workspaceKey, err := base64.StdEncoding.DecodeString(pullSecretsByInfisicalTokenResponse.Key.EncryptedKey) - if err != nil { - return nil, err - } - - nonce, err := base64.StdEncoding.DecodeString(pullSecretsByInfisicalTokenResponse.Key.Nonce) - if err != nil { - return nil, err - } - - senderPublicKey, err := base64.StdEncoding.DecodeString(pullSecretsByInfisicalTokenResponse.Key.Sender.PublicKey) - if err != nil { - return nil, err - } - - currentUsersPrivateKey, err := base64.StdEncoding.DecodeString(temPrivateKey) - if err != nil { - return nil, err - } - - workspaceKeyInBytes, _ := box.Open(nil, workspaceKey, (*[24]byte)(nonce), (*[32]byte)(senderPublicKey), (*[32]byte)(currentUsersPrivateKey)) - var listOfEnv []models.SingleEnvironmentVariable - - for _, secret := range pullSecretsByInfisicalTokenResponse.Secrets { - key_iv, _ := base64.StdEncoding.DecodeString(secret.SecretKey.Iv) - key_tag, _ := base64.StdEncoding.DecodeString(secret.SecretKey.Tag) - key_ciphertext, _ := base64.StdEncoding.DecodeString(secret.SecretKey.Ciphertext) - - plainTextKey, err := crypto.DecryptSymmetric(workspaceKeyInBytes, key_ciphertext, key_tag, key_iv) - if err != nil { - return nil, err - } - - value_iv, _ := base64.StdEncoding.DecodeString(secret.SecretValue.Iv) - value_tag, _ := base64.StdEncoding.DecodeString(secret.SecretValue.Tag) - value_ciphertext, _ := base64.StdEncoding.DecodeString(secret.SecretValue.Ciphertext) - - plainTextValue, err := crypto.DecryptSymmetric(workspaceKeyInBytes, value_ciphertext, value_tag, value_iv) - if err != nil { - return nil, err - } - - env := models.SingleEnvironmentVariable{ - Key: string(plainTextKey), - Value: string(plainTextValue), - } - - listOfEnv = append(listOfEnv, env) - } - - return listOfEnv, nil + return result, nil } -func getExpandedEnvVariable(secrets []models.SingleEnvironmentVariable, variableWeAreLookingFor string, hashMapOfCompleteVariables map[string]string, hashMapOfSelfRefs map[string]string) string { - if value, found := hashMapOfCompleteVariables[variableWeAreLookingFor]; found { - return value +func CallGetServiceTokenDetailsV2(httpClient *resty.Client) (GetServiceTokenDetailsResponse, error) { + var tokenDetailsResponse GetServiceTokenDetailsResponse + response, err := httpClient. + R(). + SetResult(&tokenDetailsResponse). + SetHeader("User-Agent", USER_AGENT_NAME). + Get(fmt.Sprintf("%v/v2/service-token", API_HOST_URL)) + + if err != nil { + return GetServiceTokenDetailsResponse{}, fmt.Errorf("CallGetServiceTokenDetails: Unable to complete api request [err=%s]", err) } - for _, secret := range secrets { - if secret.Key == variableWeAreLookingFor { - regex := regexp.MustCompile(`\${([^\}]*)}`) - variablesToPopulate := regex.FindAllString(secret.Value, -1) - - // case: variable is a constant so return its value - if len(variablesToPopulate) == 0 { - return secret.Value - } - - valueToEdit := secret.Value - for _, variableWithSign := range variablesToPopulate { - variableWithoutSign := strings.Trim(variableWithSign, "}") - variableWithoutSign = strings.Trim(variableWithoutSign, "${") - - // case: reference to self - if variableWithoutSign == secret.Key { - hashMapOfSelfRefs[variableWithoutSign] = variableWithoutSign - continue - } else { - var expandedVariableValue string - - if preComputedVariable, found := hashMapOfCompleteVariables[variableWithoutSign]; found { - expandedVariableValue = preComputedVariable - } else { - expandedVariableValue = getExpandedEnvVariable(secrets, variableWithoutSign, hashMapOfCompleteVariables, hashMapOfSelfRefs) - hashMapOfCompleteVariables[variableWithoutSign] = expandedVariableValue - } - - // If after expanding all the vars above, is the current var a self ref? if so no replacement needed for it - if _, found := hashMapOfSelfRefs[variableWithoutSign]; found { - continue - } else { - valueToEdit = strings.ReplaceAll(valueToEdit, variableWithSign, expandedVariableValue) - } - } - } - - return valueToEdit - - } else { - continue - } + if response.IsError() { + return GetServiceTokenDetailsResponse{}, fmt.Errorf("CallGetServiceTokenDetails: Unsuccessful response: [response=%s]", response) } - return "${" + variableWeAreLookingFor + "}" + return tokenDetailsResponse, nil } -func SubstituteSecrets(secrets []models.SingleEnvironmentVariable) []models.SingleEnvironmentVariable { - hashMapOfCompleteVariables := make(map[string]string) - hashMapOfSelfRefs := make(map[string]string) - expandedSecrets := []models.SingleEnvironmentVariable{} +func CallGetSecretsV2(httpClient *resty.Client, request GetEncryptedSecretsV2Request) (GetEncryptedSecretsV2Response, error) { + var encryptedSecretsResponse GetEncryptedSecretsV2Response + createHttpRequest := httpClient. + R(). + SetQueryParam("environment", request.Environment). + SetQueryParam("workspaceId", request.WorkspaceId). + SetResult(&encryptedSecretsResponse). + SetHeader("User-Agent", USER_AGENT_NAME) - for _, secret := range secrets { - expandedVariable := getExpandedEnvVariable(secrets, secret.Key, hashMapOfCompleteVariables, hashMapOfSelfRefs) - expandedSecrets = append(expandedSecrets, models.SingleEnvironmentVariable{ - Key: secret.Key, - Value: expandedVariable, - }) + createHttpRequest.SetHeader("If-None-Match", request.ETag) + response, err := createHttpRequest.Get(fmt.Sprintf("%v/v2/secrets", API_HOST_URL)) + + if err != nil { + return GetEncryptedSecretsV2Response{}, fmt.Errorf("CallGetSecretsV2: Unable to complete api request [err=%s]", err) } - return expandedSecrets + if response.IsError() { + return GetEncryptedSecretsV2Response{}, fmt.Errorf("CallGetSecretsV2: Unsuccessful response: [response=%s]", response) + } + + if response.StatusCode() == 304 { + encryptedSecretsResponse.Modified = false + } else { + encryptedSecretsResponse.Modified = true + } + + encryptedSecretsResponse.ETag = response.Header().Get("etag") + + return encryptedSecretsResponse, nil } diff --git a/k8-operator/packages/api/models.go b/k8-operator/packages/api/models.go new file mode 100644 index 000000000..7a34b8f7a --- /dev/null +++ b/k8-operator/packages/api/models.go @@ -0,0 +1,67 @@ +package api + +import "time" + +type GetEncryptedWorkspaceKeyRequest struct { + WorkspaceId string `json:"workspaceId"` +} + +type GetEncryptedWorkspaceKeyResponse struct { + ID string `json:"_id"` + EncryptedKey string `json:"encryptedKey"` + Nonce string `json:"nonce"` + Sender struct { + ID string `json:"_id"` + Email string `json:"email"` + RefreshVersion int `json:"refreshVersion"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` + V int `json:"__v"` + FirstName string `json:"firstName"` + LastName string `json:"lastName"` + PublicKey string `json:"publicKey"` + } `json:"sender"` + Receiver string `json:"receiver"` + Workspace string `json:"workspace"` + V int `json:"__v"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` +} + +type GetEncryptedSecretsV2Request struct { + Environment string `json:"environment"` + WorkspaceId string `json:"workspaceId"` + ETag string `json:"etag,omitempty"` +} + +type GetEncryptedSecretsV2Response struct { + Secrets []struct { + ID string `json:"_id"` + Version int `json:"version"` + Workspace string `json:"workspace"` + Type string `json:"type"` + Environment string `json:"environment"` + SecretKeyCiphertext string `json:"secretKeyCiphertext"` + SecretKeyIV string `json:"secretKeyIV"` + SecretKeyTag string `json:"secretKeyTag"` + SecretValueCiphertext string `json:"secretValueCiphertext"` + SecretValueIV string `json:"secretValueIV"` + SecretValueTag string `json:"secretValueTag"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` + User string `json:"user,omitempty"` + } `json:"secrets"` + + Modified bool `json:"modified,omitempty"` + ETag string `json:"ETag,omitempty"` +} + +type GetServiceTokenDetailsResponse struct { + ID string `json:"_id"` + Name string `json:"name"` + Workspace string `json:"workspace"` + Environment string `json:"environment"` + EncryptedKey string `json:"encryptedKey"` + Iv string `json:"iv"` + Tag string `json:"tag"` +} diff --git a/k8-operator/packages/api/variables.go b/k8-operator/packages/api/variables.go new file mode 100644 index 000000000..214b7e1d8 --- /dev/null +++ b/k8-operator/packages/api/variables.go @@ -0,0 +1,3 @@ +package api + +var API_HOST_URL string = "https://app.infisical.com/api" diff --git a/k8-operator/packages/models/api.go b/k8-operator/packages/models/api.go deleted file mode 100644 index 57420dac5..000000000 --- a/k8-operator/packages/models/api.go +++ /dev/null @@ -1,51 +0,0 @@ -package models - -import "time" - -type PullSecretsByInfisicalTokenResponse struct { - Secrets []struct { - ID string `json:"_id"` - Workspace string `json:"workspace"` - Type string `json:"type"` - Environment string `json:"environment"` - SecretKey struct { - Workspace string `json:"workspace"` - Ciphertext string `json:"ciphertext"` - Iv string `json:"iv"` - Tag string `json:"tag"` - Hash string `json:"hash"` - } `json:"secretKey"` - SecretValue struct { - Workspace string `json:"workspace"` - Ciphertext string `json:"ciphertext"` - Iv string `json:"iv"` - Tag string `json:"tag"` - Hash string `json:"hash"` - } `json:"secretValue"` - } `json:"secrets"` - Key struct { - EncryptedKey string `json:"encryptedKey"` - Nonce string `json:"nonce"` - Sender struct { - PublicKey string `json:"publicKey"` - } `json:"sender"` - Receiver struct { - RefreshVersion int `json:"refreshVersion"` - ID string `json:"_id"` - Email string `json:"email"` - CustomerID string `json:"customerId"` - CreatedAt time.Time `json:"createdAt"` - UpdatedAt time.Time `json:"updatedAt"` - V int `json:"__v"` - FirstName string `json:"firstName"` - LastName string `json:"lastName"` - PublicKey string `json:"publicKey"` - } `json:"receiver"` - Workspace string `json:"workspace"` - } `json:"key"` -} - -type SingleEnvironmentVariable struct { - Key string `json:"key"` - Value string `json:"value"` -} diff --git a/k8-operator/packages/util/secrets.go b/k8-operator/packages/util/secrets.go new file mode 100644 index 000000000..4cbf24648 --- /dev/null +++ b/k8-operator/packages/util/secrets.go @@ -0,0 +1,188 @@ +package util + +import ( + "encoding/base64" + "fmt" + "strings" + + "github.com/Infisical/infisical/k8-operator/packages/api" + "github.com/Infisical/infisical/k8-operator/packages/crypto" + "github.com/go-resty/resty/v2" +) + +type SingleEnvironmentVariable struct { + Key string `json:"key"` + Value string `json:"value"` + Type string `json:"type"` + ID string `json:"_id"` +} + +type DecodedSymmetricEncryptionDetails = struct { + Cipher []byte + IV []byte + Tag []byte + Key []byte +} + +func VerifyServiceToken(serviceToken string) (string, error) { + serviceTokenParts := strings.SplitN(serviceToken, ".", 4) + if len(serviceTokenParts) < 4 { + return "", fmt.Errorf("invalid service token entered. Please double check your service token and try again") + } + + serviceToken = fmt.Sprintf("%v.%v.%v", serviceTokenParts[0], serviceTokenParts[1], serviceTokenParts[2]) + return serviceToken, nil +} + +func GetServiceTokenDetails(infisicalToken string) (api.GetServiceTokenDetailsResponse, error) { + serviceTokenParts := strings.SplitN(infisicalToken, ".", 4) + if len(serviceTokenParts) < 4 { + return api.GetServiceTokenDetailsResponse{}, fmt.Errorf("invalid service token entered. Please double check your service token and try again") + } + + serviceToken := fmt.Sprintf("%v.%v.%v", serviceTokenParts[0], serviceTokenParts[1], serviceTokenParts[2]) + + httpClient := resty.New() + httpClient.SetAuthToken(serviceToken). + SetHeader("Accept", "application/json") + + serviceTokenDetails, err := api.CallGetServiceTokenDetailsV2(httpClient) + if err != nil { + return api.GetServiceTokenDetailsResponse{}, fmt.Errorf("unable to get service token details. [err=%v]", err) + } + + return serviceTokenDetails, nil +} + +func GetPlainTextSecretsViaServiceToken(fullServiceToken string, etag string) ([]SingleEnvironmentVariable, api.GetEncryptedSecretsV2Response, error) { + serviceTokenParts := strings.SplitN(fullServiceToken, ".", 4) + if len(serviceTokenParts) < 4 { + return nil, api.GetEncryptedSecretsV2Response{}, fmt.Errorf("invalid service token entered. Please double check your service token and try again") + } + + serviceToken := fmt.Sprintf("%v.%v.%v", serviceTokenParts[0], serviceTokenParts[1], serviceTokenParts[2]) + + httpClient := resty.New() + + httpClient.SetAuthToken(serviceToken). + SetHeader("Accept", "application/json") + + serviceTokenDetails, err := api.CallGetServiceTokenDetailsV2(httpClient) + if err != nil { + return nil, api.GetEncryptedSecretsV2Response{}, fmt.Errorf("unable to get service token details. [err=%v]", err) + } + + encryptedSecretsResponse, err := api.CallGetSecretsV2(httpClient, api.GetEncryptedSecretsV2Request{ + WorkspaceId: serviceTokenDetails.Workspace, + Environment: serviceTokenDetails.Environment, + ETag: etag, + }) + + if err != nil { + return nil, api.GetEncryptedSecretsV2Response{}, err + } + + decodedSymmetricEncryptionDetails, err := GetBase64DecodedSymmetricEncryptionDetails(serviceTokenParts[3], serviceTokenDetails.EncryptedKey, serviceTokenDetails.Iv, serviceTokenDetails.Tag) + if err != nil { + return nil, api.GetEncryptedSecretsV2Response{}, fmt.Errorf("unable to decode symmetric encryption details [err=%v]", err) + } + + plainTextWorkspaceKey, err := crypto.DecryptSymmetric([]byte(serviceTokenParts[3]), decodedSymmetricEncryptionDetails.Cipher, decodedSymmetricEncryptionDetails.Tag, decodedSymmetricEncryptionDetails.IV) + if err != nil { + return nil, api.GetEncryptedSecretsV2Response{}, fmt.Errorf("unable to decrypt the required workspace key") + } + + plainTextSecrets, err := GetPlainTextSecrets(plainTextWorkspaceKey, encryptedSecretsResponse) + if err != nil { + return nil, api.GetEncryptedSecretsV2Response{}, fmt.Errorf("unable to decrypt your secrets [err=%v]", err) + } + + return plainTextSecrets, encryptedSecretsResponse, nil +} + +func GetBase64DecodedSymmetricEncryptionDetails(key string, cipher string, IV string, tag string) (DecodedSymmetricEncryptionDetails, error) { + cipherx, err := base64.StdEncoding.DecodeString(cipher) + if err != nil { + return DecodedSymmetricEncryptionDetails{}, fmt.Errorf("Base64DecodeSymmetricEncryptionDetails: Unable to decode cipher text [err=%v]", err) + } + + keyx, err := base64.StdEncoding.DecodeString(key) + if err != nil { + return DecodedSymmetricEncryptionDetails{}, fmt.Errorf("Base64DecodeSymmetricEncryptionDetails: Unable to decode key [err=%v]", err) + } + + IVx, err := base64.StdEncoding.DecodeString(IV) + if err != nil { + return DecodedSymmetricEncryptionDetails{}, fmt.Errorf("Base64DecodeSymmetricEncryptionDetails: Unable to decode IV [err=%v]", err) + } + + tagx, err := base64.StdEncoding.DecodeString(tag) + if err != nil { + return DecodedSymmetricEncryptionDetails{}, fmt.Errorf("Base64DecodeSymmetricEncryptionDetails: Unable to decode tag [err=%v]", err) + } + + return DecodedSymmetricEncryptionDetails{ + Key: keyx, + Cipher: cipherx, + IV: IVx, + Tag: tagx, + }, nil +} + +func GetPlainTextSecrets(key []byte, encryptedSecretsResponse api.GetEncryptedSecretsV2Response) ([]SingleEnvironmentVariable, error) { + plainTextSecrets := []SingleEnvironmentVariable{} + for _, secret := range encryptedSecretsResponse.Secrets { + // Decrypt key + key_iv, err := base64.StdEncoding.DecodeString(secret.SecretKeyIV) + if err != nil { + return nil, fmt.Errorf("unable to decode secret IV for secret key") + } + + key_tag, err := base64.StdEncoding.DecodeString(secret.SecretKeyTag) + if err != nil { + return nil, fmt.Errorf("unable to decode secret authentication tag for secret key") + } + + key_ciphertext, err := base64.StdEncoding.DecodeString(secret.SecretKeyCiphertext) + if err != nil { + return nil, fmt.Errorf("unable to decode secret cipher text for secret key") + } + + plainTextKey, err := crypto.DecryptSymmetric(key, key_ciphertext, key_tag, key_iv) + if err != nil { + return nil, fmt.Errorf("unable to symmetrically decrypt secret key") + } + + // Decrypt value + value_iv, err := base64.StdEncoding.DecodeString(secret.SecretValueIV) + if err != nil { + return nil, fmt.Errorf("unable to decode secret IV for secret value") + } + + value_tag, err := base64.StdEncoding.DecodeString(secret.SecretValueTag) + if err != nil { + return nil, fmt.Errorf("unable to decode secret authentication tag for secret value") + } + + value_ciphertext, _ := base64.StdEncoding.DecodeString(secret.SecretValueCiphertext) + if err != nil { + return nil, fmt.Errorf("unable to decode secret cipher text for secret key") + } + + plainTextValue, err := crypto.DecryptSymmetric(key, value_ciphertext, value_tag, value_iv) + if err != nil { + return nil, fmt.Errorf("unable to symmetrically decrypt secret value") + } + + plainTextSecret := SingleEnvironmentVariable{ + Key: string(plainTextKey), + Value: string(plainTextValue), + Type: string(secret.Type), + ID: secret.ID, + } + + plainTextSecrets = append(plainTextSecrets, plainTextSecret) + } + + return plainTextSecrets, nil +} diff --git a/package-lock.json b/package-lock.json index 3a4157902..cf02a1760 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,8 +8,7 @@ "license": "ISC", "devDependencies": { "eslint": "^8.29.0", - "husky": "^8.0.2", - "prettier": "^2.8.1" + "husky": "^8.0.2" } }, "node_modules/@eslint/eslintrc": { @@ -899,21 +898,6 @@ "node": ">= 0.8.0" } }, - "node_modules/prettier": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.1.tgz", - "integrity": "sha512-lqGoSJBQNJidqCHE80vqZJHWHRFoNYsSpP9AjFhlhi9ODCJA541svILes/+/1GM3VaL/abZi7cpFzOpdR9UPKg==", - "dev": true, - "bin": { - "prettier": "bin-prettier.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, "node_modules/punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", @@ -1809,12 +1793,6 @@ "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true }, - "prettier": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.1.tgz", - "integrity": "sha512-lqGoSJBQNJidqCHE80vqZJHWHRFoNYsSpP9AjFhlhi9ODCJA541svILes/+/1GM3VaL/abZi7cpFzOpdR9UPKg==", - "dev": true - }, "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", diff --git a/package.json b/package.json index b0d02f3a0..4d042a13d 100644 --- a/package.json +++ b/package.json @@ -14,15 +14,12 @@ "prepare": "husky install" }, "lint-staged": { - "**/*": "prettier --write --ignore-unknown", "*.{js,jsx,ts,tsx}": [ - "eslint --fix", - "prettier --write" + "eslint --fix" ] }, "devDependencies": { "eslint": "^8.29.0", - "husky": "^8.0.2", - "prettier": "^2.8.1" + "husky": "^8.0.2" } }