diff --git a/.github/workflows/admin-domain-service-release.yml b/.github/workflows/admin-domain-service-release.yml new file mode 100644 index 000000000..8846b0ce2 --- /dev/null +++ b/.github/workflows/admin-domain-service-release.yml @@ -0,0 +1,125 @@ +name: Release Admin-domain-service. +on: + workflow_call: + inputs: + aks_deployment: + required: true + type: boolean + description: "Deploy to AKS" + secrets: + WSO2_BOT_TOKEN: + required: true + WSO2_BOT_USER: + required: true + WSO2_BOT_EMAIL: + required: true + DOCKER_ORGANIZATION: + required: true + AZURE_ACR_NAME: + required: true + AZURE_CREDENTIALS: + required: true + workflow_dispatch: + inputs: + release_version: + required: true + type: string + description: "Release Version" + next_version: + type: string + description: "Next Development Version" + pull_request_target: + types: + - closed + - opened + - synchronize + paths: + - '**/admin/admin-domain-service/**' + - '**/common-bal-libs/**' + branches: + - 'main' +concurrency: + group: admin-domain-service-${{ github.event.number || github.run_id }} + cancel-in-progress: true +env: + GH_TOKEN: ${{ secrets.WSO2_BOT_TOKEN }} +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Cache Ballerina. + uses: actions/cache@v3 + id: cache + with: + path: "ballerina-dist/*.deb" + key: "ballerina-2201.5.0" + - name: Download Ballerina distribution. + shell: sh + run: | + mkdir -p ballerina-dist + wget 'https://dist.ballerina.io/downloads/2201.5.0/ballerina-2201.5.0-swan-lake-linux-x64.deb' -P ballerina-dist + if: steps.cache.outputs.cache-hit != 'true' + - name: Install Ballerina distribution. + shell: sh + run: "sudo dpkg -i ballerina-dist/ballerina-2201.5.0-swan-lake-linux-x64.deb" + - name: Verify Ballerina Version + shell: sh + run: "bal -v" + - name: Checkout apk-repo + uses: actions/checkout@v3 + with: + fetch-depth: "0" + path: apk-repo + token: ${{ secrets.WSO2_BOT_TOKEN }} + - name: Set release username and email + shell: sh + run: | + git config --global user.name ${{ secrets.WSO2_BOT_USER }} + git config --global user.email ${{ secrets.WSO2_BOT_EMAIL }} + - name: checkout pull request and merge. + shell: sh + if: github.event_name == 'pull_request_target' && github.event.action == 'opened' || github.event.action == 'synchronize' + run: | + cd apk-repo + gh pr checkout ${{ github.event.number }} -b pr-${{ github.event.number }} + git checkout pr-${{ github.event.number }} + git merge origin/main + + - name: build common bal libs + run: | + cd apk-repo/common-bal-libs + ./gradlew build + - name: Run Gradle build + if: github.event_name == 'workflow_dispatch' && github.event.inputs.release_version != '' && github.event.inputs.next_version != '' + run: | + cd apk-repo/admin/admin-domain-service + ./gradlew release -Prelease.useAutomaticVersion=true -Pdocker_organization=${{ secrets.DOCKER_ORGANIZATION }} -Pdocker_username=${{ secrets.DOCKER_USERNAME }} -Pdocker_password=${{ secrets.DOCKER_PASSWORD }} -Prelease.releaseVersion=${{ github.event.inputs.release_version }} -Prelease.newVersion=${{ github.event.inputs.next_version }} -PmultiArch=true + ./gradlew :ballerina:commit_toml_files + git push + - name: Run Gradle Build + run: | + cd apk-repo/admin/admin-domain-service + ./gradlew build + - name: Run Gradle Build + if: github.event_name == 'pull_request_target' && github.event.action == 'closed' && github.event.pull_request.merged == true + run: | + cd apk-repo/admin/admin-domain-service + ./gradlew docker:docker_push -Pdocker_organization=${{ secrets.DOCKER_ORGANIZATION }} -Pdocker_username=${{ secrets.DOCKER_USERNAME }} -Pdocker_password=${{ secrets.DOCKER_PASSWORD }} -Pimage_version=latest -PmultiArch=true + ./gradlew docker:docker_push -Pdocker_organization=${{ secrets.DOCKER_ORGANIZATION }} -Pdocker_username=${{ secrets.DOCKER_USERNAME }} -Pdocker_password=${{ secrets.DOCKER_PASSWORD }} -Pimage_version=${{ github.sha }} -PmultiArch=true + - name: Login to azure. + if: ${{inputs.aks_deployment}} + uses: azure/login@v1 + with: + creds: ${{ secrets.AZURE_CREDENTIALS }} + - name: Push Docker images to aks. + if: ${{inputs.aks_deployment}} + run: | + az acr login -n ${{ secrets.AZURE_ACR_NAME }} + cd apk-repo/admin/admin-domain-service + ./gradlew docker:docker_push -Pdocker_organization=${{ secrets.DOCKER_ORGANIZATION }} -Pimage_version=${{ github.sha }} -PmultiArch=true + - name: run codecov + uses: codecov/codecov-action@v3 + with: + verbose: true # optional (default = false) + directory: apk-repo/admin/admin-domain-service + flags: admin-domain-service \ No newline at end of file diff --git a/.github/workflows/backoffice-release.yml b/.github/workflows/backoffice-release.yml new file mode 100644 index 000000000..d34e76de1 --- /dev/null +++ b/.github/workflows/backoffice-release.yml @@ -0,0 +1,126 @@ +name: Release Backoffice-domain-service. +on: + workflow_call: + inputs: + aks_deployment: + required: true + type: boolean + description: "Deploy to AKS" + secrets: + WSO2_BOT_TOKEN: + required: true + WSO2_BOT_USER: + required: true + WSO2_BOT_EMAIL: + required: true + DOCKER_ORGANIZATION: + required: true + AZURE_ACR_NAME: + required: true + AZURE_CREDENTIALS: + required: true + + workflow_dispatch: + inputs: + release_version: + required: true + type: string + description: "Release Version" + next_version: + type: string + description: "Next Development Version" + pull_request_target: + types: + - closed + - opened + - synchronize + paths: + - '**/backoffice/backoffice-domain-service/**' + - '**/common-bal-libs/**' + branches: + - 'main' +concurrency: + group: backoffice-${{ github.event.number || github.run_id }} + cancel-in-progress: true +env: + GH_TOKEN: ${{ secrets.WSO2_BOT_TOKEN }} +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Cache Ballerina. + uses: actions/cache@v3 + id: cache + with: + path: "ballerina-dist/*.deb" + key: "ballerina-2201.5.0" + - name: Download Ballerina distribution. + shell: sh + run: | + mkdir -p ballerina-dist + wget 'https://dist.ballerina.io/downloads/2201.5.0/ballerina-2201.5.0-swan-lake-linux-x64.deb' -P ballerina-dist + if: steps.cache.outputs.cache-hit != 'true' + - name: Install Ballerina distribution. + shell: sh + run: "sudo dpkg -i ballerina-dist/ballerina-2201.5.0-swan-lake-linux-x64.deb" + - name: Verify Ballerina Version + shell: sh + run: "bal -v" + - name: Checkout apk-repo + uses: actions/checkout@v3 + with: + fetch-depth: "0" + path: apk-repo + token: ${{ secrets.WSO2_BOT_TOKEN }} + - name: Set release username and email + shell: sh + run: | + git config --global user.name ${{ secrets.WSO2_BOT_USER }} + git config --global user.email ${{ secrets.WSO2_BOT_EMAIL }} + - name: checkout pull request and merge. + shell: sh + if: github.event_name == 'pull_request_target' && github.event.action == 'opened' || github.event.action == 'synchronize' + run: | + cd apk-repo + gh pr checkout ${{ github.event.number }} -b pr-${{ github.event.number }} + git checkout pr-${{ github.event.number }} + git merge origin/main + - name: build common bal libs + run: | + cd apk-repo/common-bal-libs + ./gradlew build + - name: Run Gradle build + if: github.event_name == 'workflow_dispatch' && github.event.inputs.release_version != '' && github.event.inputs.next_version != '' + run: | + cd apk-repo/backoffice/backoffice-domain-service + ./gradlew release -Prelease.useAutomaticVersion=true -Pdocker_organization=${{ secrets.DOCKER_ORGANIZATION }} -Pdocker_username=${{ secrets.DOCKER_USERNAME }} -Pdocker_password=${{ secrets.DOCKER_PASSWORD }} -Prelease.releaseVersion=${{ github.event.inputs.release_version }} -Prelease.newVersion=${{ github.event.inputs.next_version }} -PmultiArch=true + ./gradlew :ballerina:commit_toml_files + git push + - name: Run Gradle Build + run: | + cd apk-repo/backoffice/backoffice-domain-service + ./gradlew build + - name: Run Gradle Build + if: github.event_name == 'pull_request_target' && github.event.action == 'closed' && github.event.pull_request.merged == true + run: | + cd apk-repo/backoffice/backoffice-domain-service + ./gradlew docker:docker_push -Pdocker_organization=${{ secrets.DOCKER_ORGANIZATION }} -Pdocker_username=${{ secrets.DOCKER_USERNAME }} -Pdocker_password=${{ secrets.DOCKER_PASSWORD }} -Pimage_version=latest -PmultiArch=true + ./gradlew docker:docker_push -Pdocker_organization=${{ secrets.DOCKER_ORGANIZATION }} -Pdocker_username=${{ secrets.DOCKER_USERNAME }} -Pdocker_password=${{ secrets.DOCKER_PASSWORD }} -Pimage_version=${{ github.sha }} -PmultiArch=true + - name: Login to azure. + if: ${{inputs.aks_deployment}} + uses: azure/login@v1 + with: + creds: ${{ secrets.AZURE_CREDENTIALS }} + - name: Push Docker images to aks. + if: ${{inputs.aks_deployment}} + run: | + az acr login -n ${{ secrets.AZURE_ACR_NAME }} + cd apk-repo/backoffice/backoffice-domain-service + ./gradlew docker:docker_push -Pdocker_organization=${{ secrets.DOCKER_ORGANIZATION }} -Pimage_version=${{ github.sha }} -PmultiArch=true + - name: run codecov + uses: codecov/codecov-action@v3 + with: + verbose: true # optional (default = false) + directory: apk-repo/backoffice/backoffice-domain-service + flags: backoffice-domain-service + \ No newline at end of file diff --git a/.github/workflows/devportal-domain-service-release.yml b/.github/workflows/devportal-domain-service-release.yml new file mode 100644 index 000000000..974a07d94 --- /dev/null +++ b/.github/workflows/devportal-domain-service-release.yml @@ -0,0 +1,127 @@ +name: Release Devportal-domain-service. +on: + workflow_call: + inputs: + aks_deployment: + required: true + type: boolean + description: "Deploy to AKS" + secrets: + WSO2_BOT_TOKEN: + required: true + WSO2_BOT_USER: + required: true + WSO2_BOT_EMAIL: + required: true + DOCKER_ORGANIZATION: + required: true + AZURE_ACR_NAME: + required: true + AZURE_CREDENTIALS: + required: true + + workflow_dispatch: + inputs: + release_version: + required: true + type: string + description: "Release Version" + next_version: + type: string + description: "Next Development Version" + pull_request_target: + types: + - closed + - opened + - synchronize + paths: + - '**/devportal/devportal-domain-service/**' + - '**/common-bal-libs/**' + branches: + - 'main' +env: + GH_TOKEN: ${{ secrets.WSO2_BOT_TOKEN }} +concurrency: + group: devportal-domain-service-${{ github.event.number || github.run_id }} + cancel-in-progress: true +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Cache Ballerina. + uses: actions/cache@v3 + id: cache + with: + path: "ballerina-dist/*.deb" + key: "ballerina-2201.5.0" + - name: Download Ballerina distribution. + shell: sh + run: | + mkdir -p ballerina-dist + wget 'https://dist.ballerina.io/downloads/2201.5.0/ballerina-2201.5.0-swan-lake-linux-x64.deb' -P ballerina-dist + if: steps.cache.outputs.cache-hit != 'true' + + - name: Install Ballerina distribution. + shell: sh + run: "sudo dpkg -i ballerina-dist/ballerina-2201.5.0-swan-lake-linux-x64.deb" + - name: Verify Ballerina Version + shell: sh + run: "bal -v" + - name: Checkout apk-repo + uses: actions/checkout@v3 + with: + fetch-depth: "0" + path: apk-repo + token: ${{ secrets.WSO2_BOT_TOKEN }} + - name: Set release username and email + shell: sh + run: | + git config --global user.name ${{ secrets.WSO2_BOT_USER }} + git config --global user.email ${{ secrets.WSO2_BOT_EMAIL }} + - name: checkout pull request and merge. + shell: sh + if: github.event_name == 'pull_request_target' && github.event.action == 'opened' || github.event.action == 'synchronize' + run: | + cd apk-repo + gh pr checkout ${{ github.event.number }} -b pr-${{ github.event.number }} + git checkout pr-${{ github.event.number }} + git merge origin/main + - name: build common bal libs + run: | + cd apk-repo/common-bal-libs + ./gradlew build + - name: Run Gradle build + if: github.event_name == 'workflow_dispatch' && github.event.inputs.release_version != '' && github.event.inputs.next_version != '' + run: | + cd apk-repo/devportal/devportal-domain-service + ./gradlew release -Prelease.useAutomaticVersion=true -Pdocker_organization=${{ secrets.DOCKER_ORGANIZATION }} -Pdocker_username=${{ secrets.DOCKER_USERNAME }} -Pdocker_password=${{ secrets.DOCKER_PASSWORD }} -Prelease.releaseVersion=${{ github.event.inputs.release_version }} -Prelease.newVersion=${{ github.event.inputs.next_version }} -PmultiArch=true + ./gradlew :ballerina:commit_toml_files + git push + - name: Run Gradle Build + run: | + cd apk-repo/devportal/devportal-domain-service + ./gradlew build + - name: Run Gradle Build + if: github.event_name == 'pull_request_target' && github.event.action == 'closed' && github.event.pull_request.merged == true + run: | + cd apk-repo/devportal/devportal-domain-service + ./gradlew docker:docker_push -Pdocker_organization=${{ secrets.DOCKER_ORGANIZATION }} -Pdocker_username=${{ secrets.DOCKER_USERNAME }} -Pdocker_password=${{ secrets.DOCKER_PASSWORD }} -Pimage_version=latest -PmultiArch=true + ./gradlew docker:docker_push -Pdocker_organization=${{ secrets.DOCKER_ORGANIZATION }} -Pdocker_username=${{ secrets.DOCKER_USERNAME }} -Pdocker_password=${{ secrets.DOCKER_PASSWORD }} -Pimage_version=${{ github.sha }} -PmultiArch=true + - name: Login to azure. + if: ${{inputs.aks_deployment}} + uses: azure/login@v1 + with: + creds: ${{ secrets.AZURE_CREDENTIALS }} + - name: Push Docker images to aks. + if: ${{inputs.aks_deployment}} + run: | + az acr login -n ${{ secrets.AZURE_ACR_NAME }} + cd apk-repo/devportal/devportal-domain-service + ./gradlew docker:docker_push -Pdocker_organization=${{ secrets.DOCKER_ORGANIZATION }} -Pimage_version=${{ github.sha }} -PmultiArch=true + - name: run codecov + uses: codecov/codecov-action@v3 + with: + verbose: true # optional (default = false) + directory: apk-repo/devportal/devportal-domain-service + flags: devportal-domain-service + \ No newline at end of file diff --git a/.github/workflows/management-server-release.yml b/.github/workflows/management-server-release.yml new file mode 100644 index 000000000..5b6b6aed1 --- /dev/null +++ b/.github/workflows/management-server-release.yml @@ -0,0 +1,113 @@ +name: Release Management Server. +on: + workflow_call: + inputs: + aks_deployment: + required: true + type: boolean + description: "Deploy to AKS" + secrets: + WSO2_BOT_TOKEN: + required: true + WSO2_BOT_USER: + required: true + WSO2_BOT_EMAIL: + required: true + DOCKER_ORGANIZATION: + required: true + AZURE_ACR_NAME: + required: true + AZURE_CREDENTIALS: + required: true + + workflow_dispatch: + inputs: + release_version: + required: true + type: string + description: "Release Version" + next_version: + type: string + description: "Next Development Version" + pull_request_target: + types: + - closed + - opened + - synchronize + paths: + - '**/management-server/**' + branches: + - 'main' +concurrency: + group: management-server-${{ github.event.number || github.run_id }} + cancel-in-progress: true +env: + GH_TOKEN: ${{ secrets.WSO2_BOT_TOKEN }} + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Install Go + uses: actions/setup-go@v3 + with: + go-version: "1.19" + - name: Install Revive + shell: sh + run: | + go install github.com/mgechev/revive@latest + + - name: Checkout apk-repo. + uses: actions/checkout@v3 + with: + fetch-depth: "0" + path: apk-repo + token: ${{ secrets.WSO2_BOT_TOKEN }} + - name: Set release username and email + shell: sh + run: | + git config --global user.name ${{ secrets.WSO2_BOT_USER }} + git config --global user.email ${{ secrets.WSO2_BOT_EMAIL }} + - name: checkout pull request and merge. + shell: sh + if: github.event_name == 'pull_request_target' && github.event.action == 'opened' || github.event.action == 'synchronize' + run: | + cd apk-repo + gh pr checkout ${{ github.event.number }} -b pr-${{ github.event.number }} + git checkout pr-${{ github.event.number }} + git merge origin/main + + - name: Run Gradle build + if: github.event_name == 'workflow_dispatch' && github.event.inputs.release_version != '' && github.event.inputs.next_version != '' + shell: sh + run: | + cd apk-repo/management-server + ./gradlew release -Prelease.useAutomaticVersion=true -Pdocker_organization=${{ secrets.DOCKER_ORGANIZATION }} -Pdocker_username=${{ secrets.DOCKER_USERNAME }} -Pdocker_password=${{ secrets.DOCKER_PASSWORD }} -Prelease.releaseVersion=${{ github.event.inputs.release_version }} -Prelease.newVersion=${{ github.event.inputs.next_version }} -PmultiArch=true + + - name: Run Gradle Build + run: | + cd apk-repo/management-server + ./gradlew build + - name: Run Gradle Build + if: github.event_name == 'pull_request_target' && github.event.action == 'closed' && github.event.pull_request.merged == true + run: | + cd apk-repo/management-server + ./gradlew docker_push -Pdocker_organization=${{ secrets.DOCKER_ORGANIZATION }} -Pdocker_username=${{ secrets.DOCKER_USERNAME }} -Pdocker_password=${{ secrets.DOCKER_PASSWORD }} -Pimage_version=latest -PmultiArch=true + ./gradlew docker_push -Pdocker_organization=${{ secrets.DOCKER_ORGANIZATION }} -Pdocker_username=${{ secrets.DOCKER_USERNAME }} -Pdocker_password=${{ secrets.DOCKER_PASSWORD }} -Pimage_version=${{ github.sha }} -PmultiArch=true + - name: Login to azure. + if: ${{inputs.aks_deployment}} + uses: azure/login@v1 + with: + creds: ${{ secrets.AZURE_CREDENTIALS }} + - name: Push Docker images to aks. + if: ${{inputs.aks_deployment}} + run: | + az acr login -n ${{ secrets.AZURE_ACR_NAME }} + cd apk-repo/management-server + ./gradlew docker_push -Pdocker_organization=${{ secrets.DOCKER_ORGANIZATION }} -Pimage_version=${{ github.sha }} -PmultiArch=true + - name: run codecov + uses: codecov/codecov-action@v3 + with: + verbose: true # optional (default = false) + directory: apk-repo/idp/management-server + flags: management-server \ No newline at end of file diff --git a/admin/admin-domain-service/README.md b/admin/admin-domain-service/README.md new file mode 100644 index 000000000..957e3c219 --- /dev/null +++ b/admin/admin-domain-service/README.md @@ -0,0 +1,2 @@ +## Admin Domain Service + diff --git a/admin/admin-domain-service/ballerina/Ballerina.toml b/admin/admin-domain-service/ballerina/Ballerina.toml new file mode 100644 index 000000000..d349336d7 --- /dev/null +++ b/admin/admin-domain-service/ballerina/Ballerina.toml @@ -0,0 +1,25 @@ +[package] +org = "wso2" +name = "admin_service" +version = "0.0.1-SNAPSHOT" +distribution = "2201.8.0" + +[[dependency]] +org = "wso2" +name = "apk_common_lib" +version = "0.0.1-SNAPSHOT" +repository = "local" + +[[dependency]] +org = "wso2" +name = "apk_keymanager_libs" +version="0.0.1-SNAPSHOT" +repository = "local" + +[build-options] +observabilityIncluded = true + +[[platform.java11.dependency]] +groupId = "org.postgresql" +artifactId = "postgresql" +version = "42.2.20" diff --git a/admin/admin-domain-service/ballerina/Ballerina.toml.template b/admin/admin-domain-service/ballerina/Ballerina.toml.template new file mode 100644 index 000000000..b89c6c980 --- /dev/null +++ b/admin/admin-domain-service/ballerina/Ballerina.toml.template @@ -0,0 +1,25 @@ +[package] +org = "wso2" +name = "admin_service" +version = "PROJECT_VERSION" +distribution = "2201.8.0" + +[[dependency]] +org = "wso2" +name = "apk_common_lib" +version = "0.0.1-SNAPSHOT" +repository = "local" + +[[dependency]] +org = "wso2" +name = "apk_keymanager_libs" +version="0.0.1-SNAPSHOT" +repository = "local" + +[build-options] +observabilityIncluded = true + +[[platform.java11.dependency]] +groupId = "org.postgresql" +artifactId = "postgresql" +version = "42.2.20" diff --git a/admin/admin-domain-service/ballerina/Config.toml b/admin/admin-domain-service/ballerina/Config.toml new file mode 100644 index 000000000..33841ac9a --- /dev/null +++ b/admin/admin-domain-service/ballerina/Config.toml @@ -0,0 +1,15 @@ +# Sample configurations +[wso2.admin_service.datasourceConfiguration] +description = "" +url = "" +host = "" +port = 0 +databaseName = "" +username = "" +password = "" +validationTimeout = 0 +testQuery = "" +driver="" + +[wso2.admin_service.throttleConfig.blockCondition] +enabled = true diff --git a/admin/admin-domain-service/ballerina/Dependencies.toml b/admin/admin-domain-service/ballerina/Dependencies.toml new file mode 100644 index 000000000..61172bffc --- /dev/null +++ b/admin/admin-domain-service/ballerina/Dependencies.toml @@ -0,0 +1,435 @@ +# AUTO-GENERATED FILE. DO NOT MODIFY. + +# This file is auto-generated by Ballerina for managing dependency versions. +# It should not be modified by hand. + +[ballerina] +dependencies-toml-version = "2" +distribution-version = "2201.8.0" + +[[package]] +org = "ballerina" +name = "auth" +version = "2.10.0" +dependencies = [ + {org = "ballerina", name = "crypto"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.array"}, + {org = "ballerina", name = "lang.string"}, + {org = "ballerina", name = "log"} +] + +[[package]] +org = "ballerina" +name = "cache" +version = "3.7.0" +dependencies = [ + {org = "ballerina", name = "constraint"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "task"}, + {org = "ballerina", name = "time"} +] + +[[package]] +org = "ballerina" +name = "constraint" +version = "1.4.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] +modules = [ + {org = "ballerina", packageName = "constraint", moduleName = "constraint"} +] + +[[package]] +org = "ballerina" +name = "crypto" +version = "2.5.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "time"} +] + +[[package]] +org = "ballerina" +name = "file" +version = "1.9.0" +dependencies = [ + {org = "ballerina", name = "io"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "os"}, + {org = "ballerina", name = "time"} +] + +[[package]] +org = "ballerina" +name = "http" +version = "2.10.1" +dependencies = [ + {org = "ballerina", name = "auth"}, + {org = "ballerina", name = "cache"}, + {org = "ballerina", name = "constraint"}, + {org = "ballerina", name = "crypto"}, + {org = "ballerina", name = "file"}, + {org = "ballerina", name = "io"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "jwt"}, + {org = "ballerina", name = "lang.array"}, + {org = "ballerina", name = "lang.decimal"}, + {org = "ballerina", name = "lang.int"}, + {org = "ballerina", name = "lang.regexp"}, + {org = "ballerina", name = "lang.runtime"}, + {org = "ballerina", name = "lang.string"}, + {org = "ballerina", name = "lang.value"}, + {org = "ballerina", name = "log"}, + {org = "ballerina", name = "mime"}, + {org = "ballerina", name = "oauth2"}, + {org = "ballerina", name = "observe"}, + {org = "ballerina", name = "time"}, + {org = "ballerina", name = "url"} +] +modules = [ + {org = "ballerina", packageName = "http", moduleName = "http"}, + {org = "ballerina", packageName = "http", moduleName = "http.httpscerr"} +] + +[[package]] +org = "ballerina" +name = "io" +version = "1.6.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.value"} +] + +[[package]] +org = "ballerina" +name = "jballerina.java" +version = "0.0.0" + +[[package]] +org = "ballerina" +name = "jballerina.java.arrays" +version = "1.4.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] + +[[package]] +org = "ballerina" +name = "jwt" +version = "2.10.0" +dependencies = [ + {org = "ballerina", name = "cache"}, + {org = "ballerina", name = "crypto"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.int"}, + {org = "ballerina", name = "lang.string"}, + {org = "ballerina", name = "log"}, + {org = "ballerina", name = "time"} +] + +[[package]] +org = "ballerina" +name = "lang.__internal" +version = "0.0.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.object"} +] + +[[package]] +org = "ballerina" +name = "lang.array" +version = "0.0.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.__internal"} +] + +[[package]] +org = "ballerina" +name = "lang.decimal" +version = "0.0.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] + +[[package]] +org = "ballerina" +name = "lang.error" +version = "0.0.0" +scope = "testOnly" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] + +[[package]] +org = "ballerina" +name = "lang.int" +version = "0.0.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.__internal"}, + {org = "ballerina", name = "lang.object"} +] + +[[package]] +org = "ballerina" +name = "lang.object" +version = "0.0.0" + +[[package]] +org = "ballerina" +name = "lang.regexp" +version = "0.0.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] + +[[package]] +org = "ballerina" +name = "lang.runtime" +version = "0.0.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] + +[[package]] +org = "ballerina" +name = "lang.string" +version = "0.0.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.regexp"} +] + +[[package]] +org = "ballerina" +name = "lang.value" +version = "0.0.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] +modules = [ + {org = "ballerina", packageName = "lang.value", moduleName = "lang.value"} +] + +[[package]] +org = "ballerina" +name = "log" +version = "2.9.0" +dependencies = [ + {org = "ballerina", name = "io"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.value"}, + {org = "ballerina", name = "observe"} +] +modules = [ + {org = "ballerina", packageName = "log", moduleName = "log"} +] + +[[package]] +org = "ballerina" +name = "mime" +version = "2.9.0" +dependencies = [ + {org = "ballerina", name = "io"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.int"} +] + +[[package]] +org = "ballerina" +name = "oauth2" +version = "2.10.0" +dependencies = [ + {org = "ballerina", name = "cache"}, + {org = "ballerina", name = "crypto"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "log"}, + {org = "ballerina", name = "time"}, + {org = "ballerina", name = "url"} +] + +[[package]] +org = "ballerina" +name = "observe" +version = "1.2.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] + +[[package]] +org = "ballerina" +name = "os" +version = "1.8.0" +dependencies = [ + {org = "ballerina", name = "io"}, + {org = "ballerina", name = "jballerina.java"} +] + +[[package]] +org = "ballerina" +name = "regex" +version = "1.4.3" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.string"} +] + +[[package]] +org = "ballerina" +name = "sql" +version = "1.11.0" +dependencies = [ + {org = "ballerina", name = "io"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.object"}, + {org = "ballerina", name = "time"} +] +modules = [ + {org = "ballerina", packageName = "sql", moduleName = "sql"} +] + +[[package]] +org = "ballerina" +name = "task" +version = "2.5.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "time"} +] + +[[package]] +org = "ballerina" +name = "test" +version = "0.0.0" +scope = "testOnly" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.error"} +] +modules = [ + {org = "ballerina", packageName = "test", moduleName = "test"} +] + +[[package]] +org = "ballerina" +name = "time" +version = "2.4.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] +modules = [ + {org = "ballerina", packageName = "time", moduleName = "time"} +] + +[[package]] +org = "ballerina" +name = "url" +version = "2.4.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] + +[[package]] +org = "ballerina" +name = "uuid" +version = "1.7.0" +dependencies = [ + {org = "ballerina", name = "crypto"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.int"}, + {org = "ballerina", name = "time"} +] +modules = [ + {org = "ballerina", packageName = "uuid", moduleName = "uuid"} +] + +[[package]] +org = "ballerinai" +name = "observe" +version = "0.0.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "observe"} +] +modules = [ + {org = "ballerinai", packageName = "observe", moduleName = "observe"} +] + +[[package]] +org = "ballerinax" +name = "postgresql" +version = "1.11.0" +dependencies = [ + {org = "ballerina", name = "crypto"}, + {org = "ballerina", name = "io"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "sql"}, + {org = "ballerina", name = "time"} +] +modules = [ + {org = "ballerinax", packageName = "postgresql", moduleName = "postgresql"} +] + +[[package]] +org = "wso2" +name = "admin_service" +version = "0.0.1-SNAPSHOT" +dependencies = [ + {org = "ballerina", name = "constraint"}, + {org = "ballerina", name = "http"}, + {org = "ballerina", name = "lang.value"}, + {org = "ballerina", name = "log"}, + {org = "ballerina", name = "sql"}, + {org = "ballerina", name = "test"}, + {org = "ballerina", name = "time"}, + {org = "ballerina", name = "uuid"}, + {org = "ballerinai", name = "observe"}, + {org = "ballerinax", name = "postgresql"}, + {org = "wso2", name = "apk_common_lib"}, + {org = "wso2", name = "apk_keymanager_libs"} +] +modules = [ + {org = "wso2", packageName = "admin_service", moduleName = "admin_service"} +] + +[[package]] +org = "wso2" +name = "apk_common_lib" +version = "0.0.1-SNAPSHOT" +dependencies = [ + {org = "ballerina", name = "http"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "jballerina.java.arrays"}, + {org = "ballerina", name = "jwt"}, + {org = "ballerina", name = "lang.value"}, + {org = "ballerina", name = "log"}, + {org = "ballerina", name = "os"}, + {org = "ballerina", name = "regex"}, + {org = "ballerina", name = "sql"}, + {org = "ballerina", name = "uuid"}, + {org = "ballerinax", name = "postgresql"} +] +modules = [ + {org = "wso2", packageName = "apk_common_lib", moduleName = "apk_common_lib"}, + {org = "wso2", packageName = "apk_common_lib", moduleName = "apk_common_lib.java.io"}, + {org = "wso2", packageName = "apk_common_lib", moduleName = "apk_common_lib.java.lang"} +] + +[[package]] +org = "wso2" +name = "apk_keymanager_libs" +version = "0.0.1-SNAPSHOT" +dependencies = [ + {org = "ballerina", name = "file"}, + {org = "ballerina", name = "io"}, + {org = "ballerina", name = "log"}, + {org = "wso2", name = "apk_common_lib"} +] +modules = [ + {org = "wso2", packageName = "apk_keymanager_libs", moduleName = "apk_keymanager_libs"} +] + diff --git a/admin/admin-domain-service/ballerina/Dependencies.toml.template b/admin/admin-domain-service/ballerina/Dependencies.toml.template new file mode 100644 index 000000000..259732a98 --- /dev/null +++ b/admin/admin-domain-service/ballerina/Dependencies.toml.template @@ -0,0 +1,435 @@ +# AUTO-GENERATED FILE. DO NOT MODIFY. + +# This file is auto-generated by Ballerina for managing dependency versions. +# It should not be modified by hand. + +[ballerina] +dependencies-toml-version = "2" +distribution-version = "2201.8.0" + +[[package]] +org = "ballerina" +name = "auth" +version = "2.10.0" +dependencies = [ + {org = "ballerina", name = "crypto"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.array"}, + {org = "ballerina", name = "lang.string"}, + {org = "ballerina", name = "log"} +] + +[[package]] +org = "ballerina" +name = "cache" +version = "3.7.0" +dependencies = [ + {org = "ballerina", name = "constraint"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "task"}, + {org = "ballerina", name = "time"} +] + +[[package]] +org = "ballerina" +name = "constraint" +version = "1.4.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] +modules = [ + {org = "ballerina", packageName = "constraint", moduleName = "constraint"} +] + +[[package]] +org = "ballerina" +name = "crypto" +version = "2.5.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "time"} +] + +[[package]] +org = "ballerina" +name = "file" +version = "1.9.0" +dependencies = [ + {org = "ballerina", name = "io"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "os"}, + {org = "ballerina", name = "time"} +] + +[[package]] +org = "ballerina" +name = "http" +version = "2.10.1" +dependencies = [ + {org = "ballerina", name = "auth"}, + {org = "ballerina", name = "cache"}, + {org = "ballerina", name = "constraint"}, + {org = "ballerina", name = "crypto"}, + {org = "ballerina", name = "file"}, + {org = "ballerina", name = "io"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "jwt"}, + {org = "ballerina", name = "lang.array"}, + {org = "ballerina", name = "lang.decimal"}, + {org = "ballerina", name = "lang.int"}, + {org = "ballerina", name = "lang.regexp"}, + {org = "ballerina", name = "lang.runtime"}, + {org = "ballerina", name = "lang.string"}, + {org = "ballerina", name = "lang.value"}, + {org = "ballerina", name = "log"}, + {org = "ballerina", name = "mime"}, + {org = "ballerina", name = "oauth2"}, + {org = "ballerina", name = "observe"}, + {org = "ballerina", name = "time"}, + {org = "ballerina", name = "url"} +] +modules = [ + {org = "ballerina", packageName = "http", moduleName = "http"}, + {org = "ballerina", packageName = "http", moduleName = "http.httpscerr"} +] + +[[package]] +org = "ballerina" +name = "io" +version = "1.6.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.value"} +] + +[[package]] +org = "ballerina" +name = "jballerina.java" +version = "0.0.0" + +[[package]] +org = "ballerina" +name = "jballerina.java.arrays" +version = "1.4.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] + +[[package]] +org = "ballerina" +name = "jwt" +version = "2.10.0" +dependencies = [ + {org = "ballerina", name = "cache"}, + {org = "ballerina", name = "crypto"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.int"}, + {org = "ballerina", name = "lang.string"}, + {org = "ballerina", name = "log"}, + {org = "ballerina", name = "time"} +] + +[[package]] +org = "ballerina" +name = "lang.__internal" +version = "0.0.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.object"} +] + +[[package]] +org = "ballerina" +name = "lang.array" +version = "0.0.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.__internal"} +] + +[[package]] +org = "ballerina" +name = "lang.decimal" +version = "0.0.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] + +[[package]] +org = "ballerina" +name = "lang.error" +version = "0.0.0" +scope = "testOnly" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] + +[[package]] +org = "ballerina" +name = "lang.int" +version = "0.0.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.__internal"}, + {org = "ballerina", name = "lang.object"} +] + +[[package]] +org = "ballerina" +name = "lang.object" +version = "0.0.0" + +[[package]] +org = "ballerina" +name = "lang.regexp" +version = "0.0.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] + +[[package]] +org = "ballerina" +name = "lang.runtime" +version = "0.0.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] + +[[package]] +org = "ballerina" +name = "lang.string" +version = "0.0.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.regexp"} +] + +[[package]] +org = "ballerina" +name = "lang.value" +version = "0.0.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] +modules = [ + {org = "ballerina", packageName = "lang.value", moduleName = "lang.value"} +] + +[[package]] +org = "ballerina" +name = "log" +version = "2.9.0" +dependencies = [ + {org = "ballerina", name = "io"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.value"}, + {org = "ballerina", name = "observe"} +] +modules = [ + {org = "ballerina", packageName = "log", moduleName = "log"} +] + +[[package]] +org = "ballerina" +name = "mime" +version = "2.9.0" +dependencies = [ + {org = "ballerina", name = "io"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.int"} +] + +[[package]] +org = "ballerina" +name = "oauth2" +version = "2.10.0" +dependencies = [ + {org = "ballerina", name = "cache"}, + {org = "ballerina", name = "crypto"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "log"}, + {org = "ballerina", name = "time"}, + {org = "ballerina", name = "url"} +] + +[[package]] +org = "ballerina" +name = "observe" +version = "1.2.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] + +[[package]] +org = "ballerina" +name = "os" +version = "1.8.0" +dependencies = [ + {org = "ballerina", name = "io"}, + {org = "ballerina", name = "jballerina.java"} +] + +[[package]] +org = "ballerina" +name = "regex" +version = "1.4.3" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.string"} +] + +[[package]] +org = "ballerina" +name = "sql" +version = "1.11.0" +dependencies = [ + {org = "ballerina", name = "io"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.object"}, + {org = "ballerina", name = "time"} +] +modules = [ + {org = "ballerina", packageName = "sql", moduleName = "sql"} +] + +[[package]] +org = "ballerina" +name = "task" +version = "2.5.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "time"} +] + +[[package]] +org = "ballerina" +name = "test" +version = "0.0.0" +scope = "testOnly" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.error"} +] +modules = [ + {org = "ballerina", packageName = "test", moduleName = "test"} +] + +[[package]] +org = "ballerina" +name = "time" +version = "2.4.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] +modules = [ + {org = "ballerina", packageName = "time", moduleName = "time"} +] + +[[package]] +org = "ballerina" +name = "url" +version = "2.4.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] + +[[package]] +org = "ballerina" +name = "uuid" +version = "1.7.0" +dependencies = [ + {org = "ballerina", name = "crypto"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.int"}, + {org = "ballerina", name = "time"} +] +modules = [ + {org = "ballerina", packageName = "uuid", moduleName = "uuid"} +] + +[[package]] +org = "ballerinai" +name = "observe" +version = "0.0.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "observe"} +] +modules = [ + {org = "ballerinai", packageName = "observe", moduleName = "observe"} +] + +[[package]] +org = "ballerinax" +name = "postgresql" +version = "1.11.0" +dependencies = [ + {org = "ballerina", name = "crypto"}, + {org = "ballerina", name = "io"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "sql"}, + {org = "ballerina", name = "time"} +] +modules = [ + {org = "ballerinax", packageName = "postgresql", moduleName = "postgresql"} +] + +[[package]] +org = "wso2" +name = "admin_service" +version = "PROJECT_VERSION" +dependencies = [ + {org = "ballerina", name = "constraint"}, + {org = "ballerina", name = "http"}, + {org = "ballerina", name = "lang.value"}, + {org = "ballerina", name = "log"}, + {org = "ballerina", name = "sql"}, + {org = "ballerina", name = "test"}, + {org = "ballerina", name = "time"}, + {org = "ballerina", name = "uuid"}, + {org = "ballerinai", name = "observe"}, + {org = "ballerinax", name = "postgresql"}, + {org = "wso2", name = "apk_common_lib"}, + {org = "wso2", name = "apk_keymanager_libs"} +] +modules = [ + {org = "wso2", packageName = "admin_service", moduleName = "admin_service"} +] + +[[package]] +org = "wso2" +name = "apk_common_lib" +version = "0.0.1-SNAPSHOT" +dependencies = [ + {org = "ballerina", name = "http"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "jballerina.java.arrays"}, + {org = "ballerina", name = "jwt"}, + {org = "ballerina", name = "lang.value"}, + {org = "ballerina", name = "log"}, + {org = "ballerina", name = "os"}, + {org = "ballerina", name = "regex"}, + {org = "ballerina", name = "sql"}, + {org = "ballerina", name = "uuid"}, + {org = "ballerinax", name = "postgresql"} +] +modules = [ + {org = "wso2", packageName = "apk_common_lib", moduleName = "apk_common_lib"}, + {org = "wso2", packageName = "apk_common_lib", moduleName = "apk_common_lib.java.io"}, + {org = "wso2", packageName = "apk_common_lib", moduleName = "apk_common_lib.java.lang"} +] + +[[package]] +org = "wso2" +name = "apk_keymanager_libs" +version = "0.0.1-SNAPSHOT" +dependencies = [ + {org = "ballerina", name = "file"}, + {org = "ballerina", name = "io"}, + {org = "ballerina", name = "log"}, + {org = "wso2", name = "apk_common_lib"} +] +modules = [ + {org = "wso2", packageName = "apk_keymanager_libs", moduleName = "apk_keymanager_libs"} +] + diff --git a/admin/admin-domain-service/ballerina/Errors.bal b/admin/admin-domain-service/ballerina/Errors.bal new file mode 100644 index 000000000..206ff382f --- /dev/null +++ b/admin/admin-domain-service/ballerina/Errors.bal @@ -0,0 +1,390 @@ +// +// Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// +// Before adding another function for a new error code +// make sure there is no already existing error code for that. +// If there is an error code for that, reuse it. + +import wso2/apk_common_lib as commons; + +public isolated function e909400(error e) returns commons:APKError { + return error commons:APKError(e.message(), e, + code = 909400, + message = e.message(), + statusCode = 500, + description = e.message() + ); +} + +public isolated function e909401(error e) returns commons:APKError { + return error commons:APKError("Error while retrieving connection", e, + code = 909401, + message = "Error while retrieving connection", + statusCode = 500, + description = "Error while retrieving connection" + ); +} + +public isolated function e909402(error e) returns commons:APKError { + return error commons:APKError("Error while inserting data into Database", e, + code = 909402, + message = "Error while inserting data into Database", + statusCode = 500, + description = "Error while inserting data into Database" + ); +} + +public isolated function e909403(error e) returns commons:APKError { + return error commons:APKError("Internal Error occured while retrieving API Categories", e, + code = 909403, + message = "Internal Error occured while retrieving API Categories", + statusCode = 500, + description = "Internal Error occured while retrieving API Categories" + ); +} + +public isolated function e909404(error e) returns commons:APKError { + return error commons:APKError("Error while checking API Category existence", e, + code = 909404, + message = "Error while checking API Category existence", + statusCode = 500, + description = "Error while checking API Category existence" + ); +} + +public isolated function e909405(error e) returns commons:APKError { + return error commons:APKError("Error while updating data record in the Database", e, + code = 909405, + message = "Error while updating data record in the Database", + statusCode = 500, + description = "Error while updating data record in the Database" + ); +} + +public isolated function e909406(error e) returns commons:APKError { + return error commons:APKError("Error while deleting data record in the Database", e, + code = 909406, + message = "Error while deleting data record in the Database", + statusCode = 500, + description = "Error while deleting data record in the Database" + ); +} + +public isolated function e909407() returns commons:APKError { + return error commons:APKError("Invalid query parameters. Only one of the query parameters can be provided.", + code = 909407, + message = "Invalid query parameters. Only one of the query parameters can be provided.", + statusCode = 406, + description = "Invalid query parameters. Only one of the query parameters can be provided." + ); +} + +public isolated function e909408() returns commons:APKError { + return error commons:APKError("Error while inserting vhosts data into Database", + code = 909408, + message = "Error while inserting vhosts data into Database", + statusCode = 500, + description = "Error while inserting vhosts data into Database" + ); +} + +public isolated function e909409() returns commons:APKError { + return error commons:APKError("Error while inserting organization claim data into Database", + code = 909409, + message = "Error while inserting organization claim data into Database", + statusCode = 500, + description = "Error while inserting organization claim data into Database" + ); +} + +public isolated function e909410() returns commons:APKError { + return error commons:APKError("Error while validating organization name in Database", + code = 909410, + message = "Error while validating organization name in Database", + statusCode = 500, + description = "Error while validating organization name in Database" + ); +} + +public isolated function e909411() returns commons:APKError { + return error commons:APKError("Error while validating organization id in Database", + code = 909411, + message = "Error while validating organization id in Database", + statusCode = 500, + description = "Error while validating organization id in Database" + ); +} + +public isolated function e909412() returns commons:APKError { + return error commons:APKError("Error while updating vhosts data into Database", + code = 909412, + message = "Error while updating vhosts data into Database", + statusCode = 500, + description = "Error while updating vhosts data into Database" + ); +} + +public isolated function e909413() returns commons:APKError { + return error commons:APKError("Error while updating organization data into Database", + code = 909413, + message = "Error while updating organization data into Database", + statusCode = 500, + description = "Error while updating organization data into Database" + ); +} + +public isolated function e909414() returns commons:APKError { + return error commons:APKError("Organization not found", + code = 909414, + message = "Organization not found", + statusCode = 404, + description = "Organization not found" + ); +} + +public isolated function e909415(error e) returns commons:APKError { + return error commons:APKError("Internal Error occured while retrieving organization data from Database", e, + code = 909415, + message = "Internal Error occured while retrieving organization data from Database", + statusCode = 500, + description = "Internal Error occured while retrieving organization data from Database" + ); +} + +public isolated function e909416() returns commons:APKError { + return error commons:APKError("Error while deleting organization data from Database", + code = 909416, + message = "Error while deleting organization data from Database", + statusCode = 500, + description = "Error while deleting organization data from Database" + ); +} + +public isolated function e909417() returns commons:APKError { + return error commons:APKError("Error while retrieving organization data from Database", + code = 909417, + message = "Error while retrieving organization data from Database", + statusCode = 500, + description = "Error while retrieving organization data from Database" + ); +} + +public isolated function e909418() returns commons:APKError { + return error commons:APKError("Error while retrieving Application Usage Plan", + code = 909418, + message = "Error while retrieving Application Usage Plan", + statusCode = 500, + description = "Error while retrieving Application Usage Plan" + ); +} + +public isolated function e909419(error e) returns commons:APKError { + return error commons:APKError("Internal Error occured while retrieving Application Usage Plans", e, + code = 909419, + message = "Internal Error occured while retrieving Application Usage Plans", + statusCode = 500, + description = "Internal Error occured while retrieving Application Usage Plans" + ); +} + +public isolated function e909420(error e) returns commons:APKError { + return error commons:APKError("Error while retrieving Business Plan", e, + code = 909420, + message = "Error while retrieving Business Plan", + statusCode = 500, + description = "Error while retrieving Business Plan" + ); +} + +public isolated function e909421(error e) returns commons:APKError { + return error commons:APKError("Internal Error occured while retrieving Business Plans", e, + code = 909421, + message = "Internal Error occured while retrieving Business Plans", + statusCode = 500, + description = "Internal Error occured while retrieving Business Plans" + ); +} + +public isolated function e909422(error e) returns commons:APKError { + return error commons:APKError("Error while retrieving Deny Policy from DB", e, + code = 909422, + message = "Error while retrieving Deny Policy from DB", + statusCode = 500, + description = "Error while retrieving Deny Policy from DB" + ); +} + +public isolated function e909423(error e) returns commons:APKError { + return error commons:APKError("Internal Error occured while retrieving Deny Policies", e, + code = 909423, + message = "Internal Error occured while retrieving Deny Policies", + statusCode = 500, + description = "Internal Error occured while retrieving Deny Policies" + ); +} + +public isolated function e909424(string payloadName) returns commons:APKError { + return error commons:APKError("API Category already exists by name:" + payloadName, + code = 909424, + message = "API Category already exists by name:" + payloadName, + statusCode = 400, + description = "API Category already exists by name:" + payloadName + ); +} + +public isolated function e909425(string name) returns commons:APKError { + return error commons:APKError("API Category already exists by name:" + name, + code = 909425, + message = "API Category already exists by name:" + name, + statusCode = 400, + description = "API Category already exists by name:" + name + ); +} + +public isolated function e909426() returns commons:APKError { + return error commons:APKError("API Category not found", + code = 909426, + message = "API Category not found", + statusCode = 404, + description = "API Category not found" + ); +} + +public isolated function e909427(string name) returns commons:APKError { + return error commons:APKError("Organization already exists by name:" + name, + code = 909427, + message = "Organization already exists by name:" + name, + statusCode = 409, + description = "Organization already exists by name:" + name + ); +} + +public isolated function e909428(string id) returns commons:APKError { + return error commons:APKError("Organization ID not exist by:" + id, + code = 909428, + message = "Organization ID not exist by:" + id, + statusCode = 400, + description = "Organization ID not exist by:" + id + ); +} + +public isolated function e909429() returns commons:APKError { + return error commons:APKError("Application Usage Plan not found", + code = 909429, + message = "Application Usage Plan not found", + statusCode = 404, + description = "Application Usage Plan not found" + ); +} + +public isolated function e909430() returns commons:APKError { + return error commons:APKError("Business Plan not found", + code = 909430, + message = "Business Plan not found", + statusCode = 404, + description = "Business Plan not found" + ); +} + +public isolated function e909431() returns commons:APKError { + return error commons:APKError("Deny Policy not found", + code = 909431, + message = "Deny Policy not found", + statusCode = 404, + description = "Deny Policy not found" + ); +} + +public isolated function e909432(error e) returns commons:APKError { + return error commons:APKError("Internal Error occured while retrieving KeyManagers", e, + code = 909432, + message = "Internal Error occured while retrieving KeyManagers", + statusCode = 500, + description = "Internal Error occured while retrieving KeyManagers" + ); +} + +public isolated function e909433(error e) returns commons:APKError { + return error commons:APKError("Internal Error occured while retrieving KeyManager", e, + code = 909433, + message = "Internal Error occured while retrieving KeyManager", + statusCode = 500, + description = "Internal Error occured while retrieving KeyManager" + ); +} + +public isolated function e909434() returns commons:APKError { + return error commons:APKError("KeyManager Name can't be empty", + code = 909434, + message = "KeyManager Name can't be empty", + statusCode = 400, + description = "KeyManager Name can't be empty" + ); +} + +isolated function e909435(string name, string organization) returns commons:APKError { + return error commons:APKError("KeyManager Name " + name + " already exist in organization " + organization, + code = 909434, + message = "KeyManager Name " + name + " already exist in organization " + organization, + statusCode = 400, + description = "KeyManager Name " + name + " already exist in organization " + organization + ); +} + +isolated function e909436(string 'type) returns commons:APKError { + return error commons:APKError("KeyManager Type " + 'type + " not exist", + code = 909436, + message = "KeyManager Type " + 'type + " not exist", + statusCode = 400, + description = "KeyManager Type " + 'type + " not exist" + ); +} + +isolated function e909437() returns commons:APKError { + return error commons:APKError("Required Keymanager Endpoint or Configuration not available", + code = 909437, + message = "Required Keymanager Endpoint or Configuration not available", + statusCode = 400, + description = "Required Keymanager Endpoint or Configuration not available" + ); +} + +isolated function e909438(error? e) returns commons:APKError { + return error commons:APKError("Internal Server Error",e, + code = 909438, + message = "Internal Server Error", + statusCode = 500, + description = "Internal Server Error" + ); +} + +isolated function e909439(string id, string organization) returns commons:APKError { + return error commons:APKError("KeyManager from " + id + " not exist in organization " + organization, + code = 909439, + message = "KeyManager from " + id + " not exist in organization " + organization, + statusCode = 404, + description = "KeyManager from " + id + " not exist in organization " + organization + ); +} +isolated function e909440(string id, string organization,error? e) returns commons:APKError { + return error commons:APKError("Internal Error occured while deleting keymanager " + id + " from organization " + organization,e, + code = 909440, + message = "Internal Error occured while deleting keymanager " + id + " from organization " + organization, + statusCode = 500, + description = "Internal Error occured while deleting keymanager " + id + " from organization " + organization + ); +} diff --git a/admin/admin-domain-service/ballerina/Errors.md b/admin/admin-domain-service/ballerina/Errors.md new file mode 100644 index 000000000..b68f782b6 --- /dev/null +++ b/admin/admin-domain-service/ballerina/Errors.md @@ -0,0 +1,38 @@ +# Errors in Admin Domain Service + +These are the admin domain service errors and their respective error codes. + +| Error Code | Status Code | Error Message | +|---|---|---| +| 909400 | 500 | Common code for other error | +| 909401 | 500 | Error while retrieving connection | +| 909402 | 500 | Error while inserting data into Database | +| 909403 | 500 | Internal Error occured while retrieving API Categories | +| 909404 | 500 | Error while checking API Category existence | +| 909405 | 500 | Error while updating data record in the Database | +| 909406 | 500 | Error while deleting data record in the Database | +| 909407 | 406 | Invalid query parameters. Only one of the query parameters can be provided | +| 909408 | 500 | Error while inserting vhosts data into Database | +| 909409 | 500 | Error while inserting organization claim data into Database | +| 909410 | 500 | Error while validating organization name in Database | +| 909411 | 500 | Error while validating organization id in Database | +| 909412 | 500 | Error while updating vhosts data into Database | +| 909413 | 500 | Error while updating organization data into Database | +| 909414 | 406 | Organization not found | +| 909415 | 500 | Internal Error occured while retrieving organization data from Database | +| 909416 | 500 | Error while deleting organization data from Database | +| 909417 | 500 | Error while retrieving organization data from Database | +| 909418 | 500 | Error while retrieving Application Usage Plan | +| 909419 | 500 | Internal Error occured while retrieving Application Usage Plans | +| 909420 | 500 | Error while retrieving Business Plan | +| 909421 | 500 | Internal Error occured while retrieving Business Plans | +| 909422 | 500 | Error while retrieving Deny Policy from DB | +| 909423 | 500 | Internal Error occured while retrieving Deny Policies | +| 909424 | 400 | API Category already exists by name: **payloadName** | +| 909425 | 400 | API Category already exists by name: **name** | +| 909426 | 404 | API Category not found | +| 909427 | 409 | Organization already exists by name: **name** | +| 909428 | 400 | Organization ID not exist by: **id** | +| 909429 | 404 | Application Usage Plan not found | +| 909430 | 404 | Business Plan not found | +| 909431 | 404 | Deny Policy not found | diff --git a/admin/admin-domain-service/ballerina/KeyManagerClient.bal b/admin/admin-domain-service/ballerina/KeyManagerClient.bal new file mode 100644 index 000000000..e78a41c0f --- /dev/null +++ b/admin/admin-domain-service/ballerina/KeyManagerClient.bal @@ -0,0 +1,282 @@ +import apk_keymanager_libs; +import ballerina/uuid; +import ballerina/lang.value; +import ballerina/log; +import wso2/apk_common_lib as commons; + +public class KeyManagerClient { + + public isolated function addKeyManagerEntryToOrganization(KeyManager keyManager, commons:Organization organization) returns KeyManager|commons:APKError { + if keyManager.name.trim().length() == 0 { + return e909434(); + } + // validate existence + if check checkKeyManagerExist(keyManager.name, organization) { + return e909435(keyManager.name, organization.name); + } + // validate type + apk_keymanager_libs:KeyManagerConfigurations? retrieveKeyManagerConfigByType = keyManagerInitializer.retrieveKeyManagerConfigByType(keyManager.'type); + if retrieveKeyManagerConfigByType is () { + return e909436(keyManager.'type); + } + // validate configurations. + if (!self.validateKeyManagerConfigurations(keyManager, retrieveKeyManagerConfigByType)) { + return e909437(); + } + // add key manager entry. + KeyManagerDaoEntry keyManagerDtoToInsert = check self.fromKeyManagerModelToKeyManagerDaoEntry(keyManager); + _ = check addKeyManagerEntry(keyManagerDtoToInsert, organization); + return check self.getKeyManagerById(keyManagerDtoToInsert.uuid, organization); + } + private isolated function fromKeyManagerModelToKeyManagerDaoEntry(KeyManager keyManager) returns KeyManagerDaoEntry|commons:APKError { + do { + KeyManagerDaoEntry keyManagerDTO = { + name: keyManager.name, + 'type: keyManager.'type, + issuer: keyManager.issuer, + enabled: keyManager.enabled, + description: keyManager.description + }; + if keyManager.id is () { + keyManagerDTO.uuid = uuid:createType1AsString(); + } else { + keyManagerDTO.uuid = keyManager.id; + } + record {} additionalProperties = {}; + additionalProperties = keyManager.additionalProperties.clone() ?: {}; + KeyManagerEndpoint[]? endpoints = keyManager.endpoints; + if endpoints is KeyManagerEndpoint[] { + foreach KeyManagerEndpoint item in endpoints { + record {} defineEndpoints = {}; + if (additionalProperties.hasKey("endpoints")) { + defineEndpoints = additionalProperties.get("endpoints"); + } else { + additionalProperties["endpoints"] = defineEndpoints; + } + defineEndpoints[item.name] = item.value; + } + } + string[]? availableGrantTypes = keyManager.availableGrantTypes; + if availableGrantTypes is string[] { + foreach string grantType in availableGrantTypes { + string[] grantTypes = []; + if (additionalProperties.hasKey("grantTypes")) { + grantTypes = additionalProperties.get("grantTypes"); + } + grantTypes.push(grantType); + } + } + if keyManager.consumerKeyClaim is string { + additionalProperties["consumerKeyClaim"] = keyManager.consumerKeyClaim; + } + if keyManager.scopesClaim is string { + additionalProperties["scopesClaim"] = keyManager.scopesClaim; + } + KeyManager_signingCertificate? certificates = keyManager.signingCertificate; + if certificates is KeyManager_signingCertificate { + if certificates.'type is string { + additionalProperties["signing_certificate_type"] = certificates.'type; + } + string? certificateValue = certificates.value; + if certificateValue is string { + if certificates.'type == "JWKS" { + additionalProperties["signing_certificate_value"] = certificateValue; + } else { + byte[] encodedBytes = check commons:EncoderUtil_encodeBase64(certificateValue.toBytes()); + additionalProperties["signing_certificate_value"] = check string:fromBytes(encodedBytes); + } + additionalProperties["signing_certificate_value"] = certificateValue; + } + } + string? tlsCertificate = keyManager.tlsCertificate; + if tlsCertificate is string { + byte[] encodedBytes = check commons:EncoderUtil_encodeBase64(tlsCertificate.toBytes()); + additionalProperties["tls_certificate"] = check string:fromBytes(encodedBytes); + } + additionalProperties["mapOAuthConsumerApps"] = keyManager.enableMapOAuthConsumerApps; + additionalProperties["enableTokenGeneration"] = keyManager.enableTokenGeneration; + additionalProperties["enableOauthAppCreation"] = keyManager.enableOAuthAppCreation; + additionalProperties["enableOauthAppValidation"] = keyManager.enableOauthAppValidation; + keyManagerDTO.configuration = additionalProperties.toJsonString().toBytes(); + return keyManagerDTO; + } on fail var e { + log:printError("Error while converting key manager model to key manager dto: " + e.message()); + return e909438(e); + } + } + private isolated function validateKeyManagerConfigurations(KeyManager keyManagerConfiguration, apk_keymanager_libs:KeyManagerConfigurations keyManagerConnectorConfigurations) returns boolean { + KeyManager_signingCertificate? certificates = keyManagerConfiguration.signingCertificate; + if certificates is KeyManager_signingCertificate { + if certificates.'type is () || certificates.value is () { + return false; + } + } else { + return false; + } + apk_keymanager_libs:EndpointConfiguration[] endpointsDefined = keyManagerConnectorConfigurations.endpoints; + KeyManagerEndpoint[]? endpoints = keyManagerConfiguration.endpoints; + if endpoints is KeyManagerEndpoint[] && endpoints.length() > 0 { + foreach apk_keymanager_libs:EndpointConfiguration keymanagerEndpointConfiguration in endpointsDefined { + if keymanagerEndpointConfiguration.required { + boolean found = false; + foreach KeyManagerEndpoint endpoint in endpoints { + if endpoint.name == keymanagerEndpointConfiguration.name { + found = true; + if endpoint.value.length() == 0 { + return false; + } + break; + } + } + if !found { + return false; + } + } + } + } else { + foreach apk_keymanager_libs:EndpointConfiguration keymanagerEndpointConfiguration in endpointsDefined { + if keymanagerEndpointConfiguration.required { + return false; + } + } + } + // validate endpoint configurations. + record {}? additionalProperties = keyManagerConfiguration.additionalProperties; + apk_keymanager_libs:KeyManagerConfiguration[] endpointConfigurations = keyManagerConnectorConfigurations.endpointConfigurations; + if additionalProperties is record {} && additionalProperties.length() > 0 { + foreach apk_keymanager_libs:KeyManagerConfiguration endpointConfiguration in endpointConfigurations { + if endpointConfiguration.required { + if !additionalProperties.hasKey(endpointConfiguration.name) { + return false; + } + } + } + } else { + foreach apk_keymanager_libs:KeyManagerConfiguration endpointConfiguration in endpointConfigurations { + if endpointConfiguration.required { + return false; + } + } + } + return true; + } + + public isolated function getAllKeyManagersByOrganization(commons:Organization organization) returns KeyManagerList|commons:APKError { + KeyManagerListingDaoEntry[] allKeyManagersByOrganization = check getAllKeyManagersByOrganization(organization); + KeyManagerList keyManagerList = {}; + KeyManagerInfo[] keyManagerInfoList = []; + foreach KeyManagerListingDaoEntry item in allKeyManagersByOrganization { + KeyManagerInfo keyManagerInfo = { + name: item.name, + 'type: item.'type, + id: item.uuid, + description: item.description, + enabled: item.enabled + }; + keyManagerInfoList.push(keyManagerInfo); + } + keyManagerList.list = keyManagerInfoList; + keyManagerList.count = keyManagerInfoList.length(); + return keyManagerList; + } + public isolated function getKeyManagerById(string id, commons:Organization organization) returns KeyManager|commons:APKError { + KeyManagerDaoEntry keyManagerEntry = check getKeyManagerById(id, organization); + return self.fromKeyManagerDaoEntryToKeyManagerModel(keyManagerEntry); + } + public isolated function updateKeyManager(string id, KeyManager updatedKeyManager, commons:Organization organization) returns KeyManager|commons:APKError { + KeyManagerDaoEntry keyManagerEntry = check getKeyManagerById(id, organization); + KeyManagerDaoEntry updatedKeyManagerEntry = check self.fromKeyManagerModelToKeyManagerDaoEntry(updatedKeyManager); + check updateKeyManager(id, updatedKeyManagerEntry, organization); + return self.getKeyManagerById(id, organization); + } + public isolated function deleteKeyManager(string id, commons:Organization organization) returns commons:APKError? { + KeyManagerDaoEntry keyManagerEntry = check getKeyManagerById(id, organization); + check deleteKeyManager(id, organization); + } + private isolated function fromKeyManagerDaoEntryToKeyManagerModel(KeyManagerDaoEntry keyManagerDaoEntry) returns KeyManager|commons:APKError { + do { + string additionalPropertiesString = check string:fromBytes(keyManagerDaoEntry.configuration); + json additionalPropertiesJson = check value:fromJsonString(additionalPropertiesString); + KeyManager keymanager = { + id: keyManagerDaoEntry.uuid, + name: keyManagerDaoEntry.name, + 'type: keyManagerDaoEntry.'type, + description: keyManagerDaoEntry.description, + issuer: keyManagerDaoEntry.issuer, + enabled: keyManagerDaoEntry.enabled + }; + KeyManagerEndpoint[] endpoints = []; + record {} additionalProperties = check additionalPropertiesJson.cloneWithType(); + if additionalProperties.hasKey("endpoints") { + record {} endpointsInRecord = additionalProperties.get("endpoints"); + foreach string key in endpointsInRecord.keys() { + KeyManagerEndpoint endpoint = { + name: key, + value: endpointsInRecord.get(key) + }; + endpoints.push(endpoint); + } + _ = additionalProperties.removeIfHasKey("endpoints"); + keymanager.endpoints = endpoints; + } + if additionalProperties.hasKey("grantTypes") { + string[] grantTypes = additionalProperties.get("grantTypes"); + keymanager.availableGrantTypes = grantTypes; + _ = additionalProperties.removeIfHasKey("grantTypes"); + } + if additionalProperties.hasKey("consumerKeyClaim") { + keymanager.consumerKeyClaim = additionalProperties.get("consumerKeyClaim"); + _ = additionalProperties.removeIfHasKey("consumerKeyClaim"); + } + if additionalProperties.hasKey("scopesClaim") { + keymanager.scopesClaim = additionalProperties.get("scopesClaim"); + _ = additionalProperties.removeIfHasKey("scopesClaim"); + } + if additionalProperties.hasKey("signing_certificate_type") { + string certificateType = additionalProperties.get("signing_certificate_type"); + if additionalProperties.hasKey("signing_certificate_value") { + string certificateValue = additionalProperties.get("signing_certificate_value"); + if certificateType == "PEM" { + byte[] encodedBytes = check commons:EncoderUtil_decodeBase64(certificateValue.toBytes()); + certificateValue = check string:fromBytes(encodedBytes); + } + KeyManager_signingCertificate certificates = { + 'type: certificateType, + value: certificateValue + }; + keymanager.signingCertificate = certificates; + } + _ = additionalProperties.removeIfHasKey("signing_certificate_type"); + _ = additionalProperties.removeIfHasKey("signing_certificate_value"); + } + if additionalProperties.hasKey("tls_certificate") { + string certificateValue = additionalProperties.get("tls_certificate"); + byte[] encodedBytes = check commons:EncoderUtil_decodeBase64(certificateValue.toBytes()); + certificateValue = check string:fromBytes(encodedBytes); + keymanager.tlsCertificate = certificateValue; + _ = additionalProperties.removeIfHasKey("tls_certificate"); + } + if additionalProperties.hasKey("mapOAuthConsumerApps") { + keymanager.enableMapOAuthConsumerApps = additionalProperties.get("mapOAuthConsumerApps"); + _ = additionalProperties.removeIfHasKey("mapOAuthConsumerApps"); + } + if additionalProperties.hasKey("enableTokenGeneration") { + keymanager.enableTokenGeneration = additionalProperties.get("enableTokenGeneration"); + _ = additionalProperties.removeIfHasKey("enableTokenGeneration"); + } + if additionalProperties.hasKey("enableOauthAppCreation") { + keymanager.enableOAuthAppCreation = additionalProperties.get("enableOauthAppCreation"); + _ = additionalProperties.removeIfHasKey("enableOauthAppCreation"); + } + if additionalProperties.hasKey("enableOauthAppValidation"){ + keymanager.enableOauthAppValidation = additionalProperties.get("enableOauthAppValidation"); + _ = additionalProperties.removeIfHasKey("enableOauthAppValidation"); + } + keymanager.additionalProperties = additionalProperties; + return keymanager; + } on fail var e { + return e909438(e); + } + } +} + diff --git a/admin/admin-domain-service/ballerina/OrganizationDTO.bal b/admin/admin-domain-service/ballerina/OrganizationDTO.bal new file mode 100644 index 000000000..7b04bb462 --- /dev/null +++ b/admin/admin-domain-service/ballerina/OrganizationDTO.bal @@ -0,0 +1,60 @@ +// +// Copyright (c) 2022, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + +# Description +# +# + id - Org ID +# + name - Org Name +# + displayName - Org Display Name +# + enabled - Org Enabled +# + claimKey - Org Claim Key +# + production - Org Production +# + sandbox - Org Sandbox +# + workflows - Org Workflows +# + serviceNamespaces - Org Service Namespaces +# + claimValue - Org Claim Value +public type Organizations record { + string id; + string name; + string displayName; + string enabled; + string[] serviceNamespaces; + string claimKey; + string production; + string workflows; + string sandbox; + string claimValue; +}; + + +public type Internal_Organization record { + string id; + string name; + string displayName; + boolean enabled; + string[] serviceNamespaces; + string[] production?; + string[] sandbox?; + OrganizationClaim[] claimList; + WorkflowProperties[] workflows?; +}; + +public type OrganizationClaim record { + string claimKey?; + string claimValue?; +}; \ No newline at end of file diff --git a/admin/admin-domain-service/ballerina/Readme.md b/admin/admin-domain-service/ballerina/Readme.md new file mode 100644 index 000000000..eec6973b4 --- /dev/null +++ b/admin/admin-domain-service/ballerina/Readme.md @@ -0,0 +1,39 @@ +# APK Admin Domain Service + +This contains the Ballerina implementation of the Admin Domain Service. + +## OpenAPI generation + +The REST API skeleton for Admin Service is generated using the [Ballerina OpenAPI tool](https://lib.ballerina.io/ballerina/openapi/1.2.1). The OpenAPI definition for the Admin Service is available in [admin-api.yaml](/ballerina/modules/admin/resources/admin-api.yaml) + +``` +bal openapi -i admin-api.yaml --mode service +``` + +The above command will generate the service bal file and types.bal file. + +## Bridge code generation + +[Ballerina bindgen tool](https://ballerina.io/learn/java-interoperability-guide/the-bindgen-tool/) is used to generate the bridge code for the business logic available in Java code. The generated bridge code will be available under modules. + +``` +bal bindgen -mvn org.wso2.apk:org.wso2.apk.apimgt.rest.api.admin.v1.common:0.1.0-SNAPSHOT org.wso2.apk.apimgt.rest.api.admin.v1.common.impl.ThrottlingCommonImp +``` + +``` +bal bindgen -mvn org.wso2.apk:org.wso2.apk.apimgt.init:0.1.0-SNAPSHOT org.wso2.apk.apimgt.init.APKComponent +``` + +The bridge code generated using the above sample commands can be directly used in the bal files. This allows us to directly call the business logic in Java. + +## Configuration model + +- The configurations should be specified in the Config.toml +- A seperate record type for each configuration should be created in [config.bal](/ballerina/modules/admin/config.bal). This will create the mappings between the values in the toml files through configurable variables. +- Any new configuration should be added to `APKConfig` record. This config will be passed as a json string to the `APKComponent` through the generated bridge code. +- The necessary property classes should be created and linked to the [Configuration Holder](../../../common-java-libs/org.wso2.apk.apimgt.impl/src/main/java/org/wso2/apk/apimgt/impl/ConfigurationHolder.java). +- The configurations will be mapped during the runtime and will be available through e Reference Holder in Java code. + + + +![config-model](/ballerina/modules/admin/resources/apkconf.png) diff --git a/admin/admin-domain-service/ballerina/SettingsClient.bal b/admin/admin-domain-service/ballerina/SettingsClient.bal new file mode 100644 index 000000000..12de45389 --- /dev/null +++ b/admin/admin-domain-service/ballerina/SettingsClient.bal @@ -0,0 +1,56 @@ +import apk_keymanager_libs; +import wso2/apk_common_lib as commons; + +public class SettingsClient { + + public isolated function getSettings(commons:Organization? organization) returns Settings { + Settings settings = {}; + settings.keyManagerConfiguration = self.setKeyManagerConfigsToSettings(); + return settings; + } + private isolated function setKeyManagerConfigsToSettings() returns Settings_keyManagerConfiguration[] { + Settings_keyManagerConfiguration[] keyManagerConfigs = []; + apk_keymanager_libs:KeyManagerConfigurations[] kmconfigs = keyManagerInitializer.retrieveAllKeyManagerConfigs(); + foreach apk_keymanager_libs:KeyManagerConfigurations item in kmconfigs { + Settings_keyManagerConfiguration keyManagerConfig = {}; + keyManagerConfig.'type = item.'type; + keyManagerConfig.displayName = item.'display_name; + keyManagerConfig.defaultConsumerKeyClaim = item.consumerKeyClaim; + keyManagerConfig.defaultScopesClaim = item.scopesClaim; + KeyManagerConfiguration[] endpointConfiguration = []; + apk_keymanager_libs:EndpointConfiguration[] endpointConfigs = item.endpoints; + foreach apk_keymanager_libs:EndpointConfiguration endpointConfig in endpointConfigs { + KeyManagerConfiguration endpointConfigGenerated = { + name: endpointConfig.name, + tooltip: endpointConfig.toolTip, + label: endpointConfig.display_name, + 'type: "input", + mask: false, + required: endpointConfig.required, + multiple: false + }; + endpointConfiguration.push(endpointConfigGenerated); + } + keyManagerConfig.endpointConfigurations = endpointConfiguration; + apk_keymanager_libs:KeyManagerConfiguration[] keyManagerConnectorConfigs = item.endpointConfigurations; + KeyManagerConfiguration[] generatedConnectorConfigs = []; + foreach apk_keymanager_libs:KeyManagerConfiguration keyManagerConnectorConfig in keyManagerConnectorConfigs { + KeyManagerConfiguration generatedConnectorConfig = { + name: keyManagerConnectorConfig.name, + tooltip: keyManagerConnectorConfig.toolTip, + label: keyManagerConnectorConfig.display_name, + 'type: keyManagerConnectorConfig.'type, + mask: keyManagerConnectorConfig.masked, + required: keyManagerConnectorConfig.required, + multiple: keyManagerConnectorConfig.multiple, + default: keyManagerConnectorConfig?.default, + values: keyManagerConnectorConfig.values + }; + + generatedConnectorConfigs.push(generatedConnectorConfig); + } + keyManagerConfigs.push(keyManagerConfig); + } + return keyManagerConfigs; + } +} diff --git a/admin/admin-domain-service/ballerina/admin-api_service.bal b/admin/admin-domain-service/ballerina/admin-api_service.bal new file mode 100644 index 000000000..d6be998b6 --- /dev/null +++ b/admin/admin-domain-service/ballerina/admin-api_service.bal @@ -0,0 +1,614 @@ +// +// Copyright (c) 2022, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + +import ballerina/http; +import ballerina/log; +import wso2/apk_common_lib as commons; + +service http:InterceptableService /api/admin on ep0 { + public function createInterceptors() returns http:Interceptor|http:Interceptor[] { + http:Interceptor[] interceptors = [jwtValidationInterceptor, requestErrorInterceptor, responseErrorInterceptor]; + return interceptors; + } + # Retrieve/Search Policies + # + # + query - **Search**. You can search by providing a keyword. Allowed to search by type and name only. + # + return - OK. List of qualifying Policies is returned. + // resource function get policies/search(string? query) returns PolicyDetailsList { + // } + # Get all Application Rate Plans + # + # + accept - Media types acceptable for the response. Default is application/json. + # + return - returns can be any of following types + # ApplicationRatePlanList (OK. Policies returned) + # NotAcceptableError (Not Acceptable. The requested media type is not supported.) + isolated resource function get 'application\-rate\-plans(http:RequestContext requestContext, @http:Header string? accept = "application/json") returns ApplicationRatePlanList|commons:APKError { + commons:UserContext authenticatedUserContext = check commons:getAuthenticatedUserContext(requestContext); + commons:Organization organization = authenticatedUserContext.organization; + ApplicationRatePlanList|commons:APKError appPolicyList = getApplicationUsagePlans(organization); + if appPolicyList is ApplicationRatePlanList { + log:printDebug(appPolicyList.toString()); + } + return appPolicyList; + } + # Add an Application Rate Plan + # + # + 'content\-type - Media type of the entity in the body. Default is application/json. + # + payload - Application level policy object that should to be added + # + return - returns can be any of following types + # ApplicationRatePlan (Created. Successful response with the newly created object as entity in the body. Location header contains URL of newly created entity.) + # BadRequestError (Bad Request. Invalid request or validation error.) + # UnsupportedMediaTypeError (Unsupported Media Type. The entity of the request was not in a supported format.) + isolated resource function post 'application\-rate\-plans(http:RequestContext requestContext, @http:Payload ApplicationRatePlan payload, @http:Header string 'content\-type = "application/json") returns ApplicationRatePlan|commons:APKError { + commons:UserContext authenticatedUserContext = check commons:getAuthenticatedUserContext(requestContext); + commons:Organization organization = authenticatedUserContext.organization; + ApplicationRatePlan|commons:APKError createdAppPol = addApplicationUsagePlan(payload, organization); + if createdAppPol is ApplicationRatePlan { + log:printDebug(createdAppPol.toString()); + } + return createdAppPol; + } + # Get an Application Rate Plan + # + # + planId - Policy UUID + # + return - returns can be any of following types + # ApplicationRatePlan (OK. Plan returned) + # NotFoundError (Not Found. The specified resource does not exist.) + # NotAcceptableError (Not Acceptable. The requested media type is not supported.) + isolated resource function get 'application\-rate\-plans/[string planId](http:RequestContext requestContext) returns ApplicationRatePlan|commons:APKError { + commons:UserContext authenticatedUserContext = check commons:getAuthenticatedUserContext(requestContext); + commons:Organization organization = authenticatedUserContext.organization; + ApplicationRatePlan|commons:APKError appPolicy = getApplicationUsagePlanById(planId, organization); + if appPolicy is ApplicationRatePlan { + log:printDebug(appPolicy.toString()); + } + return appPolicy; + } + # Update an Application Rate Plan + # + # + planId - Policy UUID + # + 'content\-type - Media type of the entity in the body. Default is application/json. + # + payload - Policy object that needs to be modified + # + return - returns can be any of following types + # ApplicationRatePlan (OK. Plan updated.) + # BadRequestError (Bad Request. Invalid request or validation error.) + # NotFoundError (Not Found. The specified resource does not exist.) + isolated resource function put 'application\-rate\-plans/[string planId](http:RequestContext requestContext, @http:Payload ApplicationRatePlan payload, @http:Header string 'content\-type = "application/json") returns ApplicationRatePlan|commons:APKError { + commons:UserContext authenticatedUserContext = check commons:getAuthenticatedUserContext(requestContext); + commons:Organization organization = authenticatedUserContext.organization; + ApplicationRatePlan|commons:APKError appPolicy = updateApplicationUsagePlan(planId, payload, organization); + if appPolicy is ApplicationRatePlan { + log:printDebug(appPolicy.toString()); + } + return appPolicy; + } + # Delete an Application Rate Plan + # + # + planId - Policy UUID + # + return - returns can be any of following types + # http:Ok (OK. Resource successfully deleted.) + # NotFoundError (Not Found. The specified resource does not exist.) + isolated resource function delete 'application\-rate\-plans/[string planId](http:RequestContext requestContext) returns http:Ok|commons:APKError { + commons:UserContext authenticatedUserContext = check commons:getAuthenticatedUserContext(requestContext); + commons:Organization organization = authenticatedUserContext.organization; + string|commons:APKError ex = removeApplicationUsagePlan(planId, organization); + if ex is commons:APKError { + return ex; + } else { + return http:OK; + } + } + # Get all Business Plans + # + # + accept - Media types acceptable for the response. Default is application/json. + # + return - returns can be any of following types + # BusinessPlanList (OK. Plans returned) + # NotAcceptableError (Not Acceptable. The requested media type is not supported.) + isolated resource function get 'business\-plans(http:RequestContext requestContext, @http:Header string? accept = "application/json") returns BusinessPlanList|commons:APKError { + commons:UserContext authenticatedUserContext = check commons:getAuthenticatedUserContext(requestContext); + commons:Organization organization = authenticatedUserContext.organization; + BusinessPlanList|commons:APKError subPolicyList = getBusinessPlans(organization); + if subPolicyList is BusinessPlanList { + log:printDebug(subPolicyList.toString()); + } + return subPolicyList; + } + # Add a Business Plan + # + # + 'content\-type - Media type of the entity in the body. Default is application/json. + # + payload - Business Plan object that should to be added + # + return - returns can be any of following types + # BusinessPlan (Created. Successful response with the newly created object as entity in the body. Location header contains URL of newly created entity.) + # BadRequestError (Bad Request. Invalid request or validation error.) + # UnsupportedMediaTypeError (Unsupported Media Type. The entity of the request was not in a supported format.) + isolated resource function post 'business\-plans(http:RequestContext requestContext, @http:Payload BusinessPlan payload, @http:Header string 'content\-type = "application/json") returns BusinessPlan|commons:APKError { + commons:UserContext authenticatedUserContext = check commons:getAuthenticatedUserContext(requestContext); + commons:Organization organization = authenticatedUserContext.organization; + BusinessPlan|commons:APKError createdSubPol = addBusinessPlan(payload, organization); + if createdSubPol is BusinessPlan { + log:printDebug(createdSubPol.toString()); + } + return createdSubPol; + } + # Get a Business Plan + # + # + planId - Policy UUID + # + return - returns can be any of following types + # BusinessPlan (OK. Plan returned) + # NotFoundError (Not Found. The specified resource does not exist.) + # NotAcceptableError (Not Acceptable. The requested media type is not supported.) + isolated resource function get 'business\-plans/[string planId](http:RequestContext requestContext) returns BusinessPlan|commons:APKError { + commons:UserContext authenticatedUserContext = check commons:getAuthenticatedUserContext(requestContext); + commons:Organization organization = authenticatedUserContext.organization; + BusinessPlan|commons:APKError subPolicy = getBusinessPlanById(planId, organization); + if subPolicy is BusinessPlan { + log:printDebug(subPolicy.toString()); + } + return subPolicy; + } + # Update a Business Plan + # + # + planId - Policy UUID + # + 'content\-type - Media type of the entity in the body. Default is application/json. + # + payload - Plan object that needs to be modified + # + return - returns can be any of following types + # BusinessPlan (OK. Plan updated.) + # BadRequestError (Bad Request. Invalid request or validation error.) + # NotFoundError (Not Found. The specified resource does not exist.) + isolated resource function put 'business\-plans/[string planId](http:RequestContext requestContext, @http:Payload BusinessPlan payload, @http:Header string 'content\-type = "application/json") returns BusinessPlan|commons:APKError { + commons:UserContext authenticatedUserContext = check commons:getAuthenticatedUserContext(requestContext); + commons:Organization organization = authenticatedUserContext.organization; + return updateBusinessPlan(planId, payload, organization); + } + # Delete a Business Plan + # + # + planId - Policy UUID + # + return - returns can be any of following types + # http:Ok (OK. Resource successfully deleted.) + # NotFoundError (Not Found. The specified resource does not exist.) + isolated resource function delete 'business\-plans/[string planId](http:RequestContext requestContext) returns http:Ok|commons:APKError { + commons:UserContext authenticatedUserContext = check commons:getAuthenticatedUserContext(requestContext); + commons:Organization organization = authenticatedUserContext.organization; + string|commons:APKError ex = removeBusinessPlan(planId, organization); + if ex is commons:APKError { + return ex; + } else { + return http:OK; + } + } + # Export a Throttling Policy + # + # + policyId - UUID of the ThrottlingPolicy + # + name - Throttling Policy Name + # + 'type - Type of the Throttling Policy + # + format - Format of output documents. Can be YAML or JSON. + # + return - returns can be any of following types + # ExportPolicy (OK. Export Successful.) + # NotFoundError (Not Found. The specified resource does not exist.) + # InternalServerErrorError (Internal Server Error.) + // resource function get throttling/policies/export(string? policyId, string? name, string? 'type, string? format) returns ExportPolicy|NotFoundError|InternalServerErrorError { + // } + # Import a Throttling Policy + # + # + overwrite - Update an existing throttling policy with the same name. + # + request - parameter description + # + return - returns can be any of following types + # http:Ok (Created. Throttling Policy Imported Successfully.) + # ForbiddenError (Forbidden. The request must be conditional but no condition has been specified.) + # NotFoundError (Not Found. The specified resource does not exist.) + # ConflictError (Conflict. Specified resource already exists.) + # InternalServerErrorError (Internal Server Error.) + // resource function post throttling/policies/'import(boolean? overwrite, http:Request request) returns http:Ok|ForbiddenError|NotFoundError|ConflictError|InternalServerErrorError { + // } + # Get all Deny Policies + # + # + accept - Media types acceptable for the response. Default is application/json. + # + return - returns can be any of following types + # BlockingConditionList (OK. Deny Policies returned) + # NotAcceptableError (Not Acceptable. The requested media type is not supported.) + isolated resource function get 'deny\-policies(http:RequestContext requestContext, @http:Header string? accept = "application/json") returns BlockingConditionList|commons:APKError { + commons:UserContext authenticatedUserContext = check commons:getAuthenticatedUserContext(requestContext); + commons:Organization organization = authenticatedUserContext.organization; + return getAllDenyPolicies(organization); + } + # Add a deny policy + # + # + 'content\-type - Media type of the entity in the body. Default is application/json. + # + payload - Blocking condition object that should to be added + # + return - returns can be any of following types + # BlockingCondition (Created. Successful response with the newly created object as entity in the body. Location header contains URL of newly created entity.) + # BadRequestError (Bad Request. Invalid request or validation error.) + # UnsupportedMediaTypeError (Unsupported Media Type. The entity of the request was not in a supported format.) + isolated resource function post 'deny\-policies(http:RequestContext requestContext, @http:Payload BlockingCondition payload, @http:Header string 'content\-type = "application/json") returns BlockingCondition|commons:APKError { + commons:UserContext authenticatedUserContext = check commons:getAuthenticatedUserContext(requestContext); + commons:Organization organization = authenticatedUserContext.organization; + BlockingCondition|commons:APKError createdDenyPol = addDenyPolicy(payload, organization); + if createdDenyPol is BlockingCondition { + log:printDebug(createdDenyPol.toString()); + } + return createdDenyPol; + } + # Get a Deny Policy + # + # + policyId - Policy UUID + # + return - returns can be any of following types + # BlockingCondition (OK. Condition returned) + # NotFoundError (Not Found. The specified resource does not exist.) + # NotAcceptableError (Not Acceptable. The requested media type is not supported.) + isolated resource function get 'deny\-policies/[string policyId](http:RequestContext requestContext) returns BlockingCondition|commons:APKError { + commons:UserContext authenticatedUserContext = check commons:getAuthenticatedUserContext(requestContext); + commons:Organization organization = authenticatedUserContext.organization; + BlockingCondition|commons:APKError denyPolicy = getDenyPolicyById(policyId, organization); + if denyPolicy is BlockingCondition { + log:printDebug(denyPolicy.toString()); + } + return denyPolicy; + } + # Delete a Deny Policy + # + # + policyId - Policy UUID + # + return - returns can be any of following types + # http:Ok (OK. Resource successfully deleted.) + # NotFoundError (Not Found. The specified resource does not exist.) + isolated resource function delete 'deny\-policies/[string policyId](http:RequestContext requestContext) returns http:Ok|commons:APKError { + commons:UserContext authenticatedUserContext = check commons:getAuthenticatedUserContext(requestContext); + commons:Organization organization = authenticatedUserContext.organization; + string|commons:APKError ex = removeDenyPolicy(policyId, organization); + if ex is commons:APKError { + return ex; + } else { + return http:OK; + } + } + # Update a Deny Policy + # + # + policyId - Policy UUID + # + 'content\-type - Media type of the entity in the body. Default is application/json. + # + payload - Blocking condition with updated status + # + return - returns can be any of following types + # BlockingCondition (OK. Resource successfully updated.) + # BadRequestError (Bad Request. Invalid request or validation error.) + # NotFoundError (Not Found. The specified resource does not exist.) + isolated resource function patch 'deny\-policies/[string policyId](http:RequestContext requestContext, @http:Payload BlockingConditionStatus payload, @http:Header string 'content\-type = "application/json") returns BlockingCondition|commons:APKError { + commons:UserContext authenticatedUserContext = check commons:getAuthenticatedUserContext(requestContext); + commons:Organization organization = authenticatedUserContext.organization; + BlockingCondition|commons:APKError updatedPolicy = updateDenyPolicy(policyId, payload, organization); + if updatedPolicy is BlockingCondition { + log:printDebug(updatedPolicy.toString()); + } + return updatedPolicy; + } + # Retrieve/Search Applications + # + # + user - username of the application creator + # + 'limit - Maximum size of resource array to return. + # + offset - Starting point within the complete list of items qualified. + # + accept - Media types acceptable for the response. Default is application/json. + # + name - Application Name + # + tenantDomain - Tenant domain of the applications to get. This has to be specified only if it is required to get applications of a tenant other than the requester's tenant. So, if not specified, the default will be set as the requester's tenant domain. This cross tenant Application access is allowed only for super tenant admin users **only at a migration process**. + # + sortBy - parameter description + # + sortOrder - parameter description + # + return - returns can be any of following types + # ApplicationList (OK. Application list returned.) + # BadRequestError (Bad Request. Invalid request or validation error.) + # NotAcceptableError (Not Acceptable. The requested media type is not supported.) + // resource function get applications(string? user, string? name, string? tenantDomain, int 'limit = 25, int offset = 0, @http:Header string? accept = "application/json", string sortBy = "name", string sortOrder = "asc") returns ApplicationList|BadRequestError|NotAcceptableError { + // } + # Get the details of an Application + # + # + applicationId - Application UUID + # + return - returns can be any of following types + # Application (OK. Application details returned.) + # BadRequestError (Bad Request. Invalid request or validation error.) + # NotFoundError (Not Found. The specified resource does not exist.) + # NotAcceptableError (Not Acceptable. The requested media type is not supported.) + // resource function get applications/[string applicationId]() returns Application|BadRequestError|NotFoundError|NotAcceptableError { + // } + # Delete an Application + # + # + applicationId - Application UUID + # + return - returns can be any of following types + # http:Ok (OK. Resource successfully deleted.) + # AcceptedWorkflowResponse (Accepted. The request has been accepted.) + # NotFoundError (Not Found. The specified resource does not exist.) + // resource function delete applications/[string applicationId]() returns http:Ok|AcceptedWorkflowResponse|NotFoundError { + // } + # Change Application Owner + # + # + applicationId - Application UUID + # + owner - parameter description + # + return - returns can be any of following types + # http:Ok (OK. Application owner changed successfully.) + # BadRequestError (Bad Request. Invalid request or validation error.) + # NotFoundError (Not Found. The specified resource does not exist.) + // resource function post applications/[string applicationId]/'change\-owner(string owner) returns http:Ok|BadRequestError|NotFoundError { + // } + # Get all registered Environments + # + # + return - OK. Environments returned + // resource function get environments() returns EnvironmentList { + // } + # Add an Environment + # + # + payload - Environment object that should to be added + # + return - returns can be any of following types + # Environment (Created. Successful response with the newly created environment as entity in the body.) + # BadRequestError (Bad Request. Invalid request or validation error.) + // resource function post environments(@http:Payload Environment payload) returns Environment|BadRequestError { + // } + # Update an Environment + # + # + environmentId - Environment UUID (or Environment name defined in config) + # + payload - Environment object with updated information + # + return - returns can be any of following types + # Environment (OK. Environment updated.) + # BadRequestError (Bad Request. Invalid request or validation error.) + # NotFoundError (Not Found. The specified resource does not exist.) + // resource function put environments/[string environmentId](@http:Payload Environment payload) returns Environment|BadRequestError|NotFoundError { + // } + # Delete an Environment + # + # + environmentId - Environment UUID (or Environment name defined in config) + # + return - returns can be any of following types + # http:Ok (OK. Environment successfully deleted.) + # NotFoundError (Not Found. The specified resource does not exist.) + // resource function delete environments/[string environmentId]() returns http:Ok|NotFoundError { + // } + # Get Tenant Id of User + # + # + username - The state represents the current state of the tenant. Supported states are [ active, inactive] + # + return - returns can be any of following types + # TenantInfo (OK. Tenant id of the user retrieved.) + # NotFoundError (Not Found. The specified resource does not exist.) + # NotAcceptableError (Not Acceptable. The requested media type is not supported.) + // resource function get 'tenant\-info/[string username]() returns TenantInfo|NotFoundError|NotAcceptableError { + // } + # Get Custom URL Info of a Tenant Domain + # + # + tenantDomain - The tenant domain name. + # + return - returns can be any of following types + # CustomUrlInfo (OK. Custom url info of the tenant is retrieved.) + # NotFoundError (Not Found. The specified resource does not exist.) + # NotAcceptableError (Not Acceptable. The requested media type is not supported.) + // resource function get 'custom\-urls/[string tenantDomain]() returns CustomUrlInfo|NotFoundError|NotAcceptableError { + // } + # Get all API Categories + # + # + return - OK. Categories returned + isolated resource function get 'api\-categories(http:RequestContext requestContext) returns APICategoryList|commons:APKError { + commons:UserContext authenticatedUserContext = check commons:getAuthenticatedUserContext(requestContext); + commons:Organization organization = authenticatedUserContext.organization; + return getAllCategoryList(organization); + } + # Add API Category + # + # + payload - API Category object that should to be added + # + return - returns can be any of following types + # APICategory (Created. Successful response with the newly created object as entity in the body.) + # BadRequestError (Bad Request. Invalid request or validation error.) + isolated resource function post 'api\-categories(http:RequestContext requestContext, @http:Payload APICategory payload) returns APICategory|commons:APKError { + commons:UserContext authenticatedUserContext = check commons:getAuthenticatedUserContext(requestContext); + commons:Organization organization = authenticatedUserContext.organization; + return addAPICategory(payload, organization); + } + # Update an API Category + # + # + apiCategoryId - API Category UUID + # + payload - API Category object with updated information + # + return - returns can be any of following types + # APICategory (OK. Label updated.) + # BadRequestError (Bad Request. Invalid request or validation error.) + # NotFoundError (Not Found. The specified resource does not exist.) + isolated resource function put 'api\-categories/[string apiCategoryId](http:RequestContext requestContext, @http:Payload APICategory payload) returns APICategory|commons:APKError { + commons:UserContext authenticatedUserContext = check commons:getAuthenticatedUserContext(requestContext); + commons:Organization organization = authenticatedUserContext.organization; + return updateAPICategory(apiCategoryId, payload, organization); + } + # Delete an API Category + # + # + apiCategoryId - API Category UUID + # + return - returns can be any of following types + # http:Ok (OK. API Category successfully deleted.) + # NotFoundError (Not Found. The specified resource does not exist.) + isolated resource function delete 'api\-categories/[string apiCategoryId](http:RequestContext requestContext) returns http:Ok|commons:APKError { + commons:UserContext authenticatedUserContext = check commons:getAuthenticatedUserContext(requestContext); + commons:Organization organization = authenticatedUserContext.organization; + string|commons:APKError ex = removeAPICategory(apiCategoryId, organization); + if ex is commons:APKError { + return ex; + } else { + return http:OK; + } + } + # Retrieve Admin Settings + # + # + return - returns can be any of following types + # Settings (OK. Settings returned) + # NotFoundError (Not Found. The specified resource does not exist.) + resource function get settings(http:RequestContext requestContext) returns Settings|NotFoundError|commons:APKError { + commons:UserContext authenticatedUserContext = check commons:getAuthenticatedUserContext(requestContext); + commons:Organization organization = authenticatedUserContext.organization; + + SettingsClient settingsClient = new; + return settingsClient.getSettings(organization); + } + # Get all Key managers + # + # + return - OK. KeyManagers returned + isolated resource function get 'key\-managers(http:RequestContext requestContext) returns KeyManagerList|commons:APKError { + commons:UserContext authenticatedUserContext = check commons:getAuthenticatedUserContext(requestContext); + commons:Organization organization = authenticatedUserContext.organization; + + KeyManagerClient keyManagerClient = new (); + return keyManagerClient.getAllKeyManagersByOrganization(organization); + + } + # Add a new API Key Manager + # + # + payload - Key Manager object that should to be added + # + return - returns can be any of following types + # KeyManager (Created. Successful response with the newly created object as entity in the body.) + # BadRequestError (Bad Request. Invalid request or validation error.) + isolated resource function post 'key\-managers(@http:Payload KeyManager payload, http:RequestContext requestContext) returns KeyManager|BadRequestError|commons:APKError { + commons:UserContext authenticatedUserContext = check commons:getAuthenticatedUserContext(requestContext); + commons:Organization organization = authenticatedUserContext.organization; + + KeyManagerClient keyManagerClient = new (); + return check keyManagerClient.addKeyManagerEntryToOrganization(payload, organization); + } + # Get a Key Manager Configuration + # + # + keyManagerId - Key Manager UUID + # + return - returns can be any of following types + # KeyManager (OK. KeyManager Configuration returned) + # NotFoundError (Not Found. The specified resource does not exist.) + # NotAcceptableError (Not Acceptable. The requested media type is not supported.) + isolated resource function get 'key\-managers/[string keyManagerId](http:RequestContext requestContext) returns KeyManager|NotFoundError|NotAcceptableError|commons:APKError { + commons:UserContext authenticatedUserContext = check commons:getAuthenticatedUserContext(requestContext); + commons:Organization organization = authenticatedUserContext.organization; + KeyManagerClient keyManagerClient = new (); + return check keyManagerClient.getKeyManagerById(keyManagerId, organization); + } + # Update a Key Manager + # + # + keyManagerId - Key Manager UUID + # + payload - Key Manager object with updated information + # + return - returns can be any of following types + # KeyManager (OK. Label updated.) + # BadRequestError (Bad Request. Invalid request or validation error.) + # NotFoundError (Not Found. The specified resource does not exist.) + isolated resource function put 'key\-managers/[string keyManagerId](@http:Payload KeyManager payload, http:RequestContext requestContext) returns KeyManager|BadRequestError|NotFoundError|commons:APKError { + + commons:UserContext authenticatedUserContext = check commons:getAuthenticatedUserContext(requestContext); + commons:Organization organization = authenticatedUserContext.organization; + KeyManagerClient keyManagerClient = new (); + return check keyManagerClient.updateKeyManager(keyManagerId, payload, organization); + } + # Delete a Key Manager + # + # + keyManagerId - Key Manager UUID + # + return - returns can be any of following types + # http:Ok (OK. Key Manager successfully deleted.) + # NotFoundError (Not Found. The specified resource does not exist.) + isolated resource function delete 'key\-managers/[string keyManagerId](http:RequestContext requestContext) returns http:Ok|NotFoundError|commons:APKError { + commons:UserContext authenticatedUserContext = check commons:getAuthenticatedUserContext(requestContext); + commons:Organization organization = authenticatedUserContext.organization; + KeyManagerClient keyManagerClient = new (); + check keyManagerClient.deleteKeyManager(keyManagerId, organization); + http:Ok okResponse = {}; + return okResponse; + } + # Retrieve Well-known information from Key Manager Well-known Endpoint + # + # + request - parameter description + # + return - OK. KeyManagers returned + // resource function post 'key\-managers/discover(http:Request request) returns OkKeyManagerWellKnownResponse { + // } + + + # Retrieve All Pending Workflow Processes + # + # + 'limit - Maximum size of resource array to return. + # + offset - Starting point within the complete list of items qualified. + # + accept - Media types acceptable for the response. Default is application/json. + # + workflowType - We need to show the values of each workflow process separately .for that we use workflow type. Workflow type can be APPLICATION_CREATION, SUBSCRIPTION_CREATION etc. + # + return - returns can be any of following types + # WorkflowList (OK. Workflow pendding process list returned.) + # BadRequestError (Bad Request. Invalid request or validation error.) + # NotFoundError (Not Found. The specified resource does not exist.) + # NotAcceptableError (Not Acceptable. The requested media type is not supported.) + isolated resource function get workflows(http:RequestContext requestContext, string? workflowType, int 'limit = 25, int offset = 0, @http:Header string? accept = "application/json") returns WorkflowList|commons:APKError { + commons:UserContext authenticatedUserContext = check commons:getAuthenticatedUserContext(requestContext); + commons:Organization organization = authenticatedUserContext.organization; + return getWorkflowList(workflowType, organization, 'limit, offset, accept); + } + # Update Workflow Status + # + # + workflowReferenceId - Workflow reference id + # + payload - Workflow event that need to be updated + # + return - returns can be any of following types + # OkWorkflowInfo (OK. Workflow request information is returned.) + # BadRequestError (Bad Request. Invalid request or validation error.) + # NotFoundError (Not Found. The specified resource does not exist.) + resource function post workflows/'update\-workflow\-status(http:RequestContext requestContext, string workflowReferenceId, @http:Payload WorkflowInfo payload) returns OkWorkflowInfo|commons:APKError { + commons:UserContext authenticatedUserContext = check commons:getAuthenticatedUserContext(requestContext); + commons:Organization organization = authenticatedUserContext.organization; + return updateWorkflowStatus(workflowReferenceId, payload, organization); + } + + # Get all Organization + # + # + return - OK. Organization returned + isolated resource function get organizations() returns OrganizationList|commons:APKError { + return getAllOrganization(); + } + # Add Organization + # + # + payload - Organization object that should to be added + # + return - returns can be any of following types + # Organization (Created. Successful response with the newly created object as entity in the body.) + # BadRequestError (Bad Request. Invalid request or validation error.) + isolated resource function post organizations(@http:Payload Organization payload) returns Organization|commons:APKError { + return addOrganization(payload); + } + # Get the details of an Organization + # + # + organizationId - Organization UUID + # + return - returns can be any of following types + # Organization (OK. Application details returned.) + # BadRequestError (Bad Request. Invalid request or validation error.) + # NotFoundError (Not Found. The specified resource does not exist.) + # NotAcceptableError (Not Acceptable. The requested media type is not supported.) + isolated resource function get organizations/[string organizationId]() returns Organization|commons:APKError { + return getOrganizationById(organizationId); + } + # Update an Organization + # + # + organizationId - Organization UUID + # + payload - Organization object with updated information + # + return - returns can be any of following types + # Organization (OK. Label updated.) + # BadRequestError (Bad Request. Invalid request or validation error.) + # NotFoundError (Not Found. The specified resource does not exist.) + isolated resource function put organizations/[string organizationId](@http:Payload Organization payload) returns Organization|commons:APKError { + return updatedOrganization(organizationId, payload); + } + # Delete an Organization + # + # + organizationId - Organization UUID + # + return - returns can be any of following types + # http:Ok (OK. Organization successfully deleted.) + # NotFoundError (Not Found. The specified resource does not exist.) + resource function delete organizations/[string organizationId]() returns http:Ok|commons:APKError { + boolean|commons:APKError deleteOrganization = removeOrganization(organizationId); + if deleteOrganization is commons:APKError { + return deleteOrganization; + } else { + return http:OK; + } + } + # Authenticate Organization info + # + # + return - returns can be any of following types + # Organization (OK. Application details returned.) + # BadRequestError (Bad Request. Invalid request or validation error.) + # NotFoundError (Not Found. The specified resource does not exist.) + resource function get 'organization\-info() returns Organization|commons:APKError { + return getOrganizationByOrganizationClaim(); + } +} diff --git a/admin/admin-domain-service/ballerina/apiCategoryDAO.bal b/admin/admin-domain-service/ballerina/apiCategoryDAO.bal new file mode 100644 index 000000000..c805a554f --- /dev/null +++ b/admin/admin-domain-service/ballerina/apiCategoryDAO.bal @@ -0,0 +1,145 @@ +// +// Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + +import ballerina/log; +import ballerinax/postgresql; +import ballerina/sql; +import wso2/apk_common_lib as commons; + +isolated function addAPICategoryDAO(APICategory payload, string org) returns APICategory|commons:APKError { + postgresql:Client | error dbClient = getConnection(); + if dbClient is error { + return e909401(dbClient); + } else { + sql:ParameterizedQuery query = `INSERT INTO API_CATEGORIES (UUID, NAME, + DESCRIPTION, ORGANIZATION) VALUES (${payload.id},${payload.name}, + ${payload.description},${org})`; + sql:ExecutionResult | sql:Error result = dbClient->execute(query); + if result is sql:ExecutionResult { + return payload; + } else { + log:printError(result.toString()); + return e909402(result); + } + } +} + +public isolated function checkAPICategoryExistsByNameDAO(string categoryName, string org) returns boolean|commons:APKError { + postgresql:Client | error dbClient = getConnection(); + if dbClient is error { + return e909401(dbClient); + } else { + sql:ParameterizedQuery query = `SELECT UUID as ID, NAME, DESCRIPTION + FROM API_CATEGORIES WHERE NAME =${categoryName} AND ORGANIZATION =${org}`; + APICategory | sql:Error result = dbClient->queryRow(query); + if result is sql:NoRowsError { + log:printDebug(result.toString()); + return false; + } else if result is APICategory { + return true; + } else { + log:printError(result.toString()); + return e909404(result); + } + } +} + +isolated function getAPICategoriesDAO(string org) returns APICategory[]|commons:APKError { + postgresql:Client | error dbClient = getConnection(); + if dbClient is error { + return e909401(dbClient); + } else { + do { + sql:ParameterizedQuery query = `SELECT UUID as ID, NAME, DESCRIPTION + FROM API_CATEGORIES WHERE ORGANIZATION =${org} ORDER BY NAME`; + stream apiCategoryStream = dbClient->query(query); + APICategory[] apiCategoryList = check from APICategory apiCategory in apiCategoryStream select apiCategory; + check apiCategoryStream.close(); + return apiCategoryList; + } on fail var e { + return e909403(e); + } + } +} + +isolated function getAPICategoryByIdDAO(string id, string org) returns APICategory|commons:APKError { + postgresql:Client | error dbClient = getConnection(); + if dbClient is error { + return e909401(dbClient); + } else { + sql:ParameterizedQuery query = `SELECT UUID as ID, NAME, DESCRIPTION + FROM API_CATEGORIES WHERE UUID =${id} AND ORGANIZATION =${org}`; + APICategory | sql:Error result = dbClient->queryRow(query); + if result is sql:NoRowsError { + log:printDebug(result.toString()); + return e909426(); + } else if result is APICategory { + return result; + } else { + log:printError(result.toString()); + return e909404(result); + } + } +} + +isolated function updateAPICategoryDAO(APICategory body, string org) returns APICategory|commons:APKError { + postgresql:Client | error dbClient = getConnection(); + if dbClient is error { + return e909401(dbClient); + } else { + sql:ParameterizedQuery query = `UPDATE API_CATEGORIES SET NAME = ${body.name}, + DESCRIPTION = ${body.description} WHERE UUID = ${body.id} AND ORGANIZATION = ${org}`; + sql:ExecutionResult | sql:Error result = dbClient->execute(query); + if result is sql:ExecutionResult { + return body; + } else { + log:printError(result.toString()); + return e909405(result); + } + } +} + +isolated function deleteAPICategoryDAO(string id, string org) returns commons:APKError|string { + postgresql:Client | error dbClient = getConnection(); + if dbClient is error { + return e909401(dbClient); + } else { + sql:ParameterizedQuery query = `DELETE FROM API_CATEGORIES WHERE UUID = ${id} AND ORGANIZATION = ${org}`; + sql:ExecutionResult | sql:Error result = dbClient->execute(query); + if result is sql:ExecutionResult { + return ""; + } else { + log:printError(result.toString()); + return e909406(result); + } + } +} + +isolated function getAPICountOfAPICategoryDAO(string apiCategory) returns int|commons:APKError { + postgresql:Client|error dbClient = getConnection(); + if dbClient is error { + return e909401(dbClient); + } + sql:ParameterizedQuery query = `SELECT COUNT(uuid) FROM API WHERE categories ?? ${apiCategory}`; + int|sql:Error result = dbClient->queryRow(query); + if result is sql:Error { + log:printError(result.toString()); + return e909404(result); + } + return result; +} diff --git a/admin/admin-domain-service/ballerina/apiCategoryImpl.bal b/admin/admin-domain-service/ballerina/apiCategoryImpl.bal new file mode 100644 index 000000000..9d9e359d0 --- /dev/null +++ b/admin/admin-domain-service/ballerina/apiCategoryImpl.bal @@ -0,0 +1,91 @@ +// +// Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + +import ballerina/uuid; +import wso2/apk_common_lib as commons; + +isolated function addAPICategory(APICategory payload, commons:Organization org) returns APICategory|commons:APKError { + boolean|commons:APKError existingCategory = checkAPICategoryExistsByNameDAO(payload.name, org.uuid); + if existingCategory is commons:APKError { + return existingCategory; + } else if existingCategory is true { + return e909424(payload.name); + } + string categoryId = uuid:createType1AsString(); + payload.id = categoryId; + APICategory|commons:APKError category = addAPICategoryDAO(payload, org.uuid); + if category is APICategory { + category.numberOfAPIs = 0; + APICategory createdCategory = category; + return createdCategory; + } else { + return category; + } +} + +isolated function getAllCategoryList(commons:Organization org) returns APICategoryList|commons:APKError { + APICategory[]|commons:APKError categories = getAPICategoriesDAO(org.uuid); + if categories is APICategory[] { + int count = categories.length(); + if (count > 0) { + foreach APICategory apiCategory in categories { + int|commons:APKError apiCount = getAPICountOfAPICategoryDAO(apiCategory.name); + if apiCount is int { + apiCategory.numberOfAPIs = apiCount; + } + } + } + APICategoryList apiCategoriesList = {count: count, list: categories}; + return apiCategoriesList; + } else { + return categories; + } +} + +isolated function updateAPICategory(string id, APICategory body, commons:Organization org) returns APICategory|commons:APKError { + APICategory|commons:APKError existingAPICategory = getAPICategoryByIdDAO(id, org.uuid); + if existingAPICategory !is APICategory { + return existingAPICategory; + } else { + body.id = id; + string existingName = existingAPICategory.name; + if (existingName != body.name) { + boolean|commons:APKError existingCategory = checkAPICategoryExistsByNameDAO(body.name, org.uuid); + if existingCategory is commons:APKError { + return existingCategory; + } + //We allow to update API Category name given that the new category name is not taken yet + if existingCategory is true { + return e909425(body.name); + } + } + } + APICategory|commons:APKError response = updateAPICategoryDAO(body, org.uuid); + if response is APICategory { + //TODO:(Sampath) need to properly retrieve attached api count per category + //int count = isCategoryAttached(apiCategory.name); + int apiCount = 0; + response.numberOfAPIs = apiCount; + } + return response; +} + +isolated function removeAPICategory(string id, commons:Organization org) returns string|commons:APKError { + commons:APKError|string status = deleteAPICategoryDAO(id, org.uuid); + return status; +} diff --git a/admin/admin-domain-service/ballerina/build.gradle b/admin/admin-domain-service/ballerina/build.gradle new file mode 100644 index 000000000..37af8f502 --- /dev/null +++ b/admin/admin-domain-service/ballerina/build.gradle @@ -0,0 +1,41 @@ +// +// Copyright (c) 2022, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + +apply from: "$rootDir/../../common-gradle-scripts/ballerina.gradle" +apply from: "$rootDir/../../common-gradle-scripts/docker.gradle" + +tasks.register('build') { + group 'build' + description 'Build ballerina component' + dependsOn 'test' + mustRunAfter('test') + dependsOn 'bal_build' +} + +tasks.register('test') { + group 'test' + description 'Test ballerina component' + dependsOn('start_postgres_image') + dependsOn('bal_test') + finalizedBy('stop_postgres_image') + mustRunAfter('start_postgres_image') +} + +task clean{ + dependsOn 'bal_clean' +} diff --git a/admin/admin-domain-service/ballerina/config.bal b/admin/admin-domain-service/ballerina/config.bal new file mode 100644 index 000000000..d1718d6dc --- /dev/null +++ b/admin/admin-domain-service/ballerina/config.bal @@ -0,0 +1,27 @@ +// +// Copyright (c) 2022, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// +import wso2/apk_common_lib as commons; + +type ThrottlingConfiguration record { + boolean enableUnlimitedTier = true; +}; + + +public type KeyStores record {| + commons:KeyStore tls; +|}; \ No newline at end of file diff --git a/admin/admin-domain-service/ballerina/health_service.bal b/admin/admin-domain-service/ballerina/health_service.bal new file mode 100644 index 000000000..3f709738f --- /dev/null +++ b/admin/admin-domain-service/ballerina/health_service.bal @@ -0,0 +1,25 @@ +// +// Copyright (c) 2022, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// +import ballerina/http; + +service / on ep0 { + resource function get health() returns http:Ok { + json status = {"health": "Ok"}; + return {body: status}; + } +} diff --git a/admin/admin-domain-service/ballerina/init.bal b/admin/admin-domain-service/ballerina/init.bal new file mode 100644 index 000000000..03d26a4e3 --- /dev/null +++ b/admin/admin-domain-service/ballerina/init.bal @@ -0,0 +1,72 @@ +// +// Copyright (c) 2022, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + +import ballerina/log; +import ballerinax/postgresql; +import ballerina/sql; +import ballerina/http; +import wso2/apk_common_lib as commons; +import wso2/apk_keymanager_libs as keymanager; + +configurable commons:DatasourceConfiguration datasourceConfiguration = ?; +final postgresql:Client|sql:Error dbClient; +configurable ThrottlingConfiguration throttleConfig = ?; +configurable KeyStores keyStores = { + tls: {certFilePath: "/home/wso2apk/admin/security/admin.pem", keyFilePath: "/home/wso2apk/admin/security/admin.key"} +}; +configurable commons:IDPConfiguration idpConfiguration = { + publicKey: {certFilePath: "/home/wso2apk/admin/security/mg.pem"} +}; +commons:DBBasedOrgResolver organizationResolver = new (datasourceConfiguration); +commons:JWTValidationInterceptor jwtValidationInterceptor = new (idpConfiguration, organizationResolver, ["/health"]); +commons:RequestErrorInterceptor requestErrorInterceptor = new; +commons:ResponseErrorInterceptor responseErrorInterceptor = new; +final keymanager:KeyManagerTypeInitializer keyManagerInitializer = new; +listener http:Listener ep0 = new (9443, secureSocket = { + 'key: { + certFile: keyStores.tls.certFilePath, + keyFile: keyStores.tls.keyFilePath + } +}); +listener http:Listener internalAdminEp = new (9444, secureSocket = { + 'key: { + certFile: keyStores.tls.certFilePath, + keyFile: keyStores.tls.keyFilePath + } +}); +configurable string keyManagerConntectorConfigurationFilePath = "/home/wso2apk/admin/keymanager"; +function init() returns error? { + _ = check keyManagerInitializer.initialize(keyManagerConntectorConfigurationFilePath); + log:printInfo("Starting APK Admin Domain Service..."); + dbClient = + new (host = datasourceConfiguration.host, + username = datasourceConfiguration.username, + password = datasourceConfiguration.password, + database = datasourceConfiguration.databaseName, + port = datasourceConfiguration.port, + connectionPool = {maxOpenConnections: datasourceConfiguration.maxPoolSize} + ); + if dbClient is error { + return log:printError("Error while connecting to database"); + } +} + +public isolated function getConnection() returns postgresql:Client|error { + return dbClient; +} + diff --git a/admin/admin-domain-service/ballerina/internal-admin-api_service.bal b/admin/admin-domain-service/ballerina/internal-admin-api_service.bal new file mode 100644 index 000000000..00fbdd0d8 --- /dev/null +++ b/admin/admin-domain-service/ballerina/internal-admin-api_service.bal @@ -0,0 +1,47 @@ +// +// Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + +import wso2/apk_common_lib as commons; +import ballerina/http; + +service http:InterceptableService /api/internal/v1 on internalAdminEp { + public function createInterceptors() returns http:Interceptor|http:Interceptor[] { + http:Interceptor[] interceptors = [requestErrorInterceptor, responseErrorInterceptor]; + return interceptors; + } + resource function get organizations(string? organizationName, string? organizationClaimValue) returns OrganizationList|error|commons:APKError { + if organizationName is string && organizationClaimValue is () { + Internal_Organization organizationByNameDAO = check getOrganizationByNameDAO(organizationName); + OrganizationList organizationList = { + count: 1, + list: [createOrganizationFromInternal(organizationByNameDAO)] + }; + return organizationList; + } else if organizationClaimValue is string && organizationName is () { + Internal_Organization organizationByClaimDAO = check getOrganizationByOrganizationClaimDAO(organizationClaimValue); + OrganizationList organizationList = { + count: 1, + list: [createOrganizationFromInternal(organizationByClaimDAO)] + }; + return organizationList; + } else if organizationName is string && organizationClaimValue is string { + return e909407(); + } + return check getAllOrganization(); + } +} diff --git a/admin/admin-domain-service/ballerina/keymanagerDao.bal b/admin/admin-domain-service/ballerina/keymanagerDao.bal new file mode 100644 index 000000000..1ee236306 --- /dev/null +++ b/admin/admin-domain-service/ballerina/keymanagerDao.bal @@ -0,0 +1,105 @@ +import wso2/apk_common_lib as commons; +import ballerinax/postgresql; +import ballerina/sql; +import ballerina/log; + +isolated function addKeyManagerEntry(KeyManagerDaoEntry keyManager, commons:Organization organization) returns commons:APKError? { + postgresql:Client|error dbClient = getConnection(); + if dbClient is error { + return e909401(dbClient); + } else { + sql:ParameterizedQuery query = `INSERT INTO KEY_MANAGER (UUID,NAME,DISPLAY_NAME,DESCRIPTION,TYPE,ENABLED,ORGANIZATION,ISSUER,CONFIGURATION) VALUES (${keyManager.uuid},${keyManager.name},${keyManager.display_name},${keyManager.description},${keyManager.'type},${keyManager.enabled},${organization.uuid},${keyManager.issuer},${keyManager.configuration})`; + sql:ExecutionResult|sql:Error result = dbClient->execute(query); + if result is sql:ExecutionResult && result.affectedRowCount == 0 { + return e909438(()); + } else if result is sql:Error { + log:printError("Error while adding key manager entry", result); + return e909402(result); + } + } +} + +isolated function getAllKeyManagersByOrganization(commons:Organization organization) returns KeyManagerListingDaoEntry[]|commons:APKError { + postgresql:Client|error dbClient = getConnection(); + if dbClient is error { + return e909401(dbClient); + } else { + do { + sql:ParameterizedQuery query = `SELECT UUID,NAME,DESCRIPTION,TYPE,ENABLED FROM KEY_MANAGER WHERE ORGANIZATION = ${organization.uuid}`; + stream keyManagerListStream = dbClient->query(query); + KeyManagerListingDaoEntry[] keYmanagerList = check from KeyManagerListingDaoEntry keyManager in keyManagerListStream + select keyManager; + check keyManagerListStream.close(); + return keYmanagerList; + } on fail var e { + return e909432(e); + } + } +} + +isolated function checkKeyManagerExist(string name, commons:Organization organization) returns boolean|commons:APKError { + postgresql:Client|error dbClient = getConnection(); + if dbClient is error { + return e909401(dbClient); + } else { + sql:ParameterizedQuery query = `select exists(SELECT 1 FROM KEY_MANAGER WHERE ORGANIZATION = ${organization.uuid} AND NAME = ${name})`; + boolean|sql:Error result = dbClient->queryRow(query); + if result is boolean { + return result; + } else { + log:printError("Error while checking key manager existance", result); + return e909433(result); + } + } +} + +isolated function getKeyManagerById(string id, commons:Organization organization) returns KeyManagerDaoEntry|commons:APKError { + postgresql:Client|error dbClient = getConnection(); + if dbClient is error { + return e909401(dbClient); + } else { + sql:ParameterizedQuery query = `SELECT UUID,NAME,DISPLAY_NAME,ISSUER,DESCRIPTION,TYPE,CONFIGURATION,ENABLED FROM KEY_MANAGER WHERE ORGANIZATION = ${organization.uuid} AND UUID = ${id}`; + KeyManagerDaoEntry|sql:Error result = dbClient->queryRow(query); + if result is sql:NoRowsError { + return e909439(id, organization.uuid); + } else if result is KeyManagerDaoEntry { + return result; + } else { + log:printError("Error while getting key manager by id", result); + return e909433(result); + } + } +} + +public isolated function updateKeyManager(string id, KeyManagerDaoEntry keyManager, commons:Organization organization) returns commons:APKError? { + postgresql:Client|error dbClient = getConnection(); + if dbClient is error { + return e909401(dbClient); + } else { + sql:ParameterizedQuery query = `UPDATE KEY_MANAGER SET NAME = ${keyManager.name},DISPLAY_NAME = ${keyManager.display_name},DESCRIPTION = ${keyManager.description},TYPE = ${keyManager.'type},ENABLED = ${keyManager.enabled},ISSUER = ${keyManager.issuer},CONFIGURATION = ${keyManager.configuration} WHERE UUID = ${id} AND ORGANIZATION = ${organization.uuid}`; + sql:ExecutionResult|sql:Error result = dbClient->execute(query); + if result is sql:ExecutionResult && result.affectedRowCount == 0 { + return e909438(()); + } else if result is sql:Error { + log:printError("Error while updating key manager", result); + return e909402(result); + } + } +} + +public isolated function deleteKeyManager(string id, commons:Organization organization) returns commons:APKError? { + postgresql:Client|error dbClient = getConnection(); + if dbClient is error { + return e909401(dbClient); + } else { + sql:ParameterizedQuery query = `DELETE FROM KEY_MANAGER WHERE UUID = ${id} AND ORGANIZATION = ${organization.uuid}`; + sql:ExecutionResult|sql:Error result = dbClient->execute(query); + if result is sql:ExecutionResult && result.affectedRowCount == 0 { + return e909440(id, organization.uuid, ()); + } else if result is sql:Error { + log:printError(result.toString()); + return e909440(id, organization.uuid, result); + } + } +} + diff --git a/admin/admin-domain-service/ballerina/keymanagerInternalTypes.bal b/admin/admin-domain-service/ballerina/keymanagerInternalTypes.bal new file mode 100644 index 000000000..79b17dd55 --- /dev/null +++ b/admin/admin-domain-service/ballerina/keymanagerInternalTypes.bal @@ -0,0 +1,18 @@ +public type KeyManagerListingDaoEntry record {| + string uuid; + string name; + string display_name?; + string description?; + string 'type; + boolean enabled; +|}; +public type KeyManagerDaoEntry record {| +string uuid?; +string name; +string display_name?; +string issuer; +string description?; +string 'type; +byte[] configuration?; +boolean enabled; +|}; \ No newline at end of file diff --git a/admin/admin-domain-service/ballerina/organizationDAO.bal b/admin/admin-domain-service/ballerina/organizationDAO.bal new file mode 100644 index 000000000..9d74b9a1c --- /dev/null +++ b/admin/admin-domain-service/ballerina/organizationDAO.bal @@ -0,0 +1,448 @@ +// +// Copyright (c) 2022, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + +import ballerinax/postgresql; +import ballerina/log; +import ballerina/sql; +import wso2/apk_common_lib as commons; + +isolated function addOrganizationDAO(Internal_Organization payload) returns Internal_Organization|commons:APKError { + postgresql:Client | error dbClient = getConnection(); + if dbClient is error { + return e909401(dbClient); + } else { + postgresql:JsonBinaryValue namespace = new (payload.serviceNamespaces.toJson()); + sql:ParameterizedQuery query = `INSERT INTO ORGANIZATION(UUID, NAME, + DISPLAY_NAME,STATUS,NAMESPACE,WORKFLOWS) VALUES (${payload.id},${payload.name}, + ${payload.displayName},${payload.enabled},${namespace}, ${payload.workflows.toString().toBytes()})`; + sql:ExecutionResult | sql:Error result = dbClient->execute(query); + if result is sql:ExecutionResult && result.affectedRowCount == 1 { + boolean isVhostAdded = addVhostsDAO(dbClient, payload); + if(isVhostAdded) { + return addOrganizationClaimMappingDAO(dbClient, payload); + } else { + return e909408(); + } + } + } + return payload; +} + +isolated function addOrganizationClaimMappingDAO(postgresql:Client dbClient, Internal_Organization payload) returns Internal_Organization|commons:APKError { + foreach OrganizationClaim e in payload.claimList { + sql:ParameterizedQuery query = `INSERT INTO ORGANIZATION_CLAIM_MAPPING(UUID, CLAIM_KEY, + CLAIM_VALUE) VALUES (${payload.id},${e.claimKey}, + ${e.claimValue})`; + sql:ExecutionResult | sql:Error result = dbClient->execute(query); + if result is sql:ExecutionResult { + continue; + } else { + return e909409(); + } + } + return payload; +} + +isolated function addVhostsDAO (postgresql:Client dbClient, Internal_Organization payload) returns boolean{ + string[]? production = payload.production; + string[]? sandbox = payload.sandbox; + if (production !is ()) { + foreach string e in production { + sql:ParameterizedQuery query = `INSERT INTO ORGANIZATION_VHOST(UUID, VHOST, TYPE) VALUES (${payload.id},${e}, 'PRODUCTION')`; + sql:ExecutionResult | sql:Error result = dbClient->execute(query); + if result is sql:ExecutionResult && result.affectedRowCount == 1 { + continue; + } else { + return false; + } + } + } + if (sandbox !is ()) { + foreach string e in sandbox { + sql:ParameterizedQuery query = `INSERT INTO ORGANIZATION_VHOST(UUID, VHOST, TYPE) VALUES (${payload.id},${e}, 'SANDBOX')`; + sql:ExecutionResult | sql:Error result = dbClient->execute(query); + if result is sql:ExecutionResult && result.affectedRowCount == 1 { + continue; + } else { + return false; + } + } + } + return true; +} + +isolated function validateOrganizationByNameDAO(string name) returns boolean|commons:APKError { + postgresql:Client | error dbClient = getConnection(); + if dbClient is error { + return e909401(dbClient); + } + sql:ParameterizedQuery query = `SELECT ORGANIZATION.UUID as id, NAME as name, DISPLAY_NAME as displayName, STATUS as enabled FROM ORGANIZATION WHERE NAME = ${name}`; + Organization | sql:Error result = dbClient->queryRow(query); + if result is sql:NoRowsError { + return false; + } else if result is Organization { + return true; + } else { + log:printError("Error while validating organization name in Database", result); + return e909410(); + } + +} + +isolated function validateOrganizationById(string? id) returns boolean|commons:APKError { + postgresql:Client | error dbClient = getConnection(); + if dbClient is error { + return e909401(dbClient); + } + sql:ParameterizedQuery query = `select exists(SELECT 1 FROM ORGANIZATION WHERE UUID = ${id})`; + boolean | sql:Error result = dbClient->queryRow(query); + if result is boolean { + return result; + } else { + return e909411(); + } +} + +isolated function updateOrganizationDAO(string id, Internal_Organization payload) returns Internal_Organization|commons:APKError { + postgresql:Client | error dbClient = getConnection(); + if dbClient is error { + return e909401(dbClient); + } else { + postgresql:JsonBinaryValue namespace = new (payload.serviceNamespaces.toJson()); + sql:ParameterizedQuery query = `UPDATE ORGANIZATION SET NAME =${payload.name}, + DISPLAY_NAME = ${payload.displayName}, STATUS=${payload.enabled}, NAMESPACE=${namespace}, WORKFLOWS=${payload.workflows.toString().toBytes()} + WHERE UUID = ${id}`; + sql:ExecutionResult | sql:Error result = dbClient->execute(query); + if result is sql:ExecutionResult && result.affectedRowCount == 1 { + boolean isVhostAdded = updateVhostsDAO(dbClient, payload.id, payload); + if(isVhostAdded) { + return updateOrganizationClaimMappingDAO(dbClient, id, payload); + } else { + return e909412(); + } + } else { + return e909413(); + } + } +} + +isolated function updateOrganizationClaimMappingDAO(postgresql:Client dbClient, string id, Internal_Organization payload) returns Internal_Organization|commons:APKError { + sql:ParameterizedQuery query = `DELETE FROM ORGANIZATION_CLAIM_MAPPING WHERE UUID = ${id}`; + sql:ExecutionResult | sql:Error result = dbClient->execute(query); + if result is sql:ExecutionResult { + foreach OrganizationClaim e in payload.claimList { + sql:ParameterizedQuery query1 = `INSERT INTO ORGANIZATION_CLAIM_MAPPING(UUID, CLAIM_KEY, + CLAIM_VALUE) VALUES (${id},${e.claimKey}, + ${e.claimValue})`; + sql:ExecutionResult | sql:Error result1 = dbClient->execute(query1); + if result1 is sql:ExecutionResult { + continue; + } else { + return e909409(); + } + } + } + return payload; +} + +isolated function updateVhostsDAO (postgresql:Client dbClient, string id, Internal_Organization payload) returns boolean{ + sql:ParameterizedQuery query = `DELETE FROM ORGANIZATION_VHOST WHERE UUID = ${id}`; + sql:ExecutionResult | sql:Error result = dbClient->execute(query); + if result is sql:ExecutionResult { + string[]? production = payload.production; + string[]? sandbox = payload.sandbox; + if (production !is ()) { + foreach string e in production { + sql:ParameterizedQuery query1 = `INSERT INTO ORGANIZATION_VHOST(UUID, VHOST, TYPE) VALUES (${id},${e}, 'PRODUCTION')`; + sql:ExecutionResult | sql:Error result1 = dbClient->execute(query1); + if result1 is sql:ExecutionResult && result1.affectedRowCount == 1 { + continue; + } else { + return false; + } + } + } + if (sandbox !is ()) { + foreach string e in sandbox { + sql:ParameterizedQuery query1 = `INSERT INTO ORGANIZATION_VHOST(UUID, VHOST, TYPE) VALUES (${id},${e}, 'SANDBOX')`; + sql:ExecutionResult | sql:Error result1 = dbClient->execute(query1); + if result1 is sql:ExecutionResult && result1.affectedRowCount == 1 { + continue; + } else { + return false; + } + } + } + return true; + } + return false; +} + +public isolated function getAllOrganizationDAO() returns Internal_Organization[]|commons:APKError { + postgresql:Client | error dbClient = getConnection(); + if dbClient is error { + return e909401(dbClient); + } else { + do { + map organization = {}; + sql:ParameterizedQuery query = `SELECT ORGANIZATION.UUID as id, NAME as name, DISPLAY_NAME as displayName, STATUS as enabled, + encode(WORKFLOWS, 'escape')::text AS workflows, claim_key as claimKey, claim_value as claimValue FROM ORGANIZATION, ORGANIZATION_CLAIM_MAPPING where ORGANIZATION.UUID = ORGANIZATION_CLAIM_MAPPING.UUID`; + stream orgStream = dbClient->query(query); + check from Organizations org in orgStream do { + if organization.hasKey(org.id) { + OrganizationClaim claim = {claimKey: org.claimKey, claimValue: org.claimValue}; + organization.get(org.id).claimList.push(claim); + } else { + OrganizationClaim claim = {claimKey: org.claimKey, claimValue: org.claimValue}; + Internal_Organization organizationData = { + id: org.id, + name: org.name, + displayName: org.displayName, + enabled: check boolean:fromString(org.enabled), + serviceNamespaces: ["*"], + workflows: org.workflows.length() > 0 ? check org.workflows.fromJsonStringWithType() : [], + claimList: [claim] + }; + organization[org.id] = organizationData; + } + }; + + sql:ParameterizedQuery query1 = `SELECT ORGANIZATION.UUID as id, NAME as name, DISPLAY_NAME as displayName, ORGANIZATION_VHOST.VHOST AS production FROM ORGANIZATION,ORGANIZATION_VHOST where + ORGANIZATION.UUID = ORGANIZATION_VHOST.UUID and ORGANIZATION_VHOST.TYPE = 'PRODUCTION'`; + stream orgStream1 = dbClient->query(query1); + check from Organizations org1 in orgStream1 do { + if organization.hasKey(org1.id) { + string[]? hostArray = organization.get(org1.id).production; + if hostArray !is () { + hostArray.push(org1.production); + } else { + organization[org1.id].production = [org1.production]; + } + } + }; + sql:ParameterizedQuery query2 = `SELECT ORGANIZATION.UUID as id, NAME as name, DISPLAY_NAME as displayName, ORGANIZATION_VHOST.VHOST AS sandbox FROM ORGANIZATION,ORGANIZATION_VHOST where + ORGANIZATION.UUID = ORGANIZATION_VHOST.UUID and ORGANIZATION_VHOST.TYPE = 'SANDBOX'`; + stream orgStream2 = dbClient->query(query2); + check from Organizations org2 in orgStream2 do { + if organization.hasKey(org2.id) { + string[]? hostArray = organization.get(org2.id).sandbox; + if hostArray !is () { + hostArray.push(org2.sandbox); + } else { + organization[org2.id].sandbox = [org2.sandbox]; + } + } + }; + check orgStream.close(); + check orgStream1.close(); + check orgStream2.close(); + return organization.toArray(); + } on fail var e { + return e909400(e); + } + } +} + +isolated function getOrganizationByIdDAO(string id) returns Internal_Organization|commons:APKError { + postgresql:Client | error dbClient = getConnection(); + if dbClient is error { + return e909401(dbClient); + } else { + do { + sql:ParameterizedQuery query = `SELECT ORGANIZATION.UUID as id, NAME as name, DISPLAY_NAME as displayName, STATUS as enabled, claim_key as claimKey, + claim_value as claimValue, string_to_array(NAMESPACE::text,',')::text[] AS serviceNamespaces, encode(WORKFLOWS, 'escape')::text AS workflows + FROM ORGANIZATION, ORGANIZATION_CLAIM_MAPPING where ORGANIZATION.UUID = ORGANIZATION_CLAIM_MAPPING.UUID and ORGANIZATION.UUID =${id}`; + stream orgStream = dbClient->query(query); + Internal_Organization organization1 = { + id: "", + name: "", + displayName: "", + enabled: true, + serviceNamespaces: ["*"], + workflows: [], + production: [], + sandbox: [], + claimList: [] + }; + + check from Organizations org in orgStream do { + if (organization1.id == "") { + organization1 = { + id:id, + name:org.name, + displayName:org.displayName, + enabled: check boolean:fromString(org.enabled), + serviceNamespaces: org.serviceNamespaces, + workflows: org.workflows.length() > 0 ? check org.workflows.fromJsonStringWithType() : [], + claimList:[{ + claimKey:org.claimKey, + claimValue: org.claimValue + }] + }; + } else { + organization1.claimList.push({ + claimKey:org.claimKey, + claimValue: org.claimValue + }); + } + }; + + sql:ParameterizedQuery query1 = `SELECT ORGANIZATION.UUID as id, NAME as name, DISPLAY_NAME as displayName, ORGANIZATION_VHOST.VHOST AS production FROM ORGANIZATION,ORGANIZATION_VHOST where + ORGANIZATION.UUID = ORGANIZATION_VHOST.UUID and ORGANIZATION.UUID =${id} and ORGANIZATION_VHOST.TYPE = 'PRODUCTION'`; + stream orgStream1 = dbClient->query(query1); + check from Organizations org1 in orgStream1 do { + string[]? hostArray = organization1.production; + if hostArray !is () { + hostArray.push(org1.production); + } else { + organization1.production = [org1.production]; + } + }; + sql:ParameterizedQuery query2 = `SELECT ORGANIZATION.UUID as id, NAME as name, DISPLAY_NAME as displayName, ORGANIZATION_VHOST.VHOST AS sandbox FROM ORGANIZATION,ORGANIZATION_VHOST where + ORGANIZATION.UUID = ORGANIZATION_VHOST.UUID and ORGANIZATION.UUID =${id} and ORGANIZATION_VHOST.TYPE = 'SANDBOX'`; + stream orgStream2 = dbClient->query(query2); + check from Organizations org2 in orgStream2 do { + string[]? hostArray = organization1.sandbox; + if hostArray !is () { + hostArray.push(org2.sandbox); + } else { + organization1.sandbox = [org2.sandbox]; + } + }; + + if (organization1.id == "") { + return e909414(); + } else { + return organization1; + } + + } on fail var e { + return e909415(e); + } + } +} + +isolated function removeOrganizationDAO(string id) returns boolean|commons:APKError { + postgresql:Client | error dbClient = getConnection(); + if dbClient is error { + return e909401(dbClient); + } else { + sql:ParameterizedQuery query = `DELETE FROM ORGANIZATION WHERE UUID = ${id}`; + sql:ExecutionResult | sql:Error result = dbClient->execute(query); + if result is sql:ExecutionResult { + return true; + } else { + return e909416(); + } + } +} + +isolated function getOrganizationByOrganizationClaimDAO(string claim) returns Internal_Organization|commons:APKError { + postgresql:Client | error dbClient = getConnection(); + if dbClient is error { + return e909401(dbClient); + } else { + sql:ParameterizedQuery query = `SELECT UUID as id FROM ORGANIZATION_CLAIM_MAPPING where claim_value =${claim}`; + string | sql:Error result = dbClient->queryRow(query); + if result is sql:NoRowsError { + return e909414(); + } else if result is string { + return getOrganizationByIdDAO(result); + } else { + return e909417(); + } + } +} + +isolated function getOrganizationByNameDAO(string name) returns Internal_Organization|commons:APKError { + postgresql:Client | error dbClient = getConnection(); + if dbClient is error { + return e909401(dbClient); + } else { + do { + sql:ParameterizedQuery query = `SELECT ORGANIZATION.UUID as id, NAME as name, DISPLAY_NAME as displayName,STATUS as enabled, claim_key as claimKey, + claim_value as claimValue, string_to_array(NAMESPACE::text,',')::text[] AS serviceNamespaces, encode(WORKFLOWS, 'escape')::text AS workflows + FROM ORGANIZATION, ORGANIZATION_CLAIM_MAPPING where ORGANIZATION.UUID = ORGANIZATION_CLAIM_MAPPING.UUID and ORGANIZATION.NAME =${name}`; + stream orgStream = dbClient->query(query); + Internal_Organization organization1 = { + id: "", + name: "", + displayName: "", + enabled: true, + serviceNamespaces: ["*"], + production: [], + workflows: [], + sandbox: [], + claimList: [] + }; + check from Organizations org in orgStream do { + if (organization1.id == "") { + organization1 = { + id:org.id, + name:org.name, + displayName:org.displayName, + enabled: check boolean:fromString(org.enabled), + serviceNamespaces: org.serviceNamespaces, + workflows: org.workflows is string ? check org.workflows.fromJsonStringWithType() : [], + claimList:[{ + claimKey:org.claimKey, + claimValue: org.claimValue + }] + }; + } else { + organization1.claimList.push({ + claimKey:org.claimKey, + claimValue: org.claimValue + }); + } + }; + + sql:ParameterizedQuery query1 = `SELECT ORGANIZATION.UUID as id, NAME as name, DISPLAY_NAME as displayName, ORGANIZATION_VHOST.VHOST AS production FROM ORGANIZATION,ORGANIZATION_VHOST where + ORGANIZATION.UUID = ORGANIZATION_VHOST.UUID and ORGANIZATION.NAME =${name} and ORGANIZATION_VHOST.TYPE = 'PRODUCTION'`; + stream orgStream1 = dbClient->query(query1); + check from Organizations org1 in orgStream1 do { + string[]? hostArray = organization1.production; + if hostArray !is () { + hostArray.push(org1.production); + } else { + organization1.production = [org1.production]; + } + }; + sql:ParameterizedQuery query2 = `SELECT ORGANIZATION.UUID as id, NAME as name, DISPLAY_NAME as displayName, ORGANIZATION_VHOST.VHOST AS sandbox FROM ORGANIZATION,ORGANIZATION_VHOST where + ORGANIZATION.UUID = ORGANIZATION_VHOST.UUID and ORGANIZATION.NAME =${name} and ORGANIZATION_VHOST.TYPE = 'SANDBOX'`; + stream orgStream2 = dbClient->query(query2); + check from Organizations org2 in orgStream2 do { + string[]? hostArray = organization1.sandbox; + if hostArray !is () { + hostArray.push(org2.sandbox); + } else { + organization1.sandbox = [org2.sandbox]; + } + }; + + if (organization1.id == "") { + return e909414(); + } else { + return organization1; + } + + } on fail var e { + return e909415(e); + } + } +} diff --git a/admin/admin-domain-service/ballerina/organizationImpl.bal b/admin/admin-domain-service/ballerina/organizationImpl.bal new file mode 100644 index 000000000..59d203606 --- /dev/null +++ b/admin/admin-domain-service/ballerina/organizationImpl.bal @@ -0,0 +1,128 @@ +// +// Copyright (c) 2022, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + +import ballerina/uuid; +import wso2/apk_common_lib as commons; + +isolated function createInternalFromOrganization(Organization payload) returns Internal_Organization { + OrganizationClaim orgClaim = { + claimKey: "organizationClaimKey", + claimValue: payload.organizationClaimValue + }; + + Internal_Organization internalOrganization = { + id: payload.id.toString(), + name: payload.name, + displayName: payload.displayName, + enabled: payload.enabled, + serviceNamespaces: payload.serviceNamespaces, + workflows: payload.workflows, + production: payload.production, + sandbox: payload.sandbox, + claimList: [ orgClaim ] + }; + return internalOrganization; +} + +isolated function createOrganizationFromInternal(Internal_Organization payload) returns Organization { + Organization organization = { + id: payload.id, + name: payload.name, + displayName: payload.displayName, + enabled: payload.enabled, + serviceNamespaces: payload.serviceNamespaces, + production: payload.production, + sandbox: payload.sandbox, + workflows: payload.workflows, + organizationClaimValue: payload.claimList[0].claimValue + }; + return organization; +} + +isolated function addOrganization(Organization payload) returns Organization|commons:APKError { + boolean validateOrganization = check validateOrganizationByNameDAO(payload.name); + if validateOrganization is true { + return e909427(payload.name); + } + payload.id = uuid:createType1AsString(); + Internal_Organization|commons:APKError organization = addOrganizationDAO(createInternalFromOrganization(payload)); + if organization is Internal_Organization { + Organization createdOrganization = createOrganizationFromInternal(organization); + return createdOrganization; + } else { + return organization; + } +} + +isolated function updatedOrganization(string id, Organization payload) returns Organization|commons:APKError { + boolean validateOrganizationId = check validateOrganizationById(id); + if validateOrganizationId is false { + return e909428(id); + } + payload.id = id; + Internal_Organization|commons:APKError organization = updateOrganizationDAO(id, createInternalFromOrganization(payload)); + if organization is Internal_Organization { + return createOrganizationFromInternal(organization); + } else { + return organization; + } +} + +isolated function getAllOrganization() returns OrganizationList|commons:APKError { + Internal_Organization[]|commons:APKError getOrgnizations = getAllOrganizationDAO(); + if getOrgnizations is Internal_Organization[] { + int count = getOrgnizations.length(); + Organization[] organizations = []; + foreach var organization in getOrgnizations { + organizations.push(createOrganizationFromInternal(organization)); + } + OrganizationList getOrgnizationsList = {count: count, list: organizations}; + return getOrgnizationsList; + } else { + return getOrgnizations; + } +} + +isolated function getOrganizationById(string id) returns Organization|commons:APKError { + Internal_Organization|commons:APKError organization = getOrganizationByIdDAO(id); + if organization is Internal_Organization { + return createOrganizationFromInternal(organization); + } else { + return organization; + } +} + +isolated function removeOrganization(string id) returns boolean|commons:APKError { + boolean validateOrganizationId = check validateOrganizationById(id); + if validateOrganizationId is false { + return e909428(id); + } + boolean|commons:APKError organization = removeOrganizationDAO(id); + return organization; +} + +isolated function getOrganizationByOrganizationClaim() returns Organization|commons:APKError{ + //TO DO: Get organization claim from JWT + string organizationClaimValue = "organizationClaimValue"; + Internal_Organization|commons:APKError organization = getOrganizationByOrganizationClaimDAO(organizationClaimValue); + if organization is Internal_Organization { + return createOrganizationFromInternal(organization); + } else { + return organization; + } +} diff --git a/admin/admin-domain-service/ballerina/resources/admin-api.yaml b/admin/admin-domain-service/ballerina/resources/admin-api.yaml new file mode 100644 index 000000000..e84310292 --- /dev/null +++ b/admin/admin-domain-service/ballerina/resources/admin-api.yaml @@ -0,0 +1,3396 @@ +# Copyright (c) 2022, WSO2 LLC. (http://www.wso2.com). +# +# 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. +################################################################################ +openapi: 3.0.1 +info: + title: WSO2 API Platform for Kubernetes (APK) - Admin + description: | + This document specifies a **RESTful API** for WSO2 **API Platform for Kubernetes (APK)** - **Admin Portal**. + contact: + name: WSO2 + url: https://wso2.com/api-manager/ + email: architecture@wso2.com + license: + name: Apache 2.0 + url: http://www.apache.org/licenses/LICENSE-2.0.html + version: v1 +servers: + - url: https://apis.wso2.com/api/admin/v1 +paths: + ###################################################### + # The "Content Search Results" Throttling Policies + ###################################################### + /policies/search: + get: + tags: + - Unified Search + summary: | + Retrieve/Search Policies + description: | + This operation provides you a list of available Policies qualifying the given keyword match. + parameters: + - name: query + in: query + description: | + **Search**. + You can search by providing a keyword. Allowed to search by type and name only. + schema: + type: string + responses: + 200: + description: | + OK.List of qualifying Policies is returned. + headers: + Content-Type: + description: The content type of the body. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/PolicyDetailsList' + security: + - OAuth2Security: + - apk:admin + - apk:tier_view + - apk:policies_import_export + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://127.0.0.1:9443/api/admin/v3/throttling/policies/search?query=type:sub"' + operationId: policySearch + + ###################################################### + # The "Application Rate Plans Collection" resource API + ###################################################### + /application-rate-plans: + get: + tags: + - Application Rate Plan (Collection) + summary: Get all Application Rate Plans + description: | + Retrieves all existing application rate plans. + parameters: + - $ref: '#/components/parameters/Accept' + responses: + 200: + description: | + OK. Policies returned + headers: + Content-Type: + description: | + The content type of the body. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/ApplicationRatePlanList' + 406: + $ref: '#/components/responses/NotAcceptable' + security: + - OAuth2Security: + - apk:tier_manage + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://127.0.0.1:9443/api/admin/application-rate-plans"' + operationId: getApplicationRatePlans + + post: + tags: + - Application Rate Plan (Collection) + summary: Add an Application Rate Plan + description: | + This operation can be used to add a new application level rate plan. + parameters: + - $ref: '#/components/parameters/Content-Type' + requestBody: + description: | + Application level policy object that should to be added + content: + application/json: + schema: + $ref: '#/components/schemas/ApplicationRatePlan' + required: true + responses: + 201: + description: | + Created. Successful response with the newly created object as entity in the body. Location header contains URL of newly created entity. + headers: + Location: + description: | + Location of the newly created Policy object. + schema: + type: string + Content-Type: + description: | + The content type of the body. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/ApplicationRatePlan' + example: + policyId: e0fd4a15-969e-4056-94c8-8a7b56f8103f + policyName: 20PerMin + displayName: 20PerMin + description: Allows 20 request per minute + isDeployed: true + defaultLimit: + type: REQUESTCOUNTLIMIT + requestCount: + timeUnit: min + unitTime: 1 + requestCount: 20 + 400: + $ref: '#/components/responses/BadRequest' + 415: + $ref: '#/components/responses/UnsupportedMediaType' + security: + - OAuth2Security: + - apk:tier_manage + x-code-samples: + - lang: Curl + source: 'curl -k -X POST -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + -H "Content-Type: application/json" -d @data.json "https://127.0.0.1:9443/api/admin/application-rate-plans"' + operationId: addApplicationRatePlan + + ###################################################### + # The "Individual Application Rate Plan" resource API + ###################################################### + /application-rate-plans/{planId}: + get: + tags: + - Application Rate Plan (Individual) + summary: Get an Application Rate Plan + description: | + Retrieves an application rate plan. + parameters: + - $ref: '#/components/parameters/planId' + responses: + 200: + description: | + OK. Plan returned + headers: + Content-Type: + description: | + The content type of the body. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/ApplicationRatePlan' + example: + policyId: e0fd4a15-969e-4056-94c8-8a7b56f8103f + policyName: 20PerMin + displayName: 20PerMin + description: Allows 20 request per minute + isDeployed: true + defaultLimit: + type: REQUESTCOUNTLIMIT + requestCount: + timeUnit: min + unitTime: 1 + requestCount: 20 + 404: + $ref: '#/components/responses/NotFound' + 406: + $ref: '#/components/responses/NotAcceptable' + security: + - OAuth2Security: + - apk:tier_manage + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://127.0.0.1:9443/api/admin/application-rate-plans/4e098fff-7f94-459a-981f-d257332f69d0"' + operationId: getApplicationRatePlanById + + put: + tags: + - Application Rate Plan (Individual) + summary: Update an Application Rate Plan + description: | + Updates an existing application level rate plan. Upon a successful update, you will receive the updated application plan as the response. + parameters: + - $ref: '#/components/parameters/planId' + - $ref: '#/components/parameters/Content-Type' + requestBody: + description: | + Policy object that needs to be modified + content: + application/json: + schema: + $ref: '#/components/schemas/ApplicationRatePlan' + required: true + responses: + 200: + description: | + OK. Plan updated. + headers: + Location: + description: | + The URL of the newly created resource. + schema: + type: string + Content-Type: + description: | + The content type of the body. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/ApplicationRatePlan' + example: + policyId: e0fd4a15-969e-4056-94c8-8a7b56f8103f + policyName: 20PerMin + displayName: 20PerMin + description: Allows 20 request per minute + isDeployed: true + defaultLimit: + type: REQUESTCOUNTLIMIT + requestCount: + timeUnit: min + unitTime: 1 + requestCount: 20 + 400: + $ref: '#/components/responses/BadRequest' + 404: + $ref: '#/components/responses/NotFound' + security: + - OAuth2Security: + - apk:tier_manage + x-code-samples: + - lang: Curl + source: 'curl -k -X PUT -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + -H "Content-Type: application/json" -d @data.json "https://127.0.0.1:9443/api/admin/application-rate-plans/4e098fff-7f94-459a-981f-d257332f69d0"' + operationId: updateApplicationRatePlan + + delete: + tags: + - Application Rate Plan (Individual) + summary: Delete an Application Rate Plan + description: | + Deletes an application level rate plan. + parameters: + - $ref: '#/components/parameters/planId' + responses: + 200: + description: | + OK. Resource successfully deleted. + content: {} + 404: + $ref: '#/components/responses/NotFound' + security: + - OAuth2Security: + - apk:tier_manage + x-code-samples: + - lang: Curl + source: 'curl -k -X DELETE -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://127.0.0.1:9443/api/admin/application-rate-plans/4e098fff-7f94-459a-981f-d257332f69d0"' + operationId: removeApplicationRatePlan + + + ###################################################### + # The "Business Plans Collection" resource API + ###################################################### + /business-plans: + get: + tags: + - Business Plan (Collection) + summary: Get all Business Plans + description: | + This operation can be used to retrieve all Business Plans. + parameters: + - $ref: '#/components/parameters/Accept' + responses: + 200: + description: | + OK. Plans returned + headers: + Content-Type: + description: | + The content type of the body. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/BusinessPlanList' + 406: + $ref: '#/components/responses/NotAcceptable' + security: + - OAuth2Security: + - apk:tier_manage + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://127.0.0.1:9443/api/admin/business-plans"' + operationId: getAllBusinessPlans + + post: + tags: + - Business Plan (Collection) + summary: Add a Business Plan + description: | + This operation can be used to add a Business Plan specifying the details of the plan in the payload. + parameters: + - $ref: '#/components/parameters/Content-Type' + requestBody: + description: | + Business Plan object that should to be added + content: + application/json: + schema: + $ref: '#/components/schemas/BusinessPlan' + required: true + responses: + 201: + description: | + Created. Successful response with the newly created object as entity in the body. Location header contains URL of newly created entity. + headers: + Location: + description: | + Location of the newly created Plan object. + schema: + type: string + Content-Type: + description: | + The content type of the body. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/BusinessPlan' + example: + policyId: 78c3ebff-176d-40d8-9377-fb3276528291 + policyName: Gold + displayName: Gold + description: Allows 5000 requests per minute + isDeployed: true + defaultLimit: + type: REQUESTCOUNTLIMIT + requestCount: + timeUnit: min + unitTime: 1 + requestCount: 5000 + rateLimitCount: 0 + customAttributes: [] + stopOnQuotaReach: true + billingPlan: FREE + 400: + $ref: '#/components/responses/BadRequest' + 415: + $ref: '#/components/responses/UnsupportedMediaType' + security: + - OAuth2Security: + - apk:tier_manage + x-code-samples: + - lang: Curl + source: 'curl -k -X POST -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + -H "Content-Type: application/json" -d @data.json "https://127.0.0.1:9443/api/admin/business-plans"' + operationId: addBusinessPlan + + ###################################################### + # The "Individual Business Plan" resource API + ###################################################### + /business-plans/{planId}: + get: + tags: + - Business Plan (Individual) + summary: Get a Business Plan + description: | + This operation can be used to retrieves Business Plan by specifying the Id of the plan as a path parameter + parameters: + - $ref: '#/components/parameters/planId' + responses: + 200: + description: | + OK. Plan returned + headers: + Content-Type: + description: | + The content type of the body. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/BusinessPlan' + example: + policyId: 78c3ebff-176d-40d8-9377-fb3276528291 + policyName: Gold + displayName: Gold + description: Allows 5000 requests per minute + isDeployed: true + defaultLimit: + type: REQUESTCOUNTLIMIT + requestCount: + timeUnit: min + unitTime: 1 + requestCount: 5000 + rateLimitCount: 0 + customAttributes: [] + stopOnQuotaReach: true + billingPlan: FREE + 404: + $ref: '#/components/responses/NotFound' + 406: + $ref: '#/components/responses/NotAcceptable' + security: + - OAuth2Security: + - apk:tier_manage + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://127.0.0.1:9443/api/admin/business-plans/c948c723-71dd-4d50-8c77-0a0e99c8cbb1"' + operationId: getBusinessPlanById + + put: + tags: + - Business Plan (Individual) + summary: Update a Business Plan + description: | + Updates an existing Business Plan. + parameters: + - $ref: '#/components/parameters/planId' + - $ref: '#/components/parameters/Content-Type' + requestBody: + description: | + Plan object that needs to be modified + content: + application/json: + schema: + $ref: '#/components/schemas/BusinessPlan' + required: true + responses: + 200: + description: | + OK. Plan updated. + headers: + Location: + description: | + The URL of the newly created resource. + schema: + type: string + Content-Type: + description: | + The content type of the body. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/BusinessPlan' + example: + policyId: 78c3ebff-176d-40d8-9377-fb3276528291 + policyName: Gold + displayName: Gold + description: Allows 5000 requests per minute + isDeployed: true + defaultLimit: + type: REQUESTCOUNTLIMIT + requestCount: + timeUnit: min + unitTime: 1 + requestCount: 5000 + rateLimitCount: 0 + customAttributes: [] + stopOnQuotaReach: true + billingPlan: FREE + 400: + $ref: '#/components/responses/BadRequest' + 404: + $ref: '#/components/responses/NotFound' + security: + - OAuth2Security: + - apk:tier_manage + x-code-samples: + - lang: Curl + source: 'curl -k -X PUT -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + -H "Content-Type: application/json" -d @data.json "https://127.0.0.1:9443/api/admin/business-plans/c948c723-71dd-4d50-8c77-0a0e99c8cbb1"' + operationId: updateBusinessPlan + + delete: + tags: + - Business Plan (Individual) + summary: Delete a Business Plan + description: | + This operation can be used to delete a business plan by specifying the Id of the plan as a path parameter. + parameters: + - $ref: '#/components/parameters/planId' + responses: + 200: + description: | + OK. Resource successfully deleted. + content: {} + 404: + $ref: '#/components/responses/NotFound' + security: + - OAuth2Security: + - apk:tier_manage + x-code-samples: + - lang: Curl + source: 'curl -k -X DELETE -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://127.0.0.1:9443/api/admin/business-plans/c948c723-71dd-4d50-8c77-0a0e99c8cbb1"' + operationId: removeBusinessPlan + + ###################################################### + # "Export Throttling Policy" resource API + ###################################################### + /throttling/policies/export: + get: + tags: + - Import Export + summary: Export a Throttling Policy + description: | + This operation can be used to export the details of a particular Throttling Policy. + parameters: + - name: policyId + in: query + description: UUID of the ThrottlingPolicy + schema: + type: string + - name: name + in: query + description: | + Throttling Policy Name + schema: + type: string + - name: type + in: query + description: | + Type of the Throttling Policy + schema: + type: string + enum: + - sub + - app + - api + - global + - name: format + in: query + description: | + Format of output documents. Can be YAML or JSON. + schema: + type: string + enum: + - JSON + - YAML + responses: + 200: + description: | + OK. Export Successful. + headers: + Content-Type: + description: | + The content type of the body. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/ExportPolicy' + example: + type: rate-limiting policy + subtype: application + version: v4.1.0 + data: + policyId: cd828243-a0db-430c-97e9-9e41fd865d48 + policyName: 50PerMin + displayName: 50PerMin + description: Allows 50 request per minute + isDeployed: true + type: ApplicationThrottlePolicy + defaultLimit: + type: BANDWIDTHLIMIT + requestCount: + timeUnit: min + unitTime: 1 + requestCount: 50 + bandwidth: + timeUnit: min + unitTime: 5 + dataAmount: 100 + dataUnit: MB + eventCount: + timeUnit: min + unitTime: 5 + eventCount: 16 + 404: + $ref: '#/components/responses/NotFound' + 500: + $ref: '#/components/responses/InternalServerError' + security: + - OAuth2Security: + - apk:tier_manage + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://127.0.0.1:9443/api/admin/v3/throttling/policies/export?policyId=96077508-fd01-4fae-bc64-5de0e2baf43c&name=Bronze&type=subscription&format=YAML"' + operationId: exportThrottlingPolicy + #################################################################### + # Import Throttling Policy + #################################################################### + /throttling/policies/import: + post: + tags: + - Import Export + summary: Import a Throttling Policy + description: | + This operation can be used to import a Throttling Policy. + parameters: + - name: overwrite + in: query + description: | + Update an existing throttling policy with the same name. + required: false + schema: + type: boolean + requestBody: + content: + multipart/form-data: + schema: + required: + - file + properties: + file: + type: string + description: Json File + format: binary + required: true + responses: + 200: + description: | + Created. Throttling Policy Imported Successfully. + 403: + $ref: '#/components/responses/Forbidden' + 404: + $ref: '#/components/responses/NotFound' + 409: + $ref: '#/components/responses/Conflict' + 500: + $ref: '#/components/responses/InternalServerError' + security: + - OAuth2Security: + - apk:tier_manage + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://127.0.0.1:9443/api/admin/v3/throttling/policies/import?overwrite=True"' + operationId: importThrottlingPolicy + ###################################################### + # The "Deny Policy Collection" resource API + ###################################################### + /deny-policies: + get: + tags: + - Deny Policies (Collection) + summary: Get all Deny Policies + description: | + Retrieves all existing deny policies. + parameters: + - $ref: '#/components/parameters/Accept' + responses: + 200: + description: | + OK. Deny Policies returned + headers: + Content-Type: + description: | + The content type of the body. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/BlockingConditionList' + 406: + $ref: '#/components/responses/NotAcceptable' + security: + - OAuth2Security: + - apk:bl_manage + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://127.0.0.1:9443/api/admin/v3/throttling/deny-policies"' + operationId: getAllDenyPolicies + + post: + tags: + - Deny Policies (Collection) + summary: Add a deny policy + description: | + Adds a new deny policy + parameters: + - $ref: '#/components/parameters/Content-Type' + requestBody: + description: | + Blocking condition object that should to be added + content: + application/json: + schema: + $ref: '#/components/schemas/BlockingCondition' + required: true + responses: + 201: + description: | + Created. Successful response with the newly created object as entity in the body. Location header contains URL of newly created entity. + headers: + Location: + description: | + Location of the newly created resource. + schema: + type: string + Content-Type: + description: | + The content type of the body. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/BlockingCondition' + 400: + $ref: '#/components/responses/BadRequest' + 415: + $ref: '#/components/responses/UnsupportedMediaType' + security: + - OAuth2Security: + - apk:bl_manage + x-code-samples: + - lang: Curl + source: 'curl -k -X POST -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + -H "Content-Type: application/json" -d @data.json "https://127.0.0.1:9443/api/admin/v3/throttling/deny-policies"' + operationId: addDenyPolicy + + ###################################################### + # The "Individual Deny Policy" resource API + ###################################################### + /deny-policies/{policyId}: + get: + tags: + - Deny Policy (Individual) + summary: Get a Deny Policy + description: | + Retrieves a Deny policy providing the policy Id + parameters: + - $ref: '#/components/parameters/policyId' + responses: + 200: + description: | + OK. Condition returned + headers: + Content-Type: + description: | + The content type of the body. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/BlockingCondition' + 404: + $ref: '#/components/responses/NotFound' + 406: + $ref: '#/components/responses/NotAcceptable' + security: + - OAuth2Security: + - apk:bl_manage + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://127.0.0.1:9443/api/admin/v3/throttling/deny-policy/b513eb68-69e8-4c32-92cf-852c101363c"' + operationId: getDenyPolicyById + + delete: + tags: + - Deny Policy (Individual) + summary: Delete a Deny Policy + description: | + Deletes an existing deny policy + parameters: + - $ref: '#/components/parameters/policyId' + responses: + 200: + description: | + OK. Resource successfully deleted. + content: {} + 404: + $ref: '#/components/responses/NotFound' + security: + - OAuth2Security: + - apk:bl_manage + x-code-samples: + - lang: Curl + source: 'curl -k -X DELETE -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://127.0.0.1:9443/api/admin/v3/throttling/deny-policy/b513eb68-69e8-4c32-92cf-852c101363c"' + operationId: removeDenyPolicy + + patch: + tags: + - Deny Policy (Individual) + summary: Update a Deny Policy + description: | + Update a deny policy by Id + parameters: + - $ref: '#/components/parameters/policyId' + - $ref: '#/components/parameters/Content-Type' + requestBody: + description: | + Blocking condition with updated status + content: + application/json: + schema: + $ref: '#/components/schemas/BlockingConditionStatus' + required: true + responses: + 200: + description: | + OK. Resource successfully updated. + content: + application/json: + schema: + $ref: '#/components/schemas/BlockingCondition' + 400: + $ref: '#/components/responses/BadRequest' + 404: + $ref: '#/components/responses/NotFound' + security: + - OAuth2Security: + - apk:bl_manage + x-code-samples: + - lang: Curl + source: 'curl -k -X PATCH -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + -H "Content-Type: application/json" -d @data.json "https://127.0.0.1:9443/api/admin/v3/throttling/deny-policy/b513eb68-69e8-4c32-92cf-852c101363c"' + operationId: updateDenyPolicy + + ###################################################### + # The "Application Collection" resource APIs + ###################################################### + /applications: + get: + tags: + - Application (Collection) + summary: | + Retrieve/Search Applications + description: | + This operation can be used to retrieve list of applications owned by the given user, If no user + is provided, the applications owned by the user associated with the provided access token will be returned. + parameters: + - $ref: '#/components/parameters/user' + - $ref: '#/components/parameters/limit' + - $ref: '#/components/parameters/offset' + - $ref: '#/components/parameters/Accept' + - name: name + in: query + description: | + Application Name + schema: + type: string + - name: tenantDomain + in: query + description: | + Tenant domain of the applications to get. This has to be specified only if it is required to get applications of + a tenant other than the requester's tenant. So, if not specified, the default will be set as the + requester's tenant domain. This cross tenant Application access is allowed only for super tenant admin + users **only at a migration process**. + schema: + type: string + - name: sortBy + in: query + schema: + type: string + enum: + - name + - owner + default: name + - name: sortOrder + in: query + schema: + type: string + enum: + - asc + - desc + default: asc + responses: + 200: + description: | + OK. Application list returned. + headers: + Content-Type: + description: | + The content type of the body. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/ApplicationList' + 400: + $ref: '#/components/responses/BadRequest' + 406: + $ref: '#/components/responses/NotAcceptable' + security: + - OAuth2Security: + - apk:admin_application_manage + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://127.0.0.1:9443/api/admin/v3/applications"' + operationId: getApplicationsByUser + + ###################################################### + # The "Individual Application" resource APIs + ###################################################### + /applications/{applicationId}: + get: + tags: + - Applications + summary: | + Get the details of an Application + description: | + This operation can be used to get the details of an application by specifying its id. + parameters: + - $ref: '#/components/parameters/applicationId' + responses: + 200: + description: | + OK. Application details returned. + content: + application/json: + schema: + $ref: '#/components/schemas/Application' + 400: + $ref: '#/components/responses/BadRequest' + 404: + $ref: '#/components/responses/NotFound' + 406: + $ref: '#/components/responses/NotAcceptable' + security: + - OAuth2Security: + - apk:admin_application_manage + x-code-samples: + - lang: Curl + source: 'curl -k -X GET -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://127.0.0.1:9443/api/admin/v3/applications/0a043c2b-ee75-4ef3-9e1c-fc2610ccfa8b"' + operationId: getApplicationById + + delete: + tags: + - Applications + summary: | + Delete an Application + description: | + This operation can be used to delete an application by specifying its id. + parameters: + - $ref: '#/components/parameters/applicationId' + responses: + 200: + description: | + OK. Resource successfully deleted. + content: {} + 202: + description: | + Accepted. The request has been accepted. + headers: + Location: + description: | + Location of the existing Application. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/WorkflowResponse' + 404: + $ref: '#/components/responses/NotFound' + security: + - OAuth2Security: + - apk:admin_application_manage + x-code-samples: + - lang: Curl + source: 'curl -k -X DELETE -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://127.0.0.1:9443/api/admin/v3/applications/0a043c2b-ee75-4ef3-9e1c-fc2610ccfa8b"' + operationId: removeApplication + + /applications/{applicationId}/change-owner: + post: + tags: + - Application + summary: Change Application Owner + description: | + This operation is used to change the owner of an Application. + In order to change the owner of an application, we need to pass the new application owner as a query parameter + parameters: + - name: owner + in: query + required: true + schema: + type: string + - $ref: '#/components/parameters/applicationId' + responses: + 200: + description: | + OK. Application owner changed successfully. + content: {} + 400: + $ref: '#/components/responses/BadRequest' + 404: + $ref: '#/components/responses/NotFound' + security: + - OAuth2Security: + - apk:admin_application_manage + x-code-samples: + - lang: Curl + source: 'curl -k -X POST -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://127.0.0.1:9443/api/admin/v3/applications/0a043c2b-ee75-4ef3-9e1c-fc2610ccfa8b/change-owner?owner=admin"' + operationId: changeApplicationOwner + + ###################################################### + # The "Environment" resource API + ###################################################### + /environments: + get: + tags: + - Environments + summary: Get all registered Environments + description: | + Get all Registered Environments + responses: + 200: + description: | + OK. Environments returned + content: + application/json: + schema: + $ref: '#/components/schemas/EnvironmentList' + security: + - OAuth2Security: + - apk:admin + - apk:environment_read + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://127.0.0.1:9443/api/admin/v3/environments"' + operationId: getEnvironments + + post: + tags: + - Environments + summary: Add an Environment + description: | + Add a new gateway environment + requestBody: + description: | + Environment object that should to be added + content: + application/json: + schema: + $ref: '#/components/schemas/Environment' + required: true + responses: + 201: + description: | + Created. Successful response with the newly created environment as entity in the body. + content: + application/json: + schema: + $ref: '#/components/schemas/Environment' + 400: + $ref: '#/components/responses/BadRequest' + security: + - OAuth2Security: + - apk:admin + - apk:environment_manage + x-code-samples: + - lang: Curl + source: 'curl -k -X POST -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + -H "Content-Type: application/json" -d @data.json "https://127.0.0.1:9443/api/admin/v3/environments"' + operationId: addEnvironment + + ###################################################### + # The "Individual Environment" resource APIs + ###################################################### + /environments/{environmentId}: + put: + tags: + - Environments + summary: Update an Environment + description: | + Update a gateway Environment by environment Id + parameters: + - $ref: '#/components/parameters/environmentId' + requestBody: + description: | + Environment object with updated information + content: + application/json: + schema: + $ref: '#/components/schemas/Environment' + required: true + responses: + 200: + description: | + OK. Environment updated. + content: + application/json: + schema: + $ref: '#/components/schemas/Environment' + 400: + $ref: '#/components/responses/BadRequest' + 404: + $ref: '#/components/responses/NotFound' + security: + - OAuth2Security: + - apk:admin + - apk:environment_manage + x-code-samples: + - lang: Curl + source: 'curl -k -X PUT -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + -H "Content-Type: application/json" -d @data.json "https://127.0.0.1:9443/api/admin/v3/environments/d7cf8523-9180-4255-84fa-6cb171c1f779"' + operationId: updateEnvironment + + delete: + tags: + - Environments + summary: Delete an Environment + description: | + Delete a Environment by Environment Id + parameters: + - $ref: '#/components/parameters/environmentId' + responses: + 200: + description: | + OK. Environment successfully deleted. + content: {} + 404: + $ref: '#/components/responses/NotFound' + security: + - OAuth2Security: + - apk:admin + - apk:environment_manage + x-code-samples: + - lang: Curl + source: 'curl -k -X DELETE -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://127.0.0.1:9443/api/admin/v3/environments/d7cf8523-9180-4255-84fa-6cb171c1f779"' + operationId: removeEnvironment + + + ###################################################### + # The Tenant Info resource API + ###################################################### + /tenant-info/{username}: + get: + tags: + - Tenants + summary: | + Get Tenant Id of User + description: | + This operation is to get tenant id of the provided user + operationId: getTenantInfoByUsername + parameters: + - name: username + in: path + description: | + The state represents the current state of the tenant. Supported states are [ active, inactive] + required: true + schema: + type: string + default: john + responses: + 200: + description: | + OK. Tenant id of the user retrieved. + headers: + Content-Type: + description: | + The content type of the body. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/TenantInfo' + 404: + $ref: '#/components/responses/NotFound' + 406: + $ref: '#/components/responses/NotAcceptable' + security: + - OAuth2Security: + - apk:admin + - apk:tenantInfo + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://127.0.0.1:9443/api/admin/v3/tenant-info/john"' + + ###################################################### + # The Custom URL Info resource API + ###################################################### + /custom-urls/{tenantDomain}: + get: + tags: + - Tenants + summary: | + Get Custom URL Info of a Tenant Domain + description: | + This operation is to get custom-url information of the provided tenant-domain + operationId: getCustomUrlInfoByTenantDomain + parameters: + - name: tenantDomain + in: path + description: | + The tenant domain name. + required: true + schema: + type: string + responses: + 200: + description: | + OK. Custom url info of the tenant is retrieved. + headers: + Content-Type: + description: | + The content type of the body. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/CustomUrlInfo' + 404: + $ref: '#/components/responses/NotFound' + 406: + $ref: '#/components/responses/NotAcceptable' + security: + - OAuth2Security: + - apk:admin + - apk:tenantInfo + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://127.0.0.1:9443/api/admin/v3/custom-urls/wso2.com"' + + ###################################################### + # The "Category Collection" resource API + ###################################################### + /api-categories: + get: + tags: + - API Category (Collection) + summary: Get all API Categories + description: | + Get all API categories + responses: + 200: + description: | + OK. Categories returned + content: + application/json: + schema: + $ref: '#/components/schemas/APICategoryList' + security: + - OAuth2Security: + - apk:category_manage + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://127.0.0.1:9443/api/admin/v3/api-categories"' + operationId: getAllCategories + + post: + tags: + - API Category (Individual) + summary: Add API Category + description: | + Add a new API category + requestBody: + description: | + API Category object that should to be added + content: + application/json: + schema: + $ref: '#/components/schemas/APICategory' + required: true + responses: + 201: + description: | + Created. Successful response with the newly created object as entity in the body. + content: + application/json: + schema: + $ref: '#/components/schemas/APICategory' + 400: + $ref: '#/components/responses/BadRequest' + security: + - OAuth2Security: + - apk:category_manage + x-code-samples: + - lang: Curl + source: 'curl -k -X POST -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + -H "Content-Type: application/json" -d @data.json "https://127.0.0.1:9443/api/admin/v3/api-categories"' + operationId: addCategory + + ###################################################### + # The "Individual Category" resource APIs + ###################################################### + /api-categories/{apiCategoryId}: + put: + tags: + - API Category (Individual) + summary: Update an API Category + description: | + Update an API Category by category Id + parameters: + - $ref: '#/components/parameters/apiCategoryId' + requestBody: + description: | + API Category object with updated information + content: + application/json: + schema: + $ref: '#/components/schemas/APICategory' + required: true + responses: + 200: + description: | + OK. Label updated. + content: + application/json: + schema: + $ref: '#/components/schemas/APICategory' + 400: + $ref: '#/components/responses/BadRequest' + 404: + $ref: '#/components/responses/NotFound' + security: + - OAuth2Security: + - apk:category_manage + x-code-samples: + - lang: Curl + source: 'curl -k -X PUT -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + -H "Content-Type: application/json" -d @data.json "https://127.0.0.1:9443/api/admin/v3/api-categories/d7cf8523-9180-4255-84fa-6cb171c1f779"' + operationId: updateCategory + + delete: + tags: + - API Category (Individual) + summary: Delete an API Category + description: | + Delete an API Category by API Category Id + parameters: + - $ref: '#/components/parameters/apiCategoryId' + responses: + 200: + description: | + OK. API Category successfully deleted. + content: {} + 404: + $ref: '#/components/responses/NotFound' + security: + - OAuth2Security: + - apk:category_manage + x-code-samples: + - lang: Curl + source: 'curl -k -X DELETE -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://127.0.0.1:9443/api/admin/v3/api-categories/d7cf8523-9180-4255-84fa-6cb171c1f779"' + operationId: removeCategory + + ###################################################### + # The Admin settings List + ###################################################### + /settings: + get: + tags: + - Settings + summary: Retrieve Admin Settings + description: | + Retrieve admin settings + responses: + 200: + description: | + OK. Settings returned + content: + application/json: + schema: + $ref: '#/components/schemas/Settings' + 404: + $ref: '#/components/responses/NotFound' + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://127.0.0.1:9443/api/admin/v3/settings"' + operationId: getAdminSettings + + ###################################################### + # The "Key Manager Collection" resource API + ###################################################### + /key-managers: + get: + tags: + - Key Manager (Collection) + summary: Get all Key managers + description: | + Get all Key managers + responses: + 200: + description: | + OK. KeyManagers returned + content: + application/json: + schema: + $ref: '#/components/schemas/KeyManagerList' + security: + - OAuth2Security: + - apk:keymanager_operations + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://127.0.0.1:9443/api/admin/v3/key-managers"' + operationId: getAllKeyManagers + + post: + tags: + - Key Manager (Collection) + summary: Add a new API Key Manager + description: | + Add a new API Key Manager + requestBody: + description: | + Key Manager object that should to be added + content: + application/json: + schema: + $ref: '#/components/schemas/KeyManager' + required: true + responses: + 201: + description: | + Created. Successful response with the newly created object as entity in the body. + content: + application/json: + schema: + $ref: '#/components/schemas/KeyManager' + 400: + $ref: '#/components/responses/BadRequest' + security: + - OAuth2Security: + - apk:keymanager_operations + x-code-samples: + - lang: Curl + source: 'curl -k -X POST -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + -H "Content-Type: application/json" -d @data.json "https://127.0.0.1:9443/api/admin/v3/key-managers"' + operationId: addNewKeyManager + + ###################################################### + # The "Individual KeyManager" resource APIs + ###################################################### + /key-managers/{keyManagerId}: + get: + tags: + - Key Manager (Individual) + summary: Get a Key Manager Configuration + description: | + Retrieve a single Key Manager Configuration. We should provide the Id of the KeyManager as a path parameter. + parameters: + - $ref: '#/components/parameters/keyManagerId' + responses: + 200: + description: | + OK. KeyManager Configuration returned + headers: + Content-Type: + description: | + The content type of the body. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/KeyManager' + 404: + $ref: '#/components/responses/NotFound' + 406: + $ref: '#/components/responses/NotAcceptable' + security: + - OAuth2Security: + - apk:keymanager_operations + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://127.0.0.1:9443/api/admin/v3/key-managers/8d263942-a6df-4cc2-a804-7a2525501450"' + operationId: getKeyManagerConfiguration + + put: + tags: + - Key Manager (Individual) + summary: Update a Key Manager + description: | + Update a Key Manager by keyManager ID + parameters: + - $ref: '#/components/parameters/keyManagerId' + requestBody: + description: | + Key Manager object with updated information + content: + application/json: + schema: + $ref: '#/components/schemas/KeyManager' + required: true + responses: + 200: + description: | + OK. Label updated. + content: + application/json: + schema: + $ref: '#/components/schemas/KeyManager' + 400: + $ref: '#/components/responses/BadRequest' + 404: + $ref: '#/components/responses/NotFound' + security: + - OAuth2Security: + - apk:keymanager_operations + x-code-samples: + - lang: Curl + source: 'curl -k -X PUT -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + -H "Content-Type: application/json" -d @data.json "https://127.0.0.1:9443/api/admin/v3/key-managers/8d263942-a6df-4cc2-a804-7a2525501450"' + operationId: updateKeyManager + + delete: + tags: + - Key Manager (Individual) + summary: Delete a Key Manager + description: | + Delete a Key Manager by keyManager id + parameters: + - $ref: '#/components/parameters/keyManagerId' + responses: + 200: + description: | + OK. Key Manager successfully deleted. + content: {} + 404: + $ref: '#/components/responses/NotFound' + security: + - OAuth2Security: + - apk:keymanager_operations + x-code-samples: + - lang: Curl + source: 'curl -k -X DELETE -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://127.0.0.1:9443/api/admin/v3/key-managers/8d263942-a6df-4cc2-a804-7a2525501450"' + operationId: removeKeyManager + + /key-managers/discover: + post: + tags: + - Key Manager (Collection) + summary: Retrieve Well-known information from Key Manager Well-known Endpoint + description: | + Retrieve well-known information from key manager's well-known endpoint + requestBody: + content: + multipart/form-data: + schema: + properties: + url: + type: string + description: Well-Known Endpoint + type: + type: string + description: | + Key Manager Type + default: "false" + responses: + 200: + description: | + OK. KeyManagers returned + content: + application/json: + schema: + $ref: '#/components/schemas/KeyManagerWellKnownResponse' + security: + - OAuth2Security: + - apk:keymanager_operations + x-code-samples: + - lang: Curl + source: 'curl -k -X POST -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + -F "type=WSO2-IS" "https://127.0.0.1:9443/api/admin/v3/key-managers/discover"' + operationId: getWellKnownInfoKeyManager + +###################################################### + # The "Organization" resource API +###################################################### + /organizations: + get: + tags: + - Organization (Collection) + summary: Get all Organization + description: | + Get all Organization + responses: + 200: + description: | + OK. Organization returned + content: + application/json: + schema: + $ref: '#/components/schemas/OrganizationList' + security: + - OAuth2Security: + - apk:organization_manage + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://127.0.0.1:9443/api/admin/organizations"' + operationId: getAllOrganization + + post: + tags: + - Organization (Individual) + summary: Add Organization + description: | + Add a new Organization + requestBody: + description: | + Organization object that should to be added + content: + application/json: + schema: + $ref: '#/components/schemas/Organization' + required: true + responses: + 201: + description: | + Created. Successful response with the newly created object as entity in the body. + content: + application/json: + schema: + $ref: '#/components/schemas/Organization' + 400: + $ref: '#/components/responses/BadRequest' + security: + - OAuth2Security: + - apk:organization_manage + x-code-samples: + - lang: Curl + source: 'curl -k -X POST -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + -H "Content-Type: application/json" -d @data.json "https://127.0.0.1:9443/api/admin/organizations"' + operationId: addOrganization + /organizations/{organizationId}: + get: + tags: + - Organization (Individual) + summary: | + Get the details of an Organization + description: | + This operation can be used to get the details of an Organization by specifying its id. + parameters: + - $ref: '#/components/parameters/organizationId' + responses: + 200: + description: | + OK. Application details returned. + content: + application/json: + schema: + $ref: '#/components/schemas/Organization' + 400: + $ref: '#/components/responses/BadRequest' + 404: + $ref: '#/components/responses/NotFound' + 406: + $ref: '#/components/responses/NotAcceptable' + security: + - OAuth2Security: + - apk:organization_manage + x-code-samples: + - lang: Curl + source: 'curl -k -X GET -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://127.0.0.1:9443/api/admin/organizations/0a043c2b-ee75-4ef3-9e1c-fc2610ccfa8b"' + operationId: getOrganizationById + put: + tags: + - Organization (Individual) + summary: Update an Organization + description: | + Update an Organization by organization Id + parameters: + - $ref: '#/components/parameters/organizationId' + requestBody: + description: | + Organization object with updated information + content: + application/json: + schema: + $ref: '#/components/schemas/Organization' + required: true + responses: + 200: + description: | + OK. Label updated. + content: + application/json: + schema: + $ref: '#/components/schemas/Organization' + 400: + $ref: '#/components/responses/BadRequest' + 404: + $ref: '#/components/responses/NotFound' + security: + - OAuth2Security: + - apk:organization_manage + x-code-samples: + - lang: Curl + source: 'curl -k -X PUT -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + -H "Content-Type: application/json" -d @data.json "https://127.0.0.1:9443/api/admin/organizations/d7cf8523-9180-4255-84fa-6cb171c1f779"' + operationId: updateOrganization + delete: + tags: + - Organization (Individual) + summary: Delete an Organization + description: | + Delete an Organization by API Organization Id + parameters: + - $ref: '#/components/parameters/organizationId' + responses: + 200: + description: | + OK. Organization successfully deleted. + content: {} + 404: + $ref: '#/components/responses/NotFound' + security: + - OAuth2Security: + - apk:organization_manage + x-code-samples: + - lang: Curl + source: 'curl -k -X DELETE -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://127.0.0.1:9443/api/admin/organizations/d7cf8523-9180-4255-84fa-6cb171c1f779"' + operationId: removeOrganization + /organization-info: + get: + tags: + - Organization (Individual) + summary: | + Authenticate Organization info + description: | + This operation can be used to authenticate Organization by specifying its claimValue. + responses: + 200: + description: | + OK. Application details returned. + content: + application/json: + schema: + $ref: '#/components/schemas/Organization' + 400: + $ref: '#/components/responses/BadRequest' + 404: + $ref: '#/components/responses/NotFound' + security: + - OAuth2Security: + - apk:organization_manage + x-code-samples: + - lang: Curl + source: 'curl -k -X GET -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://127.0.0.1:9443/api/admin/organization-info/0a043c2b-ee75-4ef3-9e1c-fc2610ccfa8b"' + operationId: getOrganizationByClaimValue + + ###################################################### + # The "Workflow Collection" resource APIs + ###################################################### + /workflows: + get: + tags: + - Workflow (Collection) + summary: | + Retrieve All Pending Workflow Processes + description: | + This operation can be used to retrieve list of workflow pending processes. + parameters: + - $ref: '#/components/parameters/limit' + - $ref: '#/components/parameters/offset' + - $ref: '#/components/parameters/Accept' + - name: workflowType + in: query + description: | + We need to show the values of each workflow process separately.For that we use workflow type. + Workflow type can be APPLICATION_CREATION, SUBSCRIPTION_CREATION etc. + schema: + type: string + enum: + - APPLICATION_CREATION + - KEY_GENERATION + - SUBSCRIPTION_CREATION + - LIFECYCLE_CHANGE + responses: + 200: + description: | + OK. Workflow pendding process list returned. + headers: + Content-Type: + description: | + The content type of the body. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/WorkflowList' + 400: + $ref: '#/components/responses/BadRequest' + 404: + $ref: '#/components/responses/NotFound' + 406: + $ref: '#/components/responses/NotAcceptable' + security: + - OAuth2Security: + - apk:workflow_manage + + /workflows/update-workflow-status: + post: + tags: + - Workflows (Individual) + summary: Update Workflow Status + description: | + This operation can be used to approve or reject a workflow task. + parameters: + - $ref: '#/components/parameters/workflowReferenceId-Q' + requestBody: + description: | + Workflow event that need to be updated + content: + application/json: + schema: + $ref: '#/components/schemas/WorkflowInfo' + required: true + responses: + 200: + description: | + OK. Workflow request information is returned. + headers: + Content-Type: + description: | + The content type of the body. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/WorkflowInfo' + 400: + $ref: '#/components/responses/BadRequest' + 404: + $ref: '#/components/responses/NotFound' + security: + - OAuth2Security: + - apk:workflow_manage + +components: + schemas: + Error: + title: Error object returned with 4XX HTTP status + required: + - code + - message + type: object + properties: + code: + type: integer + description: Error code + format: int64 + message: + type: string + description: Error message. + description: + type: string + description: | + A detail description about the error message. + moreInfo: + type: string + description: | + Preferably an url with more details about the error. + error: + type: array + description: | + If there are more than one error list them out. + For example, list out validation errors by each field. + items: + $ref: '#/components/schemas/ErrorListItem' + ErrorListItem: + title: Description of individual errors that may have occurred during a request. + required: + - code + - message + type: object + properties: + code: + type: string + description: Error code + message: + type: string + description: | + Description about individual errors occurred + PolicyDetailsList: + title: Policy List + type: object + properties: + count: + type: integer + description: | + Number of Throttling Policies returned. + example: 1 + list: + type: array + items: + $ref: '#/components/schemas/PolicyDetails' + PolicyDetails: + title: Generic Policy + required: + - policyName + type: object + properties: + policyId: + type: integer + description: Id of policy + readOnly: true + example: 3 + uuid: + type: string + description: UUId of policy + readOnly: true + example: 0c6439fd-9b16-3c2e-be6e-1086e0b9aa93 + policyName: + maxLength: 60 + minLength: 1 + type: string + description: Name of policy + example: 30PerMin + displayName: + type: string + description: Display name of the policy + example: 30PerMin + maxLength: 512 + description: + maxLength: 1024 + type: string + description: Description of the policy + example: Allows 30 request per minute + isDeployed: + type: boolean + description: Indicates whether the policy is deployed successfully or not. + default: false + type: + type: string + description: Indicates the type of throttle policy + Policy: + title: Generic Throttling Policy + required: + - planName + type: object + properties: + planId: + type: string + description: Id of plan + readOnly: true + example: 0c6439fd-9b16-3c2e-be6e-1086e0b9aa93 + planName: + maxLength: 60 + minLength: 1 + type: string + description: Name of plan + example: 30PerMin + displayName: + type: string + description: Display name of the policy + example: 30PerMin + maxLength: 512 + description: + maxLength: 1024 + type: string + description: Description of the policy + example: Allows 30 request per minute + isDeployed: + type: boolean + description: Indicates whether the policy is deployed successfully or not. + default: false + type: + type: string + description: Indicates the type of throttle policy + discriminator: + propertyName: type + ExportPolicy: + title: Export Policy + type : object + properties: + type: + type: string + subtype: + type: string + version: + type: string + data: + type: object + ApplicationRatePlan: + title: Application Throttling Policy + allOf: + - $ref: '#/components/schemas/Policy' + - required: + - defaultLimit + type: object + properties: + defaultLimit: + $ref: '#/components/schemas/ThrottleLimit' + ApplicationRatePlanList: + title: Application level Rate Plan List + type: object + properties: + count: + type: integer + description: | + Number of Application Rate Plans returned. + example: 1 + list: + type: array + items: + $ref: '#/components/schemas/ApplicationRatePlan' + BusinessPlan: + title: Business Plan + allOf: + - $ref: '#/components/schemas/Policy' + - $ref: '#/components/schemas/GraphQLQuery' + - required: + - defaultLimit + type: object + properties: + defaultLimit: + $ref: '#/components/schemas/ThrottleLimit' + rateLimitCount: + type: integer + description: Burst control request count + example: 10 + rateLimitTimeUnit: + type: string + description: Burst control time unit + example: min + subscriberCount: + type: integer + description: Number of subscriptions allowed + example: 10 + customAttributes: + type: array + description: | + Custom attributes added to the Subscription Throttling Policy + example: [] + items: + $ref: '#/components/schemas/CustomAttribute' + permissions: + $ref: '#/components/schemas/BusinessPlanPermission' + BusinessPlanPermission: + title: Business Plan Permission + required: + - permissionType + - roles + type: object + properties: + permissionType: + type: string + example: deny + enum: + - ALLOW + - DENY + roles: + type: array + example: + - Internal/everyone + items: + type: string + GraphQLQuery: + title: GraphQL Query + type: object + properties: + graphQLMaxComplexity: + type: integer + description: Maximum Complexity of the GraphQL query + example: 400 + graphQLMaxDepth: + type: integer + description: Maximum Depth of the GraphQL query + example: 10 + BusinessPlanList: + title: Business Plan List + type: object + properties: + count: + type: integer + description: | + Number of Business Plans returned. + example: 1 + list: + type: array + items: + $ref: '#/components/schemas/BusinessPlan' + ThrottleLimitBase: + title: Throttle Limit Base + required: + - timeUnit + - unitTime + type: object + properties: + timeUnit: + type: string + description: Unit of the time. Allowed values are "sec", "min", "hour", + "day" + example: min + unitTime: + type: integer + description: Time limit that the throttling limit applies. + example: 10 + ThrottleLimit: + title: Throttle Limit + required: + - type + type: object + properties: + type: + type: string + description: | + Type of the throttling limit. Allowed values are "REQUESTCOUNTLIMIT" and "BANDWIDTHLIMIT". + Please see schemas of "RequestCountLimit" and "BandwidthLimit" throttling limit types in + Definitions section. + example: REQUESTCOUNTLIMIT + enum: + - REQUESTCOUNTLIMIT + - BANDWIDTHLIMIT + - EVENTCOUNTLIMIT + requestCount: + $ref: '#/components/schemas/RequestCountLimit' + bandwidth: + $ref: '#/components/schemas/BandwidthLimit' + eventCount: + $ref: '#/components/schemas/EventCountLimit' + BandwidthLimit: + title: Bandwidth Limit object + allOf: + - $ref: '#/components/schemas/ThrottleLimitBase' + - required: + - dataAmount + - dataUnit + type: object + properties: + dataAmount: + type: integer + description: Amount of data allowed to be transferred + format: int64 + example: 1000 + dataUnit: + type: string + description: Unit of data allowed to be transferred. Allowed values are + "KB", "MB" and "GB" + example: KB + RequestCountLimit: + title: Request Count Limit object + allOf: + - $ref: '#/components/schemas/ThrottleLimitBase' + - required: + - requestCount + type: object + properties: + requestCount: + type: integer + description: Maximum number of requests allowed + format: int64 + example: 30 + EventCountLimit: + title: Event Count Limit object + allOf: + - $ref: '#/components/schemas/ThrottleLimitBase' + - required: + - eventCount + type: object + properties: + eventCount: + type: integer + description: Maximum number of events allowed + format: int64 + example: 3000 + BlockingCondition: + title: Blocking Conditions + required: + - conditionType + - conditionValue + type: object + properties: + policyId: + type: string + description: Id of the blocking condition + example: b513eb68-69e8-4c32-92cf-852c101363cf + conditionType: + type: string + description: Type of the blocking condition + example: IP + enum: + - API + - APPLICATION + - IP + - IPRANGE + - USER + conditionValue: + type: object + properties: {} + description: Value of the blocking condition + example: + fixedIp: 192.168.1.1 + invert: false + conditionStatus: + type: boolean + description: Status of the blocking condition + example: true + description: Blocking Conditions + BlockingConditionList: + title: Blocking Conditions List + type: object + properties: + count: + type: integer + description: | + Number of Blocking Conditions returned. + example: 1 + list: + type: array + items: + $ref: '#/components/schemas/BlockingCondition' + BlockingConditionStatus: + title: Blocking Conditions Status + required: + - conditionStatus + type: object + properties: + policyId: + type: string + description: Id of the blocking condition + example: b513eb68-69e8-4c32-92cf-852c101363cf + conditionStatus: + type: boolean + description: Status of the blocking condition + example: true + description: Blocking Conditions Status + CustomAttribute: + title: Name-Value pair + required: + - name + - value + type: object + properties: + name: + type: string + description: Name of the custom attribute + example: customAttr1 + value: + type: string + description: Value of the custom attribute + example: value1 + ApplicationList: + title: Application List + type: object + properties: + count: + type: integer + description: | + Number of applications returned. + example: 1 + list: + type: array + items: + $ref: '#/components/schemas/ApplicationInfo' + pagination: + $ref: '#/components/schemas/Pagination' + ApplicationInfo: + title: Application info object with basic application details + type: object + properties: + applicationId: + type: string + example: 01234567-0123-0123-0123-012345678901 + name: + type: string + example: CalculatorApp + owner: + type: string + example: admin + status: + type: string + example: APPROVED + groupId: + type: string + example: "" + Application: + title: Application object with all the application details + type: object + properties: + applicationId: + type: string + example: 01234567-0123-0123-0123-012345678901 + name: + type: string + example: CalculatorApp + throttlingPolicy: + type: string + example: Unlimited + description: + type: string + example: Sample calculator application + tokenType: + type: string + enum: + - OAUTH + - JWT + description: | + Type of the access token generated for this application. + **OAUTH:** A UUID based access token which is issued by default. + **JWT:** A self-contained, signed JWT based access token. **Note:** This can be only used in Microgateway environments. + default: JWT + example: JWT + status: + type: string + example: APPROVED + default: "" + groups: + type: array + items: + type: string + example: "" + subscriptionCount: + type: integer + attributes: + type: object + additionalProperties: + type: string + example: External Reference ID, Billing Tier + subscriptionScopes: + type: array + items: + $ref: '#/components/schemas/ScopeInfo' + owner: + description: | + Application created user + type: string + example: admin + ScopeInfo: + title: API Scope info object with scope details + type: object + properties: + key: + type: string + example: admin_scope + name: + type: string + example: admin scope + roles: + type: array + items: + type: string + description: Allowed roles for the scope + example: ["manager","developer"] + description: + type: string + description: Description of the scope + Environment: + title: Environment + required: + - name + - vhosts + type: object + properties: + id: + type: string + readOnly: true + example: ece92bdc-e1e6-325c-b6f4-656208a041e9 + name: + maxLength: 255 + minLength: 1 + pattern: '^[a-zA-Z0-9_-]+$' + type: string + example: us-region + displayName: + maxLength: 255 + minLength: 1 + type: string + example: US Region + provider: + type: string + example: wso2 + description: + maxLength: 1023 + type: string + example: Gateway environment in US Region + isReadOnly: + type: boolean + readOnly: true + example: false + vhosts: + type: array + minItems: 1 + items: + $ref: '#/components/schemas/VHost' + endpointURIs: + type: array + items: + $ref: '#/components/schemas/GatewayEnvironmentProtocolURI' + additionalProperties: + type: array + items: + $ref: '#/components/schemas/AdditionalProperty' + EnvironmentList: + title: Environment List + type: object + properties: + count: + type: integer + description: | + Number of Environments returned. + example: 1 + list: + type: array + items: + $ref: '#/components/schemas/Environment' + VHost: + title: Virtual Host + required: + - host + type: object + properties: + host: + maxLength: 255 + minLength: 1 + # hostname regex as per RFC 1123 (http://tools.ietf.org/html/rfc1123) and appended * + pattern: '^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$' + type: string + example: mg.wso2.com + httpContext: + maxLength: 255 + minLength: 0 + # TODO (renuka) check this regex: not allowed: (_ .) and allowed: (- /) + pattern: '^\/?([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])*$' + type: string + example: pets + httpPort: + type: integer + example: 80 + httpsPort: + type: integer + example: 443 + wsPort: + type: integer + example: 9099 + wssPort: + type: integer + example: 8099 + AdditionalProperty: + title: Additional Gateway Properties + type: object + properties: + key: + type: string + example: Organization + value: + type: string + example: wso2 + GatewayEnvironmentProtocolURI: + title: Gateway Environment protocols and URIs + required: + - protocol + - endpointURI + type: object + properties: + protocol: + type: string + example: default + endpointURI: + type: string + example: default + PublishStatus: + title: Usage publish status + type: object + properties: + status: + type: string + description: Status of the usage publish request + example: successful + message: + type: string + description: detailed message of the status + example: Records published successfully + MonetizationUsagePublishInfo: + title: Usage publish status + type: object + properties: + state: + type: string + description: State of usage publish job + example: RUNNING + status: + type: string + description: Status of usage publish job + example: SUCCESSFULL + startedTime: + type: string + description: Timestamp of the started time of the Job + example: "1599196134000" + lastPublsihedTime: + type: string + description: Timestamp of the last published time + example: "1599196134000" + TenantInfo: + title: Tenant information + type: object + properties: + username: + type: string + example: john + tenantDomain: + type: string + example: carbon.super + tenantId: + type: integer + example: -1234 + description: The tenant information of the user + CustomUrlInfo: + title: Custom url information + type: object + properties: + tenantDomain: + type: string + example: carbon.super + tenantAdminUsername: + type: string + example: john@foo.com + enabled: + type: boolean + example: true + devPortal: + type: object + properties: + url: + type: string + example: http://example.com + description: The custom url information of the tenant domain + Organization: + title: Organization + required: + - name + - displayName + - claimList + type: object + properties: + id: + type: string + readOnly: true + example: 01234567-0123-0123-0123-012345678901 + name: + maxLength: 255 + minLength: 1 + type: string + example: Finance + displayName: + maxLength: 255 + minLength: 1 + type: string + example: Finance + organizationClaimValue: + maxLength: 255 + minLength: 1 + type: string + example: 01234567-0123-0123-0123 + enabled: + type: boolean + default: true + serviceNamespaces: + type: array + items: + type: string + default: + - "*" + workflows: + type: array + items: + $ref: '#/components/schemas/WorkflowProperties' + production: + type: array + items: + type: string + sandbox: + type: array + items: + type: string + OrganizationList: + title: Organization List + type: object + properties: + count: + type: integer + description: | + Number of Organization returned. + example: 1 + list: + type: array + items: + $ref: '#/components/schemas/Organization' + WorkflowList: + title: WorkflowList + type: object + properties: + count: + type: integer + description: | + Number of workflow processes returned. + example: 1 + next: + type: string + description: | + Link to the next subset of resources qualified. + Empty if no more resources are to be returned. + example: /workflows?limit=1&offset=2&user= + previous: + type: string + description: | + Link to the previous subset of resources qualified. + Empty if current subset is the first subset returned. + example: /workflows?limit=1&offset=0&user= + list: + type: array + items: + $ref: '#/components/schemas/WorkflowInfo' + WorkflowProperties: + title: workflow properties + type: object + properties: + name: + type: string + enum: + - APPLICATION_CREATION + - KEY_GENERATION + - SUBSCRIPTION_CREATION + - LIFECYCLE_CHANGE + enable: + type: boolean + properties: + type: array + items: + type: string + WorkflowInfo: + title: Workflow info object with basic workflow details + type: object + properties: + workflowType: + type: string + description: | + Type of the Workflow Request. It shows which type of request is it. + example: APPLICATION_CREATION + enum: + - APPLICATION_CREATION + - KEY_GENERATION + - SUBSCRIPTION_CREATION + - LIFECYCLE_CHANGE + workflowStatus: + type: string + description: | + Show the Status of the the workflow request whether it is approved or created. + example: APPROVED + enum: + - APPROVED + - CREATED + createdTime: + type: string + description: | + Time of the the workflow request created. + example: 2020-02-10 10:10:19.704 + updatedTime: + type: string + description: | + Time of the the workflow request updated. + example: 2020-02-10 10:10:19.704 + description: + type: string + description: | + description is a message with basic details about the workflow request. + example: Approve application [APP1] creation request from application creator + - admin with throttling tier - 10MinPer + WorkflowResponse: + title: workflow Response + required: + - workflowStatus + type: object + properties: + workflowStatus: + type: string + description: | + This attribute declares whether this workflow task is approved or rejected. + example: APPROVED + enum: + - CREATED + - APPROVED + - REJECTED + - REGISTERED + jsonPayload: + type: string + description: | + Attributes that returned after the workflow execution + APICategory: + title: API Category + required: + - name + type: object + properties: + id: + type: string + readOnly: true + example: 01234567-0123-0123-0123-012345678901 + name: + maxLength: 255 + minLength: 1 + type: string + example: Finance + description: + maxLength: 1024 + type: string + example: Finance related APIs + numberOfAPIs: + type: integer + readOnly: true + example: 1 + APICategoryList: + title: API Category List + type: object + properties: + count: + type: integer + description: | + Number of API categories returned. + example: 1 + list: + type: array + items: + $ref: '#/components/schemas/APICategory' + Settings: + title: Settings + type: object + properties: + scopes: + type: array + items: + type: string + keyManagerConfiguration: + type: array + items: + type: object + properties: + type: + type: string + example: default + displayName: + type: string + example: default + defaultConsumerKeyClaim: + type: string + example: azp + defaultScopesClaim: + type: string + example: scope + configurations: + type: array + items: + $ref: '#/components/schemas/KeyManagerConfiguration' + endpointConfigurations: + type: array + items: + $ref: '#/components/schemas/KeyManagerConfiguration' + analyticsEnabled: + type: boolean + description: To determine whether analytics is enabled or not + example: false + KeyManagerWellKnownResponse: + title: Key Manager Well-Known Response. + type: object + properties: + valid: + type: boolean + example: true + default: false + value: + $ref: '#/components/schemas/KeyManager' + KeyManager: + title: Key Manager + required: + - name + - type + - issuer + + type: object + properties: + id: + type: string + readOnly: true + example: 01234567-0123-0123-0123-012345678901 + name: + maxLength: 100 + minLength: 1 + type: string + example: WSO2 Identity Server + displayName: + maxLength: 100 + type: string + description: | + display name of Key Manager to show in UI + example: WSO2 Identity Server + type: + maxLength: 45 + minLength: 1 + type: string + example: WSO2-IS + description: + maxLength: 256 + type: string + example: This is a key manager for Developers + wellKnownEndpoint: + type: string + description: | + Well-Known Endpoint of Identity Provider. + example: "" + endpoints: + type: array + items: + $ref: '#/components/schemas/KeyManagerEndpoint' + signingCertificate: + type: object + properties: + type: + type: string + enum: + - JWKS + - PEM + value: + type: string + tlsCertificate: + type: string + description: PEM type certificate + issuer: + type: string + example: https://localhost:9444/services + availableGrantTypes: + type: array + items: + type: string + example: client_credentials + enableTokenGeneration: + type: boolean + example: true + default: true + enableMapOAuthConsumerApps: + type: boolean + example: false + default: false + enableOauthAppValidation: + type: boolean + example: false + default: true + enableOAuthAppCreation: + type: boolean + example: false + default: true + consumerKeyClaim: + type: string + example: azp + scopesClaim: + type: string + example: scopes + enabled: + type: boolean + example: true + default: true + additionalProperties: + type: object + example: + self_validate_jwt: true + Username: admin + Password: admin + + KeyManagerEndpoint: + title: Key Manager Endpoint. + required: + - name + - value + type: object + properties: + name: + type: string + example: 'token_endpoint' + value: + type: string + example: 'https://localhost:9443/oauth2/token' + KeyManagerInfo: + title: Key Manager Info + required: + - name + - type + type: object + properties: + id: + type: string + example: 01234567-0123-0123-0123-012345678901 + name: + type: string + example: WSO2 IS + type: + type: string + example: IS + description: + type: string + example: This is a key manager for Developers + enabled: + type: boolean + example: true + KeyManagerConfiguration: + title: Key Manager Configuration + type: object + properties: + name: + type: string + example: consumer_key + label: + type: string + example: Consumer Key + type: + type: string + example: select + required: + type: boolean + example: true + mask: + type: boolean + example: true + multiple: + type: boolean + example: true + tooltip: + type: string + example: Enter username to connect to key manager + default: + type: string + example: admin + values: + type: array + items: + type: string + KeyManagerList: + title: Key Manager List + type: object + properties: + count: + type: integer + description: | + Number of Key managers returned. + example: 1 + list: + type: array + items: + $ref: '#/components/schemas/KeyManagerInfo' + ClaimMappingEntry: + title: Claim Mapping Configuration + type: object + properties: + remoteClaim: + type: string + example: http://idp.org/username + localClaim: + type: string + example: http://wso2.org/username + TokenValidation: + title: Token handling Configuration + type: object + properties: + id: + type: integer + enable: + type: boolean + example: false + default: true + type: + type: string + enum: + - REFERENCE + - JWT + - CUSTOM + value: + type: object + properties: {} + Pagination: + title: Pagination + type: object + properties: + offset: + type: integer + example: 0 + limit: + type: integer + example: 1 + total: + type: integer + example: 10 + next: + type: string + description: | + Link to the next subset of resources qualified. + Empty if no more resources are to be returned. + example: "" + previous: + type: string + description: | + Link to the previous subset of resources qualified. + Empty if current subset is the first subset returned. + example: "" + responses: + BadRequest: + description: Bad Request. Invalid request or validation error. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + example: + code: 400 + message: Bad Request + description: Invalid request or validation error + moreInfo: "" + error: [] + Conflict: + description: Conflict. Specified resource already exists. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + example: + code: 409 + message: Conflict + description: Specified resource already exists + moreInfo: "" + error: [] + Forbidden: + description: Forbidden. The request must be conditional but no condition has + been specified. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + example: + code: 403 + message: Forbidden + description: The request must be conditional but no condition has been + specified + moreInfo: "" + error: [] + InternalServerError: + description: Internal Server Error. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + example: + code: 500 + message: Internal Server Error + description: The server encountered an internal error. Please contact + administrator. + moreInfo: "" + error: [] + NotAcceptable: + description: Not Acceptable. The requested media type is not supported. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + example: + code: 406 + message: Not Acceptable + description: The requested media type is not supported + moreInfo: "" + error: [] + NotFound: + description: Not Found. The specified resource does not exist. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + example: + code: 404 + message: Not Found + description: The specified resource does not exist + moreInfo: "" + error: [] + PayloadTooLarge: + description: Payload Too Large. Request entity is larger than limits defined + by server. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + example: + code: 413 + message: Payload Too Large + description: Request entity is larger than limits defined by server + moreInfo: "" + error: [] + PreconditionFailed: + description: Precondition Failed. The request has not been performed because + one of the preconditions is not met. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + example: + code: 412 + message: Precondition Failed + description: The request has not been performed because one of the preconditions + is not met + moreInfo: "" + error: [] + Unauthorized: + description: Unauthorized. The user is not authorized. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + example: + code: 401 + message: Unauthorized + description: The user is not authorized + moreInfo: "" + error: [] + UnsupportedMediaType: + description: Unsupported Media Type. The entity of the request was not in a + supported format. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + example: + code: 415 + message: Unsupported media type + description: The entity of the request was not in a supported format + moreInfo: "" + error: [] + parameters: + If-None-Match: + name: If-None-Match + in: header + description: | + Validator for conditional requests; based on the ETag of the formerly retrieved + variant of the resource. + schema: + type: string + requestedTenant: + name: X-WSO2-Tenant + in: header + description: | + For cross-tenant invocations, this is used to specify the tenant domain, where the resource need to be + retirieved from. + schema: + type: string + sortBy: + name: sortBy + in: query + description: | + Criteria for sorting. + schema: + type: string + default: createdTime + enum: + - apiName + - version + - createdTime + - status + sortOrder: + name: sortOrder + in: query + description: | + Order of sorting(ascending/descending). + schema: + type: string + default: desc + enum: + - asc + - desc + username: + name: username + in: query + description: | + username of the new application owner + required: true + schema: + type: string + scopeName: + name: scopeName + in: path + description: | + Base64 URL encoded value of the scope name to be validated + required: true + schema: + type: string + environmentId: + name: environmentId + in: path + description: | + Environment UUID (or Environment name defined in config) + required: true + schema: + type: string + policyId: + name: policyId + in: path + description: | + Policy UUID + required: true + schema: + type: string + planId: + name: planId + in: path + description: | + Policy UUID + required: true + schema: + type: string + ruleId: + name: ruleId + in: path + description: | + Custom rule UUID + required: true + schema: + type: string + applicationId: + name: applicationId + in: path + description: | + Application UUID + required: true + schema: + type: string + Accept: + name: Accept + in: header + description: | + Media types acceptable for the response. Default is application/json. + schema: + type: string + default: application/json + Content-Type: + name: Content-Type + in: header + description: | + Media type of the entity in the body. Default is application/json. + required: true + schema: + type: string + default: application/json + limit: + name: limit + in: query + description: | + Maximum size of resource array to return. + schema: + type: integer + default: 25 + offset: + name: offset + in: query + description: | + Starting point within the complete list of items qualified. + schema: + type: integer + default: 0 + user: + name: user + in: query + description: | + username of the application creator + schema: + type: string + workflowReferenceId-Q: + name: workflowReferenceId + in: query + description: | + Workflow reference id + required: true + schema: + type: string + apiCategoryId: + name: apiCategoryId + in: path + description: | + API Category UUID + required: true + schema: + type: string + organizationId: + name: organizationId + in: path + description: | + Organization UUID + required: true + schema: + type: string + keyManagerId: + name: keyManagerId + in: path + description: | + Key Manager UUID + required: true + schema: + type: string + roleId: + name: roleId + in: path + description: | + The Base 64 URL encoded role name with domain. If the given role is in PRIMARY user-store, role ID should be + derived as Base64URLEncode(role-name). If the given role is in secondary user-store, role ID should be + derived as Base64URLEncode({user-store-name}/{role-name}). + required: true + schema: + type: string + securitySchemes: + OAuth2Security: + type: oauth2 + flows: + password: + tokenUrl: https://localhost:9443/oauth2/token + scopes: + openid: Authorize access to user details + apk:organization_manage: Manage all organization + apk:admin: Manage all admin operations + apk:tier_manage: Update and delete throttling policies + apk:bl_manage: Update and delete deny policies + apk:environment_manage: Manage gateway environments + apk:category_manage: Manage API Categories + apk:keymanager_operations: Manage Key Managers related + operations + apk:admin_application_manage: Manage All Applications + apk:workflow_manage: manage All Workflows + + \ No newline at end of file diff --git a/admin/admin-domain-service/ballerina/resources/internal-admin-api.yaml b/admin/admin-domain-service/ballerina/resources/internal-admin-api.yaml new file mode 100644 index 000000000..69b346cf1 --- /dev/null +++ b/admin/admin-domain-service/ballerina/resources/internal-admin-api.yaml @@ -0,0 +1,351 @@ +# Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com). +# +# 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. +################################################################################ +openapi: 3.0.1 +info: + title: WSO2 API Manager - Internal API + description: | + + contact: + name: WSO2 + url: https://wso2.com/api-manager/ + email: architecture@wso2.com + license: + name: Apache 2.0 + url: http://www.apache.org/licenses/LICENSE-2.0.html + version: v1 +servers: + - url: https://apis.wso2.com/api/admin/v1 +paths: + +###################################################### + # The "Organization" resource API +###################################################### + /organizations: + get: + tags: + - Organization (Collection) + summary: Get all Organization + description: | + Get all Organization + parameters: + - name: organizationName + in: query + description: | + Organization Name + schema: + type: string + - name: organizationClaimValue + in: query + description: | + organizationClaimValue + schema: + type: string + responses: + 200: + description: | + OK. + Organization returned + content: + application/json: + schema: + $ref: '#/components/schemas/OrganizationList' + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://127.0.0.1:9443/api/admin/organizations"' + operationId: getAllOrganization + +components: + schemas: + Error: + title: Error object returned with 4XX HTTP status + required: + - code + - message + type: object + properties: + code: + type: integer + description: Error code + format: int64 + message: + type: string + description: Error message. + description: + type: string + description: | + A detail description about the error message. + moreInfo: + type: string + description: | + Preferably an url with more details about the error. + error: + type: array + description: | + If there are more than one error list them out. + For example, list out validation errors by each field. + items: + $ref: '#/components/schemas/ErrorListItem' + ErrorListItem: + title: Description of individual errors that may have occurred during a request. + required: + - code + - message + type: object + properties: + code: + type: string + description: Error code + message: + type: string + description: | + Description about individual errors occurred + Organization: + title: Organization + required: + - name + - displayName + - claimList + type: object + properties: + id: + type: string + readOnly: true + example: 01234567-0123-0123-0123-012345678901 + name: + maxLength: 255 + minLength: 1 + type: string + example: Finance + displayName: + maxLength: 255 + minLength: 1 + type: string + example: Finance + organizationClaimValue: + maxLength: 255 + minLength: 1 + type: string + example: 01234567-0123-0123-0123 + enabled: + type: boolean + default: true + serviceNamespaces: + type: array + items: + type: string + default: + - "*" + production: + type: array + items: + type: string + sandbox: + type: array + items: + type: string + OrganizationList: + title: Organization List + type: object + properties: + count: + type: integer + description: | + Number of Organization returned. + example: 1 + list: + type: array + items: + $ref: '#/components/schemas/Organization' + + responses: + BadRequest: + description: Bad Request. Invalid request or validation error. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + example: + code: 400 + message: Bad Request + description: Invalid request or validation error + moreInfo: "" + error: [] + Conflict: + description: Conflict. Specified resource already exists. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + example: + code: 409 + message: Conflict + description: Specified resource already exists + moreInfo: "" + error: [] + Forbidden: + description: Forbidden. The request must be conditional but no condition has + been specified. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + example: + code: 403 + message: Forbidden + description: The request must be conditional but no condition has been + specified + moreInfo: "" + error: [] + InternalServerError: + description: Internal Server Error. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + example: + code: 500 + message: Internal Server Error + description: The server encountered an internal error. Please contact + administrator. + moreInfo: "" + error: [] + NotAcceptable: + description: Not Acceptable. The requested media type is not supported. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + example: + code: 406 + message: Not Acceptable + description: The requested media type is not supported + moreInfo: "" + error: [] + NotFound: + description: Not Found. The specified resource does not exist. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + example: + code: 404 + message: Not Found + description: The specified resource does not exist + moreInfo: "" + error: [] + PayloadTooLarge: + description: Payload Too Large. Request entity is larger than limits defined + by server. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + example: + code: 413 + message: Payload Too Large + description: Request entity is larger than limits defined by server + moreInfo: "" + error: [] + PreconditionFailed: + description: Precondition Failed. The request has not been performed because + one of the preconditions is not met. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + example: + code: 412 + message: Precondition Failed + description: The request has not been performed because one of the preconditions + is not met + moreInfo: "" + error: [] + Unauthorized: + description: Unauthorized. The user is not authorized. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + example: + code: 401 + message: Unauthorized + description: The user is not authorized + moreInfo: "" + error: [] + UnsupportedMediaType: + description: Unsupported Media Type. The entity of the request was not in a + supported format. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + example: + code: 415 + message: Unsupported media type + description: The entity of the request was not in a supported format + moreInfo: "" + error: [] + parameters: + If-None-Match: + name: If-None-Match + in: header + description: | + Validator for conditional requests; based on the ETag of the formerly retrieved + variant of the resource. + schema: + type: string + Accept: + name: Accept + in: header + description: | + Media types acceptable for the response. Default is application/json. + schema: + type: string + default: application/json + Content-Type: + name: Content-Type + in: header + description: | + Media type of the entity in the body. Default is application/json. + required: true + schema: + type: string + default: application/json + limit: + name: limit + in: query + description: | + Maximum size of resource array to return. + schema: + type: integer + default: 25 + offset: + name: offset + in: query + description: | + Starting point within the complete list of items qualified. + schema: + type: integer + default: 0 + organizationId: + name: organizationId + in: path + description: | + Organization UUID + required: true + schema: + type: string + \ No newline at end of file diff --git a/admin/admin-domain-service/ballerina/tests/Config.toml b/admin/admin-domain-service/ballerina/tests/Config.toml new file mode 100644 index 000000000..50950ec8a --- /dev/null +++ b/admin/admin-domain-service/ballerina/tests/Config.toml @@ -0,0 +1,18 @@ +[wso2.admin_service] +keyManagerConntectorConfigurationFilePath = "./tests/resources/keyManager-configs" +[wso2.admin_service.datasourceConfiguration] +description = "Database for admin" +url = "jdbc:postgresql://localhost:10320/WSO2AM_DB" +host = "localhost" +port = 10320 +databaseName = "WSO2AM_DB" +username = "wso2carbon" +password = "wso2carbon" +validationTimeout = 250 +testQuery = "SELECT 1" +driver = "org.postgresql.Driver" +[wso2.admin_service.throttleConfig.blockCondition] +enabled = true +[wso2.admin_service.keyStores.tls] +keyFilePath = "./tests/resources/wso2carbon.key" +certFilePath = "./tests/resources/wso2carbon.crt" \ No newline at end of file diff --git a/admin/admin-domain-service/ballerina/tests/KeymanagerTest.bal b/admin/admin-domain-service/ballerina/tests/KeymanagerTest.bal new file mode 100644 index 000000000..6e3f2388d --- /dev/null +++ b/admin/admin-domain-service/ballerina/tests/KeymanagerTest.bal @@ -0,0 +1,135 @@ +import wso2/apk_common_lib as commons; +import ballerina/uuid; +import ballerina/log; +import ballerina/test; + +@test:Config {} +public function addKeyManager() { + KeyManagerClient keyManagerClient = new; + commons:Organization organization = {enabled: true, uuid: uuid:createType1AsString(), name: "default", displayName: "default", organizationClaimValue: ""}; + KeyManager keyManager = { + name: "abcde", + 'type: "Okta", + availableGrantTypes: [], + enabled: true, + issuer: "https://localhost:9443/oauth2/token", + endpoints: [ + {name: "dcr_endpoint", value: "https://localhost:9443/api/dcr"}, + {name: "introspection_endpoint", value: "https://localhost:9443/api/introspect"}, + {name: "token_endpoint", value: "https://localhost:9443/oauth2/token"} + ], + additionalProperties: { + "client_id": "abcde", + "client_secret": "abcde" + }, + signingCertificate: {'type: "JWKS", value: "https://localhost:9443/oauth2/jwks"} + }; + KeyManager|commons:APKError keyManagerEntryToOrganization = keyManagerClient.addKeyManagerEntryToOrganization(keyManager, organization); + if keyManagerEntryToOrganization is KeyManager { + test:assertTrue(!(keyManagerEntryToOrganization.id is ())); + test:assertEquals(keyManagerEntryToOrganization.name, keyManager.name); + } else { + log:printError("failed to insert", keyManagerEntryToOrganization); + test:assertFail(); + } + KeyManagerList|commons:APKError allKeyManagersByOrganization = keyManagerClient.getAllKeyManagersByOrganization(organization); + if allKeyManagersByOrganization is KeyManagerList { + test:assertEquals(allKeyManagersByOrganization.count, 1); + } else { + log:printError("failed to retrieve all", allKeyManagersByOrganization); + test:assertFail(); + } + if keyManagerEntryToOrganization is KeyManager { + KeyManager|error keyManagerById = keyManagerClient.getKeyManagerById(keyManagerEntryToOrganization.id ?: "", organization); + if keyManagerById is KeyManager { + test:assertEquals(keyManagerById, keyManagerEntryToOrganization); + } + // update KeyManager + KeyManager updatedKeyManager = keyManagerEntryToOrganization.clone(); + updatedKeyManager.description = "updated text"; + KeyManager|commons:APKError keyManagerResult = keyManagerClient.updateKeyManager(keyManagerEntryToOrganization.id, updatedKeyManager, organization); + if keyManagerResult is KeyManager { + test:assertEquals(keyManagerResult, updatedKeyManager); + } else { + test:assertFail(); + } + commons:APKError? deleteKeyManagerResponse = keyManagerClient.deleteKeyManager(keyManagerEntryToOrganization.id, organization); + if deleteKeyManagerResponse is commons:APKError { + test:assertFail(); + } + KeyManager|commons:APKError keyManagerByIdResult = keyManagerClient.getKeyManagerById(keyManagerEntryToOrganization.id, organization); + if keyManagerByIdResult is commons:APKError { + test:assertEquals(keyManagerByIdResult.detail().code, 909439); + } + } +} + +@test:Config {} +public function addKeyManagerNegative() { + KeyManagerClient keyManagerClient = new; + commons:Organization organization = {enabled: true, uuid: uuid:createType1AsString(), name: "default", displayName: "default", organizationClaimValue: ""}; + KeyManager keyManager = { + name: "abcde", + 'type: "Okta", + availableGrantTypes: [], + enabled: true, + issuer: "https://localhost:9443/oauth2/token", + endpoints: [ + {name: "token_endpoint", value: "https://localhost:9443/oauth2/token"} + ], + additionalProperties: { + "client_id": "abcde" + } + }; + KeyManager|commons:APKError keyManagerEntryToOrganization = keyManagerClient.addKeyManagerEntryToOrganization(keyManager, organization); + if keyManagerEntryToOrganization is commons:APKError { + test:assertEquals(keyManagerEntryToOrganization.detail().code, 909437); + } +} + +@test:Config {} +public function addKeyManagerWithTlsCert() { + commons:Organization organization = {enabled: true, uuid: uuid:createType1AsString(), name: "default", displayName: "default", organizationClaimValue: ""}; + + KeyManager keyManager = { + "name": "nonprod-idp2", + "displayName": "Non production IDP", + "type": "Okta", + "description": "This is a key manager for Developers", + "endpoints": [ + { + "name": "token_endpoint", + "value": "https://keymanager-wso2-apk-idp-ds-service:9443/oauth2/token" + }, + { + "name": "dcr_endpoint", + "value": "https://keymanager-wso2-apk-idp-ds-service:9443/dcr" + } + ], + "signingCertificate": { + "type": "JWKS", + "value": "https://keymanager-wso2-apk-idp-ds-service:9443/oauth2/jwks" + }, + "tlsCertificate": "-----BEGIN CERTIFICATE----- MIIC/TCCAeWgAwIBAgIUd4njv8ySPgo7t0F1e2aJEo9TpQ4wDQYJKoZIhvcNAQEL BQAwDjEMMAoGA1UEAwwDYXBrMB4XDTIzMDMwOTA4MTYzNFoXDTMzMDMwNjA4MTYz NFowDjEMMAoGA1UEAwwDYXBrMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC AQEA1G9BAcVa3aMemxERY+J8UmH/W8JpcEOtdeNX5YNihnNOXtlvhSzFzOPaK97P r4IqGASbVNiR+1J6WEoi/b6ZJTx0q3YUn0YlQJrz7g20TdoGJjxGVWzn0EW4beHX Gq60vXLf4t3mlLCLGIK3kJTWAoRzd74djV7+5v0Bm/6KBBAWcu5UbOD9KRpOsxGM n3Z0103oAGViyq84QtFvhXVNWttDLe2jU/7o42ddaJozRL9z+1AepdoWPyJZIZqU bXcGAk7idk7c/8dKMxwAm3CV/WvgWrVK5R+YTiGqRf5pd9WWCydEVQkNqCZgTPNy BTRvHo52onPnT6ALtMI0mnWLtQIDAQABo1MwUTAdBgNVHQ4EFgQUzxcA8ceCF5t+ vPeOpYbi11CWjwcwHwYDVR0jBBgwFoAUzxcA8ceCF5t+vPeOpYbi11CWjwcwDwYD VR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAFCKd5x8z64p1j9BnoSAl JJuNz4uWjv/YK94B3s3KUkXOXjHuLuazkSss2UHFb+KeLd6vhimM5QqkFsUEMsnC 8RyBZP58kghcLzJld5Uiwlnr/RuOANvcv4eKSavwu5/ABXuMUQb/GvKtWPrr2VbJ ULg3p7NGigXHHg84eVMA7oNX1Z5R2cS4ISklWXm5SpMPh+SNCgqwqhxRNYJ2J0EZ qlp4ofQG3GJ72J+DRHlNujWEskP5IJjw6w8Q0zjXx26yelGe2+TM6BB7PpCN6kNU zHo2k/575bu2iZztnYVmE74H1W3cXJ7c0q82uUFvdW+FlRtm+OPIiIGK74lFiZNB OQ== -----END CERTIFICATE-----", + "issuer": "https://idp.am.wso2.com/token", + "availableGrantTypes": [ + "client_credentials" + ], + "enableTokenGeneration": true, + "enableMapOAuthConsumerApps": true, + "enableOAuthAppCreation": true, + "consumerKeyClaim": "azp", + "scopesClaim": "scopes", + "enabled": true, + "additionalProperties": { + "client_id": "abcde", + "client_secret": "abcde" + } + }; + KeyManagerClient keyManagerClient = new; + KeyManager|commons:APKError keyManagerEntryToOrganization = keyManagerClient.addKeyManagerEntryToOrganization(keyManager, organization); + if keyManagerEntryToOrganization is KeyManager { + test:assertEquals(keyManagerEntryToOrganization.name, "nonprod-idp2"); + } +} + diff --git a/admin/admin-domain-service/ballerina/tests/apiCategoriesTests.bal b/admin/admin-domain-service/ballerina/tests/apiCategoriesTests.bal new file mode 100644 index 000000000..219111374 --- /dev/null +++ b/admin/admin-domain-service/ballerina/tests/apiCategoriesTests.bal @@ -0,0 +1,125 @@ +// +// Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + +import ballerina/test; +import wso2/apk_common_lib as commons; + +APICategory apiCategory = {name: "MyCat1", description: "My Desc 1", id: "01ed9241-2d5d-1b98-8ecb-40f85676b081", numberOfAPIs: 2}; + +@test:Config {} +function addAPICategoryTest() { + APICategory payload = {name: "MyCat1", description: "My Desc 1"}; + APICategory|commons:APKError createdApiCategory = addAPICategory(payload, organiztion); + if createdApiCategory is APICategory { + test:assertTrue(true,"API Category added successfully"); + apiCategory.id = createdApiCategory.id; + } else if createdApiCategory is commons:APKError { + test:assertFail("Error occured while adding API Category"); + } +} + +@test:Config {dependsOn: [addAPICategoryTest]} +function addAPICategoryTestNegative1() { + APICategory payload = {name: "MyCat1", description: "My Desc 1"}; + //API Category Name alrady exisitng + APICategory|commons:APKError createdApiCategory = addAPICategory(payload, organiztion); + if createdApiCategory is APICategory { + test:assertFail("API Category added successfully"); + } else if createdApiCategory is commons:APKError { + test:assertTrue(true, "Error occured while adding API Category"); + } +} + +@test:Config {dependsOn: [addAPICategoryTest]} +function getAllCategoryListTest() { + APICategoryList|commons:APKError apiCategoryList = getAllCategoryList(organiztion); + if apiCategoryList is APICategoryList { + test:assertTrue(true,"API Category list retrieved successfully"); + } else if apiCategoryList is commons:APKError { + test:assertFail("Error occured while retrieving API Category List"); + } +} + +@test:Config {dependsOn: [getAllCategoryListTest]} +function updateAPICategoryTest() { + APICategory payload = {name: "MyCat1", description: "My Desc 1 new"}; + string? catId = apiCategory.id; + if catId is string { + APICategory|commons:APKError createdApiCategory = updateAPICategory(catId, payload, organiztion); + if createdApiCategory is APICategory { + test:assertTrue(true,"API Category updated successfully"); + } else if createdApiCategory is commons:APKError { + test:assertFail("Error occured while adding API Category"); + } + } else { + test:assertFail("Category ID isn't a string"); + } +} + +@test:Config {dependsOn: [updateAPICategoryTest]} +function updateAPICategoryTestNegative1() { + // Exisiting API Category is not found + APICategory payload = {name: "MyCat1", description: "My Desc 1 new"}; + string? catId = apiCategory.id; + if catId is string { + APICategory|error createdApiCategory = updateAPICategory("01ed9241-2d5d-1b98-8ecb-40f85676b081",payload, organiztion); + if createdApiCategory is APICategory { + test:assertFail("API Category updated successfully"); + } else if createdApiCategory is commons:APKError { + test:assertTrue(true, "Not Found Error"); + } + } else { + test:assertFail("Category ID isn't a string"); + } +} + +@test:Config {dependsOn: [updateAPICategoryTestNegative1]} +function updateAPICategoryTestNegative2() { + // Another API Category by same name exists + APICategory payloadOther = {name: "MyCat2", description: "My Desc 1"}; + APICategory|commons:APKError anotherApiCategory = addAPICategory(payloadOther, organiztion); + + // New Name + APICategory payload = {name: "MyCat2", description: "My Desc 1 new"}; + string? catId = apiCategory.id; + if catId is string { + APICategory|commons:APKError createdApiCategory = updateAPICategory(catId,payload, organiztion); + if createdApiCategory is APICategory { + test:assertFail("API Category updated successfully"); + } else if createdApiCategory is commons:APKError { + test:assertTrue(true,"Error occured while adding API Category"); + } + } else { + test:assertFail("Category ID isn't a string"); + } +} + +@test:Config {dependsOn: [updateAPICategoryTestNegative2]} +function removeAPICategoryTest(){ + string? catId = apiCategory.id; + if catId is string { + commons:APKError|string status = removeAPICategory(catId, organiztion); + if status is string { + test:assertTrue(true, "Successfully deleted API Category"); + } else if status is commons:APKError { + test:assertFail("Error occured while deleting API Category"); + } + } else { + test:assertFail("Category ID isn't a string"); + } +} diff --git a/admin/admin-domain-service/ballerina/tests/organizationTest.bal b/admin/admin-domain-service/ballerina/tests/organizationTest.bal new file mode 100644 index 000000000..49a3f1609 --- /dev/null +++ b/admin/admin-domain-service/ballerina/tests/organizationTest.bal @@ -0,0 +1,113 @@ +// +// Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + +import ballerina/test; +import wso2/apk_common_lib as commons; + +Organization organization = { + id: "01234567-0123-0123-0123-012345678901", + name: "Finance", + displayName: "Finance", + organizationClaimValue: "01234567-0123-0123-0123", + production: [], + sandbox: [], + workflows: [ + workflowProperties + ], + serviceNamespaces: [ + "string" + ] + }; +string orgId = ""; +WorkflowProperties workflowProperties = { + name: "ApplicationCreation", + properties: [], + enable: true + }; + +@test:Config {} +function addOrganizationTest() { + Organization|commons:APKError response = addOrganization(organization); + if response is Organization { + + orgId = response.id.toString(); + test:assertTrue(true,"Organization added successfully"); + } else if response is commons:APKError { + test:assertFail("Error occured while adding Organization"); + } + +} + +@test:Config {dependsOn: [addOrganizationTest]} +function updateOrganizationTest() { + Organization updateOrganization = { + id: "01234567-0123-0123-0123-012345678901", + name: "Finance", + displayName: "Finance", + organizationClaimValue: "01234567-0123-0123-0123", + workflows: [ + { + name: "ApplicationCreation", + enable: false, + properties: [] + } + + ], + serviceNamespaces: [ + "string" + ] + }; + Organization|commons:APKError response = updatedOrganization(orgId, updateOrganization); + if response is Organization { + test:assertTrue(true,"Organization updated successfully"); + } else if response is commons:APKError { + test:assertFail("Error occured while updating Organization"); + } + +} + + +@test:Config {dependsOn: [updateOrganizationTest]} +function getOrganizationsTest() { + OrganizationList|commons:APKError response = getAllOrganization(); + if response is OrganizationList { + test:assertTrue(true,"Organization list retrieved successfully"); + } else if response is commons:APKError { + test:assertFail("Error occured while retrieving Organization list"+response.message()); + } +} + +@test:Config {dependsOn: [getOrganizationsTest]} +function getOrganizationTest() { + Organization|commons:APKError response = getOrganizationById(orgId); + if response is Organization { + test:assertTrue(true,"Organization retrieved successfully"); + } else if response is commons:APKError { + test:assertFail("Error occured while retrieving Organization"); + } +} + +@test:Config {dependsOn: [getOrganizationTest]} +function deleteOrganizationTest() { + boolean|commons:APKError response = removeOrganization(orgId); + if response is boolean { + test:assertTrue(true,"Organization deleted successfully"); + } else if response is commons:APKError { + test:assertFail("Error occured while deleting Organization"); + } +} diff --git a/admin/admin-domain-service/ballerina/tests/resources/keyManager-configs/okta.yaml b/admin/admin-domain-service/ballerina/tests/resources/keyManager-configs/okta.yaml new file mode 100644 index 000000000..818f08435 --- /dev/null +++ b/admin/admin-domain-service/ballerina/tests/resources/keyManager-configs/okta.yaml @@ -0,0 +1,77 @@ +type: "Okta" +consumerKeyClaim: "azp" +scopesClaim: "scp" +endpoints: + - + name: "dcr_endpoint" + display_name: "DCR Endpoint" + toolTip: "Okta DCR Endpoint" + required: true + - + name: "introspection_endpoint" + display_name: "Introspection Endpoint" + toolTip: "Okta Introspection Endpoint" + required: false + - + name: "revocation_endpoint" + display_name: "Revocation Endpoint" + toolTip: "Okta Revocation Endpoint" + required: false + - + name: "token_endpoint" + display_name: "Token Endpoint" + toolTip: "Okta Token Endpoint" + required: true +endpointConfigurations: + - + name: "client_id" + display_name: "Client ID" + type: "input" + toolTip: "Okta Client ID" + required: true + - + name: "client_secret" + display_name: "Client Secret" + type : "input" + toolTip: "Okta Client Secret" + required: true + masked: true +applicationConfigurations: + - + name: "application_type" + display_name: "Application Type" + type: "select" + toolTip: "Okta Application Type" + required: true + values: + - "web" + - "native" + - "service" + default: "web" + - + name: "response_types" + display_name: "Response Types" + type: "select" + toolTip: "Okta Response Types" + required: true + values: + - "code" + - "token" + - "id_token" + - "code token" + - "code id_token" + - "token id_token" + - "code token id_token" + default: "code" + multiple: true + - name: "token_endpoint_auth_method" + display_name: "Token Endpoint Auth Method" + type: "select" + toolTip: "Okta Token Endpoint Auth Method" + required: true + values: + - "client_secret_basic" + - "client_secret_post" + - "none" + default: "client_secret_basic" + \ No newline at end of file diff --git a/admin/admin-domain-service/ballerina/tests/resources/wso2carbon.crt b/admin/admin-domain-service/ballerina/tests/resources/wso2carbon.crt new file mode 100644 index 000000000..caa74a133 --- /dev/null +++ b/admin/admin-domain-service/ballerina/tests/resources/wso2carbon.crt @@ -0,0 +1,15 @@ +-----BEGIN CERTIFICATE----- +MIICTDCCAbUCFBmlzXvk8t7eLJZW7bZNZK4koJHSMA0GCSqGSIb3DQEBCwUAMGUx +CzAJBgNVBAYTAkxLMQswCQYDVQQIDAJXUDEQMA4GA1UEBwwHQ29sb21ibzENMAsG +A1UECgwEV1NPMjEUMBIGA1UECwwLRW5naW5lZXRpbmcxEjAQBgNVBAMMCWxvY2Fs +aG9zdDAeFw0yMjEyMTQwODM3MzhaFw0yMzEyMTQwODM3MzhaMGUxCzAJBgNVBAYT +AkxLMQswCQYDVQQIDAJXUDEQMA4GA1UEBwwHQ29sb21ibzENMAsGA1UECgwEV1NP +MjEUMBIGA1UECwwLRW5naW5lZXRpbmcxEjAQBgNVBAMMCWxvY2FsaG9zdDCBnzAN +BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwLPJQmKc8mWjt2ZO7b6NANIaL5cdY14+ +3wpX/rpyYG0FeMfcEU09XwApzLI0cH61HmZRAxSkOEvw5zwgLsTcgt4Z3TmbCoMq +KYtdfRVpiWK3TpmkS346mwTBsS4+tSYtqO2g3r1mcUaVqL2xaWE9Wq5sM0Vs2pjO +22IsA6BvJbcCAwEAATANBgkqhkiG9w0BAQsFAAOBgQAG9q+pkvJFuv8vdFz3XWro +aym512HJcI7pE2H+ailBR04Td63xvrq2vAINO7/0kv2CoAm8sJBLAdTxsKnhbWCh +9Pd5OSdLIgymCA/qvV24T2YTbclMyhdR95gjmYJnqJNn3YAPq2GrcjtSdEg7Lg5N +wMzx3MH2sIWDPxbYugP6EQ== +-----END CERTIFICATE----- diff --git a/admin/admin-domain-service/ballerina/tests/resources/wso2carbon.key b/admin/admin-domain-service/ballerina/tests/resources/wso2carbon.key new file mode 100644 index 000000000..aa746b158 --- /dev/null +++ b/admin/admin-domain-service/ballerina/tests/resources/wso2carbon.key @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICWwIBAAKBgQDAs8lCYpzyZaO3Zk7tvo0A0hovlx1jXj7fClf+unJgbQV4x9wR +TT1fACnMsjRwfrUeZlEDFKQ4S/DnPCAuxNyC3hndOZsKgyopi119FWmJYrdOmaRL +fjqbBMGxLj61Ji2o7aDevWZxRpWovbFpYT1armwzRWzamM7bYiwDoG8ltwIDAQAB +AoGAPkJYBgDCYHaCPKDrY1irSdaX60RRlGdAvOMkpwIqLglLOUipS1W/PFBbMO1q +j+YAMoAwMGSc4it2+96rLzEfZQD87RFH8WxSp8NIxuCcSZBvNxLaiIhjxvU7B5LC +/S3Ao2bjM26iYalPpW8Pw/FLG6QXZEtOzmfyFAknzQR5wDECQQDsVKPFOUMNU89F ++zznViTiRj2+Z3kLfY7BmP2B/0/O9qnne98RQDRI9hu8SL4o6ll3P3wucOv7I+o6 +bqh5clq7AkEA0L2VK0vEKyR6pksJDj1wxtic9TyKEINcYnkXteOPBOHRcwXA5tBS +LTgSsQSfHe41bl3SQqQWYkY65CH4LYHHNQJAa1lS/r4w9/fO2gHyOz7FCEdRupBz +ykVhOA1PceJQFTm0GaMJw2M/nLi2BoOgZSN2OhWLSekfN/eraJllS60nCwJAch5D +UAFDBOcTmphJIhza7Ar+fGAVhwOZ3Ugge1MmHGAsdrq9hDJ9yrTuGxLQvrc9RNJM +Ihy9FAsbJR+hI5fgxQJAK+oeuE/LxSI9lVFe/wl4so0AsA98aYjK0lB+qBT6F7Zf +QEN6sCv+4Peulp4pIm160LuYt2+/iJ1G/ezRyfbctw== +-----END RSA PRIVATE KEY----- diff --git a/admin/admin-domain-service/ballerina/tests/throttlePolicyTests.bal b/admin/admin-domain-service/ballerina/tests/throttlePolicyTests.bal new file mode 100644 index 000000000..81b4bacc6 --- /dev/null +++ b/admin/admin-domain-service/ballerina/tests/throttlePolicyTests.bal @@ -0,0 +1,308 @@ +// +// Copyright (c) 2022, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + +import ballerina/test; +import ballerina/log; +import wso2/apk_common_lib as commons; + +commons:Organization organiztion = { + name: "org1", + displayName: "org1", + uuid: "a3b58ccf-6ecc-4557-b5bb-0a35cce38256", + organizationClaimValue: "org1", + enabled: true, + serviceListingNamespaces: ["*"], + properties: [] +}; + +ApplicationRatePlan applicationUsagePlan = {planName: "25PerMin", description: "25 Per Minute", +'type:"ApplicationThrottlePolicy",defaultLimit: {'type: "REQUESTCOUNTLIMIT"}}; + +BusinessPlan businessPlan = {planName: "MySubPol1", description: "test sub pol", +'type:"SubscriptionThrottlePolicy",defaultLimit: {'type: "REQUESTCOUNTLIMIT"}, +subscriberCount: 12, rateLimitCount: 10,rateLimitTimeUnit: "sec", planId: "123456"}; + +BlockingCondition denyPolicy = {policyId: "123456",conditionType: "APPLICATION", +conditionValue: "admin:MyApp5",conditionStatus: true}; + +@test:Config {} +function addApplicationUsagePlanTest() { + ApplicationRatePlan payload = { + "planName": "25PerMin", + "displayName": "25PerMin", + "description": "25 Per Min", + "defaultLimit": { + "type": "REQUESTCOUNTLIMIT", + "requestCount": { + "requestCount": 25, + "timeUnit": "min", + "unitTime": 1 + } + } + }; + ApplicationRatePlan|commons:APKError createdAppPol = addApplicationUsagePlan(payload, organiztion); + if createdAppPol is ApplicationRatePlan { + test:assertTrue(true,"Application usage plan added successfully"); + applicationUsagePlan = createdAppPol; + log:printInfo(createdAppPol.toString()); + } else if createdAppPol is commons:APKError { + log:printError(createdAppPol.toString()); + test:assertFail("Error occured while adding Application Usage Plan"); + } +} + +@test:Config {dependsOn: [addApplicationUsagePlanTest]} +function getApplicationUsagePlanByIdTest(){ + string? planId = applicationUsagePlan.planId; + if planId is string { + ApplicationRatePlan|commons:APKError policy = getApplicationUsagePlanById(planId, organiztion); + if policy is ApplicationRatePlan { + test:assertTrue(true, "Successfully retrieved Application Usage Plan"); + log:printInfo(policy.toString()); + } else { + test:assertFail("Error occured while retrieving Application Usage Plan"); + } + } else { + test:assertFail("Plan ID isn't a string"); + } +} + +@test:Config {dependsOn: [getApplicationUsagePlanByIdTest]} +function getApplicationUsagePlansTest(){ + ApplicationRatePlanList|commons:APKError appPolicyList = getApplicationUsagePlans(organiztion); + if appPolicyList is ApplicationRatePlanList { + test:assertTrue(true, "Successfully retrieved all Application Usage Plans"); + log:printInfo(appPolicyList.toString()); + } else if appPolicyList is commons:APKError { + test:assertFail("Error occured while retrieving all Application Usage Plans"); + } +} + +@test:Config {dependsOn: [getApplicationUsagePlansTest]} +function updateApplicationUsagePlanTest() { + ApplicationRatePlan payload = { + "planName": "25PerMin", + "displayName": "25PerMin", + "description": "25 Per Min Updated", + "defaultLimit": { + "type": "REQUESTCOUNTLIMIT", + "requestCount": { + "requestCount": 26, + "timeUnit": "min", + "unitTime": 1 + } + } + }; + string? planId = applicationUsagePlan.planId; + if planId is string { + ApplicationRatePlan|commons:APKError createdAppPol = updateApplicationUsagePlan(planId, payload, organiztion); + if createdAppPol is ApplicationRatePlan { + test:assertTrue(true,"Application usage plan updated successfully"); + } else if createdAppPol is commons:APKError { + log:printError(createdAppPol.toString()); + test:assertFail("Error occured while updating Application Usage Plan"); + } + } else { + test:assertFail("Plan ID isn't a string"); + } +} + +@test:Config {dependsOn: [updateApplicationUsagePlanTest]} +function removeApplicationUsagePlanTest(){ + string? planId = applicationUsagePlan.planId; + if planId is string { + error?|string status = removeApplicationUsagePlan(planId, organiztion); + if status is string { + test:assertTrue(true, "Successfully deleted Application Usage Plan"); + } else if status is error { + test:assertFail("Error occured while deleting Application Usage Plan"); + } + } else { + test:assertFail("Plan ID isn't a string"); + } +} + +@test:Config +function addBusinessPlanTest() { + BusinessPlan payload = { + "planName": "BusinessPlan2", + "displayName": "BusinessPlan2", + "description": "test sub pol test2", + "defaultLimit": { + "type": "REQUESTCOUNTLIMIT", + "requestCount": { + "requestCount": 20, + "timeUnit": "min", + "unitTime": 1 + } + }, + "rateLimitCount": 10, + "rateLimitTimeUnit": "sec", + "customAttributes": [] + }; + BusinessPlan|commons:APKError createdBusinessPlan = addBusinessPlan(payload, organiztion); + if createdBusinessPlan is BusinessPlan { + test:assertTrue(true,"Business Plan added successfully"); + businessPlan.planId = createdBusinessPlan.planId; + } else if createdBusinessPlan is commons:APKError { + test:assertFail("Error occured while adding Business Plan"); + } +} + +@test:Config {dependsOn: [addBusinessPlanTest]} +function getBusinessPlanByIdTest() { + string? planId = businessPlan.planId; + if planId is string { + BusinessPlan|commons:APKError businessPlanResponse = getBusinessPlanById(planId, organiztion); + if businessPlanResponse is BusinessPlan { + test:assertTrue(true,"Successfully retrieved Business Plan"); + } else { + test:assertFail("Error occured while retrieving Business Plan"); + } + } else { + test:assertFail("Plan ID isn't a string"); + } +} + +@test:Config {dependsOn: [getBusinessPlanByIdTest]} +function getBusinessPlansTest() { + BusinessPlanList|commons:APKError businessPlansResponse = getBusinessPlans(organiztion); + if businessPlansResponse is BusinessPlanList { + test:assertTrue(true,"Successfully retrieved all Business Plans"); + } else if businessPlansResponse is commons:APKError { + test:assertFail("Error occured while retrieving all Business Plans"); + } +} + +@test:Config {dependsOn: [getBusinessPlansTest]} +function updateBusinessPlanTest() { + BusinessPlan payload = { + "planName": "BusinessPlan2", + "displayName": "BusinessPlan2", + "description": "test sub pol test2 updated", + "defaultLimit": { + "type": "REQUESTCOUNTLIMIT", + "requestCount": { + "requestCount": 25, + "timeUnit": "min", + "unitTime": 1 + } + }, + "rateLimitCount": 10, + "rateLimitTimeUnit": "sec", + "customAttributes": [] + }; + string? planId = businessPlan.planId; + if planId is string { + BusinessPlan|commons:APKError updatedBusinessPlan = updateBusinessPlan(planId, payload, organiztion); + if updatedBusinessPlan is BusinessPlan { + test:assertTrue(true,"Business Plan updated successfully"); + } else if updatedBusinessPlan is commons:APKError { + test:assertFail("Error occured while updating Business Plan"); + } + } else { + test:assertFail("Plan ID isn't a string"); + } +} + +@test:Config {dependsOn: [updateBusinessPlanTest]} +function removeBusinessPlanTest(){ + string? planId = businessPlan.planId; + if planId is string { + commons:APKError|string status = removeBusinessPlan(planId, organiztion); + if status is string { + test:assertTrue(true, "Successfully deleted Business Plan"); + } else if status is commons:APKError { + test:assertFail("Error occured while deleting Business Plan"); + } + } else { + test:assertFail("Plan ID isn't a string"); + } +} + +@test:Config {} +function addDenyPolicyTest() { + BlockingCondition payload = { + "conditionType": "APPLICATION", + "conditionValue": "admin:MyApp6", + "conditionStatus": true + }; + BlockingCondition|commons:APKError createdDenyPolicy = addDenyPolicy(payload, organiztion); + if createdDenyPolicy is BlockingCondition { + test:assertTrue(true,"Deny Policy added successfully"); + denyPolicy.policyId = createdDenyPolicy.policyId; + } else if createdDenyPolicy is commons:APKError { + test:assertFail("Error occured while adding Deny Policy"); + } +} + +@test:Config {dependsOn: [addDenyPolicyTest]} +function getDenyPolicyByIdTest() { + string? policyId = denyPolicy.policyId; + if policyId is string { + BlockingCondition|commons:APKError denyPolicyResponse = getDenyPolicyById(policyId, organiztion); + if denyPolicyResponse is BlockingCondition { + test:assertTrue(true,"Successfully retrieved Deny Policy"); + } else { + test:assertFail("Error occured while retrieving Deny Policy"); + } + } else { + test:assertFail("Policy ID isn't a string"); + } +} + +@test:Config {dependsOn: [getDenyPolicyByIdTest]} +function getAllDenyPoliciesTest() { + BlockingConditionList|commons:APKError denyPoliciesResponse = getAllDenyPolicies(organiztion); + if denyPoliciesResponse is BlockingConditionList { + test:assertTrue(true,"Successfully retrieved all Deny Policy"); + } else if denyPoliciesResponse is commons:APKError { + test:assertFail("Error occured while retrieving all Deny Policy"); + } +} + +@test:Config {dependsOn: [getAllDenyPoliciesTest]} +function updateDenyPolicyTest() { + string? policyId = denyPolicy.policyId; + if policyId is string { + BlockingConditionStatus status = {conditionStatus: false, policyId: policyId}; + string?|BlockingCondition|commons:APKError denyPolicyResponse = updateDenyPolicy(policyId, status, organiztion); + if denyPolicyResponse is BlockingCondition { + test:assertTrue(true,"Successfully updated Deny Policy Status"); + } else if denyPolicyResponse is commons:APKError { + test:assertFail("Error occured while updating Deny Policy Status"); + } + } else { + test:assertFail("Policy ID isn't a string"); + } +} + +@test:Config {dependsOn: [updateDenyPolicyTest]} +function removeDenyPolicyTest(){ + string? policyId = denyPolicy.policyId; + if policyId is string { + commons:APKError|string status = removeDenyPolicy(policyId, organiztion); + if status is string { + test:assertTrue(true, "Successfully deleted Deny Policy"); + } else if status is commons:APKError { + test:assertFail("Error occured while deleting Deny Policy"); + } + } else { + test:assertFail("Policy ID isn't a string"); + } +} diff --git a/admin/admin-domain-service/ballerina/throttlingPolicyDAO.bal b/admin/admin-domain-service/ballerina/throttlingPolicyDAO.bal new file mode 100644 index 000000000..c6bb2eeda --- /dev/null +++ b/admin/admin-domain-service/ballerina/throttlingPolicyDAO.bal @@ -0,0 +1,414 @@ +// +// Copyright (c) 2022, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + +import ballerina/log; +import ballerinax/postgresql; +import ballerina/sql; +import wso2/apk_common_lib as commons; + +public isolated function addApplicationUsagePlanDAO(ApplicationRatePlan atp, string org) returns ApplicationRatePlan|commons:APKError { + postgresql:Client | error dbClient = getConnection(); + if dbClient is error { + return e909401(dbClient); + } else { + sql:ParameterizedQuery query = `INSERT INTO APPLICATION_USAGE_PLAN (NAME, DISPLAY_NAME, + ORGANIZATION, DESCRIPTION, QUOTA_TYPE, QUOTA, UNIT_TIME, TIME_UNIT, IS_DEPLOYED, UUID) + VALUES (${atp.planName},${atp.displayName},${org},${atp.description},${atp.defaultLimit.'type}, + ${atp.defaultLimit.requestCount?.requestCount},${atp.defaultLimit.requestCount?.unitTime}, + ${atp.defaultLimit.requestCount?.timeUnit},${atp.isDeployed},${atp.planId})`; + sql:ExecutionResult | sql:Error result = dbClient->execute(query); + if result is sql:ExecutionResult { + return atp; + } else if result is sql:Error { + log:printDebug(result.toString()); + return e909402(result); + } + } +} + +public isolated function getApplicationUsagePlanByIdDAO(string policyId, string org) returns ApplicationRatePlan|commons:APKError { + postgresql:Client | error dbClient = getConnection(); + if dbClient is error { + return e909401(dbClient); + } else { + sql:ParameterizedQuery query = `SELECT NAME as PLANNAME, DISPLAY_NAME as DISPLAYNAME, DESCRIPTION, + UUID as PLANID, IS_DEPLOYED as ISDEPLOYED, + QUOTA_TYPE as DefaulLimitType, QUOTA , TIME_UNIT as TIMEUNIT, UNIT_TIME as + UNITTIME, QUOTA_UNIT as DATAUNIT FROM APPLICATION_USAGE_PLAN WHERE UUID =${policyId} AND ORGANIZATION =${org}`; + ApplicationRatePlanDAO | sql:Error result = dbClient->queryRow(query); + if result is sql:NoRowsError { + log:printDebug(result.toString()); + return e909429(); + } else if result is ApplicationRatePlanDAO { + if result.defaulLimitType == "requestCount" { + ApplicationRatePlan arp = {planName: result.planName, displayName: result.displayName, + description: result.description, planId: result.planId, isDeployed: result.isDeployed, + defaultLimit: {'type: result.defaulLimitType, requestCount: + {requestCount: result.quota, timeUnit: result.timeUnit, unitTime: result.unitTime} + }}; + log:printDebug(arp.toString()); + return arp; + } else if result.defaulLimitType == "bandwidth" { + ApplicationRatePlan arp = {planName: result.planName, displayName: result.displayName, + description: result.description, planId: result.planId, isDeployed: result.isDeployed, + defaultLimit: {'type: result.defaulLimitType, bandwidth: + {dataAmount: result.quota, dataUnit: result.dataUnit, timeUnit: result.timeUnit, unitTime: result.unitTime} + }}; + log:printDebug(arp.toString()); + return arp; + } else { + ApplicationRatePlan arp = {planName: result.planName, displayName: result.displayName, + description: result.description, planId: result.planId, isDeployed: result.isDeployed, + defaultLimit: {'type: result.defaulLimitType, eventCount: + {eventCount:result.quota, timeUnit: result.timeUnit, unitTime: result.unitTime} + }}; + log:printDebug(arp.toString()); + return arp; + } + } else { + log:printError(result.toString()); + return e909418(); + } + } +} + +public isolated function getApplicationUsagePlansDAO(string org) returns ApplicationRatePlan[]|commons:APKError { + postgresql:Client | error dbClient = getConnection(); + if dbClient is error { + return e909401(dbClient); + } else { + do { + sql:ParameterizedQuery query = `SELECT NAME as PLANNAME, DISPLAY_NAME as DISPLAYNAME, DESCRIPTION, + UUID as PLANID, IS_DEPLOYED as ISDEPLOYED, + QUOTA_TYPE as DefaulLimitType, QUOTA , TIME_UNIT as TIMEUNIT, UNIT_TIME as + UNITTIME, QUOTA_UNIT as DATAUNIT FROM APPLICATION_USAGE_PLAN WHERE ORGANIZATION =${org}`; + stream usagePlanStream = dbClient->query(query); + ApplicationRatePlanDAO[] usagePlansDAO = check from ApplicationRatePlanDAO usagePlan in usagePlanStream select usagePlan; + check usagePlanStream.close(); + ApplicationRatePlan[] usagePlans = []; + if usagePlansDAO is ApplicationRatePlanDAO[]{ + foreach ApplicationRatePlanDAO result in usagePlansDAO { + if result.defaulLimitType == "requestCount" { + ApplicationRatePlan arp = {planName: result.planName, displayName: result.displayName, + description: result.description, planId: result.planId, isDeployed: result.isDeployed, + defaultLimit: {'type: result.defaulLimitType, requestCount: + {requestCount: result.quota, timeUnit: result.timeUnit, unitTime: result.unitTime} + }}; + usagePlans.push(arp); + } else if result.defaulLimitType == "bandwidth" { + ApplicationRatePlan arp = {planName: result.planName, displayName: result.displayName, + description: result.description, planId: result.planId, isDeployed: result.isDeployed, + defaultLimit: {'type: result.defaulLimitType, bandwidth: + {dataAmount: result.quota, dataUnit: result.dataUnit, timeUnit: result.timeUnit, unitTime: result.unitTime} + }}; + usagePlans.push(arp); + } else { + ApplicationRatePlan arp = {planName: result.planName, displayName: result.displayName, + description: result.description, planId: result.planId, isDeployed: result.isDeployed, + defaultLimit: {'type: result.defaulLimitType, eventCount: + {eventCount:result.quota, timeUnit: result.timeUnit, unitTime: result.unitTime} + }}; + usagePlans.push(arp); + } + } + } + return usagePlans; + } on fail var e { + return e909419(e); + } + } +} + +public isolated function updateApplicationUsagePlanDAO(ApplicationRatePlan atp, string org) returns ApplicationRatePlan|commons:APKError { + postgresql:Client | error dbClient = getConnection(); + if dbClient is error { + return e909401(dbClient); + } else { + sql:ParameterizedQuery query = `UPDATE APPLICATION_USAGE_PLAN SET DISPLAY_NAME = ${atp.displayName}, + DESCRIPTION = ${atp.description}, QUOTA_TYPE = ${atp.defaultLimit.'type}, QUOTA = ${atp.defaultLimit.requestCount?.requestCount}, + UNIT_TIME = ${atp.defaultLimit.requestCount?.unitTime}, TIME_UNIT = ${atp.defaultLimit.requestCount?.timeUnit} + WHERE UUID = ${atp.planId} AND ORGANIZATION = ${org}`; + sql:ExecutionResult | sql:Error result = dbClient->execute(query); + if result is sql:ExecutionResult { + return atp; + } else { + log:printDebug(result.toString()); + return e909405(result); + } + } +} + +public isolated function deleteApplicationUsagePlanDAO(string policyId, string org) returns string|commons:APKError { + postgresql:Client | error dbClient = getConnection(); + if dbClient is error { + return e909401(dbClient); + } else { + sql:ParameterizedQuery query = `DELETE FROM APPLICATION_USAGE_PLAN WHERE UUID = ${policyId} AND ORGANIZATION = ${org}`; + sql:ExecutionResult | sql:Error result = dbClient->execute(query); + if result is sql:ExecutionResult { + return "deleted"; + } else { + log:printError(result.toString()); + return e909406(result); + } + } +} + +public isolated function addBusinessPlanDAO(BusinessPlan stp, string org) returns BusinessPlan|commons:APKError { + postgresql:Client | error dbClient = getConnection(); + if dbClient is error { + return e909401(dbClient); + } else { + sql:ParameterizedQuery query = `INSERT INTO BUSINESS_PLAN (NAME, DISPLAY_NAME, ORGANIZATION, DESCRIPTION, + QUOTA_TYPE, QUOTA, UNIT_TIME, TIME_UNIT, IS_DEPLOYED, UUID, + RATE_LIMIT_COUNT,RATE_LIMIT_TIME_UNIT,MAX_DEPTH, MAX_COMPLEXITY, + BILLING_PLAN,CONNECTIONS_COUNT) VALUES (${stp.planName},${stp.displayName},${org},${stp.description},${stp.defaultLimit.'type}, + ${stp.defaultLimit.requestCount?.requestCount},${stp.defaultLimit.requestCount?.unitTime},${stp.defaultLimit.requestCount?.timeUnit}, + ${stp.isDeployed},${stp.planId},${stp.rateLimitCount},${stp.rateLimitTimeUnit},0, + 0,'FREE',0)`; + sql:ExecutionResult | sql:Error result = dbClient->execute(query); + if result is sql:ExecutionResult { + log:printDebug(result.toString()); + return stp; + } else { + log:printError(result.toString()); + return e909402(result); + } + } +} + +public isolated function getBusinessPlanByIdDAO(string policyId, string org) returns BusinessPlan|commons:APKError { + postgresql:Client | error dbClient = getConnection(); + if dbClient is error { + return e909401(dbClient); + } else { + sql:ParameterizedQuery query = `SELECT NAME as PLANNAME, DISPLAY_NAME as DISPLAYNAME, DESCRIPTION, + UUID as PLANID, IS_DEPLOYED as ISDEPLOYED, + QUOTA_TYPE as DefaulLimitType, QUOTA , TIME_UNIT as TIMEUNIT, UNIT_TIME as + UNITTIME, RATE_LIMIT_COUNT as RATELIMITCOUNT, RATE_LIMIT_TIME_UNIT as RATELIMITTIMEUNIT FROM BUSINESS_PLAN WHERE UUID =${policyId} AND ORGANIZATION =${org}`; + BusinessPlanDAO | sql:Error result = dbClient->queryRow(query); + if result is sql:NoRowsError { + log:printDebug(result.toString()); + return e909430(); + } else if result is BusinessPlanDAO { + if result.defaulLimitType == "requestCount" { + BusinessPlan bp = {planName: result.planName, displayName: result.displayName, + description: result.description, planId: result.planId, isDeployed: result.isDeployed, + rateLimitCount: result.rateLimitCount, rateLimitTimeUnit: result.rateLimitTimeUnit, + defaultLimit: {'type: result.defaulLimitType, requestCount: + {requestCount: result.quota, timeUnit: result.timeUnit, unitTime: result.unitTime} + }}; + log:printDebug(bp.toString()); + return bp; + } else if result.defaulLimitType == "bandwidth" { + BusinessPlan bp = {planName: result.planName, displayName: result.displayName, + description: result.description, planId: result.planId, isDeployed: result.isDeployed, + rateLimitCount: result.rateLimitCount, rateLimitTimeUnit: result.rateLimitTimeUnit, + defaultLimit: {'type: result.defaulLimitType, bandwidth: + {dataAmount: result.quota, dataUnit: result.dataUnit, timeUnit: result.timeUnit, unitTime: result.unitTime} + }}; + log:printDebug(bp.toString()); + return bp; + } else { + BusinessPlan bp = {planName: result.planName, displayName: result.displayName, + description: result.description, planId: result.planId, isDeployed: result.isDeployed, + rateLimitCount: result.rateLimitCount, rateLimitTimeUnit: result.rateLimitTimeUnit, + defaultLimit: {'type: result.defaulLimitType, eventCount: + {eventCount:result.quota, timeUnit: result.timeUnit, unitTime: result.unitTime} + }}; + log:printDebug(bp.toString()); + return bp; + } + } else { + log:printError(result.toString()); + return e909420(result); + } + } +} + +public isolated function getBusinessPlansDAO(string org) returns BusinessPlan[]|commons:APKError { + postgresql:Client | error dbClient = getConnection(); + if dbClient is error { + return e909401(dbClient); + } else { + do { + sql:ParameterizedQuery query = `SELECT NAME as PLANNAME, DISPLAY_NAME as DISPLAYNAME, DESCRIPTION, + UUID as PLANID, IS_DEPLOYED as ISDEPLOYED, + QUOTA_TYPE as DefaulLimitType, QUOTA , TIME_UNIT as TIMEUNIT, UNIT_TIME as + UNITTIME, RATE_LIMIT_COUNT as RATELIMITCOUNT, RATE_LIMIT_TIME_UNIT as RATELIMITTIMEUNIT FROM BUSINESS_PLAN WHERE ORGANIZATION =${org}`; + stream businessPlanStream = dbClient->query(query); + BusinessPlanDAO[] businessPlansDAO = check from BusinessPlanDAO businessPlan in businessPlanStream select businessPlan; + check businessPlanStream.close(); + BusinessPlan[] businessPlans =[]; + if businessPlansDAO is BusinessPlanDAO[] { + foreach BusinessPlanDAO result in businessPlansDAO { + if result.defaulLimitType == "requestCount" { + BusinessPlan bp = {planName: result.planName, displayName: result.displayName, + description: result.description, planId: result.planId, isDeployed: result.isDeployed, + rateLimitCount: result.rateLimitCount, rateLimitTimeUnit: result.rateLimitTimeUnit, + defaultLimit: {'type: result.defaulLimitType, requestCount: + {requestCount: result.quota, timeUnit: result.timeUnit, unitTime: result.unitTime} + }}; + businessPlans.push(bp); + } else if result.defaulLimitType == "bandwidth" { + BusinessPlan bp = {planName: result.planName, displayName: result.displayName, + description: result.description, planId: result.planId, isDeployed: result.isDeployed, + rateLimitCount: result.rateLimitCount, rateLimitTimeUnit: result.rateLimitTimeUnit, + defaultLimit: {'type: result.defaulLimitType, bandwidth: + {dataAmount: result.quota, dataUnit: result.dataUnit, timeUnit: result.timeUnit, unitTime: result.unitTime} + }}; + businessPlans.push(bp); + } else { + BusinessPlan bp = {planName: result.planName, displayName: result.displayName, + description: result.description, planId: result.planId, isDeployed: result.isDeployed, + rateLimitCount: result.rateLimitCount, rateLimitTimeUnit: result.rateLimitTimeUnit, + defaultLimit: {'type: result.defaulLimitType, eventCount: + {eventCount:result.quota, timeUnit: result.timeUnit, unitTime: result.unitTime} + }}; + businessPlans.push(bp); + } + } + } + return businessPlans; + } on fail var e { + return e909421(e); + } + } +} + +public isolated function updateBusinessPlanDAO(BusinessPlan stp, string org) returns BusinessPlan|commons:APKError { + postgresql:Client | error dbClient = getConnection(); + if dbClient is error { + return e909401(dbClient); + } else { + sql:ParameterizedQuery query = `UPDATE BUSINESS_PLAN SET DISPLAY_NAME = ${stp.displayName}, + DESCRIPTION = ${stp.description}, QUOTA_TYPE = ${stp.defaultLimit.'type}, QUOTA = ${stp.defaultLimit.requestCount?.requestCount}, + UNIT_TIME = ${stp.defaultLimit.requestCount?.unitTime}, TIME_UNIT = ${stp.defaultLimit.requestCount?.timeUnit}, + RATE_LIMIT_COUNT = ${stp.rateLimitCount} , RATE_LIMIT_TIME_UNIT = ${stp.rateLimitTimeUnit}, CONNECTIONS_COUNT = 0 + WHERE UUID = ${stp.planId} AND ORGANIZATION = ${org}`; + sql:ExecutionResult | sql:Error result = dbClient->execute(query); + if result is sql:ExecutionResult { + return stp; + } else { + log:printError(result.toString()); + return e909405(result); + } + } +} + +public isolated function deleteBusinessPlanDAO(string policyId, string org) returns string|commons:APKError { + postgresql:Client | error dbClient = getConnection(); + if dbClient is error { + return e909401(dbClient); + } else { + sql:ParameterizedQuery query = `DELETE FROM BUSINESS_PLAN WHERE UUID = ${policyId} AND ORGANIZATION = ${org}`; + sql:ExecutionResult | sql:Error result = dbClient->execute(query); + if result is sql:ExecutionResult { + return ""; + } else { + log:printError(result.toString()); + return e909406(result); + } + } +} + +public isolated function addDenyPolicyDAO(BlockingCondition bc, string org) returns BlockingCondition|commons:APKError { + postgresql:Client | error dbClient = getConnection(); + if dbClient is error { + return e909401(dbClient); + } else { + sql:ParameterizedQuery query = `INSERT INTO BLOCK_CONDITION (TYPE,BLOCK_CONDITION,ENABLED,ORGANIZATION,UUID) + VALUES (${bc.conditionType},${bc.conditionValue},${bc.conditionStatus},${org},${bc.policyId})`; + sql:ExecutionResult | sql:Error result = dbClient->execute(query); + if result is sql:ExecutionResult { + return bc; + } else { + log:printError(result.toString()); + return e909402(result); + } + } +} + +public isolated function getDenyPolicyByIdDAO(string policyId, string org) returns BlockingCondition|commons:APKError { + postgresql:Client | error dbClient = getConnection(); + if dbClient is error { + return e909401(dbClient); + } else { + sql:ParameterizedQuery query = `SELECT UUID as POLICYID, TYPE as CONDITIONTYPE, BLOCK_CONDITION as CONDITIONVALUE, ENABLED::BOOLEAN as CONDITIONSTATUS FROM BLOCK_CONDITION WHERE UUID =${policyId} AND ORGANIZATION =${org}`; + BlockingCondition | sql:Error result = dbClient->queryRow(query); + if result is sql:NoRowsError { + log:printDebug(result.toString()); + return e909431(); + } else if result is BlockingCondition { + log:printDebug(result.toString()); + return result; + } else { + log:printError(result.toString()); + return e909422(result); + } + } +} + +public isolated function getDenyPoliciesDAO(string org) returns BlockingCondition[]|commons:APKError { + postgresql:Client | error dbClient = getConnection(); + if dbClient is error { + return e909401(dbClient); + } else { + do { + sql:ParameterizedQuery query = `SELECT UUID as POLICYID, TYPE as CONDITIONTYPE, BLOCK_CONDITION as CONDITIONVALUE, ENABLED::BOOLEAN as CONDITIONSTATUS FROM BLOCK_CONDITION WHERE ORGANIZATION =${org}`; + stream denyPoliciesStream = dbClient->query(query); + BlockingCondition[] denyPolicies = check from BlockingCondition denyPolicy in denyPoliciesStream select denyPolicy; + check denyPoliciesStream.close(); + return denyPolicies; + } on fail var e { + return e909423(e); + } + } +} + +public isolated function updateDenyPolicyDAO(BlockingConditionStatus status) returns string|commons:APKError { + postgresql:Client | error dbClient = getConnection(); + if dbClient is error { + return e909401(dbClient); + } else { + sql:ParameterizedQuery query = `UPDATE BLOCK_CONDITION SET ENABLED = ${status.conditionStatus} WHERE UUID = ${status.policyId}`; + sql:ExecutionResult | sql:Error result = dbClient->execute(query); + if result is sql:ExecutionResult { + return ""; + } else { + log:printError(result.toString()); + return e909402(result); + } + } +} + +public isolated function deleteDenyPolicyDAO(string policyId, string org) returns string|commons:APKError { + postgresql:Client | error dbClient = getConnection(); + if dbClient is error { + return e909401(dbClient); + } else { + sql:ParameterizedQuery query = `DELETE FROM BLOCK_CONDITION WHERE UUID = ${policyId} AND ORGANIZATION = ${org}`; + sql:ExecutionResult | sql:Error result = dbClient->execute(query); + if result is sql:ExecutionResult { + return ""; + } else { + log:printError(result.toString()); + return e909406(result); + } + } +} \ No newline at end of file diff --git a/admin/admin-domain-service/ballerina/throttlingPolicyImpl.bal b/admin/admin-domain-service/ballerina/throttlingPolicyImpl.bal new file mode 100644 index 000000000..e50a910f4 --- /dev/null +++ b/admin/admin-domain-service/ballerina/throttlingPolicyImpl.bal @@ -0,0 +1,206 @@ +// +// Copyright (c) 2022, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + +import ballerina/uuid; +import wso2/apk_common_lib as commons; + +isolated function addApplicationUsagePlan(ApplicationRatePlan body, commons:Organization org) returns ApplicationRatePlan|commons:APKError { + string policyId = uuid:createType1AsString(); + body.planId = policyId; + match body.defaultLimit.'type { + "REQUESTCOUNTLIMIT" => { + body.defaultLimit.'type = "requestCount"; + } + "BANDWIDTHLIMIT" => { + body.defaultLimit.'type = "bandwidth"; + } + "EVENTCOUNTLIMIT" => { + body.defaultLimit.'type = "eventCount"; + } + } + ApplicationRatePlan|commons:APKError policy = addApplicationUsagePlanDAO(body , org.uuid); + return policy; +} + +isolated function getApplicationUsagePlanById(string policyId, commons:Organization org) returns ApplicationRatePlan|commons:APKError { + ApplicationRatePlan|commons:APKError policy = getApplicationUsagePlanByIdDAO(policyId, org.uuid); + return policy; +} + +isolated function getApplicationUsagePlans(commons:Organization org) returns ApplicationRatePlanList|commons:APKError { + ApplicationRatePlan[]|commons:APKError usagePlans = getApplicationUsagePlansDAO(org.uuid); + if usagePlans is ApplicationRatePlan[] { + int count = usagePlans.length(); + ApplicationRatePlanList usagePlansList = {count: count, list: usagePlans}; + return usagePlansList; + } else { + return usagePlans; + } +} + +isolated function updateApplicationUsagePlan(string policyId, ApplicationRatePlan body, commons:Organization org) returns ApplicationRatePlan|commons:APKError { + ApplicationRatePlan|commons:APKError existingPolicy = getApplicationUsagePlanByIdDAO(policyId, org.uuid); + if existingPolicy is ApplicationRatePlan { + body.planId = policyId; + //body.policyName = existingPolicy.name; + } else { + return existingPolicy; + } + + match body.defaultLimit.'type { + "REQUESTCOUNTLIMIT" => { + body.defaultLimit.'type = "requestCount"; + } + "BANDWIDTHLIMIT" => { + body.defaultLimit.'type = "bandwidth"; + } + "EVENTCOUNTLIMIT" => { + body.defaultLimit.'type = "eventCount"; + } + } + ApplicationRatePlan|commons:APKError policy = updateApplicationUsagePlanDAO(body, org.uuid); + return policy; +} + +isolated function removeApplicationUsagePlan(string policyId, commons:Organization org) returns commons:APKError|string { + commons:APKError|string status = deleteApplicationUsagePlanDAO(policyId, org.uuid); + return status; +} + +isolated function addBusinessPlan(BusinessPlan body, commons:Organization org) returns BusinessPlan|commons:APKError { + string policyId = uuid:createType1AsString(); + body.planId = policyId; + match body.defaultLimit.'type { + "REQUESTCOUNTLIMIT" => { + body.defaultLimit.'type = "requestCount"; + } + "BANDWIDTHLIMIT" => { + body.defaultLimit.'type = "bandwidth"; + } + "EVENTCOUNTLIMIT" => { + body.defaultLimit.'type = "eventCount"; + } + } + BusinessPlan|commons:APKError policy = addBusinessPlanDAO(body, org.uuid); + return policy; +} + +isolated function getBusinessPlanById(string policyId, commons:Organization org) returns BusinessPlan|commons:APKError { + BusinessPlan|commons:APKError policy = getBusinessPlanByIdDAO(policyId, org.uuid); + return policy; +} + +isolated function getBusinessPlans(commons:Organization org) returns BusinessPlanList|commons:APKError { + BusinessPlan[]|commons:APKError businessPlans = getBusinessPlansDAO(org.uuid); + if businessPlans is BusinessPlan[] { + int count = businessPlans.length(); + BusinessPlanList BusinessPlansList = {count: count, list: businessPlans}; + return BusinessPlansList; + } else { + return businessPlans; + } +} + +isolated function updateBusinessPlan(string policyId, BusinessPlan body, commons:Organization org) returns BusinessPlan|commons:APKError { + BusinessPlan|commons:APKError existingPolicy = getBusinessPlanByIdDAO(policyId, org.uuid); + if existingPolicy is BusinessPlan { + body.planId = policyId; + //body.policyName = existingPolicy.name; + } else { + return existingPolicy; + } + match body.defaultLimit.'type { + "REQUESTCOUNTLIMIT" => { + body.defaultLimit.'type = "requestCount"; + } + "BANDWIDTHLIMIT" => { + body.defaultLimit.'type = "bandwidth"; + } + "EVENTCOUNTLIMIT" => { + body.defaultLimit.'type = "eventCount"; + } + } + BusinessPlan|commons:APKError policy = updateBusinessPlanDAO(body, org.uuid); + return policy; +} + +isolated function removeBusinessPlan(string policyId, commons:Organization org) returns commons:APKError|string { + commons:APKError|string status = deleteBusinessPlanDAO(policyId, org.uuid); + return status; +} + +isolated function addDenyPolicy(BlockingCondition body, commons:Organization org) returns BlockingCondition|commons:APKError { + string policyId = uuid:createType1AsString(); + body.policyId = policyId; + //Todo : need to validate each type + match body.conditionType { + "APPLICATION" => { + } + "API" => { + } + "IP" => { + } + "IPRANGE" => { + } + "USER" => { + } + } + BlockingCondition|commons:APKError policy = addDenyPolicyDAO(body, org.uuid); + return policy; +} + +isolated function getDenyPolicyById(string policyId, commons:Organization org) returns BlockingCondition|commons:APKError { + BlockingCondition|commons:APKError policy = getDenyPolicyByIdDAO(policyId, org.uuid); + return policy; +} + +isolated function getAllDenyPolicies(commons:Organization org) returns BlockingConditionList|commons:APKError { + BlockingCondition[]|commons:APKError denyPolicies = getDenyPoliciesDAO(org.uuid); + if denyPolicies is BlockingCondition[] { + int count = denyPolicies.length(); + BlockingConditionList denyPoliciesList = {count: count, list: denyPolicies}; + return denyPoliciesList; + } else { + return denyPolicies; + } +} + +isolated function updateDenyPolicy(string policyId, BlockingConditionStatus status, commons:Organization org) returns BlockingCondition|commons:APKError { + BlockingCondition|commons:APKError existingPolicy = getDenyPolicyByIdDAO(policyId, org.uuid); + if existingPolicy !is BlockingCondition { + return existingPolicy; + } else { + status.policyId = policyId; + } + string|commons:APKError response = updateDenyPolicyDAO(status); + if response is commons:APKError{ + return response; + } + BlockingCondition|commons:APKError updatedPolicy = getDenyPolicyByIdDAO(policyId, org.uuid); + if updatedPolicy is BlockingCondition { + return updatedPolicy; + } else { + return updatedPolicy; + } +} + +isolated function removeDenyPolicy(string policyId, commons:Organization org) returns commons:APKError|string { + commons:APKError|string status = deleteDenyPolicyDAO(policyId, org.uuid); + return status; +} + diff --git a/admin/admin-domain-service/ballerina/types.bal b/admin/admin-domain-service/ballerina/types.bal new file mode 100644 index 000000000..c3195ddb7 --- /dev/null +++ b/admin/admin-domain-service/ballerina/types.bal @@ -0,0 +1,560 @@ +import ballerina/http; +import ballerina/constraint; + +public type AcceptedWorkflowResponse record {| + *http:Accepted; + WorkflowResponse body; +|}; + +public type NotAcceptableError record {| + *http:NotAcceptable; + Error body; +|}; + +public type UnsupportedMediaTypeError record {| + *http:UnsupportedMediaType; + Error body; +|}; + +public type OkKeyManagerWellKnownResponse record {| + *http:Ok; + KeyManagerWellKnownResponse body; +|}; + +public type InternalServerErrorError record {| + *http:InternalServerError; + Error body; +|}; + +public type ForbiddenError record {| + *http:Forbidden; + Error body; +|}; + +public type ConflictError record {| + *http:Conflict; + Error body; +|}; + +public type OkWorkflowInfo record {| + *http:Ok; + WorkflowInfo body; +|}; + +public type NotFoundError record {| + *http:NotFound; + Error body; +|}; + +public type BadRequestError record {| + *http:BadRequest; + Error body; +|}; + +public type Policy record { + # Id of plan + string planId?; + # Name of plan + @constraint:String {maxLength: 60, minLength: 1} + string planName; + # Display name of the policy + @constraint:String {maxLength: 512} + string displayName?; + # Description of the policy + @constraint:String {maxLength: 1024} + string description?; + # Indicates whether the policy is deployed successfully or not. + boolean isDeployed = false; + # Indicates the type of throttle policy + string 'type?; +}; + +public type EnvironmentList record { + # Number of Environments returned. + int count?; + Environment[] list?; +}; + +# Blocking Conditions +public type BlockingCondition record { + # Id of the blocking condition + string policyId?; + # Type of the blocking condition + string conditionType; + # Value of the blocking condition + string conditionValue; + # Status of the blocking condition + boolean conditionStatus?; +}; + +public type WorkflowProperties record { + string name?; + boolean enable?; + string[] properties?; +}; + +public type ApplicationRatePlan record { + *Policy; + ThrottleLimit defaultLimit; +}; + +public type Pagination record { + int offset?; + int 'limit?; + int total?; + # Link to the next subset of resources qualified. + # Empty if no more resources are to be returned. + # example: "" + string next?; + # Link to the previous subset of resources qualified. + # Empty if current subset is the first subset returned. + # example: "" + string previous?; +}; + +public type EventCountLimit record { + *ThrottleLimitBase; + # Maximum number of events allowed + int eventCount; +}; + +public type ThrottleLimitBase record { + # Unit of the time. Allowed values are "sec", "min", "hour", "day" + string timeUnit; + # Time limit that the throttling limit applies. + int unitTime; +}; + +public type ClaimMappingEntry record { + string remoteClaim?; + string localClaim?; +}; + +public type BusinessPlan record { + *Policy; + *GraphQLQuery; + ThrottleLimit defaultLimit; + # Burst control request count + int rateLimitCount?; + # Burst control time unit + string rateLimitTimeUnit?; + # Number of subscriptions allowed + int subscriberCount?; + # Custom attributes added to the Subscription Throttling Policy + CustomAttribute[] customAttributes?; + BusinessPlanPermission permissions?; +}; + +public type PolicyDetails record { + # Id of policy + int policyId?; + # UUId of policy + string uuid?; + # Name of policy + @constraint:String {maxLength: 60, minLength: 1} + string policyName; + # Display name of the policy + @constraint:String {maxLength: 512} + string displayName?; + # Description of the policy + @constraint:String {maxLength: 1024} + string description?; + # Indicates whether the policy is deployed successfully or not. + boolean isDeployed = false; + # Indicates the type of throttle policy + string 'type?; +}; + +public type KeyManagerWellKnownResponse record { + boolean valid?; + KeyManager value?; +}; + +public type KeyManager record { + string id?; + @constraint:String {maxLength: 100, minLength: 1} + string name; + # display name of Key Manager to show in UI + @constraint:String {maxLength: 100} + string displayName?; + @constraint:String {maxLength: 45, minLength: 1} + string 'type; + @constraint:String {maxLength: 256} + string description?; + # Well-Known Endpoint of Identity Provider. + string wellKnownEndpoint?; + KeyManagerEndpoint[] endpoints?; + KeyManager_signingCertificate signingCertificate?; + # PEM type certificate + string tlsCertificate?; + string issuer; + string[] availableGrantTypes?; + boolean enableTokenGeneration = true; + boolean enableMapOAuthConsumerApps = false; + boolean enableOauthAppValidation = true; + boolean enableOAuthAppCreation = true; + string consumerKeyClaim?; + string scopesClaim?; + boolean enabled = true; + record {} additionalProperties?; +}; + +public type CustomUrlInfo_devPortal record { + string url?; +}; + +public type Settings record { + string[] scopes?; + Settings_keyManagerConfiguration[] keyManagerConfiguration?; + # To determine whether analytics is enabled or not + boolean analyticsEnabled?; +}; + +public type KeyManagerConfiguration record { + string name?; + string label?; + string 'type?; + boolean required?; + boolean mask?; + boolean multiple?; + string tooltip?; + string default?; + string[] values?; +}; + +public type BusinessPlanList record { + # Number of Business Plans returned. + int count?; + BusinessPlan[] list?; +}; + +public type ApplicationRatePlanList record { + # Number of Application Rate Plans returned. + int count?; + ApplicationRatePlan[] list?; +}; + +public type OrganizationList record { + # Number of Organization returned. + int count?; + Organization[] list?; +}; + +public type ThrottleLimit record { + # Type of the throttling limit. Allowed values are "REQUESTCOUNTLIMIT" and "BANDWIDTHLIMIT". + # Please see schemas of "RequestCountLimit" and "BandwidthLimit" throttling limit types in + # Definitions section. + string 'type; + RequestCountLimit requestCount?; + BandwidthLimit bandwidth?; + EventCountLimit eventCount?; +}; + +public type TokenValidation record { + int id?; + boolean enable?; + string 'type?; + record {} value?; +}; + +public type Keymanagers_discover_body record { + # Well-Known Endpoint + string url?; + # Key Manager Type + string 'type?; +}; + +public type Environment record { + string id?; + @constraint:String {maxLength: 255, minLength: 1} + string name; + @constraint:String {maxLength: 255, minLength: 1} + string displayName?; + string provider?; + @constraint:String {maxLength: 1023} + string description?; + boolean isReadOnly?; + @constraint:Array {minLength: 1} + VHost[] vhosts; + GatewayEnvironmentProtocolURI[] endpointURIs?; + AdditionalProperty[] additionalProperties?; +}; + +public type KeyManager_signingCertificate record { + string 'type?; + string value?; +}; + +public type BusinessPlanPermission record { + string permissionType; + string[] roles; +}; + +public type Application record { + string applicationId?; + string name?; + string throttlingPolicy?; + string description?; + # Type of the access token generated for this application. + # **OAUTH:** A UUID based access token which is issued by default. + # **JWT:** A self-contained, signed JWT based access token. **Note:** This can be only used in Microgateway environments. + string tokenType?; + string status?; + string[] groups?; + int subscriptionCount?; + record {|string...;|} attributes?; + ScopeInfo[] subscriptionScopes?; + # Application created user + string owner?; +}; + +public type VHost record { + @constraint:String {maxLength: 255, minLength: 1} + string host; + @constraint:String {maxLength: 255} + string httpContext?; + int httpPort?; + int httpsPort?; + int wsPort?; + int wssPort?; +}; + +public type Organization record { + string id?; + @constraint:String {maxLength: 255, minLength: 1} + string name; + @constraint:String {maxLength: 255, minLength: 1} + string displayName; + @constraint:String {maxLength: 255, minLength: 1} + string organizationClaimValue?; + boolean enabled = true; + string[] serviceNamespaces = ["*"]; + WorkflowProperties[] workflows?; + string[] production?; + string[] sandbox?; +}; + +public type MonetizationUsagePublishInfo record { + # State of usage publish job + string state?; + # Status of usage publish job + string status?; + # Timestamp of the started time of the Job + string startedTime?; + # Timestamp of the last published time + string lastPublsihedTime?; +}; + +public type ErrorListItem record { + # Error code + string code; + # Description about individual errors occurred + string message; +}; + +public type BlockingConditionList record { + # Number of Blocking Conditions returned. + int count?; + BlockingCondition[] list?; +}; + +public type CustomAttribute record { + # Name of the custom attribute + string name; + # Value of the custom attribute + string value; +}; + +public type APICategoryList record { + # Number of API categories returned. + int count?; + APICategory[] list?; +}; + +public type ApplicationInfo record { + string applicationId?; + string name?; + string owner?; + string status?; + string groupId?; +}; + +# The tenant information of the user +public type TenantInfo record { + string username?; + string tenantDomain?; + int tenantId?; +}; + +public type KeyManagerList record { + # Number of Key managers returned. + int count?; + KeyManagerInfo[] list?; +}; + +public type Policies_import_body record { + # Json File + record {byte[] fileContent; string fileName;} file; +}; + +# Blocking Conditions Status +public type BlockingConditionStatus record { + # Id of the blocking condition + string policyId?; + # Status of the blocking condition + boolean conditionStatus; +}; + +public type KeyManagerEndpoint record { + string name; + string value; +}; + +public type Settings_keyManagerConfiguration record { + string 'type?; + string displayName?; + string defaultConsumerKeyClaim?; + string defaultScopesClaim?; + KeyManagerConfiguration[] configurations?; + KeyManagerConfiguration[] endpointConfigurations?; +}; + +public type WorkflowList record { + # Number of workflow processes returned. + int count?; + # Link to the next subset of resources qualified. + # Empty if no more resources are to be returned. + string next?; + # Link to the previous subset of resources qualified. + # Empty if current subset is the first subset returned. + string previous?; + WorkflowInfo[] list?; +}; + +public type ApplicationList record { + # Number of applications returned. + int count?; + ApplicationInfo[] list?; + Pagination pagination?; +}; + +public type PublishStatus record { + # Status of the usage publish request + string status?; + # detailed message of the status + string message?; +}; + +public type RequestCountLimit record { + *ThrottleLimitBase; + # Maximum number of requests allowed + int requestCount; +}; + +public type KeyManagerInfo record { + string id?; + string name; + string 'type; + string description?; + boolean enabled?; +}; + +public type WorkflowInfo record { + string workflowReferenceId?; + # Type of the Workflow Request. It shows which type of request is it. + string workflowType?; + # Show the Status of the the workflow request whether it is approved or created. + string workflowStatus?; + string[] workflowProperties?; + # Time of the the workflow request created. + string createdTime?; + # Time of the the workflow request updated. + string updatedTime?; + # description is a message with basic details about the workflow request. + string description?; +}; + +public type ExportPolicy record { + string 'type?; + string subtype?; + string version?; + record {} data?; +}; + +public type Error record { + # Error code + int code; + # Error message. + string message; + # A detail description about the error message. + string description?; + # Preferably an url with more details about the error. + string moreInfo?; + # If there are more than one error list them out. + # For example, list out validation errors by each field. + ErrorListItem[] 'error?; +}; + +public type ScopeInfo record { + string 'key?; + string name?; + # Allowed roles for the scope + string[] roles?; + # Description of the scope + string description?; +}; + +public type GatewayEnvironmentProtocolURI record { + string protocol; + string endpointURI; +}; + +public type GraphQLQuery record { + # Maximum Complexity of the GraphQL query + int graphQLMaxComplexity?; + # Maximum Depth of the GraphQL query + int graphQLMaxDepth?; +}; + +public type PolicyDetailsList record { + # Number of Throttling Policies returned. + int count?; + PolicyDetails[] list?; +}; + +# The custom url information of the tenant domain +public type CustomUrlInfo record { + string tenantDomain?; + string tenantAdminUsername?; + boolean enabled?; + CustomUrlInfo_devPortal devPortal?; +}; + +public type WorkflowResponse record { + # This attribute declares whether this workflow task is approved or rejected. + string workflowStatus; + # Attributes that returned after the workflow execution + string jsonPayload?; +}; + +public type AdditionalProperty record { + string 'key?; + string value?; +}; + +public type APICategory record { + string id?; + @constraint:String {maxLength: 255, minLength: 1} + string name; + @constraint:String {maxLength: 1024} + string description?; + int numberOfAPIs?; +}; + +public type BandwidthLimit record { + *ThrottleLimitBase; + # Amount of data allowed to be transferred + int dataAmount; + # Unit of data allowed to be transferred. Allowed values are "KB", "MB" and "GB" + string dataUnit; +}; diff --git a/admin/admin-domain-service/ballerina/typesDAO.bal b/admin/admin-domain-service/ballerina/typesDAO.bal new file mode 100644 index 000000000..3ad486283 --- /dev/null +++ b/admin/admin-domain-service/ballerina/typesDAO.bal @@ -0,0 +1,34 @@ + +public type ApplicationRatePlanDAO record { + *Policy; + string defaulLimitType; + # Unit of the time. Allowed values are "sec", "min", "hour", "day" + string timeUnit; + # Time limit that the throttling limit applies. + int unitTime; + int quota; + # Unit of data allowed to be transfered. Allowed values are "KB", "MB" and "GB" + string dataUnit?; +}; + +public type BusinessPlanDAO record { + *Policy; + *GraphQLQuery; + string defaulLimitType; + # Unit of the time. Allowed values are "sec", "min", "hour", "day" + string timeUnit; + # Time limit that the throttling limit applies. + int unitTime; + int quota; + # Unit of data allowed to be transfered. Allowed values are "KB", "MB" and "GB" + string dataUnit?; + # Burst control request count + int rateLimitCount?; + # Burst control time unit + string rateLimitTimeUnit?; + # Number of subscriptions allowed + int subscriberCount?; + # Custom attributes added to the Subscription Throttling Policy + CustomAttribute[] customAttributes?; + BusinessPlanPermission permissions?; +}; diff --git a/admin/admin-domain-service/ballerina/workflowDAO.bal b/admin/admin-domain-service/ballerina/workflowDAO.bal new file mode 100644 index 000000000..8905f9043 --- /dev/null +++ b/admin/admin-domain-service/ballerina/workflowDAO.bal @@ -0,0 +1,127 @@ +// +// Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + + +import wso2/apk_common_lib as commons; +import ballerinax/postgresql; +import ballerina/sql; +import ballerina/time; + +//This function is used to retrive the pending workflow requests +// Using Workflow table +isolated function getApplicationCreationWorkflowListDAO(string? workflowType, commons:Organization organization) returns ApplciationWorkflowDTO[]|commons:APKError { + postgresql:Client | error dbClient = getConnection(); + if dbClient is error { + return e909401(dbClient); + } + do { + ApplciationWorkflowDTO[] appWorkflowList = []; + sql:ParameterizedQuery query = + `SELECT app.name as applicationName, app.created_by as createdBy, wf.wf_reference as workflowReferenceId, wf.wf_type as workflowType, + wf.wf_status as workflowStatus, wf.wf_created_time as createdTime, wf.wf_updated_time as updatedTime + FROM WORKFLOWS as wf, APPLICATION as app + WHERE wf.wf_status = 'CREATED' AND wf.wf_type = ${workflowType} + AND wf.wf_reference = app.uuid + AND wf.organization = ${organization.uuid};`; + stream workFlowStream = dbClient->query(query); + check from ApplciationWorkflowDTO appworkflow in workFlowStream do { + appWorkflowList.push(appworkflow); + }; + return appWorkflowList; + } on fail var e { + return e909400(e); + } +} + +isolated function getSubscriptionCreationWorkflowListDAO(string? workflowType, commons:Organization organization) returns SubscriptionWorkflowDTO[]|commons:APKError { + postgresql:Client | error dbClient = getConnection(); + if dbClient is error { + return e909401(dbClient); + } + do { + SubscriptionWorkflowDTO[] subWorkflowList = []; + sql:ParameterizedQuery query = + `SELECT api.api_name as apiName, app.name as applicationName, sub.created_by as createdBy, wf.wf_reference as workflowReferenceId, wf.wf_type as workflowType, + wf.wf_status as workflowStatus, wf.wf_created_time as createdTime, wf.wf_updated_time as updatedTime + FROM WORKFLOWS as wf, SUBSCRIPTION as sub, APPLICATION as app, API as api + WHERE wf.wf_status = 'CREATED' AND wf.wf_type = ${workflowType} + AND wf.wf_reference = sub.uuid + AND wf.organization = ${organization.uuid} + AND sub.application_uuid = app.uuid + AND sub.api_uuid = api.uuid;`; + stream workFlowStream = dbClient->query(query); + check from SubscriptionWorkflowDTO subworkflow in workFlowStream do { + subWorkflowList.push(subworkflow); + }; + return subWorkflowList; + } on fail var e { + return e909400(e); + } +} + +isolated function updateApplciationWorkflowStatusDAO(string workflowReferenceId, WorkflowInfo payload, commons:Organization organization) returns WorkflowInfo|commons:APKError { + postgresql:Client | error dbClient = getConnection(); + if dbClient is error { + return e909401(dbClient); + } + do { + sql:ParameterizedQuery query = `Update WORKFLOWS SET wf_status = 'COMPLETED', wf_updated_time = ${time:utcNow()} + WHERE wf_reference = ${workflowReferenceId} AND organization = ${organization.uuid};`; + sql:ExecutionResult | sql:Error result = dbClient->execute(query); + if result is sql:ExecutionResult { + sql:ParameterizedQuery query2 = `Update APPLICATION SET status = 'APPROVED' + WHERE uuid = ${workflowReferenceId} AND organization = ${organization};`; + sql:ExecutionResult | sql:Error result2 = dbClient->execute(query2); + if result2 is sql:ExecutionResult { + return payload; + } else { + return e909400(result2); + } + } else { + return e909400(result); + } + } on fail var e { + return e909400(e); + } +} + +isolated function updateSubscriptionWorkflowStatusDAO(string workflowReferenceId, WorkflowInfo payload, commons:Organization organization) returns WorkflowInfo|commons:APKError { + postgresql:Client | error dbClient = getConnection(); + if dbClient is error { + return e909401(dbClient); + } + do { + sql:ParameterizedQuery query = `Update WORKFLOWS SET wf_status = 'COMPLETED', wf_updated_time = ${time:utcNow()} + WHERE wf_reference = ${workflowReferenceId} AND organization = ${organization};`; + sql:ExecutionResult | sql:Error result = dbClient->execute(query); + if result is sql:ExecutionResult { + sql:ParameterizedQuery query2 = `Update SUBSCRIPTION SET status = 'APPROVED' + WHERE uuid = ${workflowReferenceId} AND organization = ${organization.uuid};`; + sql:ExecutionResult | sql:Error result2 = dbClient->execute(query2); + if result2 is sql:ExecutionResult { + return payload; + } else { + return e909400(result2); + } + } else { + return e909400(result); + } + } on fail var e { + return e909400(e); + } +} diff --git a/admin/admin-domain-service/ballerina/workflowDTO.bal b/admin/admin-domain-service/ballerina/workflowDTO.bal new file mode 100644 index 000000000..faac3a23b --- /dev/null +++ b/admin/admin-domain-service/ballerina/workflowDTO.bal @@ -0,0 +1,50 @@ +// +// Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + +public type ApplciationWorkflowDTO record { + string workflowReferenceId?; + # Type of the Workflow Request. It shows which type of request is it. + string workflowType?; + # Show the Status of the the workflow request whether it is approved or created. + string workflowStatus?; + string applicationName; + string createdBy; + # Time of the the workflow request created. + string createdTime?; + # Time of the the workflow request updated. + string updatedTime?; + # description is a message with basic details about the workflow request. + string description?; +}; + +public type SubscriptionWorkflowDTO record { + string workflowReferenceId?; + # Type of the Workflow Request. It shows which type of request is it. + string workflowType?; + # Show the Status of the the workflow request whether it is approved or created. + string workflowStatus?; + string applicationName; + string apiName; + string createdBy; + # Time of the the workflow request created. + string createdTime?; + # Time of the the workflow request updated. + string updatedTime?; + # description is a message with basic details about the workflow request. + string description?; +}; diff --git a/admin/admin-domain-service/ballerina/workflowImpl.bal b/admin/admin-domain-service/ballerina/workflowImpl.bal new file mode 100644 index 000000000..4c61924d0 --- /dev/null +++ b/admin/admin-domain-service/ballerina/workflowImpl.bal @@ -0,0 +1,99 @@ +// +// Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + +import wso2/apk_common_lib as commons; + + +//This function return the pending workflow list +isolated function getWorkflowList(string? workflowType, commons:Organization organization, int 'limit, int offset, string? accept) returns WorkflowList|commons:APKError{ + WorkflowList workflowList = {}; + if(workflowType == "APPLICATION_CREATION") { + ApplciationWorkflowDTO[]|commons:APKError appWorkflowList = getApplicationCreationWorkflowListDAO(workflowType, organization); + if(appWorkflowList is ApplciationWorkflowDTO[]) { + WorkflowInfo[] workFlowInfoList = []; + foreach ApplciationWorkflowDTO appWorkflow in appWorkflowList { + WorkflowInfo workFlowInfo = {}; + string[] applicationProperty = []; + workFlowInfo.workflowReferenceId = appWorkflow.workflowReferenceId; + workFlowInfo.workflowType = appWorkflow.workflowType; + workFlowInfo.workflowStatus = appWorkflow.workflowStatus; + workFlowInfo.createdTime = appWorkflow.createdTime; + workFlowInfo.updatedTime = appWorkflow.updatedTime; + applicationProperty.push("applicationName:",appWorkflow.applicationName); + applicationProperty.push("applicationOwner:",appWorkflow.createdBy); + workFlowInfo.workflowProperties = applicationProperty; + workFlowInfoList.push(workFlowInfo); + } + workflowList.list = workFlowInfoList; + } + } else if(workflowType == "SUBSCRIPTION_CREATION") { + SubscriptionWorkflowDTO[]|commons:APKError subWorkflowList = getSubscriptionCreationWorkflowListDAO(workflowType, organization); + if(subWorkflowList is SubscriptionWorkflowDTO[]) { + WorkflowInfo[] workFlowInfoList = []; + foreach SubscriptionWorkflowDTO subWorkflow in subWorkflowList { + WorkflowInfo workFlowInfo = {}; + string[] subscriptionProperty = []; + workFlowInfo.workflowReferenceId = subWorkflow.workflowReferenceId; + workFlowInfo.workflowType = subWorkflow.workflowType; + workFlowInfo.workflowStatus = subWorkflow.workflowStatus; + workFlowInfo.createdTime = subWorkflow.createdTime; + workFlowInfo.updatedTime = subWorkflow.updatedTime; + subscriptionProperty.push("applicationName",subWorkflow.applicationName); + subscriptionProperty.push("apiName",subWorkflow.apiName); + subscriptionProperty.push("subscriber",subWorkflow.createdBy); + workFlowInfo.workflowProperties = subscriptionProperty; + workFlowInfoList.push(workFlowInfo); + } + workflowList.list = workFlowInfoList; + } + } + return workflowList; +} + +// This function approvel/reject workflow request +isolated function updateWorkflowStatus(string workflowReferenceId, WorkflowInfo payload, commons:Organization organization) returns OkWorkflowInfo|commons:APKError { + OkWorkflowInfo okWorkflowInfo = { + body: { + workflowReferenceId: "" + } + }; + if(payload.workflowType == "APPLICATION_CREATION") { + WorkflowInfo|commons:APKError workflowInfo = updateApplciationWorkflowStatusDAO(workflowReferenceId, payload, organization); + if workflowInfo is WorkflowInfo { + okWorkflowInfo = { + body: { + workflowReferenceId: workflowInfo.workflowReferenceId + } + }; + } else { + return e909400(workflowInfo); + } + } else if (payload.workflowType == "SUBSCRIPTION_CREATION") { + WorkflowInfo|commons:APKError workflowInfo = updateSubscriptionWorkflowStatusDAO(workflowReferenceId, payload, organization); + if workflowInfo is WorkflowInfo { + okWorkflowInfo = { + body: { + workflowReferenceId: workflowInfo.workflowReferenceId + } + }; + } else { + return e909400(workflowInfo); + } + } + return okWorkflowInfo; +} diff --git a/admin/admin-domain-service/build.gradle b/admin/admin-domain-service/build.gradle new file mode 100644 index 000000000..a065666d6 --- /dev/null +++ b/admin/admin-domain-service/build.gradle @@ -0,0 +1,40 @@ +// +// Copyright (c) 2022, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + +plugins { + id 'net.researchgate.release' version '2.8.0' +} +allprojects { + group = project.group + version = project.version +} + +release { + tagTemplate = 'admin-domain-service-$version' + + git { + requireBranch= "main" + pushToRemote= "origin" + } +} + +unSnapshotVersion.finalizedBy ":ballerina:commit_toml_files" +afterReleaseBuild.dependsOn ":docker:docker_push" +task build{ + dependsOn("docker:build") +} diff --git a/admin/admin-domain-service/docker/Dockerfile b/admin/admin-domain-service/docker/Dockerfile new file mode 100644 index 000000000..8c6f53d95 --- /dev/null +++ b/admin/admin-domain-service/docker/Dockerfile @@ -0,0 +1,81 @@ +#--------------------------------------------------------------- +# +# Copyright (c) 2022, WSO2 LLC. (http://www.wso2.com). +# +# WSO2 LLC. licenses this file to you 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. +# +#--------------------------------------------------------------- + +FROM ubuntu:20.04 + +ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en' LC_ALL='en_US.UTF-8' + +# install JDK Dependencies +RUN apt-get update \ + && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends tzdata curl wget ca-certificates fontconfig locales \ + && echo "en_US.UTF-8 UTF-8" >> /etc/locale.gen \ + && locale-gen en_US.UTF-8 \ + && rm -rf /var/lib/apt/lists/* + +ENV JAVA_VERSION jdk-11.0.17+8 + +RUN set -eux; \ + ARCH="$(dpkg --print-architecture)"; \ + case "${ARCH}" in \ + amd64|i386:x86-64) \ + ESUM='752616097e09d7f60a3ad8bd312f90eaf50ac72577e55df229fe6e8091148f79'; \ + BINARY_URL='https://github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.17%2B8/OpenJDK11U-jre_x64_linux_hotspot_11.0.17_8.tar.gz'; \ + ;; \ + aarch64|arm64) \ + ESUM='bd6efe3290c8b5a42f695a55a26f3e3c9c284288574879d4b7089f31f5114177'; \ + BINARY_URL='https://github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.17%2B8/OpenJDK11U-jre_aarch64_linux_hotspot_11.0.17_8.tar.gz'; \ + ;; \ + *) \ + echo "Unsupported arch: ${ARCH}"; \ + exit 1; \ + ;; \ + esac; \ + curl -LfsSo /tmp/openjdk.tar.gz ${BINARY_URL}; \ + echo "${ESUM} */tmp/openjdk.tar.gz" | sha256sum -c -; \ + mkdir -p /opt/java/openjdk; \ + cd /opt/java/openjdk; \ + tar -xf /tmp/openjdk.tar.gz --strip-components=1; \ + rm -rf /tmp/openjdk.tar.gz; + +ENV JAVA_HOME=/opt/java/openjdk \ + PATH="/opt/java/openjdk/bin:$PATH" + +RUN echo Verifying install ... \ + && echo java --version && java --version \ + && echo Complete. + +ARG USER=wso2apk +ARG USER_ID=802 +ARG USER_GROUP=wso2 +ARG USER_GROUP_ID=802 +ARG USER_HOME=/home/${USER} + +RUN groupadd --system -g ${USER_GROUP_ID} ${USER_GROUP} && useradd --system --create-home --home-dir ${USER_HOME} --no-log-init -g ${USER_GROUP_ID} -u ${USER_ID} ${USER} + +COPY docker-entrypoint.sh ${USER_HOME} +ADD admin ${USER_HOME}/admin +RUN chown -R ${USER} ${USER_HOME}/admin +RUN chown ${USER} /home/${USER}/docker-entrypoint.sh + +EXPOSE 9443 +USER wso2apk +WORKDIR ${USER_HOME} + +ENTRYPOINT ["sh", "/home/wso2apk/docker-entrypoint.sh"] diff --git a/admin/admin-domain-service/docker/admin/admin.sh b/admin/admin-domain-service/docker/admin/admin.sh new file mode 100644 index 000000000..98f5de29f --- /dev/null +++ b/admin/admin-domain-service/docker/admin/admin.sh @@ -0,0 +1,106 @@ +# resolve links - $0 may be a softlink +PRG="$0" + +while [ -h "$PRG" ]; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '.*/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`/"$link" + fi +done + +# Get standard environment variables +PRGDIR=`dirname "$PRG"` + +[ -z "$ADMIN_HOME" ] && ADMIN_HOME=`cd "$PRGDIR" ; pwd` + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD=java + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." + echo " Admin cannot execute $JAVACMD" + exit 1 +fi + +# if JAVA_HOME is not set we're not happy +if [ -z "$JAVA_HOME" ]; then + echo "You must set the JAVA_HOME variable before running Admin." + exit 1 +fi +# ----- Process the input command ---------------------------------------------- +args="" +for c in $* +do + if [ "$c" = "--debug" ] || [ "$c" = "-debug" ] || [ "$c" = "debug" ]; then + CMD="--debug" + continue + elif [ "$CMD" = "--debug" ]; then + if [ -z "$PORT" ]; then + PORT=$c + fi + fi +done + +if [ "$CMD" = "--debug" ]; then + if [ "$PORT" = "" ]; then + echo " Please specify the debug port after the --debug option" + exit 1 + fi + if [ -n "$JAVA_OPTS" ]; then + echo "Warning !!!. User specified JAVA_OPTS will be ignored, once you give the --debug option." + fi + CMD="RUN" + JAVA_OPTS="-Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=$PORT" + echo "Please start the remote debugging client to continue..." +fi + +CLASSPATH="" +if [ -e "$JAVA_HOME/lib/tools.jar" ]; then + CLASSPATH="$JAVA_HOME/lib/tools.jar" +fi +for t in "$ADMIN_HOME"/lib/*.jar +do + CLASSPATH="$CLASSPATH":$t +done + +# ----- Execute The Requested Command ----------------------------------------- + +echo JAVA_HOME environment variable is set to $JAVA_HOME +echo ADMIN_HOME environment variable is set to "$ADMIN_HOME" +export BAL_CONFIG_FILES=$ADMIN_HOME/conf/Config.toml +cd "$ADMIN_HOME" + +TMP_DIR="$ADMIN_HOME"/tmp +if [ -d "$TMP_DIR" ]; then +rm -rf "$TMP_DIR"/* +fi + +START_EXIT_STATUS=121 +status=$START_EXIT_STATUS + +if [ -z "$JVM_MEM_OPTS" ]; then + java_version=$("$JAVACMD" -version 2>&1 | awk -F '"' '/version/ {print $2}') + JVM_MEM_OPTS="-Xms256m -Xmx1024m" +fi +echo "Using Java memory options: $JVM_MEM_OPTS" + +$JAVACMD \ + $JVM_MEM_OPTS \ + $JAVA_OPTS \ + -classpath "$CLASSPATH" \ + -Djava.io.tmpdir="$ADMIN_HOME/tmp" \ + -jar admin_service.jar $* + status=$? \ No newline at end of file diff --git a/admin/admin-domain-service/docker/admin/security/.gitkeep b/admin/admin-domain-service/docker/admin/security/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/admin/admin-domain-service/docker/build.gradle b/admin/admin-domain-service/docker/build.gradle new file mode 100644 index 000000000..c8aec273a --- /dev/null +++ b/admin/admin-domain-service/docker/build.gradle @@ -0,0 +1,35 @@ +// +// Copyright (c) 2022, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + +apply from: "$rootDir/../../common-gradle-scripts/docker.gradle" +apply from: "$rootDir/../../common-gradle-scripts/copy.gradle" + +tasks.named('copy_dist').configure{ + finalizedBy docker_build +} + +tasks.register('build') { + group 'build' + description 'Build docker image' + dependsOn 'copy_dist' + dependsOn 'docker_build' +} +build.configure{ + mustRunAfter(":ballerina:build") + dependsOn(":ballerina:build") + } \ No newline at end of file diff --git a/admin/admin-domain-service/docker/docker-entrypoint.sh b/admin/admin-domain-service/docker/docker-entrypoint.sh new file mode 100644 index 000000000..6d9a0c328 --- /dev/null +++ b/admin/admin-domain-service/docker/docker-entrypoint.sh @@ -0,0 +1,20 @@ +#!/bin/bash +# +# Copyright (c) 2022, WSO2 LLC. (http://www.wso2.com). +# +# WSO2 LLC. licenses this file to you 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. +# + +sh /home/wso2apk/admin/admin.sh diff --git a/admin/admin-domain-service/gradle.properties b/admin/admin-domain-service/gradle.properties new file mode 100644 index 000000000..036627e31 --- /dev/null +++ b/admin/admin-domain-service/gradle.properties @@ -0,0 +1,5 @@ +group=org.wso2.apk +version=0.0.1-SNAPSHOT +docker_image_name = admin-domain-service +jar_name = admin_service.jar +dist_name = admin \ No newline at end of file diff --git a/admin/admin-domain-service/gradle/wrapper/gradle-wrapper.properties b/admin/admin-domain-service/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..ae04661ee --- /dev/null +++ b/admin/admin-domain-service/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/admin/admin-domain-service/gradlew b/admin/admin-domain-service/gradlew new file mode 100755 index 000000000..a69d9cb6c --- /dev/null +++ b/admin/admin-domain-service/gradlew @@ -0,0 +1,240 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# 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 +# +# https://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. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/admin/admin-domain-service/gradlew.bat b/admin/admin-domain-service/gradlew.bat new file mode 100644 index 000000000..f127cfd49 --- /dev/null +++ b/admin/admin-domain-service/gradlew.bat @@ -0,0 +1,91 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/admin/admin-domain-service/settings.gradle b/admin/admin-domain-service/settings.gradle new file mode 100644 index 000000000..85c32ce41 --- /dev/null +++ b/admin/admin-domain-service/settings.gradle @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2022, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. + * + * 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. + * + */ + +rootProject.name = 'admin-domain-service' + +include ':ballerina' +include ':docker' +project(':ballerina').projectDir = file('ballerina') +project(':docker').projectDir = file('docker') + +dependencyResolutionManagement { + versionCatalogs { + libs { + from(files("$rootDir/../../libs.versions.toml")) + } + } +} \ No newline at end of file diff --git a/admin/admin-ui/.dockerignore b/admin/admin-ui/.dockerignore new file mode 100644 index 000000000..600e365ec --- /dev/null +++ b/admin/admin-ui/.dockerignore @@ -0,0 +1 @@ +**/node_modules \ No newline at end of file diff --git a/admin/admin-ui/.eslintrc.js b/admin/admin-ui/.eslintrc.js new file mode 100644 index 000000000..098a2a866 --- /dev/null +++ b/admin/admin-ui/.eslintrc.js @@ -0,0 +1,24 @@ +module.exports = { + "env": { + "browser": true, + "es2021": true + }, + "extends": [ + "eslint:recommended", + "plugin:react/recommended", + "plugin:@typescript-eslint/recommended" + ], + "overrides": [ + ], + "parser": "@typescript-eslint/parser", + "parserOptions": { + "ecmaVersion": "latest", + "sourceType": "module" + }, + "plugins": [ + "react", + "@typescript-eslint" + ], + "rules": { + } +} diff --git a/admin/admin-ui/.gitignore b/admin/admin-ui/.gitignore new file mode 100644 index 000000000..220570f32 --- /dev/null +++ b/admin/admin-ui/.gitignore @@ -0,0 +1,15 @@ +client/public/build +.DS_STORE +node_modules +*.pyc +.grunt +*.log* +chrome-user-data +*.sublime-project +*.sublime-workspace +.idea +*.iml +.vscode +*.swp +*.swo +!bin/ \ No newline at end of file diff --git a/admin/admin-ui/Dockerfile b/admin/admin-ui/Dockerfile new file mode 100644 index 000000000..e69de29bb diff --git a/admin/admin-ui/README.md b/admin/admin-ui/README.md new file mode 100644 index 000000000..47d044655 --- /dev/null +++ b/admin/admin-ui/README.md @@ -0,0 +1,74 @@ + +## Technologies Used +This web app was built using the following technologies: + +- Node.js 16+ +- React.js +- Express + +## How to Run the App +To run this web app, please follow these steps: + +- Install the required dependencies by running `npm install`. +- Generate types from the OpenAPI definition by running `npm run types-gen`. +- Start the server by running `npm run node-dev`. +- Open a new terminal tab and start the client app by running `npm run react-dev`. +- Access the web app in your browser at http://localhost:4000. + + +> Note: Before starting the server and client app, ensure that the latest types are available on the client side by running `npm run types-gen`. The node-dev script will start the server in development mode using nodemon which will automatically reload the server whenever changes are made. The react-dev script will watch for changes in the client app and automatically rebuild the client app when changes are detected. + +## Client and Server + +The web app has two main components: the client and the server. These components are separated into two folders to make it easier to manage and maintain. + +The purpose of the server is twofold: first, to host the static HTML, CSS, and JavaScript files generated by the webpack build. These files can be found in the `client/public` folder. This is important because these files are what the user's browser needs to load the web app. By hosting these files on the server, we ensure that the user can access them whenever they want to use the app. + +The second purpose of the server is to host server-side endpoints. These endpoints allow the server to communicate with other parts of the web app or with external services. In this case, the web app is using an OIDC flow, which is a protocol used for authentication and authorization. + +The web app is using the `/token` endpoint in the OIDC flow. When the user requests access to a protected resource, they will be redirected to a login page on the IDP side (the Identity Provider). Once the user logs in and authorizes the app to access their data, the IDP will redirect the user back to the /token endpoint on the web app's server. + +In `server/routes/tokenRoutes.js`, the server will receive the authorization code from the IDP and use it to generate a token request to the IDP. This token request will include information about the user and the requested access. When the server receives a successful token response from the IDP, it will set response cookies with the access token and redirect the user back to the client-side of the web app. +## Authentication Implementation Details + +In the React side there are two Auth implementations. The one been use at the moment is the `client/source/auth/AuthProvider.tsx`. This component is a Higher order component to provide authedication via APK IDP. From the IDP side the PKCE is not supported. `client/source/auth/AuthProviderPKCE.tsx` This file is providing the authentication with Oath0. You have to change the import in `client/source/App.jsx` and enable the correct configuration from `client/public/conf/Settings.js`. + +The AuthProvider component defines secure routes for the application by storing the user authentication state and related functions in a context, and then using this context to render the protected components. + +The AuthProvider component wraps the MainRoutes component, which contains the application's routes. When the MainRoutes component is rendered, it will check whether the user is authenticated, and if not, it will redirect the user to the login page. If the user is authenticated, the requested route will be rendered. + +The AuthProvider component defines a context for storing the user authentication state and related functions using the createContext method from the React library. The context is defined with an initial state that includes the user's authentication status (isAuthenticated), the user object (user), and a loading flag (loading). The context also includes two functions: login and logout, which handle user login and logout actions. + +### React Libraries + +We are using the latest version of MUI at the time of writing ( 5.x ), React Router (6.x), and react-table 7.x. This means that we can't directly copy the code from apim-apps repos and use them. You will have to go through the documentation of each library and make the necessary adjustments. + +### Development and reloading + +During development, we have opted not to use the webpack dev server. Instead, we've devised a method to easily view changes as we make them. We made this decision because the webpack dev server cannot proxy all API requests and the authentication flow, and there are instances where the actual environment and the proxy environment behave differently. The following describes how we have implemented live reloading. + +When the node server is running it starts a live reloading server at port @ 35729. This is done via the code segment at `server/app.js` + +```javascript +var livereload = require("livereload"); +const connectLivereload = require("connect-livereload"); +... +... +const liveReloadServer = livereload.createServer(); +liveReloadServer.watch(path.join(__dirname, '../client/public/build')); +liveReloadServer.server.once("connection", () => { + setTimeout(() => { + liveReloadServer.refresh("/"); + }, 100); +}); +``` + +We manually inject the javascript to the html file via the template html file `client/pages/index.html`. + +```html + <% if( htmlWebpackPlugin.options.templateParameters.env === 'development' ) { %> + + <% } %> +``` + +> Note: We have the drawback of not having Hot Module Replacement. diff --git a/admin/admin-ui/babel.config.json b/admin/admin-ui/babel.config.json new file mode 100644 index 000000000..84204f0fe --- /dev/null +++ b/admin/admin-ui/babel.config.json @@ -0,0 +1,24 @@ +{ + "presets": [ + [ + "@babel/preset-env", + { + "useBuiltIns": "usage", + "corejs": 3 + } + ], + [ + "@babel/preset-react" + ], + [ + "@babel/preset-typescript" + ] + ], + "plugins": [ + "@babel/plugin-transform-runtime", + "@babel/plugin-transform-async-to-generator", + "@babel/plugin-transform-arrow-functions", + "@babel/plugin-proposal-object-rest-spread", + "@babel/plugin-proposal-class-properties" + ] +} \ No newline at end of file diff --git a/admin/admin-ui/build.gradle b/admin/admin-ui/build.gradle new file mode 100644 index 000000000..125d94292 --- /dev/null +++ b/admin/admin-ui/build.gradle @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2022, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. + * + * 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. + * + */ + +plugins { + id 'net.researchgate.release' version '3.0.2' +} + +apply from: "$rootDir/../../common-gradle-scripts/docker.gradle" + +release { + // TODO: finalize release version and rules + // failOnCommitNeeded = false + // failOnUpdateNeeded = false + tagTemplate = '${project.name}-${project.version}' +} + diff --git a/admin/admin-ui/client/pages/index.html b/admin/admin-ui/client/pages/index.html new file mode 100644 index 000000000..5940ae87a --- /dev/null +++ b/admin/admin-ui/client/pages/index.html @@ -0,0 +1,21 @@ + +<% // ============================================================= %> +<% // ========== We are using lodash template syntax here ========= %> + + + + + + + <%= htmlWebpackPlugin.options.title %> + + +
+ + <% // ============================================================= %> + <% // ========== Need to load the live reloading manually ========= %> + <% if( htmlWebpackPlugin.options.templateParameters.env === 'development' ) { %> + + <% } %> + + \ No newline at end of file diff --git a/admin/admin-ui/client/public/conf/Settings.js b/admin/admin-ui/client/public/conf/Settings.js new file mode 100644 index 000000000..40f8a5c78 --- /dev/null +++ b/admin/admin-ui/client/public/conf/Settings.js @@ -0,0 +1,38 @@ + + +const Settings = { + // oath0 config + // idp: { + // client_id: 'wqCauPZqUn6UigcAZbU9Z6jxwNTfzOAb', + // well_known: 'https://construct.auth0.com/.well-known/openid-configuration', + // serverOrigin: 'https://construct.auth0.com/', + // redirect_uri: 'https://localhost:4000', + // logout_endpoint: 'https://construct.auth0.com/v2/logout', + // scope: 'openid offline_access', + // state: 'RlZyVjlqYUpHTzltWC42c2FNRDRJT1JPfk1+TUFEa0RLb04yZldwYkpxVA==', + // pkce: true, + // }, + idp: { + client_id: '01edd46c-7900-1b78-bf1e-c046a1549faa', + client_secret: '01edd46c-7900-1b78-81f6-b34ebde78558', + host: 'prod.idp.am.wso2.com:9095', + server_origin: 'https://prod.idp.am.wso2.com:9095/', + redirect_uri: 'https://localhost:4000', + logout_endpoint: 'https://prod.idp.am.wso2.com:9095/logout', + scope: 'openid offline_access', + state: 'RlZyVjlqYUpHTzltWC42c2FNRDRJT1JPfk1+TUFEa0RLb04yZldwYkpxVA==', + authorization_endpoint: 'https://prod.idp.am.wso2.com:9095/oauth2/authorize', + token_endpoint: 'https://prod.idp.am.wso2.com:9095/oauth2/token', + jwks_uri: 'https://prod.idp.am.wso2.com:9095/oauth2/jwks', + issuer: 'https://prod.idp.am.wso2.com:9095/oauth2/token', + userinfo_endpoint: 'https://prod.idp.am.wso2.com:9095/oauth2/userinfo', + pkce: false, + }, + app: { + rest_api: 'https://127.0.0.1:9095/api/admin', + } +}; + +if (typeof module !== 'undefined') { + module.exports = Settings; // For Jest unit tests +} diff --git a/admin/admin-ui/client/public/images/avatar-1.png b/admin/admin-ui/client/public/images/avatar-1.png new file mode 100644 index 000000000..6f8334486 Binary files /dev/null and b/admin/admin-ui/client/public/images/avatar-1.png differ diff --git a/admin/admin-ui/client/public/images/logo.svg b/admin/admin-ui/client/public/images/logo.svg new file mode 100644 index 000000000..cbe5dc2f9 --- /dev/null +++ b/admin/admin-ui/client/public/images/logo.svg @@ -0,0 +1,174 @@ + + + + + + + + + + + + + image/svg+xml + + + + + + + APK + + + + + + + + + + + + + + diff --git a/admin/admin-ui/client/source/App.tsx b/admin/admin-ui/client/source/App.tsx new file mode 100644 index 000000000..b6df5603e --- /dev/null +++ b/admin/admin-ui/client/source/App.tsx @@ -0,0 +1,22 @@ +/* eslint-disable react/no-unescaped-entities */ +import React from "react"; +import MainRoutes from 'routes/MainRoutes'; +import { AuthProvider } from 'auth/AuthProvider'; +import ThemeCustomization from 'themes'; +import ScrollTop from 'components/ScrollTop'; +import { IntlProvider } from 'react-intl' + +export default function AppTmp() { + return ( + + + + + + + + + + ); +} + diff --git a/admin/admin-ui/client/source/assets/images/auth/AuthBackground.js b/admin/admin-ui/client/source/assets/images/auth/AuthBackground.js new file mode 100644 index 000000000..87fc5f133 --- /dev/null +++ b/admin/admin-ui/client/source/assets/images/auth/AuthBackground.js @@ -0,0 +1,31 @@ +// material-ui +import { useTheme } from '@mui/material/styles'; +import { Box } from '@mui/material'; + +// ==============================|| AUTH BLUR BACK SVG ||============================== // + +const AuthBackground = () => { + const theme = useTheme(); + return ( + + + + + + + + ); +}; + +export default AuthBackground; diff --git a/admin/admin-ui/client/source/assets/images/icons/facebook.svg b/admin/admin-ui/client/source/assets/images/icons/facebook.svg new file mode 100644 index 000000000..6d4fd879d --- /dev/null +++ b/admin/admin-ui/client/source/assets/images/icons/facebook.svg @@ -0,0 +1,3 @@ + + + diff --git a/admin/admin-ui/client/source/assets/images/icons/google.svg b/admin/admin-ui/client/source/assets/images/icons/google.svg new file mode 100644 index 000000000..bd30fd949 --- /dev/null +++ b/admin/admin-ui/client/source/assets/images/icons/google.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/admin/admin-ui/client/source/assets/images/icons/twitter.svg b/admin/admin-ui/client/source/assets/images/icons/twitter.svg new file mode 100644 index 000000000..f868d3629 --- /dev/null +++ b/admin/admin-ui/client/source/assets/images/icons/twitter.svg @@ -0,0 +1,3 @@ + + + diff --git a/admin/admin-ui/client/source/assets/images/users/avatar-2.png b/admin/admin-ui/client/source/assets/images/users/avatar-2.png new file mode 100644 index 000000000..2f3f30956 Binary files /dev/null and b/admin/admin-ui/client/source/assets/images/users/avatar-2.png differ diff --git a/admin/admin-ui/client/source/assets/images/users/avatar-3.png b/admin/admin-ui/client/source/assets/images/users/avatar-3.png new file mode 100644 index 000000000..6024c00e6 Binary files /dev/null and b/admin/admin-ui/client/source/assets/images/users/avatar-3.png differ diff --git a/admin/admin-ui/client/source/assets/images/users/avatar-4.png b/admin/admin-ui/client/source/assets/images/users/avatar-4.png new file mode 100644 index 000000000..c4447ee38 Binary files /dev/null and b/admin/admin-ui/client/source/assets/images/users/avatar-4.png differ diff --git a/admin/admin-ui/client/source/assets/images/users/avatar-group.png b/admin/admin-ui/client/source/assets/images/users/avatar-group.png new file mode 100644 index 000000000..9b08b0c31 Binary files /dev/null and b/admin/admin-ui/client/source/assets/images/users/avatar-group.png differ diff --git a/admin/admin-ui/client/source/assets/third-party/apex-chart.css b/admin/admin-ui/client/source/assets/third-party/apex-chart.css new file mode 100644 index 000000000..94ccd2b2f --- /dev/null +++ b/admin/admin-ui/client/source/assets/third-party/apex-chart.css @@ -0,0 +1,4 @@ +.apexcharts-legend-series .apexcharts-legend-marker { + left: -4px !important; + top: 2px !important; +} diff --git a/admin/admin-ui/client/source/auth/AuthProvider.tsx b/admin/admin-ui/client/source/auth/AuthProvider.tsx new file mode 100644 index 000000000..b94cab42b --- /dev/null +++ b/admin/admin-ui/client/source/auth/AuthProvider.tsx @@ -0,0 +1,150 @@ +/* eslint-disable @typescript-eslint/no-var-requires */ +/* eslint-disable @typescript-eslint/no-empty-function */ +import React, { createContext, useContext, useEffect, useState } from 'react'; +import { useNavigate, useLocation } from 'react-router-dom'; +import { OIDCRequestParamsInterface } from 'auth/types/oidc-request-params'; +const Settings = require('Settings'); +import { REQUESTED_PATH, USER } from 'auth/constants/token'; +import { SessionUser } from 'types/SessionUser'; + +// Define a context for storing the user authentication state and related functions +type AuthContextType = { + isAuthenticated: boolean; + user: any; + loading: boolean; + login: () => void; + logout: () => void; +}; + +const AuthContext = createContext({ + isAuthenticated: false, + user: null, + loading: true, + login: () => { }, + logout: () => { }, +}); + +const requestParams: OIDCRequestParamsInterface = { + clientId: Settings.idp.client_id, + scope: Settings.idp.scope, + state: Settings.idp.state, + serverOrigin: Settings.idp.server_origin +}; + +interface AuthProviderProps { + children: React.ReactNode; +} + +// Define a higher-order component for wrapping the app with the AuthProvider context +export const AuthProvider = ({ children }: AuthProviderProps) => { + const [isAuthenticated, setIsAuthenticated] = useState(false); + const [user, setUser] = useState(null); + const [loading, setLoading] = useState(true); + const navigate = useNavigate(); + const { pathname } = useLocation(); + + // Define a function to handle user login + const handleLogin = () => { + sessionStorage.setItem(REQUESTED_PATH, pathname); + document.location.href = `${Settings.idp.authorization_endpoint}?` + + `response_type=code` + + `&client_id=${Settings.idp.client_id}` + + `&redirect_uri=${Settings.idp.redirect_uri}/token`; + // Navigate to the login page + }; + + // Define a function to handle user logout + const handleLogout = () => { + // Clear the user authentication state and navigate to the home page + setIsAuthenticated(false); + setUser(null); + sessionStorage.removeItem(USER); + navigate('/'); + }; + + /** + * Define a function to handle routing after authentication + */ + const route = async () => { + // Set the user authentication state and navigate to the requested page + setIsAuthenticated(true); + const requestedPath = sessionStorage.getItem(REQUESTED_PATH); + if (requestedPath) { + navigate(requestedPath); + sessionStorage.removeItem(REQUESTED_PATH); + } else if (pathname && pathname !== 'undefined' && pathname !== '') { + navigate(pathname) + } else { + navigate('/'); + } + setLoading(false); + } + + const updateUserFromRefreshToken = async () => { + // Call the nodejs backend to get the access token from the refresh token ( this needs to implement ) + try { + // const newUser = getAccessTokenFromRefreshToken() as any; + // sessionStorage.setItem(USER, `{user: ${newUser}}`); + throw new Error('Refresh token is expired'); + } catch (e) { + // Either the refresh token is expired or the refresh token is not valid + console.log(e); + handleLogin(); + } + } + // Define a useEffect hook to check for an authenticated user on mount + useEffect(() => { + const fetchUser = async () => { + // Check for an authenticated user by parsing the URL for an access token + const query = new URLSearchParams(window.location.search); + const user = query.get('user'); + const exp = query.get('exp'); + if (user) { + const userObject = { user, exp } as SessionUser; + sessionStorage.setItem(USER, JSON.stringify(userObject)); + setUser(userObject); + route(); + } else { + // If there is no authorization code, check for an access token in the session storage + const userFromSession = sessionStorage.getItem(USER); + + if (userFromSession === null) { + // If there is no token stored in the session storage, it means the session is cleared, + // we also assume the refresh token is expired, so we need to re-login + handleLogin(); + } else if (userFromSession !== null) { + // If there is a token stored in the session storage, it means the session is not cleared, + // we also assume the refresh token is not expired, so we can get a new access token from the refresh token + const userFromSessionObject = JSON.parse(userFromSession); + if (userFromSessionObject.exp * 1000 < Date.now()) { + // The access token is expired, we need to get a new access token from the refresh token + updateUserFromRefreshToken() + } else { + // The access token is not expired, we can use the access token to get the user info + setUser(userFromSessionObject); + route(); + } + setUser(userFromSessionObject); + route(); + } else { + updateUserFromRefreshToken(); + } + } + }; + fetchUser(); + }, [navigate]); + + if (loading) { + return
Loading...
+ } + + // Return the AuthProvider context provider with the user authentication state and related functions + return ( + + {children} + + ); +}; + +// Define a custom hook for accessing the AuthProvider context +export const useAuth = () => useContext(AuthContext); diff --git a/admin/admin-ui/client/source/auth/AuthProviderPKCE.tsx b/admin/admin-ui/client/source/auth/AuthProviderPKCE.tsx new file mode 100644 index 000000000..ad8cf4a8d --- /dev/null +++ b/admin/admin-ui/client/source/auth/AuthProviderPKCE.tsx @@ -0,0 +1,144 @@ +/* eslint-disable @typescript-eslint/no-var-requires */ +/* eslint-disable @typescript-eslint/no-empty-function */ +import React, { createContext, useContext, useEffect, useState } from 'react'; +import { useNavigate, useLocation } from 'react-router-dom'; +import { getUserInfoEndpoint, initOPConfiguration } from 'auth/op-config'; +import { sendAuthorizationRequest, sendTokenRequest } from 'auth/sign-in'; +import { OIDCRequestParamsInterface } from 'auth/types/oidc-request-params'; +import { getSessionParameter, setSessionParameter, initUserSession, getAccessTokenFromRefreshToken } from "auth/session"; +const Settings = require('Settings'); +import { ACCESS_TOKEN, REQUESTED_PATH } from 'auth/constants/token'; + +// Define a context for storing the user authentication state and related functions +type AuthContextType = { + isAuthenticated: boolean; + user: any; + loading: boolean; + login: () => void; + logout: () => void; +}; + +const AuthContext = createContext({ + isAuthenticated: false, + user: null, + loading: true, + login: () => { }, + logout: () => { }, +}); + +const requestParams: OIDCRequestParamsInterface = { + clientId: Settings.idp.client_id, + scope: Settings.idp.scope, + state: Settings.idp.state, + serverOrigin: Settings.idp.server_origin +}; + +interface AuthProviderProps { + children: React.ReactNode; +} + +// Define a higher-order component for wrapping the app with the AuthProvider context +export const AuthProvider = ({ children }: AuthProviderProps) => { + const [isAuthenticated, setIsAuthenticated] = useState(false); + const [user, setUser] = useState(null); + const [loading, setLoading] = useState(true); + const navigate = useNavigate(); + const { pathname } = useLocation(); + + // Define a function to handle user login + const handleLogin = () => { + initOPConfiguration(Settings.idp.well_known).then(() => { + sendAuthorizationRequest(requestParams); + setSessionParameter(REQUESTED_PATH, pathname); + }) + // Navigate to the login page + }; + + // Define a function to handle user logout + const handleLogout = () => { + // Clear the user authentication state and navigate to the home page + setIsAuthenticated(false); + setUser(null); + navigate('/'); + }; + + /** + * Call user info endpoint to get user details + */ + const getUserInfo = async (token) => { + // If there is a token, set the user authentication state and navigate to the home page + setIsAuthenticated(true); + const userInfoResponse = await fetch(getUserInfoEndpoint(), { + headers: { Authorization: `Bearer ${token}` }, + }); + setUser(userInfoResponse); + const requestedPath = getSessionParameter(REQUESTED_PATH); + if (requestedPath) { + navigate(requestedPath); + sessionStorage.removeItem(REQUESTED_PATH); + } else if (pathname && pathname !== 'undefined' && pathname !== '') { + navigate(pathname) + } else { + navigate('/'); + } + setLoading(false); + } + + + // Define a useEffect hook to check for an authenticated user on mount + useEffect(() => { + const fetchUser = async () => { + // Check for an authenticated user by parsing the URL for an access token + const query = new URLSearchParams(window.location.search); + const code = query.get('code'); + let response; + if (code) { + try { + // Exchange the authorization code for an access token + response = await sendTokenRequest(requestParams); + } catch (error) { + if (error.response.status === 400) { + sendAuthorizationRequest(requestParams); + setSessionParameter(REQUESTED_PATH, pathname); + } + } + initUserSession(response); + const accessToken = response.accessToken; + getUserInfo(accessToken); + } else { + // If there is no authorization code, check for an access token in the session storage + let token = getSessionParameter(ACCESS_TOKEN); + if (!token) { + // If there is no token stored in the session storage, it means the session is cleared, + // we also assume the refresh token is expired, so we need to re-login + handleLogin(); + } else { + // Note: getAccessToken() will return existing token if the access token is not expired + token = getAccessTokenFromRefreshToken() as any; + if (token) { + // If there is a token, set the user authentication state and navigate to the home page + getUserInfo(token); + } else { + // If there is no token, call the auth endpoint + handleLogin(); + } + } + } + }; + fetchUser(); + }, [navigate]); + + if (loading) { + return
Loading...
+ } + + // Return the AuthProvider context provider with the user authentication state and related functions + return ( + + {children} + + ); +}; + +// Define a custom hook for accessing the AuthProvider context +export const useAuth = () => useContext(AuthContext); diff --git a/admin/admin-ui/client/source/auth/constants/token.ts b/admin/admin-ui/client/source/auth/constants/token.ts new file mode 100644 index 000000000..cd08df4b4 --- /dev/null +++ b/admin/admin-ui/client/source/auth/constants/token.ts @@ -0,0 +1,28 @@ +interface ServiceResourcesType { + jwks: string; + token: string; +} + +export const SERVICE_RESOURCES: ServiceResourcesType = { + jwks: "/oauth2/jwks", + token: "/oauth2/token" +}; + +export const AUTHORIZATION_CODE = "code"; +export const ID_TOKEN = "id_token"; +export const REFRESH_TOKEN = "refresh_token"; +export const ACCESS_TOKEN = "access_token"; +export const PKCE_CODE_VERIFIER = "pkce_code_verifier"; +export const AUTHORIZATION_ENDPOINT = "authorization_endpoint"; +export const TOKEN_ENDPOINT = "token_endpoint"; +export const END_SESSION_ENDPOINT = "end_session_endpoint"; +export const JWKS_ENDPOINT = "jwks_uri"; +export const ISSUER = "issuer"; +export const REQUEST_PARAMS = "request_params"; +export const ACCESS_TOKEN_EXPIRE_IN = "expires_in"; +export const ACCESS_TOKEN_ISSUED_AT = "issued_at"; +export const SCOPE = "scope"; +export const TOKEN_TYPE = "token_type"; +export const USERINFO_ENDPOINT = "userinfo_endpoint"; +export const REQUESTED_PATH = "requested_path"; +export const USER = "user"; \ No newline at end of file diff --git a/admin/admin-ui/client/source/auth/crypto.ts b/admin/admin-ui/client/source/auth/crypto.ts new file mode 100644 index 000000000..115b887cf --- /dev/null +++ b/admin/admin-ui/client/source/auth/crypto.ts @@ -0,0 +1,85 @@ +import Base64 from "crypto-js/enc-base64"; +import WordArray from "crypto-js/lib-typedarrays"; +import sha256 from "crypto-js/sha256"; +import { KEYUTIL, KJUR } from "jsrsasign"; +import { JWKInterface } from "./types/crypto"; +/** + * Get URL encoded string. + * + * @param {any} value. + * @returns {string} base 64 url encoded value. + */ +export const base64URLEncode = (value: any): string => { + return Base64.stringify(value) + .replace(/\+/g, "-") + .replace(/\//g, "_") + .replace(/=/g, ""); +}; + +/** + * Generate code verifier. + * + * @returns {string} code verifier. + */ + export const getCodeVerifier = (): string => { + return base64URLEncode(WordArray.random(32)); +}; + +/** + * Derive code challenge from the code verifier. + * + * @param {string} verifier. + * @returns {string} code challenge. + */ + export const getCodeChallenge = (verifier: string): string => { + return base64URLEncode(sha256(verifier)); +}; + +/** + * Get the supported signing algorithms for the id_token. + * + * @returns {string[]} array of supported algorithms. + */ + export const getSupportedSignatureAlgorithms = (): string[] => { + return ["RS256", "RS512", "RS384", "PS256", "HS256"]; +}; + +/** + * Get JWK used for the id_token + * + * @param {string} jwtHeader header of the id_token. + * @param {JWKInterface[]} keys jwks response. + * @returns {any} public key. + */ +/* eslint-disable @typescript-eslint/no-explicit-any */ +export const getJWKForTheIdToken = (jwtHeader: string, keys: JWKInterface[]): Error|any => { + const headerJSON = JSON.parse(atob(jwtHeader)); + + for (const key of keys) { + if (headerJSON.kid === key.kid) { + return KEYUTIL.getKey({ kty: key.kty, e: key.e, n: key.n }); + } + } + + throw new Error("Failed to find the 'kid' specified in the id_token. 'kid' found in the header : " + + headerJSON.kid + ", Expected values: " + keys.map((key) => key.kid).join(", ")); +}; + +/** + * Verify id token. + * + * @param idToken id_token received from the IdP. + * @param jwk public key used for signing. + * @param {string} clientID app identification. + * @param {string} issuer id_token issuer. + * @returns {any} whether the id_token is valid. + */ +/* eslint-disable @typescript-eslint/no-explicit-any */ +export const isValidIdToken = (idToken: any, jwk: any, clientID: string, issuer: string): any => { + return KJUR.jws.JWS.verifyJWT(idToken, jwk, { + alg: getSupportedSignatureAlgorithms(), + aud: [clientID], + gracePeriod: 3600, + iss: [issuer] + }); +}; \ No newline at end of file diff --git a/admin/admin-ui/client/source/auth/op-config.ts b/admin/admin-ui/client/source/auth/op-config.ts new file mode 100644 index 000000000..34d0391e0 --- /dev/null +++ b/admin/admin-ui/client/source/auth/op-config.ts @@ -0,0 +1,171 @@ +import axios from "axios"; +import { + ACCESS_TOKEN, + AUTHORIZATION_ENDPOINT, + TOKEN_ENDPOINT, + END_SESSION_ENDPOINT, + JWKS_ENDPOINT, + ISSUER, + USERINFO_ENDPOINT, +} from './constants/token'; +import { getSessionParameter, removeSessionParameter, setSessionParameter } from "./session"; +// eslint-disable-next-line @typescript-eslint/no-var-requires +const Settings = require('Settings'); + +/** + * Set OAuth2 authorize endpoint. + * + * @param {string} authorizationEndpoint + */ +export const setAuthorizeEndpoint = (authorizationEndpoint: string): void => { + setSessionParameter(AUTHORIZATION_ENDPOINT, authorizationEndpoint); +}; + +/** + * Set OAuth2 token endpoint. + * + * @param {string} tokenEndpoint + */ +export const setTokenEndpoint = (tokenEndpoint: string): void => { + setSessionParameter(TOKEN_ENDPOINT, tokenEndpoint); +}; + +/** + * Set OIDC end session endpoint. + * + * @param {string} endSessionEndpoint + */ +export const setEndSessionEndpoint = (endSessionEndpoint: string): void => { + setSessionParameter(END_SESSION_ENDPOINT, endSessionEndpoint); +}; + +/** + * Set JWKS URI. + * + * @param jwksEndpoint + */ +export const setJwksUri = (jwksEndpoint: string): void => { + setSessionParameter(JWKS_ENDPOINT, jwksEndpoint); +}; + +/** + * Set id_token issuer. + * + * @param issuer id_token issuer. + */ +export const setIssuer = (issuer: string): void => { + setSessionParameter(ISSUER, issuer); +}; + +/** + * Set userinfo endpoint. + * @param userinfoEndpoint + */ +export const setUserinfoEndpoint = (userinfoEndpoint: string): void => { + setSessionParameter(USERINFO_ENDPOINT, userinfoEndpoint); +}; +/** + * Initialize openid provider configuration. + * + * @param {string} wellKnownEndpoint openid provider configuration. + * @returns {Promise} promise. + */ +/* eslint-disable @typescript-eslint/no-explicit-any */ +export const initOPConfiguration = ( + wellKnownEndpoint: string, +): Promise => { + if (wellKnownEndpoint && wellKnownEndpoint.trim().length > 0) { + if (!wellKnownEndpoint || wellKnownEndpoint.trim().length === 0) { + return Promise.reject(new Error("OpenID provider configuration endpoint is not defined.")); + } + return axios.get(wellKnownEndpoint) + .then((response) => { + if (response.status !== 200) { + return Promise.reject(new Error("Failed to load OpenID provider configuration from: " + + wellKnownEndpoint)); + } + setAuthorizeEndpoint(response.data.authorization_endpoint); + setTokenEndpoint(response.data.token_endpoint); + setEndSessionEndpoint(Settings.idp.logout_endpoint); + setJwksUri(response.data.jwks_uri); + setIssuer(response.data.issuer); + setUserinfoEndpoint(response.data.userinfo_endpoint); + return Promise.resolve("success"); + }).catch((error) => { + return Promise.reject(error); + }); + } else { + setAuthorizeEndpoint(Settings.idp.authorization_endpoint); + setTokenEndpoint(Settings.idp.token_endpoint); + setEndSessionEndpoint(Settings.idp.logout_endpoint); + setJwksUri(Settings.idp.jwks_uri); + setIssuer(Settings.idp.issuer); + setUserinfoEndpoint(Settings.idp.userinfo_endpoint); + return Promise.resolve("success"); + } +}; + +/** + * Reset openid provider configuration. + */ +export const resetOPConfiguration = (): void => { + removeSessionParameter(AUTHORIZATION_ENDPOINT); + removeSessionParameter(TOKEN_ENDPOINT); + removeSessionParameter(END_SESSION_ENDPOINT); + removeSessionParameter(JWKS_ENDPOINT); + removeSessionParameter(ISSUER); + removeSessionParameter(USERINFO_ENDPOINT); +}; + +/** + * Get OAuth2 authorize endpoint. + * + * @returns {string|null} + */ +export const getAuthorizeEndpoint = (): string | null => { + return getSessionParameter(AUTHORIZATION_ENDPOINT); +}; + +/** + * Get OAuth2 token endpoint. + * + * @returns {string|null} + */ +export const getTokenEndpoint = (): string | null => { + return getSessionParameter(TOKEN_ENDPOINT); +}; + +/** + * Get OIDC end session endpoint. + * + * @returns {string|null} + */ +export const getEndSessionEndpoint = (): string | null => { + return getSessionParameter(END_SESSION_ENDPOINT); +}; + +/** + * Get JWKS URI. + * + * @returns {string|null} + */ +export const getJwksUri = (): string | null => { + return getSessionParameter(JWKS_ENDPOINT); +}; + +/** + * Get id_token issuer. + * + * @returns {any} + */ +export const getIssuer = (): string => { + return getSessionParameter(ISSUER); +}; + +export const getToken = (): string => { + return getSessionParameter(ACCESS_TOKEN); +}; + +export const getUserInfoEndpoint = (): string => { + return getSessionParameter(USERINFO_ENDPOINT); +} \ No newline at end of file diff --git a/admin/admin-ui/client/source/auth/session.ts b/admin/admin-ui/client/source/auth/session.ts new file mode 100644 index 000000000..aea0e1ea2 --- /dev/null +++ b/admin/admin-ui/client/source/auth/session.ts @@ -0,0 +1,133 @@ +import { Semaphore } from "await-semaphore"; +import jwtDecode from 'jwt-decode'; +import { + ACCESS_TOKEN, + ID_TOKEN, + REQUEST_PARAMS, + REFRESH_TOKEN, + SCOPE, + TOKEN_TYPE, + ACCESS_TOKEN_EXPIRE_IN, + ACCESS_TOKEN_ISSUED_AT +} from "./constants/token"; +import { sendRefreshTokenRequest } from "./sign-in"; +import { TokenResponseInterface } from "./types/token-response"; + +/** + * Semaphore used for synchronizing the refresh token requests. + */ +const semaphore = new Semaphore(1); + +/** + * Remove parameter from session storage. + * + * @param {string} key. + */ +export const removeSessionParameter = (key: string): void => { + sessionStorage.removeItem(key); +}; + +/** + * Set parameter to session storage. + * + * @param {string} key. + * @param value value. + */ +export const setSessionParameter = (key: string, value: string): void => { + sessionStorage.setItem(key, value); +}; + +/** + * Get parameter from session storage. + * + * @param {string} key. + * @returns {string | null} parameter value or null. + */ +export const getSessionParameter = (key: string): string => { + return sessionStorage.getItem(key) || ''; +}; + + + +/** + * End authenticated user session. + */ +export const endAuthenticatedSession = (): void => { + removeSessionParameter(ACCESS_TOKEN); + removeSessionParameter(ID_TOKEN); + removeSessionParameter(ACCESS_TOKEN_EXPIRE_IN); + removeSessionParameter(ACCESS_TOKEN_ISSUED_AT); + removeSessionParameter(SCOPE); + removeSessionParameter(REFRESH_TOKEN); + removeSessionParameter(TOKEN_TYPE); +}; + +/** + * Initialize authenticated user session. + * + * @param {TokenResponseInterface} tokenResponse. + * @param authenticatedUser authenticated user. + */ +export const initUserSession = (tokenResponse: TokenResponseInterface): void => { + endAuthenticatedSession(); + setSessionParameter(ACCESS_TOKEN, tokenResponse.accessToken); + setSessionParameter(ID_TOKEN, tokenResponse.idToken); + setSessionParameter(ACCESS_TOKEN_EXPIRE_IN, tokenResponse.expiresIn); + setSessionParameter(ACCESS_TOKEN_ISSUED_AT, (Date.now() / 1000).toString()); + setSessionParameter(SCOPE, tokenResponse.scope); + setSessionParameter(REFRESH_TOKEN, tokenResponse.refreshToken); + setSessionParameter(TOKEN_TYPE, tokenResponse.tokenType); +}; + +/** + * Use this method when need to get a token using the refresh token. + * Get access token. + * + * @returns {Promise} access token. + */ +export const getAccessTokenFromRefreshToken = async (): Promise => { + const accessToken = getSessionParameter(ACCESS_TOKEN); + const expiresIn = getSessionParameter(ACCESS_TOKEN_EXPIRE_IN); + const issuedAt = getSessionParameter(ACCESS_TOKEN_ISSUED_AT); + + // Check if session parameters are present + if (!accessToken || accessToken.trim().length === 0 || !expiresIn || expiresIn.length === 0 || !issuedAt + || issuedAt.length === 0) { + // If not, end the authenticated session and reject the promise + endAuthenticatedSession(); + return null; + } + + function getValidityPeriod(): number { + const currentExpiresIn = getSessionParameter(ACCESS_TOKEN_EXPIRE_IN); + const currentIssuedAt = getSessionParameter(ACCESS_TOKEN_ISSUED_AT); + // Return validity period in seconds + return (parseInt(currentIssuedAt, 10) + parseInt(currentExpiresIn, 10)) - Math.floor(Date.now() / 1000); + } + + let validityPeriod = getValidityPeriod(); + + // Check if token is about to expire + if (validityPeriod <= 300) { + try { + validityPeriod = getValidityPeriod(); + if (validityPeriod <= 300) { + const requestParams = JSON.parse(getSessionParameter(REQUEST_PARAMS)); + // Send refresh token request and init new session with the response + const tokenResponse: any = await sendRefreshTokenRequest(requestParams, getSessionParameter(REFRESH_TOKEN)); + initUserSession(tokenResponse); + return tokenResponse.accessToken; + } else { + // Return existing access token if validity period is greater than 300 seconds + return getSessionParameter(ACCESS_TOKEN); + } + } catch (error) { + return null; + } + } else { + // Return existing access token if validity period is greater than 300 seconds + return accessToken; + } + return false; +}; + diff --git a/admin/admin-ui/client/source/auth/sign-in.ts b/admin/admin-ui/client/source/auth/sign-in.ts new file mode 100644 index 000000000..61f83dc80 --- /dev/null +++ b/admin/admin-ui/client/source/auth/sign-in.ts @@ -0,0 +1,208 @@ +import axios from 'axios'; +import { getCodeVerifier, getCodeChallenge, getJWKForTheIdToken, isValidIdToken } from './crypto'; +import { OIDCRequestParamsInterface } from './types/oidc-request-params'; +import { TokenResponseInterface } from './types/token-response'; +import { + AUTHORIZATION_CODE, + PKCE_CODE_VERIFIER, + SERVICE_RESOURCES, + REQUEST_PARAMS, +} from './constants/token'; +import { getSessionParameter, removeSessionParameter, setSessionParameter } from "./session"; +import { getAuthorizeEndpoint, getTokenEndpoint, getJwksUri, getIssuer, getToken } from "./op-config"; +// eslint-disable-next-line @typescript-eslint/no-var-requires +const Settings = require('Settings'); +/** + * Send authorization request. + * @param requestParams Request parameters. + * @returns Promise. + */ +export const sendAuthorizationRequest = (requestParams: OIDCRequestParamsInterface): Promise | any => { + const authorizeEndpoint = getAuthorizeEndpoint(); + if (!authorizeEndpoint || authorizeEndpoint.trim().length === 0) { + return Promise.reject(new Error("Invalid authorize endpoint found.")); + } + // Generate code verifier and code challenge. + + const codeVerifier = getCodeVerifier(); + const codeChallenge = getCodeChallenge(codeVerifier); + setSessionParameter(PKCE_CODE_VERIFIER, codeVerifier); + const authorizeRequest = `${authorizeEndpoint}?` + + `response_type=code` + + `&client_id=${requestParams.clientId}` + + `&scope=${requestParams.scope}` + + `&state=${requestParams.state}` + + `&code_challenge_method=S256` + + `&code_challenge=${codeChallenge}` + + `&redirect_uri=${Settings.idp.redirect_uri}`; + + document.location.href = authorizeRequest; + return false; +}; + +/** + * +This function is used to validate an ID token obtained from the authorization server after exchanging an authorization code. + +The ID token is a JSON Web Token (JWT) that contains information about the authenticated user and the authorization transaction. +The ID token is signed by the authorization server using a private key and can be verified using the public key obtained from the + server's JSON Web Key Set (JWKS) endpoint. + +The purpose of the validateIdToken function is to retrieve the public key from the JWKS endpoint and use it to verify the +signature on the ID token. The function also checks that the iss (issuer) claim in the ID token matches the expected issuer +(i.e., the authorization server), that the aud (audience) claim in the ID token matches the client ID, and that the nonce +value passed during the authentication request matches the nonce value in the ID token. + +By validating the ID token, the function ensures that the token was issued by a trusted authority, +that it has not been tampered with, and that it contains the expected claims. This helps prevent impersonation and other +security threats in the SPA. + * + * @param {string} clientId client ID. + * @param {string} idToken id_token received from the IdP. + * @returns {Promise} whether token is valid. + */ +/* eslint-disable @typescript-eslint/no-explicit-any */ +const validateIdToken = (clientId: string, idToken: string, serverOrigin: string): Promise => { + // Get the JWKS endpoint from the OP configuration. + const jwksEndpoint = getJwksUri(); + + // If the JWKS endpoint is not available, return an error. + if (!jwksEndpoint || jwksEndpoint.trim().length === 0) { + return Promise.reject("Invalid JWKS URI found."); + } + // Get the public key from the JWKS endpoint. + return axios.get(jwksEndpoint) + .then((response: any) => { + if (response.status !== 200) { + return Promise.reject(new Error("Failed to load public keys from JWKS URI: " + + jwksEndpoint)); + } + // Get the public key from the JWKS endpoint. + const jwk = getJWKForTheIdToken(idToken.split(".")[0], response.data.keys); + let issuer = getIssuer(); + // If the issuer is not available, use the server origin. + if (!issuer || issuer.trim().length === 0) { + issuer = serverOrigin + SERVICE_RESOURCES.token; + } + // Validate the ID token. + return Promise.resolve(isValidIdToken(idToken, jwk, clientId, issuer)); + }).catch((error: any) => { + return Promise.reject(error); + }); +}; + +/** + * Send token request. + * + * @param {OIDCRequestParamsInterface} requestParams request parameters required for token request. + * @returns {Promise} token response data or error. + */ +export const sendTokenRequest = ( + requestParams: OIDCRequestParamsInterface +): Promise => { + + const tokenEndpoint = getTokenEndpoint(); + // const stsEndoint = 'https://da59-203-94-95-4.in.ngrok.io/api/sts/v1/oauth2/token'; + + if (!tokenEndpoint || tokenEndpoint.trim().length === 0) { + return Promise.reject(new Error("Invalid token endpoint found.")); + } + + const code = new URL(window.location.href).searchParams.get(AUTHORIZATION_CODE); + + const body = [ + `client_id=${requestParams.clientId}`, + `code=${code}`, + "grant_type=authorization_code", + `redirect_uri=${Settings.idp.redirect_uri}`]; + + if (Settings.idp.pkce) { + body.push(`code_verifier=${getSessionParameter(PKCE_CODE_VERIFIER)}`); + } + + return axios.post(tokenEndpoint, body.join("&")) + .then((response: any) => { + if (response.status !== 200) { + return Promise.reject(new Error("Invalid status code received in the token response: " + + response.status)); + } + const tokenResponse: TokenResponseInterface = { + accessToken: response.data.access_token, + expiresIn: response.data.expires_in, + idToken: response.data.id_token, + refreshToken: response.data.refresh_token, + scope: response.data.scope, + tokenType: response.data.token_type + }; + if (Settings.idp.pkce) { + removeSessionParameter(PKCE_CODE_VERIFIER); + return validateIdToken(requestParams.clientId, response.data.id_token, requestParams.serverOrigin) + .then((valid) => { + if (valid) { + setSessionParameter(REQUEST_PARAMS, JSON.stringify(requestParams)); + + return Promise.resolve(tokenResponse) + } + return Promise.reject(new Error("Invalid id_token in the token response: " + response.data.id_token)); + }); + } else { + // If PKCE is disabled, set the request parameters in the session storage without the verification. + return Promise.resolve(tokenResponse) + } + + }).catch((error: any) => { + return Promise.reject(error); + }); +}; + +/** + * Send refresh token request. + * + * @param {OIDCRequestParamsInterface} requestParams request parameters required for token request. + * @param {string} refreshToken + * @returns {Promise} refresh token response data or error. + */ +export const sendRefreshTokenRequest = ( + requestParams: OIDCRequestParamsInterface, + refreshToken: string +): Promise => { + + const tokenEndpoint = getTokenEndpoint(); + + if (!tokenEndpoint || tokenEndpoint.trim().length === 0) { + return Promise.reject("Invalid token endpoint found."); + } + + const body = [ + `client_id=${requestParams.clientId}`, + `refresh_token=${refreshToken}`, + "grant_type=refresh_token"]; + + return axios.post(tokenEndpoint, body.join("&")) + .then((response: any) => { + if (response.status !== 200) { + return Promise.reject(new Error("Invalid status code received in the refresh token response: " + + response.status)); + } + + return validateIdToken(requestParams.clientId, response.data.id_token, requestParams.serverOrigin) + .then((valid) => { + if (valid) { + const tokenResponse: TokenResponseInterface = { + accessToken: response.data.access_token, + expiresIn: response.data.expires_in, + idToken: response.data.id_token, + refreshToken: response.data.refresh_token, + scope: response.data.scope, + tokenType: response.data.token_type + }; + + return Promise.resolve(tokenResponse); + } + return Promise.reject(new Error("Invalid id_token in the token response: " + + response.data.id_token)); + }); + }).catch((error: any) => { + return Promise.reject(error); + }); +}; diff --git a/admin/admin-ui/client/source/auth/sign-out.ts b/admin/admin-ui/client/source/auth/sign-out.ts new file mode 100644 index 000000000..eb01206e8 --- /dev/null +++ b/admin/admin-ui/client/source/auth/sign-out.ts @@ -0,0 +1,29 @@ +import { ID_TOKEN } from "./constants/token"; +import { getEndSessionEndpoint } from "./op-config"; +import { getSessionParameter } from "./session"; +// eslint-disable-next-line @typescript-eslint/no-var-requires +const Settings = require('Settings'); +/** + * Handle user sign out. + * + * @returns {} + */ +/* eslint-disable @typescript-eslint/no-explicit-any */ +export const sendSignOutRequest = (redirectUri: string, sessionClearCallback: any): Promise | undefined => { + const logoutEndpoint = getEndSessionEndpoint(); + const logoutRequest = logoutEndpoint + "?client_id=" + Settings.idp.client_id + "&returnTo=" + redirectUri + if (!logoutEndpoint || logoutEndpoint.trim().length === 0) { + return Promise.reject(new Error("Invalid logout endpoint found.")); + } + + const idToken = getSessionParameter(ID_TOKEN); + + if (!idToken || idToken.trim().length === 0) { + return Promise.reject(new Error("Invalid id_token found.")); + } + + sessionClearCallback(); + Promise.resolve("Logout success!"); + + document.location.href = logoutRequest; +}; \ No newline at end of file diff --git a/admin/admin-ui/client/source/auth/types/crypto.ts b/admin/admin-ui/client/source/auth/types/crypto.ts new file mode 100644 index 000000000..1381faff1 --- /dev/null +++ b/admin/admin-ui/client/source/auth/types/crypto.ts @@ -0,0 +1,11 @@ +/** + * JWK Model + */ + export interface JWKInterface { + kty: string; + e: string; + use: string; + kid: string; + alg: string; + n: string; +} \ No newline at end of file diff --git a/admin/admin-ui/client/source/auth/types/oidc-request-params.ts b/admin/admin-ui/client/source/auth/types/oidc-request-params.ts new file mode 100644 index 000000000..d4a7f84d9 --- /dev/null +++ b/admin/admin-ui/client/source/auth/types/oidc-request-params.ts @@ -0,0 +1,10 @@ +/** + * OIDC request parameters. + */ + export interface OIDCRequestParamsInterface { + clientId: string; + // redirectUri: string; + scope: string; + state: string; + serverOrigin: string; +} \ No newline at end of file diff --git a/admin/admin-ui/client/source/auth/types/token-response.ts b/admin/admin-ui/client/source/auth/types/token-response.ts new file mode 100644 index 000000000..3a5b0f008 --- /dev/null +++ b/admin/admin-ui/client/source/auth/types/token-response.ts @@ -0,0 +1,11 @@ +/** + * Interface of the OAuth2/OIDC tokens. + */ + export interface TokenResponseInterface { + accessToken: string; + idToken: string; + refreshToken: string; + expiresIn: string; + scope: string; + tokenType: string; +} \ No newline at end of file diff --git a/admin/admin-ui/client/source/auth/utils/password-strength.ts b/admin/admin-ui/client/source/auth/utils/password-strength.ts new file mode 100644 index 000000000..51e812d92 --- /dev/null +++ b/admin/admin-ui/client/source/auth/utils/password-strength.ts @@ -0,0 +1,29 @@ +// has number +const hasNumber = (number) => new RegExp(/[0-9]/).test(number); + +// has mix of small and capitals +const hasMixed = (number) => new RegExp(/[a-z]/).test(number) && new RegExp(/[A-Z]/).test(number); + +// has special chars +const hasSpecial = (number) => new RegExp(/[!#@$%^&*)(+=._-]/).test(number); + +// set color based on password strength +export const strengthColor = (count) => { + if (count < 2) return { label: 'Poor', color: 'error.main' }; + if (count < 3) return { label: 'Weak', color: 'warning.main' }; + if (count < 4) return { label: 'Normal', color: 'warning.dark' }; + if (count < 5) return { label: 'Good', color: 'success.main' }; + if (count < 6) return { label: 'Strong', color: 'success.dark' }; + return { label: 'Poor', color: 'error.main' }; +}; + +// password strength indicator +export const strengthIndicator = (number) => { + let strengths = 0; + if (number.length > 5) strengths += 1; + if (number.length > 7) strengths += 1; + if (hasNumber(number)) strengths += 1; + if (hasSpecial(number)) strengths += 1; + if (hasMixed(number)) strengths += 1; + return strengths; +}; diff --git a/admin/admin-ui/client/source/components/@extended/Breadcrumbs.tsx b/admin/admin-ui/client/source/components/@extended/Breadcrumbs.tsx new file mode 100644 index 000000000..8d9fe41d5 --- /dev/null +++ b/admin/admin-ui/client/source/components/@extended/Breadcrumbs.tsx @@ -0,0 +1,107 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { useEffect, useState } from 'react'; +import { Link, useLocation } from 'react-router-dom'; + +// material-ui +import MuiBreadcrumbs from '@mui/material/Breadcrumbs'; +import { Grid, Typography } from '@mui/material'; + +// project imports +import MainCard from '../MainCard'; + +// ==============================|| BREADCRUMBS ||============================== // + +interface BreadcrumbsProps { + navigation: any; + title: boolean; + divider?: boolean; + others?: any; +} + +const Breadcrumbs = ({ navigation, title, ...others }: BreadcrumbsProps) => { + const location = useLocation(); + const [main, setMain] = useState<{ type?: string; title?: string; url?: string, breadcrumbs?: any}>(); + const [item, setItem] = useState<{ type?: string; title?: string; url?: string, breadcrumbs?: any}>(); + + // set active item state + const getCollapse = (menu: any) => { + if (menu.children) { + menu.children.filter((collapse) => { + if (collapse.type && collapse.type === 'collapse') { + getCollapse(collapse); + } else if (collapse.type && collapse.type === 'item') { + if (location.pathname === collapse.url) { + setMain(menu); + setItem(collapse); + } + } + return false; + }); + } + }; + + useEffect(() => { + navigation?.items?.map((menu) => { + if (menu.type && menu.type === 'group') { + getCollapse(menu); + } + return false; + }); + }); + + // only used for component demo breadcrumbs + if (location.pathname === '/breadcrumbs') { + location.pathname = '/dashboard/analytics'; + } + + let mainContent; + let itemContent; + let breadcrumbContent = ; + + // collapse item + if (main && main.type === 'collapse') { + mainContent = ( + + {main.title} + + ); + } + + // items + if (item && item.type === 'item') { + itemContent = ( + + {item.title} + + ); + + // main + if (item.breadcrumbs !== false) { + breadcrumbContent = ( + + + + + + Home + + {mainContent} + {itemContent} + + + + + ); + } + } + + return breadcrumbContent; +}; + +Breadcrumbs.propTypes = { + navigation: PropTypes.object, + title: PropTypes.bool +}; + +export default Breadcrumbs; diff --git a/admin/admin-ui/client/source/components/@extended/Dot.tsx b/admin/admin-ui/client/source/components/@extended/Dot.tsx new file mode 100644 index 000000000..b69e71db7 --- /dev/null +++ b/admin/admin-ui/client/source/components/@extended/Dot.tsx @@ -0,0 +1,53 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +// material-ui +import { useTheme } from '@mui/material/styles'; +import { Box } from '@mui/material'; + +interface DotProps { + color: string; + size: number; +} +const Dot = ({ color, size }: DotProps) => { + const theme = useTheme(); + let main; + switch (color) { + case 'secondary': + main = theme.palette.secondary.main; + break; + case 'error': + main = theme.palette.error.main; + break; + case 'warning': + main = theme.palette.warning.main; + break; + case 'info': + main = theme.palette.info.main; + break; + case 'success': + main = theme.palette.success.main; + break; + case 'primary': + default: + main = theme.palette.primary.main; + } + + return ( + + ); +}; + +Dot.propTypes = { + color: PropTypes.string, + size: PropTypes.number +}; + +export default Dot; diff --git a/admin/admin-ui/client/source/components/@extended/FormDialogBase.tsx b/admin/admin-ui/client/source/components/@extended/FormDialogBase.tsx new file mode 100644 index 000000000..595e54f93 --- /dev/null +++ b/admin/admin-ui/client/source/components/@extended/FormDialogBase.tsx @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * + * 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. + * + */ + +import Button from '@mui/material/Button'; +import CircularProgress from '@mui/material/CircularProgress'; +import Dialog from '@mui/material/Dialog'; +import DialogActions from '@mui/material/DialogActions'; +import DialogContent from '@mui/material/DialogContent'; +import DialogTitle from '@mui/material/DialogTitle'; +import IconButton from '@mui/material/IconButton'; +import Alert from "components/Alert"; +import PropTypes from 'prop-types'; +import React, { useState } from 'react'; + +export default function FormDialogBase({ + title, + children, + icon, + saveButtonText, + formSaveCallback, + dialogOpenCallback, + triggerIconProps, +}) { + const [open, setOpen] = useState(false); + const [saving, setSaving] = useState(false); + + const handleClickOpen = () => { + dialogOpenCallback(); + setOpen(true); + }; + + const handleClose = () => { + setOpen(false); + }; + + const saveTriggerd = () => { + const savedPromise = formSaveCallback(); + if (typeof savedPromise === 'function') { + savedPromise(setOpen); + } else if (savedPromise) { + setSaving(true); + savedPromise.then((data) => { + Alert.success(data); + }).catch((e) => { + Alert.error(e); + }).finally(() => { + setSaving(false); + handleClose(); + }); + } + }; + + return ( + <> + {icon && ( + + {icon} + + )} + + + {title} + + {children} + + + + + + + + ); +} +FormDialogBase.defaultProps = { + dialogOpenCallback: () => { }, + triggerButtonProps: { + variant: 'contained', + color: 'primary', + }, + triggerIconProps: { + color: 'primary', + component: 'span', + }, +}; + +FormDialogBase.propTypes = { + title: PropTypes.string.isRequired, + children: PropTypes.element, + icon: PropTypes.element.isRequired, + saveButtonText: PropTypes.string.isRequired, + dialogOpenCallback: PropTypes.func, +}; diff --git a/admin/admin-ui/client/source/components/@extended/Transitions.tsx b/admin/admin-ui/client/source/components/@extended/Transitions.tsx new file mode 100644 index 000000000..281e5112c --- /dev/null +++ b/admin/admin-ui/client/source/components/@extended/Transitions.tsx @@ -0,0 +1,69 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { forwardRef, ReactNode } from 'react'; + +// material-ui +import { Fade, Box, Grow } from '@mui/material'; + +// ==============================|| TRANSITIONS ||============================== // +interface Props { + children?: ReactNode; + position?: string; + type?: string; + others?: any; +} + +const Transitions = forwardRef(({ children, position, type, ...others }, ref) => { + let positionSX = { + transformOrigin: '0 0 0' + }; + + switch (position) { + case 'top-right': + case 'top': + case 'bottom-left': + case 'bottom-right': + case 'bottom': + case 'top-left': + default: + positionSX = { + transformOrigin: '0 0 0' + }; + break; + } + + return ( + + {type === 'grow' && ( + + {children} + + )} + {type === 'fade' && ( + + {children} + + )} + + ); +}); + +Transitions.propTypes = { + children: PropTypes.node, + type: PropTypes.oneOf(['grow', 'fade', 'collapse', 'slide', 'zoom']), + position: PropTypes.oneOf(['top-left', 'top-right', 'top', 'bottom-left', 'bottom-right', 'bottom']) +}; + +Transitions.defaultProps = { + type: 'grow', + position: 'top-left' +}; + +export default Transitions; diff --git a/admin/admin-ui/client/source/components/Alert.jsx b/admin/admin-ui/client/source/components/Alert.jsx new file mode 100644 index 000000000..243440291 --- /dev/null +++ b/admin/admin-ui/client/source/components/Alert.jsx @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2019, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you 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. + */ +import toast from 'react-hot-toast'; +import React from 'react'; + +export default { + info: toast, + success: toast.success, + error: toast.error, + warning: (message, options) => toast(message, { + style: { background: '#ffd891' }, + icon: ( + + ⚠ + + ), + ...options, + }), + loading: toast.promise, +}; diff --git a/admin/admin-ui/client/source/components/Loadable.js b/admin/admin-ui/client/source/components/Loadable.js new file mode 100644 index 000000000..10098d0ac --- /dev/null +++ b/admin/admin-ui/client/source/components/Loadable.js @@ -0,0 +1,16 @@ +import React from 'react'; +import { Suspense } from 'react'; + +// project import +import Loader from './Loader'; + +// ==============================|| LOADABLE - LAZY LOADING ||============================== // + +const Loadable = (Component) => (props) => + ( + }> + + + ); + +export default Loadable; diff --git a/admin/admin-ui/client/source/components/Loader.js b/admin/admin-ui/client/source/components/Loader.js new file mode 100644 index 000000000..e4e8372a6 --- /dev/null +++ b/admin/admin-ui/client/source/components/Loader.js @@ -0,0 +1,26 @@ +import React from 'react'; +// material-ui +import { styled } from '@mui/material/styles'; +import LinearProgress from '@mui/material/LinearProgress'; + +// loader style +const LoaderWrapper = styled('div')(({ theme }) => ({ + position: 'fixed', + top: 0, + left: 0, + zIndex: 2001, + width: '100%', + '& > * + *': { + marginTop: theme.spacing(2) + } +})); + +// ==============================|| Loader ||============================== // + +const Loader = () => ( + + + +); + +export default Loader; diff --git a/admin/admin-ui/client/source/components/Logo/index.js b/admin/admin-ui/client/source/components/Logo/index.js new file mode 100644 index 000000000..d6f4549ea --- /dev/null +++ b/admin/admin-ui/client/source/components/Logo/index.js @@ -0,0 +1,24 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { Link } from 'react-router-dom'; + +// material-ui +import { ButtonBase } from '@mui/material'; + +// eslint-disable-next-line @typescript-eslint/no-var-requires, no-undef +const Settings = require('Settings'); + +// ==============================|| MAIN LOGO ||============================== // + +const LogoSection = ({ sx, to }) => ( + + + +); + +LogoSection.propTypes = { + sx: PropTypes.object, + to: PropTypes.string +}; + +export default LogoSection; diff --git a/admin/admin-ui/client/source/components/MainCard.tsx b/admin/admin-ui/client/source/components/MainCard.tsx new file mode 100644 index 000000000..71a157e3b --- /dev/null +++ b/admin/admin-ui/client/source/components/MainCard.tsx @@ -0,0 +1,106 @@ +import React, { ReactNode } from 'react'; +import PropTypes from 'prop-types'; +import { forwardRef } from 'react'; + +// material-ui +import { useTheme, SxProps } from '@mui/material/styles'; +import { Card, CardContent, CardHeader, CardProps, Divider, Typography } from '@mui/material'; + +// header style +const headerSX = { + p: 2.5, + '& .MuiCardHeader-action': { m: '0px auto', alignSelf: 'center' }, + backgroundColor: 'transparent',//(theme) => (theme.palette.mode === 'dark' ? theme.palette.dark.main : theme.palette.grey[50]) +}; + +// ==============================|| CUSTOM - MAIN CARD ||============================== // +export type CardSXProps = { + sx: SxProps; +} + +interface MainCardProps extends Omit { + border?: boolean, + boxShadow?: boolean, + contentSX?: SxProps, + darkTitle?: boolean, + divider?: boolean, + secondary?: ReactNode, + shadow?: string, + sx?: CardSXProps, + title?: string, + codeHighlight?: boolean, + content?: boolean, + children?: ReactNode +} + +type Ref = HTMLDivElement | null; + +const MainCard = forwardRef( + ( + { + border = true, + boxShadow, + children, + content = true, + contentSX = { backgroundColor: '#fff'}, + darkTitle, + divider = true, + elevation, + secondary, + shadow, + sx = {}, + title, + codeHighlight, + ...others + }, + ref + ): JSX.Element => { + const theme = useTheme(); + boxShadow = theme.palette.mode === 'dark' ? boxShadow || true : boxShadow; + + return ( + + {/* card header and action */} + {!darkTitle && title && ( + + )} + {darkTitle && title && ( + {title}} action={secondary} /> + )} + + {/* content & header divider */} + {title && divider && } + + {/* card content */} + {content && {children}} + {!content && children} + + + ); + } +); +MainCard.displayName = 'MainCard'; +export default MainCard; diff --git a/admin/admin-ui/client/source/components/ScrollTop.js b/admin/admin-ui/client/source/components/ScrollTop.js new file mode 100644 index 000000000..809ac4dcc --- /dev/null +++ b/admin/admin-ui/client/source/components/ScrollTop.js @@ -0,0 +1,26 @@ +import PropTypes from 'prop-types'; +import { useEffect } from 'react'; +import { useLocation } from 'react-router-dom'; + +// ==============================|| NAVIGATION - SCROLL TO TOP ||============================== // + +const ScrollTop = ({ children }) => { + const location = useLocation(); + const { pathname } = location; + + useEffect(() => { + window.scrollTo({ + top: 0, + left: 0, + behavior: 'smooth' + }); + }, [pathname]); + + return children || null; +}; + +ScrollTop.propTypes = { + children: PropTypes.node +}; + +export default ScrollTop; diff --git a/admin/admin-ui/client/source/components/data-table/PaginatedClientSide/PageNumbers.tsx b/admin/admin-ui/client/source/components/data-table/PaginatedClientSide/PageNumbers.tsx new file mode 100644 index 000000000..7da76b42e --- /dev/null +++ b/admin/admin-ui/client/source/components/data-table/PaginatedClientSide/PageNumbers.tsx @@ -0,0 +1,90 @@ +import React from 'react' +import TextField from '@mui/material/TextField'; +import Button from '@mui/material/Button'; +import Box from '@mui/material/Box'; +import { faAngleRight, faAngleLeft, faForwardFast, faBackwardFast } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import InputLabel from '@mui/material/InputLabel'; +import MenuItem from '@mui/material/MenuItem'; +import FormControl from '@mui/material/FormControl'; +import Select, { SelectChangeEvent } from '@mui/material/Select'; + +interface PageNumbersProps { + canPreviousPage: boolean; + canNextPage: boolean; + pageOptions: any[]; + pageCount: number; + gotoPage: (page: number) => void; + nextPage: () => void; + previousPage: () => void; + setPageSize: (size: number) => void; + pageIndex: number; + pageSize: number; +} +export default function PageNumbers({ + canPreviousPage, + canNextPage, + pageOptions, + pageCount, + gotoPage, + nextPage, + previousPage, + setPageSize, + pageIndex, + pageSize }: PageNumbersProps) { + return ( + + + + + + + Page{' '} + + {pageIndex + 1} of {pageOptions.length} + {' '} + + + { + const page = e.target.value ? Number(e.target.value) - 1 : 0 + gotoPage(page) + }} + sx={{ width: 100, textAlign: 'center', backgroundColor: 'white', margin: 0, padding: 0 }} + /> + + + No of Items + + + + ) +} diff --git a/admin/admin-ui/client/source/components/data-table/PaginatedClientSide/SearchTable.tsx b/admin/admin-ui/client/source/components/data-table/PaginatedClientSide/SearchTable.tsx new file mode 100644 index 000000000..130d2ffbb --- /dev/null +++ b/admin/admin-ui/client/source/components/data-table/PaginatedClientSide/SearchTable.tsx @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you 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. + */ + +import React from 'react'; +import TextField from '@mui/material/TextField'; +import AppBar from '@mui/material/AppBar'; +import Toolbar from '@mui/material/Toolbar'; +import Grid from '@mui/material/Grid'; +import SearchIcon from '@mui/icons-material/Search'; + +interface SearchTableProps { + filter: string; + setFilter: (filter: string) => void; + searchProps: { + searchPlaceholder: string; + }; +} + +export default function SearchTable({ filter, setFilter, searchProps: { searchPlaceholder } }: SearchTableProps) { + + const handleFilterChange = (e: React.ChangeEvent) => { + setFilter(e.target.value); + }; + + return ( + + + + + {} + + + { + + } + + + + + ); +} diff --git a/admin/admin-ui/client/source/components/data-table/PaginatedClientSide/index.tsx b/admin/admin-ui/client/source/components/data-table/PaginatedClientSide/index.tsx new file mode 100644 index 000000000..e7075c161 --- /dev/null +++ b/admin/admin-ui/client/source/components/data-table/PaginatedClientSide/index.tsx @@ -0,0 +1,135 @@ +/* eslint-disable react/jsx-key */ +import React, { useState } from 'react' +import { useTable, usePagination, useGlobalFilter, useSortBy } from 'react-table' +import Table from '@mui/material/Table'; +import TableBody from '@mui/material/TableBody'; +import TableCell from '@mui/material/TableCell'; +import TableContainer from '@mui/material/TableContainer'; +import TableHead from '@mui/material/TableHead'; +import TableRow from '@mui/material/TableRow'; +import Paper from '@mui/material/Paper'; +import PageNumbers from './PageNumbers'; +import SearchTable from './SearchTable'; +import KeyboardArrowUpIcon from '@mui/icons-material/KeyboardArrowUp'; +import KeyboardArrowDownwardIcon from '@mui/icons-material/KeyboardArrowDown'; +import Box from '@mui/material/Box'; +import Grid from '@mui/material/Grid'; + +// import '../Tmp.css'; + +interface TableProps { + columns: any, + data: any, + searchProps: any, +} +interface PaginatedClientSideProps { + data: any, + columns: any, + searchProps: any, +} + +function ApplicationPoliciesTable({ columns, data, searchProps }: TableProps) { + // Use the state and functions returned from useTable to build your UI + const { + getTableProps, + getTableBodyProps, + headerGroups, + prepareRow, + state, + setGlobalFilter, + page, // Instead of using 'rows', we'll use page, + // which has only the rows for the active page + + // The rest of these things are super handy, too ;) + canPreviousPage, + canNextPage, + pageOptions, + pageCount, + gotoPage, + nextPage, + previousPage, + setPageSize, + toggleSortBy, + state: { pageIndex, pageSize }, + } = useTable( + { + columns, + data, + initialState: { pageIndex: 0, }, + disableSortRemove: true, + }, + useGlobalFilter, + useSortBy, + usePagination, + ) + + const { globalFilter } = state; + + // Render the UI for your table + return ( + <> + + + + + {headerGroups.map(headerGroup => ( + + {headerGroup.headers.map(column => ( + + + + {column.render('Header')} + + {column.sortable && ( + + + toggleSortBy(column.id, false, false)} color={column.isSorted && !column.isSortedDesc ? 'disabled' : 'primary'}/> + toggleSortBy(column.id, true, false)} color={column.isSorted && column.isSortedDesc ? 'disabled' : 'primary'}/> + + + )} + + + ))} + + ))} + + + {page.map((row, i) => { + prepareRow(row) + return ( + + {row.cells.map(cell => { + return {cell.render('Cell')} + })} + + ) + })} + +
+
+ + + ) +} + +function PaginatedClientSide({ data, columns, searchProps }: PaginatedClientSideProps) { + return ( +
+ +
+ ) +} + +export default PaginatedClientSide \ No newline at end of file diff --git a/admin/admin-ui/client/source/components/hooks/Utils.ts b/admin/admin-ui/client/source/components/hooks/Utils.ts new file mode 100644 index 000000000..d01e62ca6 --- /dev/null +++ b/admin/admin-ui/client/source/components/hooks/Utils.ts @@ -0,0 +1,16 @@ +// eslint-disable-next-line @typescript-eslint/no-var-requires +const Settings = require('Settings'); +const restApi = Settings.app.rest_api; + +// Function to return formatted URL +export const getFormattedUrl = (url: string) => { + let fetchUrl = ''; + if (restApi.endsWith('/') && url.startsWith('/')) { + fetchUrl = restApi.slice(0, -1) + url; + } else if (!restApi.endsWith('/') && !url.startsWith('/')) { + fetchUrl = restApi + '/' + url; + } else { + fetchUrl = restApi + url; + } + return fetchUrl; +} \ No newline at end of file diff --git a/admin/admin-ui/client/source/components/hooks/dummyPayloads.js b/admin/admin-ui/client/source/components/hooks/dummyPayloads.js new file mode 100644 index 000000000..eb65962b1 --- /dev/null +++ b/admin/admin-ui/client/source/components/hooks/dummyPayloads.js @@ -0,0 +1,151 @@ +export const settings = { + "analyticsEnabled": false, + "keyManagerConfiguration": [ + { + "defaultConsumerKeyClaim": "azp", + "endpointConfigurations": [ + null, + null + ], + "displayName": "default", + "configurations": [ + { + "default": "admin", + "values": [ + {}, + {} + ], + "name": "consumer_key", + "multiple": true, + "tooltip": "Enter username to connect to key manager", + "label": "Consumer Key", + "type": "select", + "required": true, + "mask": true + }, + { + "default": "admin", + "values": [ + {}, + {} + ], + "name": "consumer_key", + "multiple": true, + "tooltip": "Enter username to connect to key manager", + "label": "Consumer Key", + "type": "select", + "required": true, + "mask": true + } + ], + "defaultScopesClaim": "scope", + "type": "default" + }, + { + "defaultConsumerKeyClaim": "azp", + "endpointConfigurations": [ + null, + null + ], + "displayName": "default", + "configurations": [ + { + "default": "admin", + "values": [ + {}, + {} + ], + "name": "consumer_key", + "multiple": true, + "tooltip": "Enter username to connect to key manager", + "label": "Consumer Key", + "type": "select", + "required": true, + "mask": true + }, + { + "default": "admin", + "values": [ + {}, + {} + ], + "name": "consumer_key", + "multiple": true, + "tooltip": "Enter username to connect to key manager", + "label": "Consumer Key", + "type": "select", + "required": true, + "mask": true + } + ], + "defaultScopesClaim": "scope", + "type": "default" + } + ], + "scopes": [ + "scopes", + "scopes" + ] + } + + export const tenant = { + "tenantId": -1234, + "tenantDomain": "carbon.super", + "username": "john" + } + + export const apiCategories = { + "count": 1, + "list": [ + { + "numberOfAPIs": 1, + "name": "Finance", + "description": "Finance related APIs", + "id": "01234567-0123-0123-0123-012345678901" + }, + { + "numberOfAPIs": 1, + "name": "Finance", + "description": "Finance related APIs", + "id": "01234567-0123-0123-0123-012345678901" + } + ] + }; + + export const applicationThrottlePolicies = { + "count": 2, + "list": [ + { + "defaultLimit": { + "type": "REQUESTCOUNTLIMIT", + "requestCount": { + "requestCount": 41, + "timeUnit": "min", + "unitTime": 1 + } + }, + "policyId": "cbee719f-ea93-4578-91a5-df94df99a008", + "policyName": "42PerMin", + "displayName": "41PerMin", + "description": "Allows 30 request per minute", + "isDeployed": false, + "type": "ApplicationThrottlePolicy" + }, + { + "defaultLimit": { + "type": "REQUESTCOUNTLIMIT", + "requestCount": { + "requestCount": 32, + "timeUnit": "min", + "unitTime": 1 + } + }, + "policyId": "d94c27e8-3867-482d-8218-9dc69e027ebe", + "policyName": "32PerMin", + "displayName": "32PerMin", + "description": "Allows 32 request per minute", + "isDeployed": false, + "type": "ApplicationThrottlePolicy" + } + ] +} \ No newline at end of file diff --git a/admin/admin-ui/client/source/components/hooks/getKeyManagers.tsx b/admin/admin-ui/client/source/components/hooks/getKeyManagers.tsx new file mode 100644 index 000000000..e396a663c --- /dev/null +++ b/admin/admin-ui/client/source/components/hooks/getKeyManagers.tsx @@ -0,0 +1,48 @@ +import axios from "axios"; +import { useEffect, useState } from "react"; + +type JSONValue = + | string + | number + | boolean + | { [x: string]: JSONValue } + | Array; + +interface orgProps { trigger: boolean, setTrigger: (boolean) => void } + +const getKeyManagers = ({trigger, setTrigger} : orgProps ) => { + const [data, setData] = useState(null); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(""); + + const viewData = () => { + axios('/api/am/admin/key-managers', { + method: 'GET', + withCredentials: true, + }) + .then((res) => { + setData(res.data); + }) + .catch((err) => { + setError(err); + }) + .finally(() => { + setLoading(false); + setTrigger(false); + }); + } + + useEffect(() => { + viewData(); + }, []); + + useEffect(() => { + if (trigger) { + viewData(); + } + }, [trigger]); + + return { data, loading, error }; +}; + +export default getKeyManagers; diff --git a/admin/admin-ui/client/source/components/hooks/getOrganizations.tsx b/admin/admin-ui/client/source/components/hooks/getOrganizations.tsx new file mode 100644 index 000000000..180c7ba4b --- /dev/null +++ b/admin/admin-ui/client/source/components/hooks/getOrganizations.tsx @@ -0,0 +1,48 @@ +import axios from "axios"; +import { useEffect, useState } from "react"; + +type JSONValue = + | string + | number + | boolean + | { [x: string]: JSONValue } + | Array; + +interface orgProps { trigger: boolean, setTrigger: (boolean) => void } + +const getOrganizations = ({trigger, setTrigger} : orgProps ) => { + const [data, setData] = useState(null); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(""); + + const viewData = () => { + axios('/api/admin/organizations', { + method: 'GET', + withCredentials: true, + }) + .then((res) => { + setData(res.data); + }) + .catch((err) => { + setError(err); + }) + .finally(() => { + setLoading(false); + setTrigger(false); + }); + } + + useEffect(() => { + viewData(); + }, []); + + useEffect(() => { + if (trigger) { + viewData(); + } + }, [trigger]); + + return { data, loading, error }; +}; + +export default getOrganizations; diff --git a/admin/admin-ui/client/source/components/hooks/useApplicationRatePlans.tsx b/admin/admin-ui/client/source/components/hooks/useApplicationRatePlans.tsx new file mode 100644 index 000000000..24f6f718d --- /dev/null +++ b/admin/admin-ui/client/source/components/hooks/useApplicationRatePlans.tsx @@ -0,0 +1,39 @@ +import axios from "axios"; +import { useEffect, useState } from "react"; +import { getFormattedUrl } from './Utils'; + +type JSONValue = + | string + | number + | boolean + | { [x: string]: JSONValue } + | Array; + + +const useApplicationRatePlans = () => { + const [data, setData] = useState(null); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(""); + + //const fetchUrl = getFormattedUrl('application-rate-plans'); + useEffect(() => { + axios('/api', { + method: 'GET', + withCredentials: true, + }) + .then((res) => { + setData(res.data); + }) + .catch((err) => { + setError(err); + }) + .finally(() => { + setLoading(false); + }); + }, []); + + + return { data, loading, error }; +}; + +export default useApplicationRatePlans; \ No newline at end of file diff --git a/admin/admin-ui/client/source/components/hooks/useAxios.tsx b/admin/admin-ui/client/source/components/hooks/useAxios.tsx new file mode 100644 index 000000000..626284d91 --- /dev/null +++ b/admin/admin-ui/client/source/components/hooks/useAxios.tsx @@ -0,0 +1,83 @@ +import { useEffect, useState } from "react"; +import axios from "axios"; +import { settings, tenant, apiCategories, applicationThrottlePolicies } from './dummyPayloads'; +// eslint-disable-next-line @typescript-eslint/no-var-requires +// const Settings = require('Settings'); +// const restApi = Settings.server.restApi; + +type JSONValue = + | string + | number + | boolean + | { [x: string]: JSONValue } + | Array; +interface useFetchProps { + url: string, +} + +/** =================== Remove the following logics when the actual impl is there */ +const getDummyData = (url) => { + return new Promise(function (resolve, reject) { + const resFunction = () => { + if (url === '/settings') { + resolve(settings) + } + if (url === '/tenant-info/YWRtaW5AY2FyYm9uLnN1cGVy') { + resolve(tenant) + } + if (url === '/api-categories') { + resolve(apiCategories) + } + if (url === '/throttling/policies/application') { + // Duplicate applicationThrottlePolicies.list to test pagination 100 times + const oneItem = applicationThrottlePolicies.list[0]; + for (let i = 0; i < 100; i++){ + applicationThrottlePolicies.list.push(oneItem); + } + resolve(applicationThrottlePolicies) + } + } + setTimeout(resFunction, 0); + }); +} +/** ========================= End of sleep function =========================== */ + +const useAxios = ({ url }: useFetchProps) => { + const [data, setData] = useState(null); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(""); + // let fetchUrl = ''; + // if (restApi.endsWith('/') && url.startsWith('/')) { + // fetchUrl = restApi.slice(0, -1) + url; + // } else if (!restApi.endsWith('/') && !url.startsWith('/')) { + // fetchUrl = restApi + '/' + url; + // } else { + // fetchUrl = restApi + url; + // } + + useEffect(() => { + /** =================== Remove the following logics when the actual impl is there */ + getDummyData(url) + .then((data) => { + setData(data); + }) + .finally(() => { + setLoading(false); + }); + /** ========================= End of dummy data return =========================== */ + // axios.get(fetchUrl) + // .then((res) => { + // setData(res.data); + // }) + // .catch((e) => { + // setError(e); + // }) + // .finally(() => { + // setLoading(false); + // }) + }, [url]); + + return { data, loading, error }; +}; + +export default useAxios; \ No newline at end of file diff --git a/admin/admin-ui/client/source/components/hooks/useAxiosPromise.tsx b/admin/admin-ui/client/source/components/hooks/useAxiosPromise.tsx new file mode 100644 index 000000000..14b97ad22 --- /dev/null +++ b/admin/admin-ui/client/source/components/hooks/useAxiosPromise.tsx @@ -0,0 +1,27 @@ +import axios from "axios"; +// eslint-disable-next-line @typescript-eslint/no-var-requires +const Settings = require('Settings'); +const restApi = Settings.server.restApi; +interface useFetchProps { + url: string, +} + +const useAxiosPromise = ({ url }: useFetchProps) => { + let fetchUrl = ''; + if (restApi.endsWith('/') && url.startsWith('/')) { + fetchUrl = restApi.slice(0, -1) + url; + } else if (!restApi.endsWith('/') && !url.startsWith('/')) { + fetchUrl = restApi + '/' + url; + } else { + fetchUrl = restApi + url; + } + const promise = axios.get(fetchUrl) + .then((res) => { + return (res.data); + }) + + + return promise; +}; + +export default useAxiosPromise; \ No newline at end of file diff --git a/admin/admin-ui/client/source/components/third-party/SimpleBar.js b/admin/admin-ui/client/source/components/third-party/SimpleBar.js new file mode 100644 index 000000000..d6d581ae0 --- /dev/null +++ b/admin/admin-ui/client/source/components/third-party/SimpleBar.js @@ -0,0 +1,63 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +// material-ui +import { alpha, styled } from '@mui/material/styles'; +import { Box } from '@mui/material'; + +// third-party +import SimpleBar from 'simplebar-react'; +import { BrowserView, MobileView } from 'react-device-detect'; + +// root style +const RootStyle = styled(BrowserView)({ + flexGrow: 1, + height: '100%', + overflow: 'hidden' +}); + +// scroll bar wrapper +const SimpleBarStyle = styled(SimpleBar)(({ theme }) => ({ + maxHeight: '100%', + '& .simplebar-scrollbar': { + '&:before': { + backgroundColor: alpha(theme.palette.grey[500], 0.48) + }, + '&.simplebar-visible:before': { + opacity: 1 + } + }, + '& .simplebar-track.simplebar-vertical': { + width: 10 + }, + '& .simplebar-track.simplebar-horizontal .simplebar-scrollbar': { + height: 6 + }, + '& .simplebar-mask': { + zIndex: 'inherit' + } +})); + +// ==============================|| SIMPLE SCROLL BAR ||============================== // + +export default function SimpleBarScroll({ children, sx, ...other }) { + return ( + <> + + + {children} + + + + + {children} + + + + ); +} + +SimpleBarScroll.propTypes = { + children: PropTypes.node, + sx: PropTypes.object +}; diff --git a/admin/admin-ui/client/source/config.ts b/admin/admin-ui/client/source/config.ts new file mode 100644 index 000000000..b015d6fa5 --- /dev/null +++ b/admin/admin-ui/client/source/config.ts @@ -0,0 +1,20 @@ +// ==============================|| THEME CONFIG ||============================== // + +const config = { + defaultPath: '/dashboard/default', + fontFamily: `'Montserrat', sans-serif;`, + i18n: 'en', + miniDrawer: false, + container: true, + mode: 'light', + presetColor: 'default', + themeDirection: 'ltr', + docUrl: 'https://apim.docs.wso2.com/en/' +}; + +export default config; +export const drawerWidth = 260; + +export const twitterColor = '#1DA1F2'; +export const facebookColor = '#3b5998'; +export const linkedInColor = '#0e76a8'; diff --git a/admin/admin-ui/client/source/context/AppContext.tsx b/admin/admin-ui/client/source/context/AppContext.tsx new file mode 100644 index 000000000..4063f87b7 --- /dev/null +++ b/admin/admin-ui/client/source/context/AppContext.tsx @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2019, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you 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. + */ +import React, { useContext } from 'react'; +import LoggedInUser from 'types/LoggedInUser'; + +interface AppContextProps { + settings: any; + user: LoggedInUser; + isSuperTenant: boolean; + selectedRoute: string; + setSelectedRoute: (route: string) => void; +} +const AppContext = React.createContext({} as AppContextProps); +export const useAppContext = () => useContext(AppContext); +export const AppContextProvider = AppContext.Provider; +export default AppContext; diff --git a/admin/admin-ui/client/source/data/APIClient.js b/admin/admin-ui/client/source/data/APIClient.js new file mode 100644 index 000000000..6e1584921 --- /dev/null +++ b/admin/admin-ui/client/source/data/APIClient.js @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you 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. + */ + +import SwaggerClient from 'swagger-client'; +import { Mutex } from 'async-mutex'; +import Configurations from 'Config'; +import AuthManager from 'AppData/AuthManager'; +import Utils from './Utils'; + +/** + * This class expose single swaggerClient instance created using the given swagger URL (Publisher, Store, ect ..) + * it's highly unlikely to change the REST API Swagger definition (swagger.json) file on the fly, + * Hence this singleton class help to preserve consecutive swagger client object creations saving redundant IO + * operations. + */ +class APIClient { + /** + * @param {Object} environment - Environment to get host for the swagger-client's spec property. + * @param {{}} args - Accept as an optional argument for APIClient constructor.Merge the given args with + * default args. + * @returns {APIClient} + */ + constructor(environment, args = {}) { + this.environment = environment || Utils.getCurrentEnvironment(); + SwaggerClient.http.withCredentials = true; + const promisedResolve = SwaggerClient.resolve({ + url: Utils.getSwaggerURL(), + requestInterceptor: (request) => { + request.headers.Accept = 'text/yaml'; + }, + }); + APIClient.spec = promisedResolve; + this._client = promisedResolve.then((resolved) => { + const argsv = Object.assign(args, { + spec: this._fixSpec(resolved.spec), + requestInterceptor: this._getRequestInterceptor(), + responseInterceptor: this._getResponseInterceptor(), + }); + SwaggerClient.http.withCredentials = true; + return new SwaggerClient(argsv); + }); + this._client.catch(AuthManager.unauthorizedErrorHandler); + this.mutex = new Mutex(); + } + + /** + * Expose the private _client property to public + * @returns {APIClient} an instance of APIClient class + */ + get client() { + return this._client; + } + + /** + * Get the ETag of a given resource key from the session storage + * @param {String} key - key of resource. + * @returns {String} ETag value for the given key + */ + static getETag(key) { + return sessionStorage.getItem('etag_' + key); + } + + /** + * Add an ETag to a given resource key into the session storage + * @param key {string} key of resource. + * @param etag {string} etag value to be stored against the key + */ + static addETag(key, etag) { + sessionStorage.setItem('etag_' + key, etag); + } + + /** + * Get Scope for a particular resource path + * + * @param resourcePath resource path of the action + * @param resourceMethod resource method of the action + */ + static getScopeForResource(resourcePath, resourceMethod) { + if (!APIClient.spec) { + SwaggerClient.http.withCredentials = true; + APIClient.spec = SwaggerClient.resolve({ url: Utils.getSwaggerURL() }); + } + return APIClient.spec.then((resolved) => { + return ( + resolved.spec.paths[resourcePath] + && resolved.spec.paths[resourcePath][resourceMethod] + && resolved.spec.paths[resourcePath][resourceMethod].security[0].OAuth2Security[0] + ); + }); + } + + /** + * Temporary method to fix the hostname attribute Till following issues get fixed ~tmkb + * https://github.com/swagger-api/swagger-js/issues/1081 + * https://github.com/swagger-api/swagger-js/issues/1045 + * @param spec {JSON} : Json object of the specification + * @returns {JSON} : Fixed specification + * @private + */ + _fixSpec(spec) { + const updatedSpec = spec; + const url = new URL(spec.servers[0].url); + if (this.environment.host !== url.host) { + url.host = this.environment.host; + if (Configurations.app.proxy_context_path && Configurations.app.proxy_context_path !== '') { + url.pathname = Configurations.app.proxy_context_path + url.pathname; + } + // updatedSpec.servers[0].url = String(url); + } + return updatedSpec; + } + + _getResponseInterceptor() { + /* + return (data) => { + if (data.headers.etag) { + APIClient.addETag(data.url, data.headers.etag); + } + + // If an unauthenticated response is received, we check whether the token is valid by introspecting it. + // If it is not valid, we need to clear the stored tokens (in cookies etc) in the browser by redirecting the + // user to logout. + if (data.status === 401 && data.body != null && data.body.description === 'Unauthenticated request') { + const userData = AuthManager.getUserFromToken(); + userData.catch((error) => { + console.error('Error occurred while checking token status. Hence redirecting to login', error); + window.location = Configurations.app.context + Utils.CONST.LOGOUT_CALLBACK; + }); + } + return data; + }; + */ + } + + /** + * + * + * @returns + * @memberof APIClient + */ + _getRequestInterceptor() { + /* + return (request) => { + const existingUser = AuthManager.getUser(this.environment.label); + if (!existingUser) { + console.log('User not found. Token refreshing failed.'); + return request; + } + let existingToken = AuthManager.getUser(this.environment.label).getPartialToken(); + const refToken = AuthManager.getUser(this.environment.label).getRefreshPartialToken(); + if (existingToken) { + request.headers.authorization = 'Bearer ' + existingToken; + return request; + } else { + console.log('Access token is expired. Trying to refresh.'); + if (!refToken) { + console.log('Refresh token not found. Token refreshing failed.'); + return request; + } + } + + const env = this.environment; + const promise = new Promise((resolve, reject) => { + this.mutex.acquire().then((release) => { + existingToken = AuthManager.getUser(env.label).getPartialToken(); + if (existingToken) { + request.headers.authorization = 'Bearer ' + existingToken; + release(); + resolve(request); + } else { + AuthManager.refresh(env).then((res) => res.json()) + .then(() => { + request.headers.authorization = 'Bearer ' + + AuthManager.getUser(env.label).getPartialToken(); + release(); + resolve(request); + }).catch((error) => { + console.error('Error:', error); + release(); + reject(); + }) + .finally(() => { + release(); + }); + } + }); + }); + + if (APIClient.getETag(request.url) + && (request.method === 'PUT' || request.method === 'DELETE' || request.method === 'POST')) { + request.headers['If-Match'] = APIClient.getETag(request.url); + } + return promise; + }; + */ + } +} + +APIClient.spec = null; + +export default APIClient; diff --git a/admin/admin-ui/client/source/data/APIClientFactory.js b/admin/admin-ui/client/source/data/APIClientFactory.js new file mode 100644 index 000000000..a11a67ac4 --- /dev/null +++ b/admin/admin-ui/client/source/data/APIClientFactory.js @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you 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. + */ + +import APIClient from './APIClient'; +import Utils from './Utils'; + +/** + * Class representing a Factory of APIClients + */ +class APIClientFactory { + /** + * Initialize a single instance of APIClientFactory + * @returns {APIClientFactory} + */ + constructor() { + /* eslint-disable no-underscore-dangle */ + // indicate “private” members of APIClientFactory that is why underscore has used here + if (APIClientFactory._instance) { + return APIClientFactory._instance; + } + + this._APIClientMap = new Map(); + APIClientFactory._instance = this; + /* eslint-enable no-underscore-dangle */ + } + + /** + * + * @param {Object} environment + * @returns {APIClient} APIClient object for the environment + */ + getAPIClient(environment = Utils.getDefaultEnvironment()) { + let apiClient = this._APIClientMap.get(environment.label); + + if (apiClient) { + return apiClient; + } + + apiClient = new APIClient(environment); + this._APIClientMap.set(environment.label, apiClient); + return apiClient; + } + + /** + * Remove an APIClient object from the environment + * @param {String} environmentLabel name of the environment + */ + destroyAPIClient(environmentLabel) { + this._APIClientMap.delete(environmentLabel); + } +} + +/** + * Single instance of APIClientFactory indicate “private” members of objects + * @type {APIClientFactory} + * @private + */ +// eslint-disable-next-line no-underscore-dangle +APIClientFactory._instance = null; + +export default APIClientFactory; diff --git a/admin/admin-ui/client/source/data/AuthManager.js b/admin/admin-ui/client/source/data/AuthManager.js new file mode 100644 index 000000000..cd175b6a8 --- /dev/null +++ b/admin/admin-ui/client/source/data/AuthManager.js @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you 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. + */ + +import qs from 'qs'; +import CONSTS from 'AppData/Constants'; +import Configurations from 'Config'; +import Utils from './Utils'; +import User from './User'; + +/** + * Class managing authentication + */ +class AuthManager { + constructor() { + this.isLogged = false; + this.username = null; + } + + /** + * Static method to handle unauthorized user action error catch, It will look for response status + * code and skip !401 errors + * @param {object} errorResponse + */ + static unauthorizedErrorHandler(errorResponse) { + if (errorResponse.status !== 401) { + /* Skip unrelated response code to handle in unauthorizedErrorHandler */ + throw errorResponse; + /* re throwing the error since we don't handle it here and propagate to downstream error + handlers in catch chain */ + } + const message = 'The session has expired.
You will be redirect to the login page ...'; + + throw new Error(errorResponse + message); + } + + /** + * An user object is return in present of logged in user info in browser local storage, at the same + * time checks for partialToken in the cookie as well. + * This may give a partial indication(passive check not actually check the token validity via an API) of + * whether the user has logged in or not, The actual API call may get denied + * if the cookie stored access token is invalid/expired + * @param {string} environmentName - label of the environment, the user to be retrieved from + * @returns {User | null} Is any user has logged in or not + */ + static getUser(environmentName = Utils.getCurrentEnvironment().label) { + // const userData = localStorage.getItem(`${User.CONST.LOCAL_STORAGE_USER}_${environmentName}`); + // const partialToken = Utils.getCookie(User.CONST.WSO2_AM_TOKEN_1, environmentName); + // const refreshToken = Utils.getCookie(User.CONST.WSO2_AM_REFRESH_TOKEN_1, environmentName); + // if (!(userData && (partialToken || refreshToken))) { + // return null; + // } + return { + name: 'admin@carbon.super', + _scopes: ['apim:admin', 'apim:admin_alert_manage', 'apim:admin_application_view', + 'apim:admin_operations', 'apim:admin_settings', 'apim:api_import_export', + 'apim:api_product_import_export', 'apim:api_workflow_approve', + 'apim:api_workflow_view', 'apim:app_import_export', 'apim:app_owner_change', + 'apim:bl_manage', 'apim:bl_view', 'apim:bot_data', + 'apim:environment_manage', 'apim:environment_read', 'apim:mediation_policy_create', + 'apim:mediation_policy_view', + 'apim:monetization_usage_publish', 'apim:policies_import_export', 'apim:role_manage', + 'apim:scope_manage', 'apim:tenantInfo', + 'apim:tenant_theme_manage', 'apim:tier_manage', 'apim:tier_view', 'openid'], + _remember: false, + _environmentName: 'Default', + rememberMe: false, + }; + // APK the following line need to be updated with the ID token info. + // return User.fromJson(JSON.parse(userData), environmentName); + } + + /** + * Do token introspection and Get the currently logged in user's details + * When user authentication happens via redirection flow, This method might get used to + * retrieve the user information + * after setting the access token parts in cookies, Because access token parts are stored in /admin_portal path , + * just making an external request in same path will submit both cookies, allowing the service to build the + * complete access token and do the introspection. + * Return a promise resolving to user object iff introspect calls return active user else null + * @static + * @returns {Promise} fetch response promise resolving to introspect response JSON or null otherwise + * @memberof AuthManager + */ + static getUserFromToken() { + const partialToken = Utils.getCookie(User.CONST.WSO2_AM_TOKEN_1); + if (!partialToken) { + return new Promise((resolve, reject) => reject(new Error(CONSTS.errorCodes.NO_TOKEN_FOUND))); + } + const introspectUrl = Configurations.app.context + Utils.CONST.INTROSPECT; + const promisedResponse = fetch(introspectUrl, { credentials: 'same-origin' }); + return promisedResponse + .then((response) => response.json()) + .then((data) => { + let user = null; + if (data.active) { + const currentEnv = Utils.getCurrentEnvironment(); + user = new User(currentEnv.label, data.username); + const scopes = data.scope.split(' '); + if (this.hasBasicLoginPermission(scopes)) { + user.scopes = scopes; + AuthManager.setUser(user, currentEnv.label); + } else { + console.warn('The user with ' + partialToken + " doesn't enough have permission!"); + throw new Error(CONSTS.errorCodes.INSUFFICIENT_PREVILEGES); + } + } else { + console.warn('The user with ' + partialToken + ' is not active!'); + throw new Error(CONSTS.errorCodes.INVALID_TOKEN); + } + return user; + }); + } + + /** + * Persist an user in browser local storage and in-memory, Since only one use can be + * logged into the application at a time, + * This method will override any previously persist user data. + * @param {User} user - An instance of the {User} class + * @param {string} environmentName - label of the environment to be set the user + */ + static setUser(user, environmentName = Utils.getCurrentEnvironment().label) { + if (!(user instanceof User)) { + throw new Error('Invalid user object'); + } + if (user) { + localStorage.setItem(`${User.CONST.LOCAL_STORAGE_USER}_${environmentName}`, JSON.stringify(user.toJson())); + } + } + + /** + * Clear all user records from the browser (opposite of `getUser`). + * partial token, Local storage user object etc + * consequent `getUser` user will fallback to `getUserFromToken`. + * @memberof User + * @returns {void} + */ + static discardUser() { + // Since we don't have multi environments currentEnv will always get `default` + const currentEnv = Utils.getCurrentEnvironment().label; + localStorage.removeItem(User.CONST.USER_EXPIRY_TIME); + localStorage.removeItem(`${User.CONST.LOCAL_STORAGE_USER}_${currentEnv}`); + Utils.getCookie(User.CONST.WSO2_AM_TOKEN_1, currentEnv); + Utils.getCookie(User.CONST.WSO2_AM_REFRESH_TOKEN_1, currentEnv); + } + + static hasBasicLoginPermission(scopes) { + if (scopes.includes('apim:admin')) { + return true; + } else { + let { minScopesToLogin } = Configurations.app; + if (!minScopesToLogin) { + minScopesToLogin = CONSTS.DEFAULT_MIN_SCOPES_TO_LOGIN; + } + for (let i = 0; i < minScopesToLogin.length; i++) { + if (!scopes.includes(minScopesToLogin[i])) { + return false; + } + } + return true; + } + } + + /** + * Return an user object given the login request response object + * @param {Object} response - Response object received from either Axios or Fetch libraries + * @param {String} environmentName - Name of the environment + * @returns {User} Instance of an user who is currently logged in (for the selected environment) + */ + static loginUserMapper(response, environmentName) { + const { data } = response; + const { AM_ACC_TOKEN_DEFAULT_P1, expires_in: expiresIn } = data; + const user = new User(environmentName, data.authUser); + user.setPartialToken(AM_ACC_TOKEN_DEFAULT_P1, expiresIn, Configurations.app.context); + user.setExpiryTime(expiresIn); + user.scopes = data.scopes.split(' '); + return user; + } + + /** + * Call Token API with refresh token grant type + * @param {Object} environment - Name of the environment + * @return {Promise} + */ + static refresh(environment) { + const params = { + refresh_token: AuthManager.getUser(environment.label).getRefreshPartialToken(), + validity_period: -1, + }; + const referrer = document.referrer.indexOf('https') !== -1 ? document.referrer : null; + const url = Configurations.app.context + environment.refreshTokenPath; + const headers = { + Accept: 'application/json', + 'Content-Type': 'application/x-www-form-urlencoded', + 'X-Alt-Referer': referrer, + }; + return fetch(url, { + method: 'POST', + body: qs.stringify(params), + headers, + }); + } +} + +export default AuthManager; diff --git a/admin/admin-ui/client/source/data/Constants.js b/admin/admin-ui/client/source/data/Constants.js new file mode 100644 index 000000000..6613f6dca --- /dev/null +++ b/admin/admin-ui/client/source/data/Constants.js @@ -0,0 +1,32 @@ +/** + * Copyright (c) 2019, WSO2 Inc. (http://wso2.com) All Rights Reserved. + * + * 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. + */ + +const CONSTS = { + API: 'API', + APIProduct: 'APIProduct', + HTTP_METHODS: ['get', 'put', 'post', 'delete', 'patch', 'head', 'options'], + errorCodes: { + INSUFFICIENT_PREVILEGES: '900403: Insufficient privileges to login', + UNEXPECTED_SERVER_ERROR: 'Unexpected token S in JSON at position 0', + INVALID_TOKEN: '900401: Invalid token', + NO_TOKEN_FOUND: '901401: No partial token found!', + }, + TENANT_STATE_ACTIVE: 'ACTIVE', + DEFAULT_MIN_SCOPES_TO_LOGIN: ['apim:api_workflow_view', 'apim:api_workflow_approve', 'apim:tenantInfo', + 'apim:admin_settings'], +}; + +export default CONSTS; diff --git a/admin/admin-ui/client/source/data/PermissionScopes.js b/admin/admin-ui/client/source/data/PermissionScopes.js new file mode 100644 index 000000000..23d2cc7ab --- /dev/null +++ b/admin/admin-ui/client/source/data/PermissionScopes.js @@ -0,0 +1,104 @@ +/* eslint-disable no-underscore-dangle */ +/* + * Copyright (c) 2019, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you 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. + */ + +import APIClientFactory from 'AppData/APIClientFactory'; +import Resource from './Resource'; + +/** + * An abstract representation of an API + */ +class Permissions extends Resource { + /** + *Creates an instance of Permissions to Scope mapping. + * @param {String} role user role name + * @param {Array} scopes list of scopes associate with above roles + * @memberof Permissions + */ + constructor(role, scopes) { + super(); + this.role = role; + this.scopes = scopes; + } + + /** + * + * + * @static + * @returns + * @memberof Permissions + */ + static systemScopes() { + const apiClient = new APIClientFactory().getAPIClient().client; + return apiClient.then((client) => { + return client.apis['System Scopes'].systemScopesGet(); + }); + } + + /** + * + * + * @static + * @returns + * @memberof Permissions + */ + static updateSystemScopes(updatedAPIPermissions) { + const payload = []; + for (const appScopes of Object.values(updatedAPIPermissions)) { + for (const scopeMap of appScopes) { + payload.push(scopeMap); + } + } + const scopeMapping = { count: payload.length, list: payload }; + + const apiClient = new APIClientFactory().getAPIClient().client; + return apiClient.then((client) => { + return client.apis['System Scopes'].updateRolesForScope({}, { requestBody: scopeMapping }); + }); + } + + /** + * + * + * @static + * @returns + * @memberof Permissions + */ + static getRoleAliases() { + const apiClient = new APIClientFactory().getAPIClient().client; + return apiClient.then((client) => { + return client.apis['System Scopes'].get_system_scopes_role_aliases(); + }); + } + + /** + * + * + * @static + * @memberof Permissions + */ + static updateRoleAliases(updatedRoleAliases) { + const roleAliasesMapping = { count: updatedRoleAliases.length, list: updatedRoleAliases }; + const apiClient = new APIClientFactory().getAPIClient().client; + return apiClient.then((client) => { + return client.apis['System Scopes'].put_system_scopes_role_aliases({}, { requestBody: roleAliasesMapping }); + }); + } +} + +export default Permissions; diff --git a/admin/admin-ui/client/source/data/README.md b/admin/admin-ui/client/source/data/README.md new file mode 100644 index 000000000..1a999a726 --- /dev/null +++ b/admin/admin-ui/client/source/data/README.md @@ -0,0 +1,21 @@ +## What is this directory ? + +// todo: modify this accordingly + +This directory contains the data fetching related source files.So these are vanilla JS source codes. Please use the `.js` +extension in the files created under + +``` +/source/src/app/data/ +``` + +directory. + +If es-lint suggest to rename the file extension to `.jsx` (That means you have jsx syntax there), + You are most probably putting the file in wrong directory. Consider moving it to + +``` +/source/src/app/components/ +``` + +directory. diff --git a/admin/admin-ui/client/source/data/Resource.js b/admin/admin-ui/client/source/data/Resource.js new file mode 100644 index 000000000..37447680e --- /dev/null +++ b/admin/admin-ui/client/source/data/Resource.js @@ -0,0 +1,73 @@ +/** + * Copyright (c), WSO2 Inc. (http://wso2.com) All Rights Reserved. + * + * 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. + */ +import APIClientFactory from './APIClientFactory'; +import Utils from './Utils'; + +/** * + * Abstract resource representation, Host for generic resource related methods + */ +export default class Resource { + /** + *Creates an instance of Resource. + * @memberof Resource + */ + constructor() { + this.client = new APIClientFactory().getAPIClient(Utils.getCurrentEnvironment()).client; + } + + /** + * @param data + * @returns {object} Metadata for API request + */ + static _requestMetaData(data = {}) { + /* TODO: This should be moved to an interceptor ~tmkb */ + return { + requestContentType: data['Content-Type'] || 'application/json', + }; + } + + /** + * Check whether current resource is of type APIProduct + * + * @returns {boolean} condition + * @memberof Resource + */ + isAPIProduct() { + return this.apiType === 'APIProduct'; + } + + /** + * Check whether current api is of type WebSocket + * + * @returns {boolean} condition + * @memberof Resource + */ + isWebSocket() { + return this.type === 'WS'; + } + + isGraphql() { + return this.type === 'GRAPHQL'; + } + + isSOAPToREST() { + return this.type === 'SOAPTOREST'; + } + + isSOAP() { + return this.type === 'SOAP'; + } +} diff --git a/admin/admin-ui/client/source/data/User.js b/admin/admin-ui/client/source/data/User.js new file mode 100644 index 000000000..cba1c902e --- /dev/null +++ b/admin/admin-ui/client/source/data/User.js @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you 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. + */ + +import Utils from './Utils'; + +/** + * Represent an user logged in to the application, There will be allays one user per session and + * this user details will be persist in browser local-storage. + */ +export default class User { + /** + * Create a user for the given environment + * @param {string} environmentName - name of the environment + * @param {string} name - name of the cookie + * @param {boolean} remember + * @returns {User|null} user object + */ + constructor(environmentName, name, remember = false) { + /* eslint-disable no-underscore-dangle */ + // indicate “private” members of APIClientFactory that is why underscore has used here + const user = User._userMap.get(environmentName); + if (user) { + return user; + } + this.name = name; + this._scopes = []; + this._remember = remember; + this._environmentName = environmentName; + User._userMap.set(environmentName, this); + } + + /** + * OAuth scopes which are available for use by this user + * @returns {Array} - An array of scopes + */ + get scopes() { + return this._scopes; + } + + /** + * Set OAuth scopes available to be used by this user + * @param {Array} newScopes - An array of scopes + */ + set scopes(newScopes) { + Object.assign(this.scopes, newScopes); + } + + /** + * User utility method to create an user from JSON object. + * @param {JSON} userJson - Need to provide user information in JSON structure to create an user object + * @param {String} environmentName - Name of the environment to be assigned to the user + * @returns {User} - An instance of User(this) class. + */ + static fromJson(userJson, environmentName = Utils.getCurrentEnvironment().label) { + if (!userJson.name) { + throw new Error('Need to provide user `name` key in the JSON object, to create an user'); + } + + const _user = new User(environmentName, userJson.name); + _user.scopes = userJson.scopes; + _user.rememberMe = userJson.remember; + return _user; + } + + /** + * Get the JS accessible access token fragment from cookie storage. + * @returns {String|null} + */ + getPartialToken() { + return Utils.getCookie(User.CONST.WSO2_AM_TOKEN_1, this._environmentName); + } + + /** + * Get the JS accessible refresh token fragment from cookie storage. + * @returns {String|null} + */ + getRefreshPartialToken() { + return Utils.getCookie(User.CONST.WSO2_AM_REFRESH_TOKEN_1, this._environmentName); + } + + /** + * Store the JavaScript accessible access token segment in cookie storage + * @param {String} newToken - Part of the access token which needs when accessing REST API + * @param {Number} validityPeriod - Validity period of the cookie in seconds + * @param {String} path - Path which need to be set to cookie + */ + setPartialToken(newToken, validityPeriod, path) { + Utils.deleteCookie(User.CONST.WSO2_AM_TOKEN_1, path, this._environmentName); + Utils.setCookie(User.CONST.WSO2_AM_TOKEN_1, newToken, validityPeriod, path, this._environmentName); + } + + /** + * Get the expiry time of the user + * @returns {Date} JS Date object of the expiring time of the user + */ + getExpiryTime() { + const expireTime = +localStorage.getItem(User.CONST.USER_EXPIRY_TIME); + return new Date(expireTime); + } + + /** + * Set user expiry time, User validity expires with the expiry of user's access token + * Negative value will imply removal of existing expiry time + * @param {Integer} expireTime of seconds till the expire time from the current time + * @returns {Integer} expire time + */ + setExpiryTime(expireTime) { + if (expireTime < 0) { + localStorage.removeItem(User.CONST.USER_EXPIRY_TIME); + return expireTime; + } + const currentTime = Date.now(); + const timeDiff = 1000 * expireTime; + localStorage.setItem(User.CONST.USER_EXPIRY_TIME, currentTime + timeDiff); + this.expiryTime = new Date(currentTime + timeDiff); + return this.expiryTime; + } + + /** + * + * @param type + */ + checkPermission() { + throw new Error('Not implemented!'); + } + + /** + * Get tenant domain from username + * sc1 - normal time : td is always carbon.super + * sc2 - tenanted : td can be something + * sc3 - tenanted : td can be carbon.super + */ + getTenantDomain() { + const domains = this.name.split('@'); + if (domains.length > 1) { + return domains[domains.length - 1]; + } + return null; + } + + /** + * Provide user data in JSON structure. + * @returns {JSON} - JSON representation of the user object + */ + toJson() { + return { + name: this.name, + scopes: this._scopes, + remember: this._remember, + expiryTime: this.getExpiryTime(), + }; + } +} + +User.CONST = { + WSO2_AM_TOKEN_MSF4J: 'WSO2_AM_TOKEN_MSF4J', + WSO2_AM_TOKEN_1: 'WSO2_AM_TOKEN_1', + WSO2_AM_REFRESH_TOKEN_1: 'WSO2_AM_REFRESH_TOKEN_1', + ADMIN_CLIENT_ID: 'CLIENT_ID', + LOCAL_STORAGE_USER: 'wso2_user_admin', + USER_EXPIRY_TIME: 'user_expiry_time', + ADMIN_SESSION_STATE: 'admin_session_state', +}; +/** + * Map of users (key = environmentLabel, value = User instance) + * @type {Map} + * @private + */ +User._userMap = new Map(); +/* eslint-enable no-underscore-dangle */ diff --git a/admin/admin-ui/client/source/data/Utils.js b/admin/admin-ui/client/source/data/Utils.js new file mode 100644 index 000000000..edbaae7c9 --- /dev/null +++ b/admin/admin-ui/client/source/data/Utils.js @@ -0,0 +1,360 @@ +/* + * Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you 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. + */ +// import Configurations from 'Config'; +/** + * Utility class for Admin Portal application + */ +class Utils { + /** + * Get JavaScript accessible cookies saved in browser, by giving the cooke name. + * @param {String} nameWithEnv - Name of the cookie which need to be retrieved + * @param {String} environmentName - label of the environment of the cookie + * @returns {String|null} - If found a cookie with given name , return its value,Else null value is returned + */ + static getCookie(name, environmentName = Utils.getCurrentEnvironment().label) { + const nameWithEnv = `${name}_${environmentName}`; + + const pairs = document.cookie.split(';'); + let cookie = null; + for (let pair of pairs) { + pair = pair.split('='); + const cookieName = pair[0].trim(); + if (pair[1] !== 'undefined') { + const value = encodeURIComponent(pair[1]); + if (cookieName === nameWithEnv) { + cookie = value; + break; + } + } + } + return cookie; + } + + /** + * Get JavaScript accessible cookies saved in browser, by giving the cooke name. + * @param {String} name - Name of the cookie which need to be retrieved + * @returns {String|null} - If found a cookie with given name , return its value,Else null value is returned + */ + static getCookieWithoutEnvironment(name) { + const pairs = document.cookie.split(';'); + let cookie = null; + for (let pair of pairs) { + pair = pair.split('='); + const cookieName = pair[0].trim(); + if (pair[1] !== 'undefined') { + const value = encodeURIComponent(pair[1]); + if (cookieName === name) { + cookie = value; + break; + } + } + } + return cookie; + } + + /** + * Delete a browser cookie given its name + * @param {String} name - Name of the cookie which need to be deleted + * @param {String} path - Path of the cookie which need to be deleted + * @param {String} environmentName - label of the environment of the cookie + */ + static deleteCookie(name, path, environmentName = Utils.getCurrentEnvironment().label) { + document.cookie = `${name}_${environmentName}=; path=${path}; expires=Thu, 01 Jan 1970 00:00:01 GMT`; + } + + /** + * Set a cookie with given name and value assigned to it. Cookies can be only set to the same origin, + * which the script is running + * @param {String} name - Name of the cookie which need to be set + * @param {String} value - Value of the cookie, expect it to be URLEncoded + * @param {number} validityPeriod - (Optional) Validity period of the cookie in seconds + * @param {String} path - Path which needs to set the given cookie + * @param {String} environmentName - Name of the environment to be appended to cookie name + * @param {boolean} secured - secured parameter is set + */ + static setCookie( + name, + value, + validityPeriod, + path = '/', + environmentName = Utils.getCurrentEnvironment().label, + secured = true, + ) { + let expiresDirective = ''; + const securedDirective = secured ? '; Secure' : ''; + if (validityPeriod) { + const date = new Date(); + if (validityPeriod < 0) { + date.setTime(date.getTime() + 1000000000000); + } else { + date.setTime((date.getTime() + validityPeriod) * 1000); + } + expiresDirective = '; expires=' + date.toUTCString(); + } + + document.cookie = `${name}_${environmentName}=${value}; path=${path}${expiresDirective}${securedDirective}`; + } + + /** + * Given an object returns whether the object is empty or not + * @param {Object} object - Any JSON object + * @returns {boolean} + */ + static isEmptyObject(object) { + return Object.keys(object).length === 0 && object.constructor === Object; + } + + /** + * Get the current environment from local-storage + * @returns {Object} environment: {label, host, loginTokenPath} + */ + static getCurrentEnvironment() { + if (Utils.environment) { + return Utils.environment; + } + + const environmentData = localStorage.getItem(Utils.CONST.LOCAL_STORAGE_ENVIRONMENT); + if (!environmentData) { + return Utils.getDefaultEnvironment(); + } + + return JSON.parse(environmentData); + } + + /** + * Get current environment's index from the given environment array + * @param {Array} environments - Array of environments + * @param {string} name - name of the environment + * @returns {number} + */ + static getEnvironmentID(environments, name = Utils.getCurrentEnvironment().label) { + if (!name) { + return 0; + } + + for (let i = 0; i < environments.length; i++) { + if (name === environments[i].label) { + return i; + } + } + return -1; + } + + /** + * Store the given environment in local-storage + * @param {object} defaultEnvironment + */ + static setEnvironment(environment) { + let defaultEnvironment = environment; + if (!environment) { + defaultEnvironment = Utils.getDefaultEnvironment(); + } + + if (!environment.host) { + defaultEnvironment.host = window.location.host; + } + // Store environment. + Utils.environment = defaultEnvironment; + localStorage.setItem(Utils.CONST.LOCAL_STORAGE_ENVIRONMENT, JSON.stringify(defaultEnvironment)); + } + + /** + * + * Get swagger definition URL + * @static + * @returns + * @memberof Utils + */ + static getSwaggerURL() { + return 'https://localhost:4000/conf/admin-api.yaml'; + + // if (Configurations.app.proxy_context_path) { + // return 'https://' + // + Utils.getCurrentEnvironment().host + // + Configurations.app.proxy_context_path + // + Utils.CONST.SWAGGER_JSON; + // } else { + // return 'https://' + // + Utils.getCurrentEnvironment().host + // + Utils.CONST.SWAGGER_JSON; + // } + } + + /** + * Return the time difference between the current time and the given time in the Date object in seconds + * @param targetTime {Date|Integer} Date object which needs to be compared with current time + * @returns {Integer} Time difference in seconds + */ + static timeDifference(targetTime) { + const currentTime = Date.now(); + return Math.floor((targetTime - currentTime) / 1000); + } + + /** + * Set Auto login info in local-storage according to environment + * @param {Array} environments - Array of Environment objects + * @param {Array} configs - Array of Auth Config objects + */ + static setMultiEnvironmentOverviewEnabledInfo(environments, configs) { + const autoLoginInfo = {}; + if (!Array.isArray(environments) || !Array.isArray(configs)) { + console.error('Error while storing auto login configs in local-storage'); + } + + for (let i = 0; i < environments.length; i++) { + autoLoginInfo[environments[i].label] = configs[i].is_multi_environment_overview_enabled.value; + } + + const data = JSON.stringify(autoLoginInfo); + localStorage.setItem(Utils.CONST.MULTI_ENVIRONMENT_OVERVIEW_ENABLED, data); + } + + /** + * Get whether Multi-Environment Overview feature is enabled in the specified environment or not + * @param environmentName - Name of the environment + * @return {Boolean|undefined} auto login enabled + */ + static isMultiEnvironmentOverviewEnabled(environmentName = Utils.getCurrentEnvironment().label) { + const autoLoginInfo = JSON.parse(localStorage.getItem(Utils.CONST.MULTI_ENVIRONMENT_OVERVIEW_ENABLED)); + return autoLoginInfo[environmentName]; + } + + /** + * Get an environment object with default values. + * @returns {Object} environment: {label: string, host: string, loginTokenPath: string} + * @private + */ + static getDefaultEnvironment() { + return { + label: 'Default', + host: window.location.host, + loginTokenPath: '/login/token', + refreshTokenPath: '/services/refresh', + }; + } + + /** + * Recursively freeze and object properties. + * Source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze + * @static + * @param {Object} object Object that needs to be frozen + * @returns {Object} Completely freeze an object + * @memberof Utils + */ + static deepFreeze(object) { + if (Object.isFrozen(object)) { + return object; + } + const trickObject = object; // This is to satisfy the es-lint rule + // Retrieve the property names defined on object + const propNames = Object.getOwnPropertyNames(object); + + // Freeze properties before freezing self + for (const name of propNames) { + const value = object[name]; + trickObject[name] = value && typeof value === 'object' ? Utils.deepFreeze(value) : value; + } + + return Object.freeze(object); + } + + /** + * + * + * @static + * @param {*} hex Color value in hex + * @param {*} alpha alpha channel intensity (0.0 to 1.0) + * @returns {String} CSS friendly RGBA string + * @memberof Utils + */ + static hexToRGBA(hex, alpha) { + const r = parseInt(hex.slice(1, 3), 16); + const g = parseInt(hex.slice(3, 5), 16); + const b = parseInt(hex.slice(5, 7), 16); + + if (alpha) { + return 'rgba(' + r + ', ' + g + ', ' + b + ', ' + alpha + ')'; + } else { + return 'rgb(' + r + ', ' + g + ', ' + b + ')'; + } + } + + /** + * Force file download in browser + * + * @static + * @param {*} response + * @memberof Utils + */ + static forceDownload(response) { + let fileName = ''; + const contentDisposition = response.headers['content-disposition']; + + if (contentDisposition && contentDisposition.indexOf('attachment') !== -1) { + const fileNameReg = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/; + const matches = fileNameReg.exec(contentDisposition); + if (matches != null && matches[1]) fileName = matches[1].replace(/['"]/g, ''); + } + const contentType = response.headers['content-type']; + const blob = new Blob([response.data], { + type: contentType, + }); + if (typeof window.navigator.msSaveBlob !== 'undefined') { + window.navigator.msSaveBlob(blob, fileName); + } else { + const URL = window.URL || window.webkitURL; + const downloadUrl = URL.createObjectURL(blob); + + if (fileName) { + const aTag = document.createElement('a'); + if (typeof aTag.download === 'undefined') { + window.location = downloadUrl; + } else { + aTag.href = downloadUrl; + aTag.download = fileName; + document.body.appendChild(aTag); + aTag.click(); + } + } else { + window.location = downloadUrl; + } + + setTimeout(() => { + URL.revokeObjectURL(downloadUrl); + }, 100); + } + } +} + +Utils.CONST = { + // TODO: fix/remove below wrong paths + MULTI_ENVIRONMENT_OVERVIEW_ENABLED: 'multi_env_overview', + + LOGOUT_CALLBACK: '/services/auth/callback/logout', + INTROSPECT: '/services/auth/introspect', + SWAGGER_JSON: '/api/admin/v3/swagger.yaml', + PROTOCOL: 'https://', +}; + +/** + * Current environment + * @type {object} environment object + * @private + */ +Utils.environment = undefined; +export default Utils; diff --git a/admin/admin-ui/client/source/data/api.js b/admin/admin-ui/client/source/data/api.js new file mode 100644 index 000000000..5ba5e67e2 --- /dev/null +++ b/admin/admin-ui/client/source/data/api.js @@ -0,0 +1,977 @@ +/** + * Copyright (c) 2020, WSO2 Inc. (http://wso2.com) All Rights Reserved. + * + * 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. + */ + +/* eslint-disable */ +import Utils from './Utils'; +import Resource from './Resource'; +import cloneDeep from 'lodash.clonedeep'; +import APIClientFactory from 'AppData/APIClientFactory'; + +/** + * An abstract representation of an API + */ +class API extends Resource { + constructor(name, version, context, kwargs) { + super(); + let properties = kwargs; + if (name instanceof Object) { + properties = name; + Utils.deepFreeze(properties); + } else { + this.name = name; + this.version = version; + this.context = context; + this.isDefaultVersion = false; + this.gatewayEnvironments = ['Default']; //todo: load the environments from settings API + this.transport = ['http', 'https']; + this.visibility = 'PUBLIC'; + this.endpointConfig = { + endpoint_type: 'http', + sandbox_endpoints: { + url: '', + }, + production_endpoints: { + url: '', + }, + }; + } + this.apiType = API.CONSTS.API; + this._data = properties; + for (const key in properties) { + if (Object.prototype.hasOwnProperty.call(properties, key)) { + this[key] = properties[key]; + } + } + } + + /** + * + * @param data + * @returns {object} Metadata for API request + * @private + */ + _requestMetaData() { + Resource._requestMetaData(); + } + + /** + * + * Instance method of the API class to provide raw JSON object + * which is API body friendly to use with REST api requests + * Use this method instead of accessing the private _data object for + * converting to a JSON representation of an API object. + * Note: This is deep coping, Use sparingly, Else will have a bad impact on performance + * Basically this is the revers operation in constructor. + * This method simply iterate through all the object properties (excluding the properties in `excludes` list) + * and copy their values to new object. + * So use this method with care!! + * @memberof API + * @param {Array} [userExcludes=[]] List of properties that are need to be excluded from the generated JSON object + * @returns {JSON} JSON representation of the API + */ + toJSON(userExcludes = []) { + var copy = {}, + excludes = ['_data', 'client', 'apiType', ...userExcludes]; + for (var prop in this) { + if (!excludes.includes(prop)) { + copy[prop] = cloneDeep(this[prop]); + } + } + return copy; + } + + /** + * Importing a WSDL and creating an API by a .wsdl file or a WSDL archive zip file + * + * @static + * @param {*} url WSDL url + * @param {*} additionalProperties additional properties of the API eg: name, version, context + * @param {*} implementationType SOAPTOREST or SOAP + * @returns {API} API object which was created + * @memberof Wsdl + */ + static importByUrl(url, additionalProperties, implementationType = 'SOAP') { + const apiClient = new APIClientFactory().getAPIClient( + Utils.getCurrentEnvironment(), + ).client; + return apiClient.then((client) => { + client.apis.APIs; + const promisedResponse = client.apis.APIs.importWSDLDefinition({ + url, + additionalProperties: JSON.stringify(additionalProperties), + implementationType, + }); + + return promisedResponse.then((response) => new API(response.body)); + }); + } + + /** + * Get settings of an API + */ + getSettings() { + // const promisedSettings = this.client.then(client => { + // return client.apis['Settings'].get_settings(); + // }); + // return promisedSettings.then(response => response.body); + const apiCall = fetch('http://localhost:81/chanaka3d/wso-2_api_manager_admin/v3/settings', { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + }, + }) + .then((r) => { + console.log(r); + return (r.json() + ); + }); + return apiCall.then((data) => data); + } + + /** + * Retrieve scopes for a particular user + */ + getUserScope(username, scope) { + return this.client.then((client) => { + const data = { + username: username, + scopeName: btoa(scope), + }; + return client.apis['System Scopes'].systemScopesScopeNameGet( + data, + this._requestMetaData(), + ); + }); + } + + /** + * Validate a given role + */ + validateSystemRole(role) { + const promise = this.client.then(client => { + return client.apis.Roles.validateSystemRole({ roleId: role }); + }); + return promise; + } + + /** + * Get list of advanced throttling policies + */ + getThrottlingPoliciesAdvanced() { + return this.client.then((client) => { + return client.apis['Advanced Policy (Collection)'].get_throttling_policies_advanced( + this._requestMetaData(), + ); + }); + } + + /** + * Get list of api categories + */ + getThrottlingPoliciesAdvancedPolicyId(policyId) { + return this.client.then((client) => { + return client.apis['Advanced Policy (Individual)'].get_throttling_policies_advanced__policyId_( + { policyId: policyId }, + this._requestMetaData(), + ); + }); + } + + /** + * Update an advanced throttling policy + */ + putThrottlingPoliciesAdvanced(policyId, policy) { + return this.client.then((client) => { + return client.apis['Advanced Policy (Individual)'].put_throttling_policies_advanced__policyId_( + { + policyId: policyId, + 'Content-Type': 'application/json', + }, + { requestBody: policy }, + this._requestMetaData(), + ); + }); + } + + /** + * Add new advanced throttling policy + */ + postThrottlingPoliciesAdvanced(policy) { + return this.client.then((client) => { + return client.apis['Advanced Policy (Collection)'].post_throttling_policies_advanced( + { 'Content-Type': 'application/json' }, + { requestBody: policy }, + this._requestMetaData(), + ); + }); + } + /** + * delete policy + */ + deleteThrottlingPoliciesAdvanced(policyId) { + return this.client.then((client) => { + return client.apis['Advanced Policy (Individual)'].delete_throttling_policies_advanced__policyId_( + { policyId: policyId }, + this._requestMetaData(), + ); + }); + } + + + /** + * Get list of api categories + */ + apiCategoriesListGet() { + return this.client.then((client) => { + return client.apis['API Category (Collection)'].get_api_categories( + this._requestMetaData(), + ); + }); + } + + /** + * Update an API category + */ + updateAPICategory(id, name, description) { + return this.client.then((client) => { + const data = { + name: name, + description: description, + }; + return client.apis[ + 'API Category (Individual)' + ].put_api_categories__apiCategoryId_( + { apiCategoryId: id }, + { requestBody: data }, + this._requestMetaData(), + ); + }); + } + + /** + * Delete an API Category + */ + deleteAPICategory(id) { + return this.client.then((client) => { + return client.apis[ + 'API Category (Individual)' + ].delete_api_categories__apiCategoryId_( + { apiCategoryId: id }, + this._requestMetaData(), + ); + }); + } + + /** + * Add an API Category + */ + createAPICategory(name, description) { + return this.client.then((client) => { + const data = { + name: name, + description: description, + }; + const payload = { + 'Content-Type': 'application/json', + }; + return client.apis['API Category (Individual)'].post_api_categories( + payload, + { requestBody: data }, + this._requestMetaData(), + ); + }); + } + + /** + * Get Application Throttling Policies + */ + applicationThrottlingPoliciesGet() { + return this.client.then((client) => { + return client.apis['Application Policy (Collection)'].get_throttling_policies_application( + this._requestMetaData(), + ); + }); + } + + /** + * Delete an Application Throttling Policy + */ + deleteApplicationThrottlingPolicy(policyId) { + return this.client.then((client) => { + return client.apis['Application Policy (Individual)'].delete_throttling_policies_application__policyId_( + { policyId: policyId }, + this._requestMetaData(), + ); + }); + } + + /** + * Add a Subscription Throttling Policy + */ + addSubscriptionThrottlingPolicy(body) { + return this.client.then((client) => { + const payload = { + 'Content-Type': 'application/json', + }; + return client.apis['Subscription Policy (Collection)'].post_throttling_policies_subscription( + payload, + { requestBody: body }, + this._requestMetaData(), + ); + }); + } + + /** + * Delete a Subscription Throttling Policy + */ + deleteSubscriptionPolicy(policyId) { + return this.client.then((client) => { + return client.apis['Subscription Policy (Individual)'].delete_throttling_policies_subscription__policyId_( + { policyId: policyId }, + this._requestMetaData(), + ); + }); + } + + /** + * Update a Subscription Throttling Policy + */ + updateSubscriptionThrottlingPolicy(policyId, body) { + return this.client.then((client) => { + const payload = { + policyId: policyId, + 'Content-Type': 'application/json', + }; + return client.apis['Subscription Policy (Individual)'].put_throttling_policies_subscription__policyId_( + payload, + { requestBody: body }, + this._requestMetaData(), + ); + }); + } + + /** + * Get details of a Subscription Throttling Policy + */ + subscriptionThrottlingPolicyGet(policyId) { + return this.client.then((client) => { + return client.apis['Subscription Policy (Individual)'].get_throttling_policies_subscription__policyId_( + { policyId: policyId }, + this._requestMetaData(), + ); + }); + } + + /** + * Add an Application Throttling Policy + */ + addApplicationThrottlingPolicy(body) { + return this.client.then((client) => { + const payload = { + 'Content-Type': 'application/json', + }; + return client.apis['Application Policy (Collection)'].post_throttling_policies_application( + payload, + { requestBody: body }, + this._requestMetaData(), + ); + }); + } + + /** + * Get details of an Application Throttling Policy + */ + applicationThrottlingPolicyGet(policyId) { + return this.client.then((client) => { + return client.apis['Application Policy (Individual)'].get_throttling_policies_application__policyId_( + { policyId: policyId }, + this._requestMetaData(), + ); + }); + } + + /** + * Update an Application Throttling Policy + */ + updateApplicationThrottlingPolicy(policyId, body) { + return this.client.then((client) => { + const payload = { + policyId: policyId, + 'Content-Type': 'application/json', + }; + return client.apis['Application Policy (Individual)'].put_throttling_policies_application__policyId_( + payload, + { requestBody: body }, + this._requestMetaData(), + ); + }); + } + + /** + * Get a list of applications from all users + */ + getApplicationList(params) { + return this.client.then((client) => { + return client.apis['Application (Collection)'].get_applications( + params, this._requestMetaData(), + ); + }); + } + + /** + * Get Subscription Throttling Policies + */ + getSubscritionPolicyList() { + return this.client.then((client) => { + return client.apis['Subscription Policy (Collection)'].get_throttling_policies_subscription( + this._requestMetaData(), + ); + }); + } + + /** + * Update an application's owner + */ + updateApplicationOwner(id, owner) { + return this.client.then((client) => { + return client.apis[ + 'Application' + ].post_applications__applicationId__change_owner( + { owner: owner, applicationId: id }, + this._requestMetaData(), + ); + }); + } + + /** + * Get a list of available Gateway Environments + */ + getGatewayEnvironmentList() { + return this.client.then((client) => { + return client.apis['Environments'].get_environments( + this._requestMetaData(), + ); + }); + } + + /** + * Delete a Gateway Environment + */ + deleteGatewayEnvironment(id) { + return this.client.then((client) => { + return client.apis['Environments'].delete_environments__environmentId_( + { environmentId: id }, + this._requestMetaData(), + ); + }); + } + + /** + * Add a Gateway Environment + */ + addGatewayEnvironment(name, displayName, description, vhosts, provider = "wso2", callback = null) { + return this.client.then((client) => { + const data = { name, displayName, description, vhosts, provider }; + const payload = { + 'Content-Type': 'application/json', + }; + return client.apis['Environments'].post_environments( + payload, + { requestBody: data }, + this._requestMetaData(), + ); + }); + } + + /** + * Update a Gateway Environment + */ + updateGatewayEnvironment(id, name, displayName, description, vhosts, callback = null) { + return this.client.then((client) => { + const data = { name, displayName, description, vhosts }; + return client.apis['Environments'].put_environments__environmentId_( + { environmentId: id }, + { requestBody: data }, + this._requestMetaData(), + ); + }); + } + + /** + * Get Blacklist Policies + */ + blacklistPoliciesGet() { + return this.client.then((client) => { + return client.apis['Deny Policies (Collection)'].get_throttling_deny_policies( + this._requestMetaData(), + ); + }); + } + + /** + * Delete an Deny Policy + */ + deleteBlacklistPolicy(policyId) { + return this.client.then((client) => { + return client.apis['Deny Policy (Individual)'].delete_throttling_deny_policy__conditionId_( + { conditionId: policyId }, + this._requestMetaData(), + ); + }); + } + + /** + * Add a Deny Policy + */ + addBlacklistPolicy(body) { + return this.client.then((client) => { + const payload = { + 'Content-Type': 'application/json', + }; + return client.apis['Deny Policies (Collection)'].post_throttling_deny_policies( + payload, + { requestBody: body }, + this._requestMetaData(), + ); + }); + } + + /** + * Get details of a Deny Policy + */ + blacklistPolicyGet(policyId) { + return this.client.then((client) => { + return client.apis['Deny Policy (Individual)'].get_throttling_deny_policy__conditionId_( + { conditionId: policyId }, + this._requestMetaData(), + ); + }); + } + + /** + * Update the Condition Status of a Deny Policy + */ + updateBlacklistPolicy(policyId, conditionStatus) { + return this.client.then((client) => { + const payload = { + conditionStatus: conditionStatus, + }; + return client.apis['Deny Policy (Individual)'].patch_throttling_deny_policy__conditionId_( + { conditionId: policyId, 'Content-Type': 'application/json', }, + { requestBody: payload }, + this._requestMetaData(), + ); + }); + } + + /** + * Get Custom Policies + */ + customPoliciesGet() { + return this.client.then((client) => { + return client.apis['Custom Rules (Collection)'].get_throttling_policies_custom( + this._requestMetaData(), + ); + }); + } + + /** + * Add a Custom Policy + */ + addCustomPolicy(body) { + return this.client.then((client) => { + const payload = { + 'Content-Type': 'application/json', + }; + return client.apis['Custom Rules (Collection)'].post_throttling_policies_custom( + payload, + { requestBody: body }, + this._requestMetaData(), + ); + }); + } + + /** + * Delete a Custom Policy + */ + deleteCustomPolicy(policyId) { + return this.client.then((client) => { + return client.apis['Custom Rules (Individual)'].delete_throttling_policies_custom__ruleId_( + { ruleId: policyId }, + this._requestMetaData(), + ); + }); + } + + /** + * Get details of a Custom Policy + */ + customPolicyGet(policyId) { + return this.client.then((client) => { + return client.apis['Custom Rules (Individual)'].get_throttling_policies_custom__ruleId_( + { ruleId: policyId }, + this._requestMetaData(), + ); + }); + } + + /** + * Update a Custom Policy + */ + updateCustomPolicy(policyId, body) { + return this.client.then((client) => { + const payload = { + ruleId: policyId, + 'Content-Type': 'application/json', + }; + return client.apis['Custom Rules (Individual)'].put_throttling_policies_custom__ruleId_( + payload, + { requestBody: body }, + this._requestMetaData(), + ); + }); + } + + /** + * Get Detected bot data + */ + getDetectedBotData() { + return this.client.then((client) => { + return client.apis['default'].getBotDetectionData( + this._requestMetaData(), + ); + }); + } + + /** + * Get list of emails configured at Bot Detection --> Configure Emails + */ + botDetectionNotifyingEmailsGet() { + return this.client.then((client) => { + return client.apis['Bot Detection Alert Subscriptions'].getBotDetectionAlertSubscriptions( + this._requestMetaData(), + ); + }); + } + + /** + * Add an email for Bot Detection notifications + */ + addBotDetectionNotifyingEmail(email) { + return this.client.then((client) => { + const data = { + email: email, + }; + const payload = { + 'Content-Type': 'application/json', + }; + return client.apis['Bot Detection Alert Subscriptions'].subscribeForBotDetectionAlerts( + payload, + { requestBody: data }, + this._requestMetaData(), + ); + }); + } + + /** + * Delete an email from Bot Detection notification configuration + */ + deleteBotDetectionNotifyingEmail(id) { + return this.client.then((client) => { + return client.apis['Bot Detection Alert Subscriptions'].unsubscribeFromBotDetectionAlerts( + { uuid: id }, + this._requestMetaData(), + ); + }); + } + + /** + * Retrieve tenant information of the given username + */ + getTenantInformation(username) { + const apiCall = fetch(`http://localhost:81/chanaka3d/wso-2_api_manager_admin/v3/tenant-info/${username}`, { + method: 'GET', + // mode: 'no-cors', + headers: { + 'Content-Type': 'application/json', + }, + }) + .then((r) => { + console.log(r); + return (r.json() + ); + }); + + return apiCall.then((response) => response); + + } + + /** + * Upload a Tenant Theme + */ + uploadTenantTheme(file) { + return this.client.then( + client => { + return client.apis['Tenant Theme'].importTenantTheme( + {}, + { + requestBody: { + file: file, + } + } + ); + }, + this._requestMetaData({ + 'Content-Type': 'multipart/form-data', + }), + ); + } + + /** + * Export a Tenant Theme + */ + exportTenantTheme() { + return this.client.then( + client => { + return client.apis['Tenant Theme'].exportTenantTheme(); + }, + this._requestMetaData(), + ); + } + + /** + * @static + * Get the supported alert types for admin + * @return {Promise} + * */ + getSupportedAlertTypes() { + return this.client.then((client) => { + return client.apis.Alerts.getAdminAlertTypes(this._requestMetaData()); + }); + } + + /** + * @static + * Get the subscribed alert types by the current user. + * @returns {Promise} + * */ + getSubscribedAlertTypesByUser() { + return this.client.then((client) => { + return client.apis['Alert Subscriptions'] + .getSubscribedAlertTypes(this._requestMetaData()); + }); + } + + /** + * @static + * Subscribe to the provided set of alerts. + * @return {Promise} + * */ + subscribeAlerts(alerts) { + return this.client.then((client) => { + return client.apis['Alert Subscriptions'] + .subscribeToAlerts({}, { requestBody: alerts }, this._requestMetaData()); + }); + } + + /** + * @static + * Unsubscribe from all the alerts. + * @return {Promise} + * */ + unsubscribeAlerts() { + return this.client.then((client) => { + return client.apis['Alert Subscriptions'] + .unsubscribeAllAlerts(this._requestMetaData()); + }); + } + + /** + * Get lis of keymanagers Registrered + */ + getKeyManagersList() { + return this.client.then((client) => { + return client.apis['Key Manager (Collection)'].get_key_managers( + this._requestMetaData(), + ); + }); + } + + /** + * Discover keymanager from well known url + */ + keyManagersDiscover(url) { + return this.client.then((client) => { + return client.apis['Key Manager (Collection)'].post_key_managers_discover( + this._requestMetaData(), + ); + }); + } + + keyManagersDiscover(requestData) { + return this.client.then((client) => { + const payload = { + 'Content-Type': 'application/json', + }; + return client.apis['Key Manager (Collection)'].post_key_managers_discover( + payload, + { requestBody: requestData }, + this._requestMetaData(), + ); + }); + } + /** + * Get details of an Application Throttling Policy + */ + keyManagerGet(keyManagerId) { + return this.client.then((client) => { + return client.apis['Key Manager (Individual)'].get_key_managers__keyManagerId_( + { keyManagerId: keyManagerId }, + this._requestMetaData(), + ); + }); + } + + /** + * Add an Key Manager + */ + addKeyManager(body) { + return this.client.then((client) => { + const payload = { + 'Content-Type': 'application/json', + }; + return client.apis['Key Manager (Collection)'].post_key_managers( + payload, + { requestBody: body }, + this._requestMetaData(), + ); + }); + } + + /** + * Update an Key Manager + */ + updateKeyManager(keyManagerId, body) { + return this.client.then((client) => { + const payload = { + keyManagerId: keyManagerId, + 'Content-Type': 'application/json', + }; + return client.apis['Key Manager (Individual)'].put_key_managers__keyManagerId_( + payload, + { requestBody: body }, + this._requestMetaData(), + ); + }); + } + /** + * Delete an Key Manager + */ + deleteKeyManager(keyManagerId) { + return this.client.then((client) => { + return client.apis['Key Manager (Individual)'].delete_key_managers__keyManagerId_( + { keyManagerId: keyManagerId }, + this._requestMetaData(), + ); + }); + } + + /** + * Get list of workflow pending requests + */ + workflowsGet(workflowType) { + return this.client.then((client) => { + return client.apis['Workflow (Collection)'].get_workflows( + { workflowType: workflowType }, + this._requestMetaData(), + ); + }); + } + + /** + * Get workflow pending request according to external workflow reference + */ + workflowGet(externalWorkflowReference) { + return this.client.then((client) => { + return client.apis['Workflows (Individual)'].get_workflows__externalWorkflowRef_( + { externalWorkflowReference: externalWorkflowReference }, + this._requestMetaData(), + ); + }); + } + + /** + * Update workflow request according to external workflow reference + */ + updateWorkflow(workflowReferenceId, body) { + return this.client.then((client) => { + const payload = { + workflowReferenceId: workflowReferenceId, + 'Content-Type': 'application/json', + }; + return client.apis['Workflows (Individual)'].post_workflows_update_workflow_status( + payload, + { requestBody: body }, + this._requestMetaData(), + ); + }); + } + + + /** + * Retrieve tenant conf + */ + tenantConfGet() { + return this.client.then((client) => { + return client.apis['Tenant Config'].exportTenantConfig(); + }); + } + + /** + * Update tenant conf + */ + updateTenantConf(body) { + return this.client.then((client) => { + const payload = { + 'Content-Type': 'application/json', + }; + return client.apis['Tenant Config'].updateTenantConfig( + payload, + { requestBody: body }, + this._requestMetaData(), + ); + }); + } + + /** + * Retrieve tenant conf + */ + tenantConfSchemaGet() { + return this.client.then((client) => { + return client.apis['Tenant Config Schema'].exportTenantConfigSchema(); + }); + } + +} + +API.CONSTS = { + API: 'API', + APIProduct: 'APIProduct', +}; + +Object.freeze(API.CONSTS); + +export default API; diff --git a/admin/admin-ui/client/source/index.tsx b/admin/admin-ui/client/source/index.tsx new file mode 100644 index 000000000..b095526ae --- /dev/null +++ b/admin/admin-ui/client/source/index.tsx @@ -0,0 +1,19 @@ + +import React from 'react'; +import { createRoot } from 'react-dom/client'; +import { BrowserRouter } from 'react-router-dom'; +// scroll bar +import 'simplebar/src/simplebar.css'; +// project import +import App from './App'; + + +// ==============================|| MAIN - REACT DOM RENDER ||============================== // + +const container = document.getElementById('root'); +const root = createRoot(container!); +root.render( + + + +); diff --git a/admin/admin-ui/client/source/layout/MainLayout/Drawer/DrawerContent/Navigation/NavGroup.js b/admin/admin-ui/client/source/layout/MainLayout/Drawer/DrawerContent/Navigation/NavGroup.js new file mode 100644 index 000000000..b5a2b121b --- /dev/null +++ b/admin/admin-ui/client/source/layout/MainLayout/Drawer/DrawerContent/Navigation/NavGroup.js @@ -0,0 +1,60 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +// import { useSelector } from 'react-redux'; + +// material-ui +import { Box, List, Typography } from '@mui/material'; + +// project import +import NavItem from './NavItem'; + +// ==============================|| NAVIGATION - LIST GROUP ||============================== // + +const NavGroup = ({ item }) => { + // const menu = useSelector((state) => state.menu); + const drawerOpen= true; + + const navCollapse = item.children?.map((menuItem) => { + switch (menuItem.type) { + case 'collapse': + return ( + + collapse - only available in paid version + + ); + case 'item': + return ; + default: + return ( + + Fix - Group Collapse or Items + + ); + } + }); + + return ( + + + {item.title} + + {/* only available in paid version */} + + ) + } + sx={{ py: 0, zIndex: 0 }} + > + {navCollapse} + + ); +}; + +NavGroup.propTypes = { + item: PropTypes.object +}; + +export default NavGroup; diff --git a/admin/admin-ui/client/source/layout/MainLayout/Drawer/DrawerContent/Navigation/NavItem.js b/admin/admin-ui/client/source/layout/MainLayout/Drawer/DrawerContent/Navigation/NavItem.js new file mode 100644 index 000000000..c4b95f7db --- /dev/null +++ b/admin/admin-ui/client/source/layout/MainLayout/Drawer/DrawerContent/Navigation/NavItem.js @@ -0,0 +1,150 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { forwardRef, useEffect } from 'react'; +import { Link } from 'react-router-dom'; +// import { useDispatch, useSelector } from 'react-redux'; + +// material-ui +import { useTheme } from '@mui/material/styles'; +import { Avatar, Chip, ListItemButton, ListItemIcon, ListItemText, Typography } from '@mui/material'; +import { useAppContext } from 'context/AppContext'; + +// project import +// import { activeItem } from 'store/reducers/menu'; + +// ==============================|| NAVIGATION - LIST ITEM ||============================== // + +const NavItem = ({ item, level, onlyChild }) => { + const theme = useTheme(); + const { selectedRoute, setSelectedRoute } = useAppContext(); + // const dispatch = useDispatch(); + // const menu = useSelector((state) => state.menu); + // const { drawerOpen, openItem } = menu; + const drawerOpen = true; + + let itemTarget = '_self'; + if (item.target) { + itemTarget = '_blank'; + } + + let listItemProps = { component: forwardRef((props, ref) => ) }; + if (item?.external) { + listItemProps = { component: 'a', href: item.url, target: itemTarget }; + } + + const itemHandler = (id) => { + setSelectedRoute(id); + }; + + const Icon = item.icon; + const itemIcon = item.icon ? : false; + + const isSelected = false;//openItem.findIndex((id) => id === item.id) > -1; + + // active menu item on page load + useEffect(() => { + const currentIndex = document.location.pathname + .toString() + .split('/') + .findIndex((id) => id === item.id); + if (currentIndex > -1) { + // dispatch(activeItem({ openItem: [item.id] })); + } + // eslint-disable-next-line + }, []); + + const textColor = 'text.primary'; + const iconSelectedColor = 'primary.main'; + + return ( + itemHandler(item.id)} + selected={item.id === selectedRoute} + sx={{ + zIndex: 1201, + pl: drawerOpen ? `${level * 28}px` : 1.5, + py: !drawerOpen && level === 1 ? 1.25 : 1, + ...(drawerOpen && { + '&:hover': { + bgcolor: 'primary.lighter' + }, + '&.Mui-selected': { + bgcolor: 'primary.lighter', + borderRight: `2px solid ${theme.palette.primary.main}`, + color: iconSelectedColor, + '&:hover': { + color: iconSelectedColor, + bgcolor: 'primary.lighter' + } + } + }), + ...(!drawerOpen && { + '&:hover': { + bgcolor: 'transparent' + }, + '&.Mui-selected': { + '&:hover': { + bgcolor: 'transparent' + }, + bgcolor: 'transparent' + } + }) + }} + > + {itemIcon && ( + + {itemIcon} + + )} + {(drawerOpen || (!drawerOpen && level !== 1)) && ( + + {item.title} + + } + /> + )} + {(drawerOpen || (!drawerOpen && level !== 1)) && item.chip && ( + {item.chip.avatar}} + /> + )} + + ); +}; + +NavItem.propTypes = { + item: PropTypes.object, + level: PropTypes.number +}; + +export default NavItem; diff --git a/admin/admin-ui/client/source/layout/MainLayout/Drawer/DrawerContent/Navigation/index.js b/admin/admin-ui/client/source/layout/MainLayout/Drawer/DrawerContent/Navigation/index.js new file mode 100644 index 000000000..530dd9c03 --- /dev/null +++ b/admin/admin-ui/client/source/layout/MainLayout/Drawer/DrawerContent/Navigation/index.js @@ -0,0 +1,31 @@ +import React from 'react'; +// material-ui +import { Box, Typography } from '@mui/material'; + +// project import +import NavGroup from './NavGroup'; +import menuItem from 'menu-items'; +import { palette } from '@mui/system'; + +// ==============================|| DRAWER CONTENT - NAVIGATION ||============================== // + +const Navigation = () => { + const navGroups = menuItem.items.map((item) => { + switch (item.type) { + case 'group': + return item.children?.length === 1 ? + + : ; + default: + return ( + + Fix - Navigation Group + + ); + } + }); + + return {navGroups}; +}; + +export default Navigation; diff --git a/admin/admin-ui/client/source/layout/MainLayout/Drawer/DrawerContent/index.js b/admin/admin-ui/client/source/layout/MainLayout/Drawer/DrawerContent/index.js new file mode 100644 index 000000000..0f28ab7a3 --- /dev/null +++ b/admin/admin-ui/client/source/layout/MainLayout/Drawer/DrawerContent/index.js @@ -0,0 +1,21 @@ +// project import +import React from 'react'; +import Navigation from './Navigation'; +import SimpleBar from 'components/third-party/SimpleBar'; + +// ==============================|| DRAWER CONTENT ||============================== // + +const DrawerContent = () => ( + + + +); + +export default DrawerContent; diff --git a/admin/admin-ui/client/source/layout/MainLayout/Drawer/DrawerHeader/DrawerHeaderStyled.js b/admin/admin-ui/client/source/layout/MainLayout/Drawer/DrawerHeader/DrawerHeaderStyled.js new file mode 100644 index 000000000..f0d22c7bc --- /dev/null +++ b/admin/admin-ui/client/source/layout/MainLayout/Drawer/DrawerHeader/DrawerHeaderStyled.js @@ -0,0 +1,16 @@ +import React from 'react'; +// material-ui +import { styled } from '@mui/material/styles'; +import { Box } from '@mui/material'; + +// ==============================|| DRAWER HEADER - STYLED ||============================== // + +const DrawerHeaderStyled = styled(Box, { shouldForwardProp: (prop) => prop !== 'open' })(({ theme, open }) => ({ + ...theme.mixins.toolbar, + display: 'flex', + alignItems: 'center', + justifyContent: open ? 'flex-start' : 'center', + paddingLeft: theme.spacing(open ? 3 : 0) +})); + +export default DrawerHeaderStyled; diff --git a/admin/admin-ui/client/source/layout/MainLayout/Drawer/DrawerHeader/index.js b/admin/admin-ui/client/source/layout/MainLayout/Drawer/DrawerHeader/index.js new file mode 100644 index 000000000..cac80f533 --- /dev/null +++ b/admin/admin-ui/client/source/layout/MainLayout/Drawer/DrawerHeader/index.js @@ -0,0 +1,40 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +// material-ui +import { useTheme } from '@mui/material/styles'; +import { Stack, Chip } from '@mui/material'; + +// project import +import DrawerHeaderStyled from './DrawerHeaderStyled'; +import Logo from 'components/Logo'; +import { Link } from 'react-router-dom'; + +// ==============================|| DRAWER HEADER ||============================== // + +const DrawerHeader = ({ open }) => { + const theme = useTheme(); + + return ( + // only available in paid version + + + + + + + ); +}; + +DrawerHeader.propTypes = { + open: PropTypes.bool +}; + +export default DrawerHeader; diff --git a/admin/admin-ui/client/source/layout/MainLayout/Drawer/MiniDrawerStyled.js b/admin/admin-ui/client/source/layout/MainLayout/Drawer/MiniDrawerStyled.js new file mode 100644 index 000000000..262efd56c --- /dev/null +++ b/admin/admin-ui/client/source/layout/MainLayout/Drawer/MiniDrawerStyled.js @@ -0,0 +1,44 @@ +// material-ui +import { styled } from '@mui/material/styles'; +import Drawer from '@mui/material/Drawer'; + +const openedMixin = (theme) => ({ + width: 260, + borderRight: `1px solid ${theme.palette.divider}`, + transition: theme.transitions.create('width', { + easing: theme.transitions.easing.sharp, + duration: theme.transitions.duration.enteringScreen + }), + overflowX: 'hidden', + boxShadow: 'none' +}); + +const closedMixin = (theme) => ({ + transition: theme.transitions.create('width', { + easing: theme.transitions.easing.sharp, + duration: theme.transitions.duration.leavingScreen + }), + overflowX: 'hidden', + width: 0, + borderRight: 'none', + boxShadow: theme.customShadows.z1 +}); + +// ==============================|| DRAWER - MINI STYLED ||============================== // + +const MiniDrawerStyled = styled(Drawer, { shouldForwardProp: (prop) => prop !== 'open' })(({ theme, open }) => ({ + width: 260, + flexShrink: 0, + whiteSpace: 'nowrap', + boxSizing: 'border-box', + ...(open && { + ...openedMixin(theme), + '& .MuiDrawer-paper': openedMixin(theme) + }), + ...(!open && { + ...closedMixin(theme), + '& .MuiDrawer-paper': closedMixin(theme) + }) +})); + +export default MiniDrawerStyled; diff --git a/admin/admin-ui/client/source/layout/MainLayout/Drawer/index.js b/admin/admin-ui/client/source/layout/MainLayout/Drawer/index.js new file mode 100644 index 000000000..96f4783ce --- /dev/null +++ b/admin/admin-ui/client/source/layout/MainLayout/Drawer/index.js @@ -0,0 +1,68 @@ +import PropTypes from 'prop-types'; +import React, { useMemo } from 'react'; + +// material-ui +import { useTheme } from '@mui/material/styles'; +import { Box, Drawer, useMediaQuery } from '@mui/material'; + +// project import +import DrawerHeader from './DrawerHeader'; +import DrawerContent from './DrawerContent'; +import MiniDrawerStyled from './MiniDrawerStyled'; + +// eslint-disable-next-line @typescript-eslint/no-var-requires, no-undef +const Settings = require('Settings'); + +// ==============================|| MAIN LAYOUT - DRAWER ||============================== // + +const MainDrawer = ({ open, handleDrawerToggle, window }) => { + const theme = useTheme(); + const matchDownMD = useMediaQuery(theme.breakpoints.down('lg')); + + // responsive drawer container + const container = window !== undefined ? () => window().document.body : undefined; + + // header content + const drawerContent = useMemo(() => , []); + const drawerHeader = useMemo(() => , [open]); + + return ( + + {!matchDownMD ? ( + + {drawerHeader} + {drawerContent} + + ) : ( + + {open && drawerHeader} + {open && drawerContent} + + )} + + ); +}; + +MainDrawer.propTypes = { + open: PropTypes.bool, + handleDrawerToggle: PropTypes.func, + window: PropTypes.object +}; + +export default MainDrawer; diff --git a/admin/admin-ui/client/source/layout/MainLayout/Header/AppBarStyled.ts b/admin/admin-ui/client/source/layout/MainLayout/Header/AppBarStyled.ts new file mode 100644 index 000000000..5fd822f4b --- /dev/null +++ b/admin/admin-ui/client/source/layout/MainLayout/Header/AppBarStyled.ts @@ -0,0 +1,31 @@ +import React from 'react'; +// material-ui +import { styled, Theme } from '@mui/material/styles'; +import AppBar, { AppBarProps } from '@mui/material/AppBar'; + +// eslint-disable-next-line @typescript-eslint/no-var-requires, no-undef +const Settings = require('Settings'); + +interface AppBarStyledProps extends AppBarProps { + open: boolean, +} + +// ==============================|| HEADER - APP BAR STYLED ||============================== // + +const AppBarStyled = styled(AppBar, { shouldForwardProp: (prop) => prop !== 'open' })(({ theme, open }) => ({ + zIndex: theme.zIndex.drawer + 1, + transition: theme.transitions.create(['width', 'margin'], { + easing: theme.transitions.easing.sharp, + duration: theme.transitions.duration.leavingScreen + }), + ...(open && { + marginLeft: 260, + width: `calc(100% - 260px)`, + transition: theme.transitions.create(['width', 'margin'], { + easing: theme.transitions.easing.sharp, + duration: theme.transitions.duration.enteringScreen + }) + }) +})); + +export default AppBarStyled; diff --git a/admin/admin-ui/client/source/layout/MainLayout/Header/HeaderContent/MobileSection.tsx b/admin/admin-ui/client/source/layout/MainLayout/Header/HeaderContent/MobileSection.tsx new file mode 100644 index 000000000..3a1b1f46e --- /dev/null +++ b/admin/admin-ui/client/source/layout/MainLayout/Header/HeaderContent/MobileSection.tsx @@ -0,0 +1,102 @@ +import React, { useEffect, useRef, useState } from 'react'; + +// material-ui +import { useTheme } from '@mui/material/styles'; +import { AppBar, Box, ClickAwayListener, IconButton, Paper, Popper, Toolbar } from '@mui/material'; + +// project import +import Search from './Search'; +import Profile from './Profile'; +import Transitions from 'components/@extended/Transitions'; + +// assets +import { MoreOutlined } from '@ant-design/icons'; + +// ==============================|| HEADER CONTENT - MOBILE ||============================== // + +const MobileSection = () => { + const theme = useTheme(); + + const [open, setOpen] = useState(false); + const anchorRef = useRef(null); + + const handleToggle = () => { + setOpen((prevOpen) => !prevOpen); + }; + + const handleClose = (event) => { + if (anchorRef.current && anchorRef.current.contains(event.target)) { + return; + } + + setOpen(false); + }; + + const prevOpen = useRef(open); + useEffect(() => { + if (prevOpen.current === true && open === false && anchorRef && anchorRef.current) { + anchorRef.current.focus(); + } + + prevOpen.current = open; + }, [open]); + + return ( + <> + + + + + + + {({ TransitionProps }) => ( + + + + + + + + + + + + + )} + + + ); +}; + +export default MobileSection; diff --git a/admin/admin-ui/client/source/layout/MainLayout/Header/HeaderContent/Notification.tsx b/admin/admin-ui/client/source/layout/MainLayout/Header/HeaderContent/Notification.tsx new file mode 100644 index 000000000..3916f4584 --- /dev/null +++ b/admin/admin-ui/client/source/layout/MainLayout/Header/HeaderContent/Notification.tsx @@ -0,0 +1,279 @@ +import React, { useRef, useState } from 'react'; + +// material-ui +import { useTheme } from '@mui/material/styles'; +import { + Avatar, + Badge, + Box, + ClickAwayListener, + Divider, + IconButton, + List, + ListItemButton, + ListItemAvatar, + ListItemText, + ListItemSecondaryAction, + Paper, + Popper, + Typography, + useMediaQuery +} from '@mui/material'; + +// project import +import MainCard from 'components/MainCard'; +import Transitions from 'components/@extended/Transitions'; + +// assets +import { BellOutlined, CloseOutlined, GiftOutlined, MessageOutlined, SettingOutlined } from '@ant-design/icons'; + +// sx styles +const avatarSX = { + width: 36, + height: 36, + fontSize: '1rem' +}; + +const actionSX = { + mt: '6px', + ml: 1, + top: 'auto', + right: 'auto', + alignSelf: 'flex-start', + + transform: 'none' +}; + +// ==============================|| HEADER CONTENT - NOTIFICATION ||============================== // + +const Notification = () => { + const theme = useTheme(); + const matchesXs = useMediaQuery(theme.breakpoints.down('md')); + + const anchorRef = useRef(null); + const [open, setOpen] = useState(false); + const handleToggle = () => { + setOpen((prevOpen) => !prevOpen); + }; + + const handleClose = (event) => { + if (anchorRef.current && anchorRef.current.contains(event.target)) { + return; + } + setOpen(false); + }; + + const iconBackColorOpen = 'grey.300'; + const iconBackColor = 'grey.100'; + + return ( + + + + + + + + {({ TransitionProps }) => ( + + + + + + + } + > + + + + + + + + + It's{' '} + + Cristina danny's + {' '} + birthday today. + + } + secondary="2 min ago" + /> + + + 3:00 AM + + + + + + + + + + + + + Aida Burg + {' '} + commented your post. + + } + secondary="5 August" + /> + + + 6:00 PM + + + + + + + + + + + + Your Profile is Complete   + + 60% + {' '} + + } + secondary="7 hours ago" + /> + + + 2:45 PM + + + + + + + + C + + + + + Cristina Danny + {' '} + invited to join{' '} + + Meeting. + + + } + secondary="Daily scrum meeting time" + /> + + + 9:10 PM + + + + + + + View All + + } + /> + + + + + + + )} + + + ); +}; + +export default Notification; diff --git a/admin/admin-ui/client/source/layout/MainLayout/Header/HeaderContent/Profile/ProfileTab.js b/admin/admin-ui/client/source/layout/MainLayout/Header/HeaderContent/Profile/ProfileTab.js new file mode 100644 index 000000000..166d3cffb --- /dev/null +++ b/admin/admin-ui/client/source/layout/MainLayout/Header/HeaderContent/Profile/ProfileTab.js @@ -0,0 +1,45 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { useState } from 'react'; + +// material-ui +import { useTheme } from '@mui/material/styles'; +import { List, ListItemButton, ListItemIcon, ListItemText } from '@mui/material'; +import { sendSignOutRequest } from "auth/sign-out"; +import { endAuthenticatedSession } from "auth/session"; +import { resetOPConfiguration } from "auth/op-config"; +import { useAuth } from 'auth/AuthProvider'; + +// assets +import { EditOutlined, ProfileOutlined, LogoutOutlined, UserOutlined, WalletOutlined } from '@ant-design/icons'; + +// eslint-disable-next-line @typescript-eslint/no-var-requires, no-undef +const Settings = require('Settings'); +// ==============================|| HEADER PROFILE - PROFILE TAB ||============================== // + +const ProfileTab = () => { + const theme = useTheme(); + const { logout } = useAuth(); + + const [selectedIndex, setSelectedIndex] = useState(0); + const handleListItemClick = (event, index) => { + setSelectedIndex(index); + }; + + return ( + + + + + + + + + ); +}; + +ProfileTab.propTypes = { + handleLogout: PropTypes.func +}; + +export default ProfileTab; diff --git a/admin/admin-ui/client/source/layout/MainLayout/Header/HeaderContent/Profile/SettingTab.js b/admin/admin-ui/client/source/layout/MainLayout/Header/HeaderContent/Profile/SettingTab.js new file mode 100644 index 000000000..5f7a79b5a --- /dev/null +++ b/admin/admin-ui/client/source/layout/MainLayout/Header/HeaderContent/Profile/SettingTab.js @@ -0,0 +1,56 @@ +import { useState } from 'react'; + +// material-ui +import { useTheme } from '@mui/material/styles'; +import { List, ListItemButton, ListItemIcon, ListItemText } from '@mui/material'; + +// assets +import { CommentOutlined, LockOutlined, QuestionCircleOutlined, UserOutlined, UnorderedListOutlined } from '@ant-design/icons'; + +// ==============================|| HEADER PROFILE - SETTING TAB ||============================== // + +const SettingTab = () => { + const theme = useTheme(); + + const [selectedIndex, setSelectedIndex] = useState(0); + const handleListItemClick = (event, index) => { + setSelectedIndex(index); + }; + + return ( + + handleListItemClick(event, 0)}> + + + + + + handleListItemClick(event, 1)}> + + + + + + handleListItemClick(event, 2)}> + + + + + + handleListItemClick(event, 3)}> + + + + + + handleListItemClick(event, 4)}> + + + + + + + ); +}; + +export default SettingTab; diff --git a/admin/admin-ui/client/source/layout/MainLayout/Header/HeaderContent/Profile/index.tsx b/admin/admin-ui/client/source/layout/MainLayout/Header/HeaderContent/Profile/index.tsx new file mode 100644 index 000000000..0a4e019ab --- /dev/null +++ b/admin/admin-ui/client/source/layout/MainLayout/Header/HeaderContent/Profile/index.tsx @@ -0,0 +1,154 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { useRef, useState } from 'react'; + +// material-ui +import { useTheme } from '@mui/material/styles'; +import { + Avatar, + Box, + ButtonBase, + CardContent, + ClickAwayListener, + Grid, + IconButton, + Paper, + Popper, + Stack, + Typography +} from '@mui/material'; + +// project import +import MainCard from 'components/MainCard'; +import Transitions from 'components/@extended/Transitions'; +import ProfileTab from './ProfileTab'; +import { useAuth } from 'auth/AuthProvider'; + +// assets +import { LogoutOutlined } from '@ant-design/icons'; + +// tab panel wrapper +function TabPanel({ children, value, index, ...other }) { + return ( + + ); +} + +TabPanel.propTypes = { + children: PropTypes.node, + index: PropTypes.any.isRequired, + value: PropTypes.any.isRequired +}; + +function a11yProps(index) { + return { + id: `profile-tab-${index}`, + 'aria-controls': `profile-tabpanel-${index}` + }; +} + +// ==============================|| HEADER CONTENT - PROFILE ||============================== // + +const Profile = () => { + const theme = useTheme(); + const { user, logout } = useAuth(); + + const anchorRef = useRef(null); + const [open, setOpen] = useState(false); + const handleToggle = () => { + setOpen((prevOpen) => !prevOpen); + }; + + const handleClose = (event) => { + if (anchorRef.current && anchorRef.current.contains(event.target)) { + return; + } + setOpen(false); + }; + const [value, setValue] = useState(0); + const iconBackColorOpen = 'grey.300'; + + return ( + + + + + {user.user} + + + + {({ TransitionProps }) => ( + + {open && ( + + + + + + + + + + {user.user} + {/* Here relevant organization name should be added */} + + + + + + {open && ( + + )} + + + + )} + + )} + + + ); +}; + +export default Profile; diff --git a/admin/admin-ui/client/source/layout/MainLayout/Header/HeaderContent/Search.tsx b/admin/admin-ui/client/source/layout/MainLayout/Header/HeaderContent/Search.tsx new file mode 100644 index 000000000..97a80de96 --- /dev/null +++ b/admin/admin-ui/client/source/layout/MainLayout/Header/HeaderContent/Search.tsx @@ -0,0 +1,31 @@ +import React from 'react'; +// material-ui +import { Box, FormControl, InputAdornment, OutlinedInput } from '@mui/material'; + +// assets +import { SearchOutlined } from '@ant-design/icons'; + +// ==============================|| HEADER CONTENT - SEARCH ||============================== // + +const Search = () => ( + + + + + + } + aria-describedby="header-search-text" + inputProps={{ + 'aria-label': 'weight' + }} + placeholder="Ctrl + K" + /> + + +); + +export default Search; diff --git a/admin/admin-ui/client/source/layout/MainLayout/Header/HeaderContent/index.tsx b/admin/admin-ui/client/source/layout/MainLayout/Header/HeaderContent/index.tsx new file mode 100644 index 000000000..7cf1c34a6 --- /dev/null +++ b/admin/admin-ui/client/source/layout/MainLayout/Header/HeaderContent/index.tsx @@ -0,0 +1,31 @@ + +import React from 'react'; +// material-ui +import { Box, Theme, useMediaQuery } from '@mui/material'; + +// project import +import Profile from './Profile'; +import MobileSection from './MobileSection'; +import { Grid } from '@mui/material'; + +// ==============================|| HEADER - CONTENT ||============================== // + +const HeaderContent = () => { + const matchesXs = useMediaQuery((theme: Theme) => theme.breakpoints.down('md')); + + return ( + <> + + + {matchesXs && } + + + {!matchesXs && } + {matchesXs && } + + + + ); +}; + +export default HeaderContent; diff --git a/admin/admin-ui/client/source/layout/MainLayout/Header/index.tsx b/admin/admin-ui/client/source/layout/MainLayout/Header/index.tsx new file mode 100644 index 000000000..0e67cd977 --- /dev/null +++ b/admin/admin-ui/client/source/layout/MainLayout/Header/index.tsx @@ -0,0 +1,69 @@ +import React, { MouseEventHandler } from 'react'; +import PropTypes from 'prop-types'; + +// material-ui +import { useTheme } from '@mui/material/styles'; +import { AppBar, AppBarProps, IconButton, Toolbar, useMediaQuery } from '@mui/material'; + +// project import +import AppBarStyled from './AppBarStyled'; +import HeaderContent from './HeaderContent'; + +// assets +import { MenuFoldOutlined, MenuUnfoldOutlined } from '@ant-design/icons'; + +// ==============================|| MAIN LAYOUT - HEADER ||============================== // +export interface HeaderProps { + open: boolean; + handleDrawerToggle: MouseEventHandler; +} + +const Header = ({ open, handleDrawerToggle }: HeaderProps) => { + const theme = useTheme(); + const matchDownMD = useMediaQuery(theme.breakpoints.down('lg')); + + const iconBackColor = 'grey.100'; + const iconBackColorOpen = 'grey.200'; + + // common header + const mainHeader = ( + + + {!open ? : } + + + + ); + + // app-bar params + const appBar: AppBarProps = { + position: 'fixed', + color: 'inherit', + elevation: 0, + sx: { + borderBottom: `1px solid ${theme.palette.divider}` + // boxShadow: theme.customShadows.z1 + } + }; + + return ( + <> + {!matchDownMD ? ( + + {mainHeader} + + ) : ( + {mainHeader} + )} + + ); +}; + +export default Header; diff --git a/admin/admin-ui/client/source/layout/MainLayout/index.tsx b/admin/admin-ui/client/source/layout/MainLayout/index.tsx new file mode 100644 index 000000000..f267165f5 --- /dev/null +++ b/admin/admin-ui/client/source/layout/MainLayout/index.tsx @@ -0,0 +1,58 @@ +import React, { useEffect, useState } from 'react'; +import { Outlet } from 'react-router-dom'; +// import { useDispatch, useSelector } from 'react-redux'; + +// material-ui +import { useTheme } from '@mui/material/styles'; +import { Box, Toolbar, useMediaQuery } from '@mui/material'; + +// project import +import Drawer from './Drawer'; +import Header from './Header'; +import navigation from 'menu-items'; +import Breadcrumbs from 'components/@extended/Breadcrumbs'; + +// types +// import { openDrawer } from 'store/reducers/menu'; + +// ==============================|| MAIN LAYOUT ||============================== // + +const MainLayout = () => { + const theme = useTheme(); + const matchDownLG = useMediaQuery(theme.breakpoints.down('xl')); + // const dispatch = useDispatch(); + + // const { drawerOpen } = useSelector((state) => state.menu); + + // drawer toggler + const [open, setOpen] = useState(true); + const handleDrawerToggle = () => { + setOpen(!open); + //dispatch(openDrawer({ drawerOpen: !open })); + }; + + // set media wise responsive drawer + useEffect(() => { + setOpen(!matchDownLG); + //dispatch(openDrawer({ drawerOpen: !matchDownLG })); + }, [matchDownLG]); + + // useEffect(() => { + // if (open !== drawerOpen) setOpen(drawerOpen); + // // eslint-disable-next-line react-hooks/exhaustive-deps + // }, [drawerOpen]); + + return ( + +
+ + + + + + + + ); +}; + +export default MainLayout; diff --git a/admin/admin-ui/client/source/layout/MinimalLayout/index.tsx b/admin/admin-ui/client/source/layout/MinimalLayout/index.tsx new file mode 100644 index 000000000..584f90e46 --- /dev/null +++ b/admin/admin-ui/client/source/layout/MinimalLayout/index.tsx @@ -0,0 +1,12 @@ +import React from 'react'; +import { Outlet } from 'react-router-dom'; + +// ==============================|| MINIMAL LAYOUT ||============================== // + +const MinimalLayout = () => ( + <> + + +); + +export default MinimalLayout; diff --git a/admin/admin-ui/client/source/menu-items/index.tsx b/admin/admin-ui/client/source/menu-items/index.tsx new file mode 100644 index 000000000..ba0a8137e --- /dev/null +++ b/admin/admin-ui/client/source/menu-items/index.tsx @@ -0,0 +1,168 @@ +// project import +import React from 'react'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faGaugeSimple, faShieldAlt, + faBuildingShield, + faRssSquare, + faFilePen, + faServer, + faBan, + faObjectGroup, + faKey, + faUserPlus, + faSquarePlus, + faNewspaper, + faSquareMinus, + faPersonCircleMinus, + faPersonCircleQuestion, + faFilm, + faHandshake, + faPenToSquare, + faScrewdriverWrench, + faShapes, + faGears, + faSitemap} from '@fortawesome/free-solid-svg-icons'; + +// ==============================|| MENU ITEMS ||============================== // + +const menuItems = { + items: [ + // { + // id: 'group-dashboard', + // title: '', + // type: 'group', + // children: [ + // { + // id: 'dashboard', + // title: 'Dashboard', + // type: 'item', + // url: '/dashboard', + // icon: () => , + // } + // ] + // }, + // { + // id: 'rate-limiting-policies', + // title: 'Rate Limiting Policies', + // type: 'group', + // children: [ + // { + // id: 'advanced-policies', + // title: 'Advanced Policies', + // type: 'item', + // url: '/advanced-policies', + // icon: () => , + // }, + // { + // id: 'application-rate-plans', + // title: 'Application Rate Plans', + // type: 'item', + // url: '/application-rate-plans', + // icon: () => , + // }, + // { + // id: 'business-plans', + // title: 'Business Plans', + // type: 'item', + // url: '/business-plans', + // icon: () => , + // }, + // // { + // // id: 'custom-policies', + // // title: 'Custom Policies', + // // type: 'item', + // // url: '/custom-policies', + // // icon: () => , + // // }, + // { + // id: 'deny-policies', + // title: 'Deny Policies', + // type: 'item', + // url: '/deny-policies', + // icon: () => , + // } + // ] + // }, + // { + // id: 'gateways', + // title: '', + // type: 'group', + // children: [ + // { + // id: 'gateways', + // title: 'Gateways', + // type: 'item', + // url: '/gateways', + // icon: () => , + // } + // ] + // }, + { + id: 'organizations', + title: '', + type: 'group', + children: [ + { + id: 'organizations', + title: 'Organizations', + type: 'item', + url: '/organizations', + icon: () => , + } + ] + }, + { + id: 'api-categories', + title: '', + type: 'group', + children: [ + { + id: 'api-categories', + title: 'API Categories', + type: 'item', + url: '/api-categories', + icon: () => , + } + ] + }, + { + id: 'key-managers', + title: '', + type: 'group', + children: [ + { + id: 'key-managers', + title: 'Key Managers', + type: 'item', + url: '/key-managers', + icon: () => , + } + ] + }, + // { + // id: 'settings', + // title: 'Settings', + // type: 'group', + // children: [ + // { + // id: 'applications', + // title: 'Applications', + // type: 'item', + // url: '/applications', + // icon: () => , + // }, + // // { + // // id: 'scope-assignments', + // // title: 'Documentation', + // // type: 'item', + // // url: '/scope-assignments', + // // icon: StarOutlined, + // // external: true, + // // target: true + // // } + // ] + // } +] +}; + +export default menuItems; diff --git a/admin/admin-ui/client/source/pages/APICategories/AddUpdateAPICategory.tsx b/admin/admin-ui/client/source/pages/APICategories/AddUpdateAPICategory.tsx new file mode 100644 index 000000000..f7cffe03f --- /dev/null +++ b/admin/admin-ui/client/source/pages/APICategories/AddUpdateAPICategory.tsx @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * + * 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. + * + */ + +import AddCircleOutlineIcon from '@mui/icons-material/AddCircleOutline'; +import EditIcon from '@mui/icons-material/Edit'; +import Button from '@mui/material/Button'; +import CircularProgress from '@mui/material/CircularProgress'; +import Dialog from '@mui/material/Dialog'; +import DialogActions from '@mui/material/DialogActions'; +import DialogContent from '@mui/material/DialogContent'; +import DialogTitle from '@mui/material/DialogTitle'; +import IconButton from '@mui/material/IconButton'; +import TextField from '@mui/material/TextField'; +import axios from 'axios'; +import Alert from "components/Alert"; +import PropTypes from 'prop-types'; +import React, { useEffect, useState } from 'react'; +import { FormattedMessage } from 'react-intl'; + +export default function AddUpdateAPICategory({ id, nameProp, descriptionProp, updateList }) { + // This component has been used to add API category when id is undefined and edit API category when id is defined + const [APICategory, setAPICategory] = useState<{ name: string; description: string }>({ name: "", description: "" }); + const [open, setOpen] = useState(false); + const [saving, setSaving] = useState(false); + + const handleClickOpen = () => { + // dialogOpenCallback(); + setOpen(true); + }; + + const handleClose = () => { + setOpen(false); + }; + + const saveTriggerd = () => { + const savedPromise = formSaveCallback; + if (typeof savedPromise === 'function') { + savedPromise(); + } else if (savedPromise) { + setSaving(true); + savedPromise.then((data) => { + Alert.success(data); + }).catch((e) => { + Alert.error(e); + }).finally(() => { + setSaving(false); + handleClose(); + }); + } + }; + useEffect(() => { + if (id !== undefined) { + setAPICategory({ name: nameProp, description: descriptionProp }); + } + }, []); + + const hasErrors = (fieldName: string, value: string) => { + let error: string | boolean = false; + switch (fieldName) { + case 'name': + if (value === undefined) { + error = false; + break; + } + if (value === '') { + error = 'Name is Empty'; + } else if (value.length > 255) { + error = 'API Category name is too long'; + } else if (/\s/.test(value)) { + error = 'Name contains spaces'; + } else if (/[!@#$%^&*(),?"{}[\]|<>\t\n]/i.test(value)) { + error = 'Name field contains special characters'; + } else { + error = false; + } + break; + case 'description': + if (value && value.length > 1024) { + error = 'API Category description is too long'; + } + break; + default: + break; + } + return error; + }; + + const getAllFormErrors = () => { + let errorText: string = ''; + let NameErrors: string | boolean = false; + let DescriptionErrors: string | boolean = false; + + if (APICategory.name === undefined) { + NameErrors = hasErrors('name', ''); + } else { + NameErrors = hasErrors('name', APICategory.name); + } + if (NameErrors) { + errorText += NameErrors + '\n'; + } + if (APICategory.description !== undefined) { + DescriptionErrors = hasErrors('description', APICategory.description); + } + if (DescriptionErrors) { + errorText += DescriptionErrors + '\n'; + } + return errorText; + }; + + const formSaveCallback = () => { + const formErrors = getAllFormErrors(); + if (formErrors !== '') { + console.log(formErrors); + Alert.error(formErrors); + return false; + } else { + if (id !== undefined) { + axios.put('/api/admin/api-categories/' + id, { 'name': APICategory.name, 'description': APICategory.description }, { + withCredentials: true, + }).then(() => { + return ( + + ); + }).catch((error) => { + throw error.response.body.description; + }).finally(() => { + updateList(); + }); + } else { + axios.post('/api/admin/api-categories/', { 'name': APICategory.name, 'description': APICategory.description }, { + withCredentials: true, + }).then(() => { + return ( + + ); + }).catch((error) => { + throw error.response.body.description; + }).finally(() => { + updateList(); + }); + } + } + }; + + const onChange = (e) => { + setAPICategory({ ...APICategory, [e.target.name]: e.target.value }); + }; + + return ( + <> + {id !== undefined ? : + } + + + {id !== undefined ? 'Edit API Category' : 'Add API Category'} + + <> + + + * + + )} + helperText={'Name of the API category'} + /> + + + * + + )} + helperText={'Description of the API category'} + /> + + + + + + + + + ); +} + +AddUpdateAPICategory.propTypes = { + id: PropTypes.string, + nameProp: PropTypes.string, + descriptionProp: PropTypes.string, + updateList: PropTypes.func.isRequired +}; diff --git a/admin/admin-ui/client/source/pages/APICategories/DeleteAPICategory.tsx b/admin/admin-ui/client/source/pages/APICategories/DeleteAPICategory.tsx new file mode 100644 index 000000000..a344f19c6 --- /dev/null +++ b/admin/admin-ui/client/source/pages/APICategories/DeleteAPICategory.tsx @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * + * 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. + * + */ + +import DeleteForeverIcon from '@mui/icons-material/DeleteForever'; +import { Button, CircularProgress, Dialog, DialogActions, DialogContent, DialogTitle, IconButton } from '@mui/material'; +import DialogContentText from '@mui/material/DialogContentText'; +import axios from 'axios'; +import PropTypes from 'prop-types'; +import React, { useState } from 'react'; +import { FormattedMessage } from 'react-intl'; + +export default function DeleteAPICategory({ id, updateList }) { + + const [open, setOpen] = useState(false); + const [saving, setSaving] = useState(false); + + const handleClickOpen = () => { + setOpen(true); + }; + + const handleClose = () => { + setOpen(false); + }; + + const saveTriggered = () => { + setSaving(true); + deleteOrganization(); + handleClose(); + }; + + const deleteOrganization = () => { + axios.delete('/api/admin/api-categories/' + id, { + withCredentials: true, + }).then(() => { + return ( + + ); + }).catch((error) => { + throw error.response.body.description; + }).finally(() => { + updateList(); + setSaving(false); + }); + }; + + return ( + <> + + + + + + Delete API category? + + Are you sure you want to delete this API Category? + + + + + + + + ); +} + +DeleteAPICategory.propTypes = { + id: PropTypes.string.isRequired, + updateList: PropTypes.func.isRequired +}; diff --git a/admin/admin-ui/client/source/pages/APICategories/ListAPICategories.tsx b/admin/admin-ui/client/source/pages/APICategories/ListAPICategories.tsx new file mode 100644 index 000000000..c2965815e --- /dev/null +++ b/admin/admin-ui/client/source/pages/APICategories/ListAPICategories.tsx @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * + * 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. + * + */ + +import { Grid, Typography } from '@mui/material'; +import { default as Alert, default as MuiAlert } from '@mui/material/Alert'; +import AlertTitle from '@mui/material/AlertTitle'; +import Snackbar from '@mui/material/Snackbar'; +import Stack from '@mui/material/Stack'; +import axios from 'axios'; +import Loader from 'components/Loader'; +import PaginatedClientSide from 'components/data-table/PaginatedClientSide'; +import React, { useEffect, useState } from 'react'; +import { FormattedMessage, useIntl } from 'react-intl'; +import AddUpdateAPICategory from './AddUpdateAPICategory'; +import DeleteAPICategory from './DeleteAPICategory'; + +export default function ListAPICategories() { + + const [data, setData] = useState<{ count: number; list: [{ id: string; name: string; description: string; numberOfAPIs: number; }]; } | null>(null); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(""); + const [snackbarOpen, setSnackbarOpen] = useState(false); + const [formattedMessage, setFormattedMessage] = useState({ + id: '', + defaultMessage: '', + }); + + const intl = useIntl(); + + const fetchData = () => { + setLoading(true); + axios('/api/admin/api-categories', { + method: 'GET', + withCredentials: true, + }).then((res) => { + setData(res.data); + }).catch((err) => { + setError(err); + }).finally(() => { + setLoading(false); + }); + }; + + useEffect(() => { + fetchData(); + }, []); + + const columns = React.useMemo( + () => [ + { + Header: 'Category Name', + accessor: 'name', + }, + { + Header: 'Description', + accessor: 'description', + }, + { + Header: 'Number Of APIs', + accessor: 'numberOfAPIs', + }, + { + Header: 'Actions', + accessor: 'actions', + Cell: (e) => { + return ( + + + + + ); + }, + }, + ], + [] + ) + + const searchProps = { + searchPlaceholder: intl.formatMessage({ + id: 'AdminPages.APICategories.List.search.default', + defaultMessage: 'Search by Category name', + }), + }; + + if (loading) { + return ; + } + return ( +
+
+ + + API Categories + + + + + + + {(error || data === null || data === undefined) && + + Error + There's an error when fetching API Categories — check it out! + + } + + {data && data.count > 0 && !error && +
+ +
+ } +
+ setSnackbarOpen(false)}> + setSnackbarOpen(false)} severity='success' sx={{ width: '100%' }}> + { + + } + + +
+ ); +} diff --git a/admin/admin-ui/client/source/pages/ApplicationRatePlans/ListApplicationRatePlans.tsx b/admin/admin-ui/client/source/pages/ApplicationRatePlans/ListApplicationRatePlans.tsx new file mode 100644 index 000000000..1e2a2de47 --- /dev/null +++ b/admin/admin-ui/client/source/pages/ApplicationRatePlans/ListApplicationRatePlans.tsx @@ -0,0 +1,47 @@ +/* eslint-disable @typescript-eslint/ban-types */ +/* eslint-disable no-empty-pattern */ +import React from 'react'; +import PaginatedClientSide from 'components/data-table/PaginatedClientSide' +import useApplicationRatePlans from "components/hooks/useApplicationRatePlans"; +import Loader from "components/Loader"; +// import { components, paths, operations } from 'types/Types'; + +type Props = {} + +export default function ListApplicationRatePlans({ }: Props) { + const { data, loading, error } = useApplicationRatePlans(); + const columns = React.useMemo( + () => [ + { + Header: 'Policy Name', + accessor: 'policyName', + }, + { + Header: 'Display Name', + accessor: 'displayName', + }, + { + Header: 'policyId', + accessor: 'policyId', + }, + { + Header: 'isDeployed', + accessor: 'isDeployed', + }, + + ], + [] + ) + if (error) { + return
Error
; + } + if (loading) { + return ; + } + if (data && data.length === 0) { + return
No data
; + } + return ( + + ) +} \ No newline at end of file diff --git a/admin/admin-ui/client/source/pages/Dashboard/APICategoriesCard.tsx b/admin/admin-ui/client/source/pages/Dashboard/APICategoriesCard.tsx new file mode 100644 index 000000000..c1c3e3137 --- /dev/null +++ b/admin/admin-ui/client/source/pages/Dashboard/APICategoriesCard.tsx @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you 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. + */ + +import React, { useEffect, useState } from 'react'; +import { FormattedMessage } from 'react-intl'; +import { Link as RouterLink } from 'react-router-dom'; +import { Card } from '@mui/material'; +import Box from '@mui/material/Box'; +import Button from '@mui/material/Button'; +import CardContent from '@mui/material/CardContent'; +import Divider from '@mui/material/Divider'; +import { makeStyles } from 'tss-react/mui'; +import Typography from '@mui/material/Typography'; +import CategoryIcon from '@ant-design/icons/GroupOutlined'; +import LaunchIcon from '@ant-design/icons/LinkOutlined'; +import Loader from 'components/Loader'; +import useAxios from 'components/hooks/useAxios'; + +const Configurations = require("Config") + +const useStyles = makeStyles()(() => { + return { + root: { + minWidth: 275, + minHeight: 270, + textAlign: 'center', + + }, + title: { + fontSize: 20, + fontWeight: 'fontWeightBold', + }, + cardText: { + whiteSpace: 'nowrap', + overflow: 'hidden', + textOverflow: 'ellipsis', + }, + } +}); + +/** + * Render progress inside a container centering in the container. + * @returns {JSX} Loading animation. + */ +export default function APICategoriesCard() { + const { classes } = useStyles(); + const { data: apiCategoriesList, loading, error } = useAxios({ url: '/api-categories' }); + + if (loading) { + return + } + + if (error) { + return
Error
+ } + + if (apiCategoriesList.list.length === 0) { + return + + + + + + + + + + + + + Go to Category Documentation + + , + }} + defaultMessage='API categories allow API providers to categorize APIs + that have similar attributes. When a categorized API + gets published to the Developer Portal, its categories + appear as clickable links to the API consumers. + The API consumers can use the available API categories + to quickly jump to a category of interest. {learnMoreLink}' + /> + + + + + + + + } else { + return + + + + + + + + + + {apiCategoriesList.count} + + + + + + + + {apiCategoriesList.list.map((category) => { + return ( + + + + {category.name} + + + {category.description || ( + + )} + + + + + {category.numberOfAPIs} + {' APIs'} + + + + ); + })} + + + + + + + + + ; + } + +} diff --git a/admin/admin-ui/client/source/pages/Dashboard/Dashboard.tsx b/admin/admin-ui/client/source/pages/Dashboard/Dashboard.tsx new file mode 100644 index 000000000..286215f34 --- /dev/null +++ b/admin/admin-ui/client/source/pages/Dashboard/Dashboard.tsx @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you 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. + */ + +import React from 'react'; +import Grid from '@mui/material/Grid'; +import Item from '@mui/material/Grid'; +// import ContentBase from 'AppComponents/AdminPages/Addons/ContentBase'; +import APICategoriesCard from './APICategoriesCard'; +import RateLimitingCard from './RateLimitingCard'; +import TasksWorkflowCard from './TasksWorkflowCard'; +import OrganizationsCard from '../Organizations/ListOrganizations'; +import { useAppContext } from 'context/AppContext'; + +/** + * Render progress inside a container centering in the container. + * @returns {JSX} Loading animation. + */ +export default function Dashboard() { + const { user: { _scopes } } = useAppContext(); + const hasWorkflowViewPermission = _scopes.includes('apim:api_workflow_view'); + return ( + + + + + + + + + + + {hasWorkflowViewPermission && ( + + + + + )} + + + ); +} diff --git a/admin/admin-ui/client/source/pages/Dashboard/RateLimitingCard.tsx b/admin/admin-ui/client/source/pages/Dashboard/RateLimitingCard.tsx new file mode 100644 index 000000000..eedea3197 --- /dev/null +++ b/admin/admin-ui/client/source/pages/Dashboard/RateLimitingCard.tsx @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you 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. + */ + +import React from 'react'; +import { FormattedMessage, useIntl } from 'react-intl'; +import { Link as RouterLink } from 'react-router-dom'; +import { Card } from '@mui/material'; +import Box from '@mui/material/Box'; +import CardContent from '@mui/material/CardContent'; +import Divider from '@mui/material/Divider'; +import Link from '@mui/material/Link'; +import { makeStyles } from 'tss-react/mui'; +import Typography from '@mui/material/Typography'; +import PolicyIcon from '@ant-design/icons/GroupOutlined'; +import AssignmentTurnedInIcon from '@ant-design/icons/GroupOutlined'; +import AssignmentIcon from '@ant-design/icons/GroupOutlined'; +import PhonelinkSetupIcon from '@ant-design/icons/GroupOutlined'; +import { useAppContext } from 'context/AppContext'; + +const useStyles = makeStyles()(() => { + return { + root: { + minWidth: 275, + minHeight: 270, + textAlign: 'center', + }, + title: { + fontSize: 20, + fontWeight: 'fontWeightBold', + }, + pos: { + marginBottom: 12, + }, + } +}); + +/** + * Render progress inside a container centering in the container. + * @returns {JSX} Loading animation. + */ +export default function RateLimitingCard() { + const {classes} = useStyles(); + const { isSuperTenant } = useAppContext(); + const intl = useIntl(); + const selectedRateLimitingPolicies = [ + { + name: intl.formatMessage({ + id: 'Dashboard.rateLimiting.card.advancedPolicies.name', + defaultMessage: 'Advanced Policies', + }), + description: intl.formatMessage({ + id: 'Dashboard.rateLimiting.card.advancedPolicies.description', + defaultMessage: 'Control access per API or API resource using advanced rules', + }), + icon: , + path: '/throttling/advanced', + }, + { + name: intl.formatMessage({ + id: 'Dashboard.rateLimiting.card.applicationPolicies.name', + defaultMessage: 'Application Policies', + }), + description: intl.formatMessage({ + id: 'Dashboard.rateLimiting.card.applicationPolicies.description', + defaultMessage: 'Applicable per access token generated for an application', + }), + icon: , + path: '/throttling/application', + }, + { + name: intl.formatMessage({ + id: 'Dashboard.rateLimiting.card.subscriptionPolicies.name', + defaultMessage: 'Subscription Policies', + }), + description: intl.formatMessage({ + id: 'Dashboard.rateLimiting.card.subscriptionPolicies.description', + defaultMessage: 'Control access per Subscription', + }), + icon: , + path: '/throttling/subscription', + }, + { + name: intl.formatMessage({ + id: 'Dashboard.rateLimiting.card.customPolicies.name', + defaultMessage: 'Custom Policies', + }), + description: intl.formatMessage({ + id: 'Dashboard.rateLimiting.card.customPolicies.description', + defaultMessage: 'Allows system administrators to define dynamic ' + + 'rules for specific use cases, which are applied globally across all tenants.', + }), + icon: , + path: '/throttling/custom', + id: 'Custom Policies', + }, + ]; + let selectedPolicies = selectedRateLimitingPolicies; + if (!isSuperTenant) { + selectedPolicies = selectedRateLimitingPolicies.filter((item) => item.id !== 'Custom Policies'); + } + + return ( + + + + + + + + + {selectedPolicies.map((policy) => { + return ( + + + {policy.icon} + + + + + {policy.name} + + + + {policy.description} + + + + ); + })} + + + + ); +} diff --git a/admin/admin-ui/client/source/pages/Dashboard/TasksWorkflowCard.tsx b/admin/admin-ui/client/source/pages/Dashboard/TasksWorkflowCard.tsx new file mode 100644 index 000000000..7c2d9a801 --- /dev/null +++ b/admin/admin-ui/client/source/pages/Dashboard/TasksWorkflowCard.tsx @@ -0,0 +1,756 @@ +/* + * Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you 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. + */ + +import React, { useEffect, useState } from 'react'; +import { FormattedMessage, useIntl } from 'react-intl'; +import { Link as RouterLink } from 'react-router-dom'; +import { Card } from '@mui/material'; +import Avatar from '@mui/material/Avatar'; +import Box from '@mui/material/Box'; +import Button from '@mui/material/Button'; +import CardContent from '@mui/material/CardContent'; +import Divider from '@mui/material/Divider'; +import Link from '@mui/material/Link'; +import { makeStyles } from 'tss-react/mui'; +import Typography from '@mui/material/Typography'; +import DeviceHubIcon from '@ant-design/icons/GroupOutlined'; +import DnsRoundedIcon from '@ant-design/icons/GroupOutlined'; +import PeopleIcon from '@ant-design/icons/GroupOutlined'; +import PermMediaOutlinedIcon from '@ant-design/icons/GroupOutlined'; +import PublicIcon from '@ant-design/icons/GroupOutlined'; +import SettingsEthernetIcon from '@ant-design/icons/GroupOutlined'; +import Alert from 'components/Alert'; +import moment from 'moment'; +import useAxiosPromise from 'components/hooks/useAxiosPromise'; + +const useStyles = makeStyles()((theme) => { + return { + root: { + minWidth: 275, + minHeight: 270, + textAlign: 'center', + + }, + title: { + fontSize: 20, + fontWeight: 'fontWeightBold', + }, + avatar: { + width: theme.spacing(4), + height: theme.spacing(4), + }, + approveButton: { + textDecoration: 'none', + backgroundColor: theme.palette.success.light, + margin: theme.spacing(0.5), + }, + rejectButton: { + textDecoration: 'none', + backgroundColor: theme.palette.error.light, + margin: theme.spacing(0.5), + }, + } +}); + +/** + * Render progress inside a container centering in the container. + * @returns {JSX} Loading animation. + */ +export default function TasksWorkflowCard() { + const {classes} = useStyles(); + const intl = useIntl(); + const [allTasksSet, setAllTasksSet] = useState({} as any); + + /** + * Calculate total task count + * @returns {int} total task count + */ + function getAllTaskCount() { + let counter = 0; + for (const task in allTasksSet) { + if (allTasksSet[task]) { + counter += allTasksSet[task].length; + } + } + return counter; + } + + // Fetch all workflow tasks + const fetchAllWorkFlows = () => { + const promiseUserSign = useAxiosPromise({url: 'workflows?workflowType=AM_USER_SIGNUP'}); + const promiseStateChange = useAxiosPromise({url: 'workflows?workflowType=AM_API_STATE'}); + const promiseApiProductStateChange = useAxiosPromise({url: 'workflows?workflowType=AM_API_PRODUCT_STATE'}); + const promiseAppCreation = useAxiosPromise({url: 'workflows?workflowType=AM_APPLICATION_CREATION'}); + const promiseAppDeletion = useAxiosPromise({url: 'workflows?workflowType=AM_APPLICATION_DELETION'}); + const promiseSubCreation = useAxiosPromise({url: 'workflows?workflowType=AM_SUBSCRIPTION_CREATION'}); + const promiseSubDeletion = useAxiosPromise({url: 'workflows?workflowType=AM_SUBSCRIPTION_DELETION'}); + const promiseSubUpdate = useAxiosPromise({url: 'workflows?workflowType=AM_SUBSCRIPTION_UPDATE'}); + const promiseRegProd = useAxiosPromise({url: 'workflows?workflowType=AM_APPLICATION_REGISTRATION_PRODUCTION'}); + const promiseRegSb = useAxiosPromise({url: 'workflows?workflowType=AM_APPLICATION_REGISTRATION_SANDBOX'}); + Promise.all([promiseUserSign, promiseStateChange, promiseAppCreation, promiseAppDeletion, promiseSubCreation, + promiseSubDeletion, promiseSubUpdate, promiseRegProd, promiseRegSb, promiseApiProductStateChange]) + .then(([resultUserSign, resultStateChange, resultAppCreation, resultAppDeletion, resultSubCreation, + resultSubDeletion, resultSubUpdate, resultRegProd, resultRegSb, resultApiProductStateChange]) => { + const userCreation = resultUserSign.body.list; + const stateChange = resultStateChange.body.list; + const productStateChange = resultApiProductStateChange.body.list; + const applicationCreation = resultAppCreation.body.list; + const applicationDeletion = resultAppDeletion.body.list; + const subscriptionCreation = resultSubCreation.body.list; + const subscriptionDeletion = resultSubDeletion.body.list; + const subscriptionUpdate = resultSubUpdate.body.list; + const registration = resultRegProd.body.list.concat(resultRegSb.body.list); + setAllTasksSet({ + userCreation, + stateChange, + applicationCreation, + applicationDeletion, + subscriptionCreation, + subscriptionDeletion, + subscriptionUpdate, + registration, + productStateChange, + }); + }); + }; + + useEffect(() => { + fetchAllWorkFlows(); + }, []); + + // Component to be displayed when there's no task available + // Note: When workflow is not enabled, this will be displayed + const noTasksCard = ( + + + + + + + + + + + + + + + + ); + + // Compact task card component's individual category component + const getCompactTaskComponent = (IconComponent, path, name, numberOfTasks) => { + return ( + + + + + + + + + + {name} + + + + {numberOfTasks + ' '} + {numberOfTasks === 1 + ? ( + + ) : ( + + )} + + + + ); + }; + + // Component to be displayed when there are more than 4 tasks available + // Renders the total task count, each task category remaining task count and links + const compactTasksCard = () => { + const compactTaskComponentDetails = [ + { + icon: PeopleIcon, + path: '/tasks/user-creation', + name: intl.formatMessage({ + id: 'Dashboard.tasksWorkflow.compactTasks.userCreation.name', + defaultMessage: 'User Creation', + }), + count: allTasksSet.userCreation.length, + }, + { + icon: DnsRoundedIcon, + path: '/tasks/application-creation', + name: intl.formatMessage({ + id: 'Dashboard.tasksWorkflow.compactTasks.applicationCreation.name', + defaultMessage: 'Application Creation', + }), + count: allTasksSet.applicationCreation.length, + }, + { + icon: DnsRoundedIcon, + path: '/tasks/application-deletion', + name: intl.formatMessage({ + id: 'Dashboard.tasksWorkflow.compactTasks.applicationDeletion.name', + defaultMessage: 'Application Deletion', + }), + count: allTasksSet.applicationDeletion.length, + }, + { + icon: PermMediaOutlinedIcon, + path: '/tasks/subscription-creation', + name: intl.formatMessage({ + id: 'Dashboard.tasksWorkflow.compactTasks.subscriptionCreation.name', + defaultMessage: 'Subscription Creation', + }), + count: allTasksSet.subscriptionCreation.length, + }, + { + icon: PermMediaOutlinedIcon, + path: '/tasks/subscription-deletion', + name: intl.formatMessage({ + id: 'Dashboard.tasksWorkflow.compactTasks.subscriptionDeletion.name', + defaultMessage: 'Subscription Deletion', + }), + count: allTasksSet.subscriptionDeletion.length, + }, + { + icon: PermMediaOutlinedIcon, + path: '/tasks/subscription-update', + name: intl.formatMessage({ + id: 'Dashboard.tasksWorkflow.compactTasks.subscriptionUpdate.name', + defaultMessage: 'Subscription Update', + }), + count: allTasksSet.subscriptionUpdate.length, + }, + { + icon: PublicIcon, + path: '/tasks/application-registration', + name: intl.formatMessage({ + id: 'Dashboard.tasksWorkflow.compactTasks.applicationRegistration.name', + defaultMessage: 'Application Registration', + }), + count: allTasksSet.registration.length, + }, + { + icon: SettingsEthernetIcon, + path: '/tasks/api-state-change', + name: intl.formatMessage({ + id: 'Dashboard.tasksWorkflow.compactTasks.apiStateChange.name', + defaultMessage: 'API State Change', + }), + count: allTasksSet.stateChange.length, + }, + { + icon: SettingsEthernetIcon, + path: '/tasks/api-product-state-change', + name: intl.formatMessage({ + id: 'Dashboard.tasksWorkflow.compactTasks.apiProductStateChange.name', + defaultMessage: 'API Product State Change', + }), + count: allTasksSet.productStateChange.length, + }, + ]; + return ( + + + + + + + + + + + {getAllTaskCount()} + + + + + + + + {compactTaskComponentDetails.map((c) => { + return getCompactTaskComponent(c.icon, c.path, c.name, c.count); + })} + + + + ); + }; + + // Approve/Reject button onClick handler + const updateStatus = (referenceId, value) => { + const body = { + status: value, + }; + /* + restApi.updateWorkflow(referenceId, body) + .then(() => { + Alert.success( + , + ); + }) + .catch(() => { + Alert.error( + , + ); + }) + .finally(() => { + fetchAllWorkFlows(); + }); + */ + }; + + // Renders the approve/reject buttons with styles + const getApproveRejectButtons = (referenceId) => { + return ( + + + + + ); + }; + + // Fewer task component's application creation task element + const getApplicationCreationFewerTaskComponent = () => { + // Application Creation tasks related component generation + return allTasksSet.applicationCreation.map((task) => { + return ( + + + + {task.properties.applicationName} + + + + + + +   + {task.properties.userName} +   + + + {moment(task.createdTime).fromNow()} + + + + {getApproveRejectButtons(task.referenceId)} + + ); + }); + }; + + const getApplicationDeletionFewerTaskComponent = () => { + // Application Creation tasks related component generation + return allTasksSet.applicationDeletion.map((task) => { + return ( + + + + {task.properties.applicationName} + + + + + + +   + {task.properties.userName} +   + + + {moment(task.createdTime).fromNow()} + + + + {getApproveRejectButtons(task.referenceId)} + + ); + }); + }; + + // Fewer task component's user creation task element + const getUserCreationFewerTaskComponent = () => { + // User Creation tasks related component generation + return allTasksSet.userCreation.map((task) => { + return ( + + + + {task.properties.tenantAwareUserName} + + + + + + +   + {task.properties.tenantDomain} +   + + + {moment(task.createdTime).fromNow()} + + + + {getApproveRejectButtons(task.referenceId)} + + ); + }); + }; + + // Fewer task component's subscription creation task element + const getSubscriptionCreationFewerTaskComponent = () => { + // Subscription Creation tasks related component generation + return allTasksSet.subscriptionCreation.map((task) => { + return ( + + + + {task.properties.apiName + '-' + task.properties.apiVersion} + + + + {task.properties.applicationName + ','} +   + + + + + +   + {task.properties.subscriber} +   + + + {moment(task.createdTime).fromNow()} + + + + {getApproveRejectButtons(task.referenceId)} + + ); + }); + }; + + // Fewer task component's subscription creation task element + const getSubscriptionDeletionFewerTaskComponent = () => { + // Subscription Update tasks related component generation + return allTasksSet.subscriptionDeletion.map((task) => { + return ( + + + + {task.properties.apiName + '-' + task.properties.apiVersion} + + + + {task.properties.applicationName + ','} +   + + + + + +   + {task.properties.subscriber} +   + + + {moment(task.createdTime).fromNow()} + + + + {getApproveRejectButtons(task.referenceId)} + + ); + }); + }; + + // Fewer task component's subscription creation task element + const getSubscriptionUpdateFewerTaskComponent = () => { + // Subscription Update tasks related component generation + return allTasksSet.subscriptionUpdate.map((task) => { + return ( + + + + {task.properties.apiName + '-' + task.properties.apiVersion} + + + + {task.properties.applicationName + ','} +   + + + + + +   + {task.properties.subscriber} +   + + + {moment(task.createdTime).fromNow()} + + + + {getApproveRejectButtons(task.referenceId)} + + ); + }); + }; + + // Fewer task component's registration creation task element + const getRegistrationCreationFewerTaskComponent = () => { + // Registration Creation tasks related component generation + return allTasksSet.registration.map((task) => { + let keyType; + if (task.properties.keyType === 'PRODUCTION') { + keyType = ( + + ); + } else if (task.properties.keyType === 'SANDBOX') { + keyType = ( + + ); + } else { + keyType = task.properties.keyType; + } + return ( + + + + {task.properties.applicationName} + + + + {keyType} +   + + + + + +   + {task.properties.userName} +   + + + {moment(task.createdTime).fromNow()} + + + + {getApproveRejectButtons(task.referenceId)} + + ); + }); + }; + + // Fewer task component's api state change task element + const getStateChangeFewerTaskComponent = () => { + // State Change tasks related component generation + return allTasksSet.stateChange.map((task) => { + return ( + + + + {task.properties.apiName + '-' + task.properties.apiVersion} + + + + +   + + + {task.properties.action} +   + + + {moment(task.createdTime).fromNow()} + + + + {getApproveRejectButtons(task.referenceId)} + + ); + }); + }; + + const getAPIProductStateChangeFewerTaskComponent = () => { + // State Change tasks related component generation + return allTasksSet.productStateChange.map((task) => { + return ( + + + + {task.properties.apiName} + + + + +   + + + {task.properties.action} +   + + + {moment(task.createdTime).fromNow()} + + + + {getApproveRejectButtons(task.referenceId)} + + ); + }); + }; + + // Component to be displayed when there are 4 or less remaining tasks + // Renders some details of the task and approve/reject buttons + const fewerTasksCard = () => { + return ( + + + + + + + + + + + {getAllTaskCount()} + + + + + + {getApplicationCreationFewerTaskComponent()} + {getApplicationDeletionFewerTaskComponent()} + {getUserCreationFewerTaskComponent()} + {getSubscriptionCreationFewerTaskComponent()} + {getSubscriptionDeletionFewerTaskComponent()} + {getSubscriptionUpdateFewerTaskComponent()} + {getRegistrationCreationFewerTaskComponent()} + {getStateChangeFewerTaskComponent()} + {getAPIProductStateChangeFewerTaskComponent()} + + + ); + }; + + // Render the card depending on the number of all remaining tasks + const cnt = getAllTaskCount(); + if (cnt > 4) { + return compactTasksCard(); + } else if (cnt > 0) { + return fewerTasksCard(); + } else { + return noTasksCard; + } +} diff --git a/admin/admin-ui/client/source/pages/KeyManagers/DeleteKeyManager.tsx b/admin/admin-ui/client/source/pages/KeyManagers/DeleteKeyManager.tsx new file mode 100644 index 000000000..1e04bf17f --- /dev/null +++ b/admin/admin-ui/client/source/pages/KeyManagers/DeleteKeyManager.tsx @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you 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. + */ + +/** + * Render delete dialog box. + * @param {JSON} props component props. + * @returns {TSX} Loading animation. + */ +import React, { useState } from 'react'; +import DialogContentText from '@mui/material/DialogContentText'; +import DeleteForeverIcon from '@mui/icons-material/DeleteForever'; +import axios from "axios"; +import Button from '@mui/material/Button'; +import Dialog from '@mui/material/Dialog'; +import DialogActions from '@mui/material/DialogActions'; +import DialogContent from '@mui/material/DialogContent'; +import DialogTitle from '@mui/material/DialogTitle'; +import IconButton from '@mui/material/IconButton'; +import CircularProgress from '@mui/material/CircularProgress'; + +interface DeleteProps { + keyManagerId: string; + updateList: () => void; +} + +const DeleteKeyManager: React.FC = ({ keyManagerId, updateList }) => { + const [open, setOpen] = useState(false); + const [saving, setSaving] = useState(false); + + const handleClickOpen = () => { + setOpen(true); + }; + + const handleClose = () => { + setOpen(false); + }; + + const saveTriggered = () => { + setSaving(true); + deleteOrganization(); + handleClose(); + }; + + const deleteOrganization = () => { + axios + .delete(`/api/am/admin/key-managers/${keyManagerId}`, { + withCredentials: true, + }) + .then(() => { + }) + .catch((error) => { + throw error.response.body.description; + }) + .finally(() => { + updateList(); + setSaving(false); + }); + }; + + return ( + <> + + + + + + Delete KeyManager? + + Are you sure you want to delete this KeyManager? + + + + + + + + ); +}; + +export default DeleteKeyManager; diff --git a/admin/admin-ui/client/source/pages/KeyManagers/ListKeyManagers.tsx b/admin/admin-ui/client/source/pages/KeyManagers/ListKeyManagers.tsx new file mode 100644 index 000000000..7a048831c --- /dev/null +++ b/admin/admin-ui/client/source/pages/KeyManagers/ListKeyManagers.tsx @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you 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. + */ + +/** + * Render organization data table. + * @param {JSON} props component props. + * @returns {TSX} Loading animation. + */ +import React, { useState } from 'react'; +import Stack from '@mui/material/Stack'; +import { useIntl } from 'react-intl'; +import { Grid, Typography } from '@mui/material'; +import Button from '@mui/material/Button'; +import AddCircleOutlineIcon from '@mui/icons-material/AddCircleOutline'; + +import PaginatedClientSide from 'components/data-table/PaginatedClientSide'; +import GetKeyManagers from 'components/hooks/getKeyManagers'; +import Loader from 'components/Loader'; +import Switch from '@mui/material/Switch'; +import Delete from './DeleteKeyManager'; +import IconButton from '@mui/material/IconButton'; +import EditIcon from '@mui/icons-material/Edit'; + +export default function ListKeyManagers() { + const [trigger, setTrigger] = useState(false); + const { data, loading, error } = GetKeyManagers({ trigger: trigger, setTrigger: setTrigger }); + + const intl = useIntl(); + + const searchProps = { + searchPlaceholder: intl.formatMessage({ + id: 'AdminPages.Organizations.List.search.default', + defaultMessage: 'Search by KeyManager name', + }), + }; + + const fetchData = () => { + setTrigger(true); + }; + + const columns = [ + { + Header: 'Name', + accessor: 'name', + }, + { + Header: 'Type', + accessor: 'type', + }, + { + Header: 'Issuer', + accessor: 'issuer', + }, + { + Header: 'Enabled', + accessor: 'enabled', + Cell: ({ row }: { row: any }) => ( + + ), + }, + { + Header: 'Actions', + accessor: 'actions', + Cell: ({ row }: { row: any }) => ( + + + + + + + ), + }, + ]; + + if (error) { + return
Error
; + } + if (loading) { + return ; + } + if (data && data.length === 0) { + return
No data
; + } + return ( +
+
+ + + Key Managers + + + + + +
+
+ +
+
+ ); +} \ No newline at end of file diff --git a/admin/admin-ui/client/source/pages/Organizations/AddEditOrganization.tsx b/admin/admin-ui/client/source/pages/Organizations/AddEditOrganization.tsx new file mode 100644 index 000000000..70c4fceeb --- /dev/null +++ b/admin/admin-ui/client/source/pages/Organizations/AddEditOrganization.tsx @@ -0,0 +1,289 @@ +/* + * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you 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. + */ + +import React, { useEffect, useState } from 'react'; +import { FormattedMessage } from 'react-intl'; +import { styled } from '@mui/material/styles'; +import Button from '@mui/material/Button'; +import CircularProgress from '@mui/material/CircularProgress'; +import Dialog from '@mui/material/Dialog'; +import DialogActions from '@mui/material/DialogActions'; +import DialogContent from '@mui/material/DialogContent'; +import DialogTitle from '@mui/material/DialogTitle'; +import IconButton from '@mui/material/IconButton'; +import TextField from '@mui/material/TextField'; + +import EditIcon from '@mui/icons-material/Edit'; +import AddCircleOutlineIcon from '@mui/icons-material/AddCircleOutline'; + +import { MuiChipsInput } from 'mui-chips-input'; + +interface OrganizationData { + id: string + name: string; + displayName: string; + organizationClaimValue: string; + enabled: boolean; +} + +interface Props { + datarow: any; + updateList: (organization) => void; +} + +/** + * Render add & edit dialog boxes. + * @param {JSON} props component props. + * @returns {TSX} Loading animation. + */ +const AddEditOrganization: React.FC = ({ + datarow, + updateList, +}) => { + // const emptyDatarow = Object.keys(datarow).length === 0 + const [open, setOpen] = useState(false); + const [saving, setSaving] = useState(false); + const [organization, setOrganization] = useState({ + id: datarow ? datarow.id : '', + name: datarow ? datarow.name : '', + displayName: datarow ? datarow.displayName : '', + organizationClaimValue: datarow ? datarow.organizationClaimValue : '', + enabled: datarow ? datarow.enabled : true, + }); + const [serviceNamespaces, setServiceNamespaces] = useState({ serviceNamespaces: datarow ? datarow.serviceNamespaces : [] }); + const [production, setProduction] = useState({ production: datarow ? datarow.production : [] }); + const [sandbox, setSandbox] = useState({ sandbox: datarow ? datarow.sandbox : [] }); + const [dialogTitle, setDialogTitle] = useState('Edit Organization'); + const [errors, setErrors] = useState<{ + name?: string; + claimValue?: string; + displayName?: string; + }>({}); + + const handleClickOpen = () => { + setOpen(true); + } + + const handleClose = () => { + setOpen(false); + }; + + const handleSave = () => { + const newErrors = validateOrganizationForm(); + setSaving(true); + if (Object.keys(newErrors).length === 0) { + updateList({ ...organization, ...serviceNamespaces, ...production, ...sandbox }); + setSaving(false); + } else { + setErrors(newErrors); + setSaving(false); + return false; + } + + handleClose(); + return true; + }; + + const handleInputChange = (e: React.ChangeEvent) => { + setOrganization({ ...organization, [e.target.name]: e.target.value }); + if (e.target.name === 'name') { + setErrors((prevErrors) => ({ ...prevErrors, name: '' })); + } + if (e.target.name === 'displayName') { + setErrors((prevErrors) => ({ ...prevErrors, displayName: '' })); + } + if (e.target.name === 'organizationClaimValue') { + setErrors((prevErrors) => ({ ...prevErrors, claimValue: '' })); + } + }; + + const handleSeriveNamespacesChipChange = (newValue) => { + setServiceNamespaces({ ...serviceNamespaces, serviceNamespaces: newValue }); + } + + const handleProductionChipChange = (newValue) => { + setProduction({ ...production, production: newValue }) + } + + const handleSandboxChipChange = (newValue) => { + setSandbox({ ...sandbox, sandbox: newValue }) + } + + const { name: orgName, displayName: orgDisplayName, organizationClaimValue: orgClaimValue } = organization; + const { serviceNamespaces: orgServiceNamespaces } = serviceNamespaces; + const { production: orgProduction } = production; + const { sandbox: orgSandbox } = sandbox; + + const validateOrganizationForm = (): { name?: string; orgClaimValue?: string } => { + let newErrors: { name?: string; claimValue?: string; displayName?: string } = {}; + + if (!orgName) { + newErrors.name = 'Organization name should not be empty'; + } + if (!orgClaimValue) { + newErrors.claimValue = 'Organization claim value should not be empty'; + } + if (!orgDisplayName) { + newErrors.displayName = 'Organization display name should not be empty'; + } + + return newErrors; + }; + + const StyledChipsInput = styled(MuiChipsInput)(({ }) => ({ + '& .MuiChipsInput-Chip': { + borderRadius: '25px', + } + })); + + useEffect(() => { + if (!datarow) { + setOrganization({ + id: '', + name: '', + displayName: '', + organizationClaimValue: '', + enabled: true, + }) + setServiceNamespaces({ serviceNamespaces: [] }); + setProduction({ production: [] }) + setSandbox({ sandbox: [] }) + setDialogTitle('Add Organization'); + } + setErrors((prevErrors) => ({ ...prevErrors, name: '' })); + setErrors((prevErrors) => ({ ...prevErrors, displayName: '' })); + setErrors((prevErrors) => ({ ...prevErrors, claimValue: '' })); + }, [open]); + + return ( + <> + {datarow && ( + + + + )} + + {!datarow && ( + + )} + + + {dialogTitle} + + <> + + + * + + )} + helperText={errors?.name ? errors.name : 'Name of the Organization'} + error={!!errors?.name} + style={{ marginTop: '15px' }} + /> + + + * + + )} + helperText={errors?.displayName ? errors.displayName : 'Display Name of the Organization'} + error={!!errors?.displayName} + variant='outlined' + style={{ marginTop: '15px' }} + /> + + + * + + )} + helperText={errors?.claimValue ? errors.claimValue : 'Claim Value of the Organization'} + error={!!errors?.claimValue} + variant='outlined' + style={{ marginTop: '15px' }} + /> + + + + + + + + + + + + ); +} +export default AddEditOrganization; diff --git a/admin/admin-ui/client/source/pages/Organizations/DeleteOrganization.tsx b/admin/admin-ui/client/source/pages/Organizations/DeleteOrganization.tsx new file mode 100644 index 000000000..a54979e03 --- /dev/null +++ b/admin/admin-ui/client/source/pages/Organizations/DeleteOrganization.tsx @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you 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. + */ + +/** + * Render delete dialog box. + * @param {JSON} props component props. + * @returns {TSX} Loading animation. + */ +import React, { useState } from 'react'; +import DialogContentText from '@mui/material/DialogContentText'; +import DeleteForeverIcon from '@mui/icons-material/DeleteForever'; +import axios from "axios"; +import Button from '@mui/material/Button'; +import Dialog from '@mui/material/Dialog'; +import DialogActions from '@mui/material/DialogActions'; +import DialogContent from '@mui/material/DialogContent'; +import DialogTitle from '@mui/material/DialogTitle'; +import IconButton from '@mui/material/IconButton'; +import CircularProgress from '@mui/material/CircularProgress'; + +interface DeleteProps { + orgId: string; + updateList: () => void; +} + +const DeleteOrganization: React.FC = ({ orgId, updateList }) => { + const [open, setOpen] = useState(false); + const [saving, setSaving] = useState(false); + + const handleClickOpen = () => { + setOpen(true); + }; + + const handleClose = () => { + setOpen(false); + }; + + const saveTriggered = () => { + setSaving(true); + deleteOrganization(); + handleClose(); + }; + + const deleteOrganization = () => { + axios + .delete(`/api/admin/organizations/${orgId}`, { + withCredentials: true, + }) + .then(() => { + }) + .catch((error) => { + throw error.response.body.description; + }) + .finally(() => { + updateList(); + setSaving(false); + }); + }; + + + + return ( + <> + + + + + + Delete Organization? + + Are you sure you want to delete this Organization? + + + + + + + + ); +}; + +export default DeleteOrganization; diff --git a/admin/admin-ui/client/source/pages/Organizations/ListOrganizations.tsx b/admin/admin-ui/client/source/pages/Organizations/ListOrganizations.tsx new file mode 100644 index 000000000..e3fa052c8 --- /dev/null +++ b/admin/admin-ui/client/source/pages/Organizations/ListOrganizations.tsx @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you 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. + */ + +/** + * Render organization data table. + * @param {JSON} props component props. + * @returns {TSX} Loading animation. + */ +import React, { useState } from 'react'; +import Stack from '@mui/material/Stack'; +import { useIntl, FormattedMessage } from 'react-intl'; +import { Grid, Typography } from '@mui/material'; + +import axios from 'axios'; +import PaginatedClientSide from 'components/data-table/PaginatedClientSide'; +import GetOrganizations from 'components/hooks/getOrganizations'; +import Loader from 'components/Loader'; +import Delete from './DeleteOrganization'; +import AddEdit from './AddEditOrganization'; +import TooltipPopup from './TooltipPopup'; +import Switch from '@mui/material/Switch'; +import Snackbar from '@mui/material/Snackbar'; + +import MuiAlert from '@mui/material/Alert'; + +export default function ListOrganizations() { + const [trigger, setTrigger] = useState(false); + const { data, loading, error } = GetOrganizations({ trigger: trigger, setTrigger: setTrigger }); + const [snackbarOpen, setSnackbarOpen] = useState(false); + const [formattedMessage, setFormattedMessage] = useState({ + id: '', + defaultMessage: '', + }); + const intl = useIntl(); + + const fetchData = () => { + setTrigger(true); + }; + + const createOrganization = (organization) => { + axios + .post('/api/admin/organizations/', { + ...organization + }, { + withCredentials: true, + }) + .then(() => { + setFormattedMessage({ + id: 'AdminPages.Organizations.AddEdit.form.add.successful', + defaultMessage: 'Organization added successfully' + }); + setSnackbarOpen(true); + }) + .catch((error) => { + throw error.response.body.description; + }) + .finally(() => { + fetchData(); + }); + }; + + const updateOrganization = (organization) => { + axios + .put('/api/admin/organizations/' + organization.id, { + ...organization + }, { + withCredentials: true, + }) + .then(() => { + setFormattedMessage({ + id: 'AdminPages.Organizations.AddEdit.form.edit.successful', + defaultMessage: 'Organization edited successfully' + }); + setSnackbarOpen(true); + }) + .catch((error) => { + throw error.response.body.description; + }) + .finally(() => { + fetchData(); + }); + }; + + const handleEnabledChange = (e: React.ChangeEvent, organization) => { + updateOrganization({ ...organization, [e.target.name]: e.target.checked} ); + }; + + const searchProps = { + searchPlaceholder: intl.formatMessage({ + id: 'AdminPages.Organizations.List.search.default', + defaultMessage: 'Search by Organization name', + }), + }; + + const columns = [ + { + Header: 'Organization Name', + accessor: 'displayName', + sortable: true, + Cell: ({ row }: { row: any }) => ( + + + + ), + }, + { + Header: 'Organization Claim Value', + accessor: 'organizationClaimValue', + }, + { + Header: 'Enabled', + accessor: 'enabled', + Cell: ({ row }: { row: any }) => ( + handleEnabledChange(e, row.original)} + color='primary' + name='enabled' + key={row.original.id} + size='small' + /> + ), + }, + { + Header: 'Actions', + accessor: 'actions', + Cell: ({ row }: { row: any }) => ( + + updateOrganization(updatedOrganization)} + /> + + + ), + }, + ]; + + if (error) { + return
Error
; + } + if (loading) { + return ; + } + if (data && data.length === 0) { + return
No data
; + } + return ( +
+
+ + + Organizations + + + createOrganization(newOrganization)} + /> + + +
+
+ +
+ setSnackbarOpen(false)}> + setSnackbarOpen(false)} severity='success' sx={{ width: '100%' }}> + { + + } + + +
+ ); +} diff --git a/admin/admin-ui/client/source/pages/Organizations/TooltipPopup.tsx b/admin/admin-ui/client/source/pages/Organizations/TooltipPopup.tsx new file mode 100644 index 000000000..21a7d1f49 --- /dev/null +++ b/admin/admin-ui/client/source/pages/Organizations/TooltipPopup.tsx @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you 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. + */ + +import React from 'react'; +import Tooltip, { TooltipProps, tooltipClasses } from '@mui/material/Tooltip'; +import { styled } from '@mui/material/styles'; +import Link from '@mui/material/Link'; + +interface Organization { + name: string; + displayName: string; + organizationClaimValue: string; + serviceNamespaces: string; + production: string; + sandbox: string; +} + +interface TooltipPopupProps { + org: Organization; +} + +const CustomWidthTooltip = styled(({ className, ...props }: TooltipProps) => ( + +))(({ theme }) => ({ + [`& .${tooltipClasses.tooltip}`]: { + maxWidth: 500, + backgroundColor: theme.palette.common.white, + color: 'rgba(0, 0, 0, 0.87)', + boxShadow: theme.shadows[1], + }, +})); + +const TooltipPopup: React.FC = ({ org }) => { + + const title = org && ( +
+ Name: {org.name}
+ Display Name: {org.displayName}
+ Organization Claim Value: {org.organizationClaimValue}
+ Service Namespaces: {org.serviceNamespaces}
+ Production Endpoints: {org.production}
+ Sandbox Endpoints: {org.sandbox}
+
+ ); + + return ( +
+ + + {org.displayName} + + +
+ ); +} + +export default TooltipPopup; diff --git a/admin/admin-ui/client/source/pages/sample/SamplePage.tsx b/admin/admin-ui/client/source/pages/sample/SamplePage.tsx new file mode 100644 index 000000000..eee3434b3 --- /dev/null +++ b/admin/admin-ui/client/source/pages/sample/SamplePage.tsx @@ -0,0 +1,21 @@ +import React from 'react'; +// material-ui +import { Typography } from '@mui/material'; + +// project import +import MainCard from 'components/MainCard'; + +// ==============================|| SAMPLE PAGE ||============================== // + +const SamplePage = () => ( + + + Lorem ipsum dolor sit amen, consenter nipissing eli, sed do elusion tempos incident ut laborers et doolie magna alissa. Ut enif + ad minim venice, quin nostrum exercitation illampu laborings nisi ut liquid ex ea commons construal. Duos aube grue dolor in + reprehended in voltage veil esse colum doolie eu fujian bulla parian. Exceptive sin ocean cuspidate non president, sunk in culpa + qui officiate descent molls anim id est labours. + + +); + +export default SamplePage; diff --git a/admin/admin-ui/client/source/routes/MainRoutes.tsx b/admin/admin-ui/client/source/routes/MainRoutes.tsx new file mode 100644 index 000000000..c17a3fa79 --- /dev/null +++ b/admin/admin-ui/client/source/routes/MainRoutes.tsx @@ -0,0 +1,40 @@ +// Import your page components +import React, { lazy } from 'react'; +import { Route, Routes } from "react-router-dom"; + +// project import +import Loadable from 'components/Loadable'; +import MainLayout from 'layout/MainLayout'; + +// render - dashboard +// const DashboardDefault = Loadable(lazy(() => import('pages/Dashboard/Dashboard'))); + +// render - sample page +const SamplePage = Loadable(lazy(() => import('pages/sample/SamplePage'))); +const ApplicationRatePlans = Loadable(lazy(() => import('pages/ApplicationRatePlans/ListApplicationRatePlans'))); +const APICategories = Loadable(lazy(() => import('pages/APICategories/ListAPICategories'))); +const OrganizationsPage = Loadable(lazy(() => import('pages/Organizations/ListOrganizations'))); +const KeyManagers = Loadable(lazy(() => import('pages/KeyManagers/ListKeyManagers'))); + +// ==============================|| MAIN ROUTING ||============================== // +export default function MainRoutes() { + return ( + + }> + } /> + } /> + } /> + } /> + } /> + } /> + {/* } /> */} + {/* } /> */} + } /> + } /> + } /> + {/* } /> */} + } /> + + + ); +} diff --git a/admin/admin-ui/client/source/themes/index.tsx b/admin/admin-ui/client/source/themes/index.tsx new file mode 100644 index 000000000..9c259189a --- /dev/null +++ b/admin/admin-ui/client/source/themes/index.tsx @@ -0,0 +1,76 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { useMemo } from 'react'; + +// material-ui +import { CssBaseline, StyledEngineProvider } from '@mui/material'; +import { createTheme, ThemeProvider, ThemeOptions, Shadows } from '@mui/material/styles'; + +// project import +import Palette from './palette'; +import Typography from './typography'; +import componentsOverride from './overrides'; +import CustomShadows, { CustomShadowsProps } from './shadows'; + +// ==============================|| DEFAULT THEME - MAIN ||============================== // +declare module '@mui/material/styles' { + interface Theme { + customShadows: CustomShadowsProps; + } + + interface ThemeOptions { + customShadows?: CustomShadowsProps; + } + +} + +export default function ThemeCustomization({ children }) { + const theme = Palette('light'); + + const themeTypography = Typography(`'Montserrat', sans-serif;`); + const themeCustomShadows = useMemo(() => CustomShadows(theme), [theme]); + + const themeOptions = useMemo( + (): ThemeOptions => ({ + breakpoints: { + values: { + xs: 0, + sm: 768, + md: 1024, + lg: 1266, + xl: 1536 + } + }, + direction: 'ltr', + mixins: { + toolbar: { + minHeight: 60, + paddingTop: 8, + paddingBottom: 8 + } + }, + palette: theme.palette, + customShadows: themeCustomShadows, + typography: themeTypography + }), + [theme, themeTypography] + ); + + const themes = createTheme(themeOptions); + themes.components = componentsOverride(themes); + + return ( + + + <> + + {children} + + + + ); +} + +ThemeCustomization.propTypes = { + children: PropTypes.node +}; diff --git a/admin/admin-ui/client/source/themes/overrides/Badge.ts b/admin/admin-ui/client/source/themes/overrides/Badge.ts new file mode 100644 index 000000000..21e8a8ca7 --- /dev/null +++ b/admin/admin-ui/client/source/themes/overrides/Badge.ts @@ -0,0 +1,15 @@ +// ==============================|| OVERRIDES - BADGE ||============================== // + +export default function Badge(theme) { + return { + MuiBadge: { + styleOverrides: { + standard: { + minWidth: theme.spacing(2), + height: theme.spacing(2), + padding: theme.spacing(0.5) + } + } + } + }; +} diff --git a/admin/admin-ui/client/source/themes/overrides/Button.ts b/admin/admin-ui/client/source/themes/overrides/Button.ts new file mode 100644 index 000000000..3cf97dbec --- /dev/null +++ b/admin/admin-ui/client/source/themes/overrides/Button.ts @@ -0,0 +1,28 @@ +// ==============================|| OVERRIDES - BUTTON ||============================== // + +export default function Button(theme) { + const disabledStyle = { + '&.Mui-disabled': { + backgroundColor: theme.palette.grey[200] + } + }; + + return { + MuiButton: { + defaultProps: { + disableElevation: true + }, + styleOverrides: { + root: { + fontWeight: 400 + }, + contained: { + ...disabledStyle + }, + outlined: { + ...disabledStyle + } + } + } + }; +} diff --git a/admin/admin-ui/client/source/themes/overrides/CardContent.ts b/admin/admin-ui/client/source/themes/overrides/CardContent.ts new file mode 100644 index 000000000..2edc544b3 --- /dev/null +++ b/admin/admin-ui/client/source/themes/overrides/CardContent.ts @@ -0,0 +1,16 @@ +// ==============================|| OVERRIDES - CARD CONTENT ||============================== // + +export default function CardContent() { + return { + MuiCardContent: { + styleOverrides: { + root: { + padding: 20, + '&:last-child': { + paddingBottom: 20 + } + } + } + } + }; +} diff --git a/admin/admin-ui/client/source/themes/overrides/Checkbox.ts b/admin/admin-ui/client/source/themes/overrides/Checkbox.ts new file mode 100644 index 000000000..81209491a --- /dev/null +++ b/admin/admin-ui/client/source/themes/overrides/Checkbox.ts @@ -0,0 +1,13 @@ +// ==============================|| OVERRIDES - CHECKBOX ||============================== // + +export default function Checkbox(theme) { + return { + MuiCheckbox: { + styleOverrides: { + root: { + color: theme.palette.secondary[300] + } + } + } + }; +} diff --git a/admin/admin-ui/client/source/themes/overrides/Chip.ts b/admin/admin-ui/client/source/themes/overrides/Chip.ts new file mode 100644 index 000000000..db0a0bb46 --- /dev/null +++ b/admin/admin-ui/client/source/themes/overrides/Chip.ts @@ -0,0 +1,40 @@ +// ==============================|| OVERRIDES - CHIP ||============================== // + +export default function Chip(theme) { + return { + MuiChip: { + styleOverrides: { + root: { + borderRadius: 4, + '&:active': { + boxShadow: 'none' + } + }, + sizeLarge: { + fontSize: '1rem', + height: 40 + }, + light: { + color: theme.palette.primary.main, + backgroundColor: theme.palette.primary.lighter, + borderColor: theme.palette.primary.light, + '&.MuiChip-lightError': { + color: theme.palette.error.main, + backgroundColor: theme.palette.error.lighter, + borderColor: theme.palette.error.light + }, + '&.MuiChip-lightSuccess': { + color: theme.palette.success.main, + backgroundColor: theme.palette.success.lighter, + borderColor: theme.palette.success.light + }, + '&.MuiChip-lightWarning': { + color: theme.palette.warning.main, + backgroundColor: theme.palette.warning.lighter, + borderColor: theme.palette.warning.light + } + } + } + } + }; +} diff --git a/admin/admin-ui/client/source/themes/overrides/IconButton.ts b/admin/admin-ui/client/source/themes/overrides/IconButton.ts new file mode 100644 index 000000000..648dba47d --- /dev/null +++ b/admin/admin-ui/client/source/themes/overrides/IconButton.ts @@ -0,0 +1,28 @@ +// ==============================|| OVERRIDES - ICON BUTTON ||============================== // + +export default function IconButton(theme) { + return { + MuiIconButton: { + styleOverrides: { + root: { + borderRadius: 4 + }, + sizeLarge: { + width: theme.spacing(5.5), + height: theme.spacing(5.5), + fontSize: '1.25rem' + }, + sizeMedium: { + width: theme.spacing(4.5), + height: theme.spacing(4.5), + fontSize: '1rem' + }, + sizeSmall: { + width: theme.spacing(3.75), + height: theme.spacing(3.75), + fontSize: '0.75rem' + } + } + } + }; +} diff --git a/admin/admin-ui/client/source/themes/overrides/InputLabel.ts b/admin/admin-ui/client/source/themes/overrides/InputLabel.ts new file mode 100644 index 000000000..d2300a427 --- /dev/null +++ b/admin/admin-ui/client/source/themes/overrides/InputLabel.ts @@ -0,0 +1,25 @@ +// ==============================|| OVERRIDES - INPUT LABEL ||============================== // + +export default function InputLabel(theme) { + return { + MuiInputLabel: { + styleOverrides: { + root: { + color: theme.palette.grey[600] + }, + outlined: { + lineHeight: '0.8em', + '&.MuiInputLabel-sizeSmall': { + lineHeight: '1em' + }, + '&.MuiInputLabel-shrink': { + background: theme.palette.background.paper, + padding: '0 8px', + marginLeft: -6, + lineHeight: '1.4375em' + } + } + } + } + }; +} diff --git a/admin/admin-ui/client/source/themes/overrides/LinearProgress.ts b/admin/admin-ui/client/source/themes/overrides/LinearProgress.ts new file mode 100644 index 000000000..ffbe1eff3 --- /dev/null +++ b/admin/admin-ui/client/source/themes/overrides/LinearProgress.ts @@ -0,0 +1,17 @@ +// ==============================|| OVERRIDES - LINER PROGRESS ||============================== // + +export default function LinearProgress() { + return { + MuiLinearProgress: { + styleOverrides: { + root: { + height: 6, + borderRadius: 100 + }, + bar: { + borderRadius: 100 + } + } + } + }; +} diff --git a/admin/admin-ui/client/source/themes/overrides/Link.ts b/admin/admin-ui/client/source/themes/overrides/Link.ts new file mode 100644 index 000000000..16279df57 --- /dev/null +++ b/admin/admin-ui/client/source/themes/overrides/Link.ts @@ -0,0 +1,11 @@ +// ==============================|| OVERRIDES - LINK ||============================== // + +export default function Link() { + return { + MuiLink: { + defaultProps: { + underline: 'hover' + } + } + }; +} diff --git a/admin/admin-ui/client/source/themes/overrides/ListItemIcon.ts b/admin/admin-ui/client/source/themes/overrides/ListItemIcon.ts new file mode 100644 index 000000000..9001ab658 --- /dev/null +++ b/admin/admin-ui/client/source/themes/overrides/ListItemIcon.ts @@ -0,0 +1,13 @@ +// ==============================|| OVERRIDES - LIST ITEM ICON ||============================== // + +export default function ListItemIcon() { + return { + MuiListItemIcon: { + styleOverrides: { + root: { + minWidth: 24 + } + } + } + }; +} diff --git a/admin/admin-ui/client/source/themes/overrides/OutlinedInput.ts b/admin/admin-ui/client/source/themes/overrides/OutlinedInput.ts new file mode 100644 index 000000000..96709f264 --- /dev/null +++ b/admin/admin-ui/client/source/themes/overrides/OutlinedInput.ts @@ -0,0 +1,47 @@ +// material-ui +import { alpha } from '@mui/material/styles'; + +// ==============================|| OVERRIDES - OUTLINED INPUT ||============================== // + +export default function OutlinedInput(theme) { + return { + MuiOutlinedInput: { + styleOverrides: { + input: { + padding: '10.5px 14px 10.5px 12px' + }, + notchedOutline: { + borderColor: theme.palette.grey[300] + }, + root: { + '&:hover .MuiOutlinedInput-notchedOutline': { + borderColor: theme.palette.primary.light + }, + '&.Mui-focused': { + boxShadow: `0 0 0 2px ${alpha(theme.palette.primary.main, 0.2)}`, + '& .MuiOutlinedInput-notchedOutline': { + border: `1px solid ${theme.palette.primary.light}` + } + }, + '&.Mui-error': { + '&:hover .MuiOutlinedInput-notchedOutline': { + borderColor: theme.palette.error.light + }, + '&.Mui-focused': { + boxShadow: `0 0 0 2px ${alpha(theme.palette.error.main, 0.2)}`, + '& .MuiOutlinedInput-notchedOutline': { + border: `1px solid ${theme.palette.error.light}` + } + } + } + }, + inputSizeSmall: { + padding: '7.5px 8px 7.5px 12px' + }, + inputMultiline: { + padding: 0 + } + } + } + }; +} diff --git a/admin/admin-ui/client/source/themes/overrides/Tab.ts b/admin/admin-ui/client/source/themes/overrides/Tab.ts new file mode 100644 index 000000000..dbd899f87 --- /dev/null +++ b/admin/admin-ui/client/source/themes/overrides/Tab.ts @@ -0,0 +1,14 @@ +// ==============================|| OVERRIDES - TAB ||============================== // + +export default function Tab(theme) { + return { + MuiTab: { + styleOverrides: { + root: { + minHeight: 46, + color: theme.palette.text.primary + } + } + } + }; +} diff --git a/admin/admin-ui/client/source/themes/overrides/TableCell.ts b/admin/admin-ui/client/source/themes/overrides/TableCell.ts new file mode 100644 index 000000000..74ebd9541 --- /dev/null +++ b/admin/admin-ui/client/source/themes/overrides/TableCell.ts @@ -0,0 +1,21 @@ +// ==============================|| OVERRIDES - TABLE CELL ||============================== // + +export default function TableCell(theme) { + return { + MuiTableCell: { + styleOverrides: { + root: { + fontSize: '0.875rem', + padding: 12, + borderColor: theme.palette.divider + }, + head: { + fontWeight: 600, + paddingTop: 20, + paddingBottom: 20, + backgroundColor: theme.palette.grey[50], + } + } + } + }; +} diff --git a/admin/admin-ui/client/source/themes/overrides/Tabs.ts b/admin/admin-ui/client/source/themes/overrides/Tabs.ts new file mode 100644 index 000000000..8e906ccfb --- /dev/null +++ b/admin/admin-ui/client/source/themes/overrides/Tabs.ts @@ -0,0 +1,13 @@ +// ==============================|| OVERRIDES - TABS ||============================== // + +export default function Tabs() { + return { + MuiTabs: { + styleOverrides: { + vertical: { + overflow: 'visible' + } + } + } + }; +} diff --git a/admin/admin-ui/client/source/themes/overrides/Typography.ts b/admin/admin-ui/client/source/themes/overrides/Typography.ts new file mode 100644 index 000000000..9c95a3796 --- /dev/null +++ b/admin/admin-ui/client/source/themes/overrides/Typography.ts @@ -0,0 +1,13 @@ +// ==============================|| OVERRIDES - TYPOGRAPHY ||============================== // + +export default function Typography() { + return { + MuiTypography: { + styleOverrides: { + gutterBottom: { + marginBottom: 12 + } + } + } + }; +} diff --git a/admin/admin-ui/client/source/themes/overrides/index.ts b/admin/admin-ui/client/source/themes/overrides/index.ts new file mode 100644 index 000000000..e5e39e7e6 --- /dev/null +++ b/admin/admin-ui/client/source/themes/overrides/index.ts @@ -0,0 +1,41 @@ +// third-party +import { merge } from 'lodash'; + +// project import +import Badge from './Badge'; +import Button from './Button'; +import CardContent from './CardContent'; +import Checkbox from './Checkbox'; +import Chip from './Chip'; +import IconButton from './IconButton'; +import InputLabel from './InputLabel'; +import LinearProgress from './LinearProgress'; +import Link from './Link'; +import ListItemIcon from './ListItemIcon'; +import OutlinedInput from './OutlinedInput'; +import Tab from './Tab'; +import TableCell from './TableCell'; +import Tabs from './Tabs'; +import Typography from './Typography'; + +// ==============================|| OVERRIDES - MAIN ||============================== // + +export default function ComponentsOverrides(theme) { + return merge( + Button(theme), + Badge(theme), + CardContent(), + Checkbox(theme), + Chip(theme), + IconButton(theme), + InputLabel(theme), + LinearProgress(), + Link(), + ListItemIcon(), + OutlinedInput(theme), + Tab(theme), + TableCell(theme), + Tabs(), + Typography() + ); +} diff --git a/admin/admin-ui/client/source/themes/palette.ts b/admin/admin-ui/client/source/themes/palette.ts new file mode 100644 index 000000000..f5667156b --- /dev/null +++ b/admin/admin-ui/client/source/themes/palette.ts @@ -0,0 +1,63 @@ +// material-ui +import { createTheme } from '@mui/material/styles'; + +// third-party +import { presetPalettes } from '@ant-design/colors'; + +// project import +import ThemeOption from './theme'; + +// ==============================|| DEFAULT THEME - PALETTE ||============================== // + +const Palette = (mode) => { + const colors = presetPalettes; + + const greyPrimary = [ + '#ffffff', + '#fafafa', + '#f5f5f5', + '#f0f0f0', + '#d9d9d9', + '#bfbfbf', + '#8c8c8c', + '#595959', + '#262626', + '#141414', + '#000000' + ]; + const greyAscent = ['#fafafa', '#bfbfbf', '#434343', '#1f1f1f']; + const greyConstant = ['#fafafb', '#e6ebf1']; + + colors.grey = [...greyPrimary, ...greyAscent, ...greyConstant]; + + const paletteColor = ThemeOption(colors); + + return createTheme({ + palette: { + mode, + common: { + black: '#000', + white: '#fff' + }, + ...paletteColor, + text: { + primary: paletteColor.grey[700], + secondary: paletteColor.grey[500], + disabled: paletteColor.grey[400] + }, + action: { + disabled: paletteColor.grey[300] + }, + divider: paletteColor.grey[200], + background: { + paper: paletteColor.grey[0], + default: '#f3f4f4', + }, + primary: { + main: '#f47b20', + } + } + }); +}; + +export default Palette; diff --git a/admin/admin-ui/client/source/themes/shadows.ts b/admin/admin-ui/client/source/themes/shadows.ts new file mode 100644 index 000000000..9e10469d8 --- /dev/null +++ b/admin/admin-ui/client/source/themes/shadows.ts @@ -0,0 +1,17 @@ +// material-ui +import { alpha } from '@mui/material/styles'; +import { Interface } from 'readline'; + +// ==============================|| DEFAULT THEME - CUSTOM SHADOWS ||============================== // +export interface CustomShadowsProps { + button: string; + text: string; + z1: string; +} +const CustomShadows = (theme): CustomShadowsProps => ({ + button: `0 2px #0000000b`, + text: `0 -1px 0 rgb(0 0 0 / 12%)`, + z1: `0px 2px 8px ${alpha(theme.palette.grey[900], 0.15)}` +}); + +export default CustomShadows; diff --git a/admin/admin-ui/client/source/themes/theme/index.ts b/admin/admin-ui/client/source/themes/theme/index.ts new file mode 100644 index 000000000..17f926952 --- /dev/null +++ b/admin/admin-ui/client/source/themes/theme/index.ts @@ -0,0 +1,92 @@ +// ==============================|| PRESET THEME - THEME SELECTOR ||============================== // + +const Theme = (colors) => { + const { blue, red, yellow, cyan, green, grey } = colors; + const greyColors = { + 0: grey[0], + 50: grey[1], + 100: grey[2], + 200: grey[3], + 300: grey[4], + 400: grey[5], + 500: grey[6], + 600: grey[7], + 700: grey[8], + 800: grey[9], + 900: grey[10], + A50: grey[15], + A100: grey[11], + A200: grey[12], + A400: grey[13], + A700: grey[14], + A800: grey[16] + }; + const contrastText = '#fff'; + + return { + primary: { + lighter: cyan[0], + 100: blue[1], + 200: blue[2], + light: blue[3], + 400: blue[4], + main: blue[5], + dark: blue[6], + 700: blue[7], + darker: blue[8], + 900: blue[9], + contrastText + }, + secondary: { + lighter: greyColors[100], + 100: greyColors[100], + 200: greyColors[200], + light: greyColors[300], + 400: greyColors[400], + main: greyColors[500], + 600: greyColors[600], + dark: greyColors[700], + 800: greyColors[800], + darker: greyColors[900], + A100: greyColors[0], + A200: greyColors.A400, + A300: greyColors.A700, + contrastText: greyColors[0] + }, + error: { + lighter: red[0], + light: red[2], + main: red[4], + dark: red[7], + darker: red[9], + contrastText + }, + warning: { + lighter: yellow[0], + light: yellow[3], + main: yellow[5], + dark: yellow[7], + darker: yellow[9], + contrastText: greyColors[100] + }, + info: { + lighter: cyan[0], + light: cyan[3], + main: cyan[5], + dark: cyan[7], + darker: cyan[9], + contrastText + }, + success: { + lighter: green[0], + light: green[3], + main: green[5], + dark: green[7], + darker: green[9], + contrastText + }, + grey: greyColors + }; +}; + +export default Theme; diff --git a/admin/admin-ui/client/source/themes/typography.ts b/admin/admin-ui/client/source/themes/typography.ts new file mode 100644 index 000000000..96e25e584 --- /dev/null +++ b/admin/admin-ui/client/source/themes/typography.ts @@ -0,0 +1,73 @@ +// ==============================|| DEFAULT THEME - TYPOGRAPHY ||============================== // + +import { TypographyOptions } from "@mui/material/styles/createTypography"; + +const Typography = (fontFamily: string) : TypographyOptions => ({ + htmlFontSize: 16, + fontFamily, + fontWeightLight: 300, + fontWeightRegular: 400, + fontWeightMedium: 500, + fontWeightBold: 600, + h1: { + fontWeight: 600, + fontSize: '2.375rem', + lineHeight: 1.21 + }, + h2: { + fontWeight: 600, + fontSize: '1.875rem', + lineHeight: 1.27 + }, + h3: { + fontWeight: 600, + fontSize: '1.5rem', + lineHeight: 1.33 + }, + h4: { + fontWeight: 600, + fontSize: '1.25rem', + lineHeight: 1.4 + }, + h5: { + fontWeight: 600, + fontSize: '1rem', + lineHeight: 1.5 + }, + h6: { + fontWeight: 400, + fontSize: '0.875rem', + lineHeight: 1.57 + }, + caption: { + fontWeight: 400, + fontSize: '0.75rem', + lineHeight: 1.66 + }, + body1: { + fontSize: '0.875rem', + lineHeight: 1.57 + }, + body2: { + fontSize: '0.75rem', + lineHeight: 1.66 + }, + subtitle1: { + fontSize: '0.875rem', + fontWeight: 600, + lineHeight: 1.57 + }, + subtitle2: { + fontSize: '0.75rem', + fontWeight: 500, + lineHeight: 1.66 + }, + overline: { + lineHeight: 1.66 + }, + button: { + textTransform: 'capitalize' + } +}); + +export default Typography; diff --git a/admin/admin-ui/client/source/types/Error.ts b/admin/admin-ui/client/source/types/Error.ts new file mode 100644 index 000000000..0dd236bbf --- /dev/null +++ b/admin/admin-ui/client/source/types/Error.ts @@ -0,0 +1,4 @@ +export default interface Error { + key: string, + value: string +} \ No newline at end of file diff --git a/admin/admin-ui/client/source/types/LoggedInUser.ts b/admin/admin-ui/client/source/types/LoggedInUser.ts new file mode 100644 index 000000000..d243db7d8 --- /dev/null +++ b/admin/admin-ui/client/source/types/LoggedInUser.ts @@ -0,0 +1,8 @@ + +export default interface User { + name: string, + _scopes: Array, + _remember: boolean, + _environmentName: string, + rememberMe: boolean +} \ No newline at end of file diff --git a/admin/admin-ui/client/source/types/SessionUser.ts b/admin/admin-ui/client/source/types/SessionUser.ts new file mode 100644 index 000000000..7bb8e3aa0 --- /dev/null +++ b/admin/admin-ui/client/source/types/SessionUser.ts @@ -0,0 +1,4 @@ +export interface SessionUser { + user: string; + exp: string; + } \ No newline at end of file diff --git a/admin/admin-ui/client/source/types/Types.ts b/admin/admin-ui/client/source/types/Types.ts new file mode 100644 index 000000000..3ac5c059e --- /dev/null +++ b/admin/admin-ui/client/source/types/Types.ts @@ -0,0 +1,3432 @@ +/** + * This file was auto-generated by openapi-typescript. + * Do not make direct changes to the file. + */ + + +export interface paths { + "/policies/search": { + /** + * Retrieve/Search Policies + * + * @description This operation provides you a list of available Policies qualifying the given keyword match. + */ + get: operations["policySearch"]; + }; + "/application-rate-plans": { + /** + * Get all Application Rate Plans + * @description Retrieves all existing application rate plans. + */ + get: operations["getApplicationRatePlans"]; + /** + * Add an Application Rate Plan + * @description This operation can be used to add a new application level rate plan. + */ + post: operations["addApplicationRatePlan"]; + }; + "/application-rate-plans/{planId}": { + /** + * Get an Application Rate Plan + * @description Retrieves an application rate plan. + */ + get: operations["getApplicationRatePlanById"]; + /** + * Update an Application Rate Plan + * @description Updates an existing application level rate plan. Upon a successful update, you will receive the updated application plan as the response. + */ + put: operations["updateApplicationRatePlan"]; + /** + * Delete an Application Rate Plan + * @description Deletes an application level rate plan. + */ + delete: operations["removeApplicationRatePlan"]; + }; + "/business-plans": { + /** + * Get all Business Plans + * @description This operation can be used to retrieve all Business Plans. + */ + get: operations["getAllBusinessPlans"]; + /** + * Add a Business Plan + * @description This operation can be used to add a Business Plan specifying the details of the plan in the payload. + */ + post: operations["addBusinessPlan"]; + }; + "/business-plans/{planId}": { + /** + * Get a Business Plan + * @description This operation can be used to retrieves Business Plan by specifying the Id of the plan as a path parameter + */ + get: operations["getBusinessPlanById"]; + /** + * Update a Business Plan + * @description Updates an existing Business Plan. + */ + put: operations["updateBusinessPlan"]; + /** + * Delete a Business Plan + * @description This operation can be used to delete a business plan by specifying the Id of the plan as a path parameter. + */ + delete: operations["removeBusinessPlan"]; + }; + "/throttling/policies/advanced": { + /** + * Get all Advanced Throttling Policies + * @description Retrieves all existing advanced throttling policies. + */ + get: operations["getAllAdvancedPolicy"]; + /** + * Add an Advanced Throttling Policy + * @description Add a new advanced throttling policy. + */ + post: operations["addAdvancedPolicy"]; + }; + "/throttling/policies/advanced/{policyId}": { + /** + * Get an Advanced Throttling Policy + * @description Retrieves an advanced throttling policy. + */ + get: operations["getAdvancedPolicyById"]; + /** + * Update an Advanced Throttling Policy + * @description Updates an existing Advanced throttling policy. + */ + put: operations["updateAdvancedPolicy"]; + /** + * Delete an Advanced Throttling Policy + * @description Deletes an advanced throttling policy. + */ + delete: operations["removeAdvancedPolicy"]; + }; + "/throttling/policies/export": { + /** + * Export a Throttling Policy + * @description This operation can be used to export the details of a particular Throttling Policy. + */ + get: operations["exportThrottlingPolicy"]; + }; + "/throttling/policies/import": { + /** + * Import a Throttling Policy + * @description This operation can be used to import a Throttling Policy. + */ + post: operations["importThrottlingPolicy"]; + }; + "/deny-policies": { + /** + * Get all Deny Policies + * @description Retrieves all existing deny policies. + */ + get: operations["getAllDenyPolicies"]; + /** + * Add a deny policy + * @description Adds a new deny policy + */ + post: operations["addDenyPolicy"]; + }; + "/deny-policies/{policyId}": { + /** + * Get a Deny Policy + * @description Retrieves a Deny policy providing the policy Id + */ + get: operations["getDenyPolicyById"]; + /** + * Delete a Deny Policy + * @description Deletes an existing deny policy + */ + delete: operations["removeDenyPolicy"]; + /** + * Update a Deny Policy + * @description Update a deny policy by Id + */ + patch: operations["updateDenyPolicy"]; + }; + "/applications": { + /** + * Retrieve/Search Applications + * + * @description This operation can be used to retrieve list of applications owned by the given user, If no user + * is provided, the applications owned by the user associated with the provided access token will be returned. + */ + get: operations["getApplicationsByUser"]; + }; + "/applications/{applicationId}": { + /** + * Get the details of an Application + * + * @description This operation can be used to get the details of an application by specifying its id. + */ + get: operations["getApplicationById"]; + /** + * Delete an Application + * + * @description This operation can be used to delete an application by specifying its id. + */ + delete: operations["removeApplication"]; + }; + "/applications/{applicationId}/change-owner": { + /** + * Change Application Owner + * @description This operation is used to change the owner of an Application. + * In order to change the owner of an application, we need to pass the new application owner as a query parameter + */ + post: operations["changeApplicationOwner"]; + }; + "/environments": { + /** + * Get all registered Environments + * @description Get all Registered Environments + */ + get: operations["getEnvironments"]; + /** + * Add an Environment + * @description Add a new gateway environment + */ + post: operations["addEnvironment"]; + }; + "/environments/{environmentId}": { + /** + * Update an Environment + * @description Update a gateway Environment by environment Id + */ + put: operations["updateEnvironment"]; + /** + * Delete an Environment + * @description Delete a Environment by Environment Id + */ + delete: operations["removeEnvironment"]; + }; + "/bot-detection-data": { + /** + * Get all Bot Detected Data + * + * @description Get all bot detected data + */ + get: operations["getBotDetectionData"]; + }; + "/monetization/publish-usage": { + /** + * Publish Usage Records + * @description Publish usage records of monetized APIs + */ + post: operations["publishMonetizationRecords"]; + }; + "/monetization/publish-usage/status": { + /** + * Get the Status of Monetization Usage Publisher + * @description Get the status of monetization usage publisher + */ + get: operations["getMonetizationUsagePublisherStatus"]; + }; + "/workflows": { + /** + * Retrieve All Pending Workflow Processes + * + * @description This operation can be used to retrieve list of workflow pending processes. + */ + get: operations["getAllPendingWorkflows"]; + }; + "/workflows/{externalWorkflowRef}": { + /** + * Get Pending Workflow Details by External Workflow Reference + * + * @description Using this operation, you can retrieve complete details of a pending workflow request that either belongs to application creation, application subscription, application registration, api state change, user self sign up.. You need to provide the External_Workflow_Reference of the workflow Request to retrieve it. + */ + get: operations["getWorkflowByExternalRef"]; + }; + "/workflows/update-workflow-status": { + /** + * Update Workflow Status + * @description This operation can be used to approve or reject a workflow task. + */ + post: operations["updateWorkflowStatus"]; + }; + "/tenant-info/{username}": { + /** + * Get Tenant Id of User + * + * @description This operation is to get tenant id of the provided user + */ + get: operations["getTenantInfoByUsername"]; + }; + "/custom-urls/{tenantDomain}": { + /** + * Get Custom URL Info of a Tenant Domain + * + * @description This operation is to get custom-url information of the provided tenant-domain + */ + get: operations["getCustomUrlInfoByTenantDomain"]; + }; + "/api-categories": { + /** + * Get all API Categories + * @description Get all API categories + */ + get: operations["getAllCategories"]; + /** + * Add API Category + * @description Add a new API category + */ + post: operations["addCategory"]; + }; + "/api-categories/{apiCategoryId}": { + /** + * Update an API Category + * @description Update an API Category by category Id + */ + put: operations["updateCategory"]; + /** + * Delete an API Category + * @description Delete an API Category by API Category Id + */ + delete: operations["removeCategory"]; + }; + "/settings": { + /** + * Retrieve Admin Settings + * @description Retrieve admin settings + */ + get: operations["getAdminSettings"]; + }; + "/system-scopes/{scopeName}": { + /** + * Retrieve Scopes for a Particular User + * @description This operation will return the scope list of particular user + * In order to get it, we need to pass the userId as a query parameter + */ + get: operations["systemScopesScopeNameGet"]; + }; + "/system-scopes": { + /** + * Get Role Scope Mappings + * + * @description This operation is used to get the list of role scope mapping from tenant-conf for the APK admin dashboard + */ + get: operations["systemScopesGet"]; + /** + * Update Roles For Scope + * + * @description This operation is used to update the roles for all scopes + */ + put: operations["updateRolesForScope"]; + }; + "/system-scopes/role-aliases": { + /** + * Retrieve Role Alias Mappings + * @description This operation can be used to retrieve role alias mapping + */ + get: operations["getRoleAliasMappings"]; + /** + * Add a New Role Alias + * @description This operation can be used to add a new role alias mapping for system scope roles + */ + put: operations["addRoleAliasMapping"]; + }; + "/roles/{roleId}": { + /** + * Check Whether Given Role Name already Exist + * @description Using this operation, user can check a given role name exists or not. + */ + head: operations["validateSystemRole"]; + }; + "/tenant-theme": { + /** + * Export a DevPortal Tenant Theme + * @description This operation can be used to export a DevPortal tenant theme as a zip file. + */ + get: operations["exportTenantTheme"]; + /** + * Import a DevPortal Tenant Theme + * @description This operation can be used to import a DevPortal tenant theme. + */ + put: operations["importTenantTheme"]; + }; + "/tenant-config": { + /** + * Export a tenant-Config. + * @description This operation can be used to export a tenant-config.json used in deployment. + */ + get: operations["exportTenantConfig"]; + /** + * Update a tenant-config. + * @description This operation can be used to update tenant-config. + */ + put: operations["updateTenantConfig"]; + }; + "/tenant-config-schema": { + /** + * Export a tenant-Config-Schema. + * @description This operation can be used to export a tenant-config-schema.json used in deployment. + */ + get: operations["exportTenantConfigSchema"]; + }; + "/key-managers": { + /** + * Get all Key managers + * @description Get all Key managers + */ + get: operations["getAllKeyManagers"]; + /** + * Add a new API Key Manager + * @description Add a new API Key Manager + */ + post: operations["addNewKeyManager"]; + }; + "/key-managers/{keyManagerId}": { + /** + * Get a Key Manager Configuration + * @description Retrieve a single Key Manager Configuration. We should provide the Id of the KeyManager as a path parameter. + */ + get: operations["getKeyManagerConfiguration"]; + /** + * Update a Key Manager + * @description Update a Key Manager by keyManager ID + */ + put: operations["updateKeyManager"]; + /** + * Delete a Key Manager + * @description Delete a Key Manager by keyManager id + */ + delete: operations["removeKeyManager"]; + }; + "/key-managers/discover": { + /** + * Retrieve Well-known information from Key Manager Well-known Endpoint + * @description Retrieve well-known information from key manager's well-known endpoint + */ + post: operations["getWellKnownInfoKeyManager"]; + }; + "/organizations": { + /** + * Get all Organization + * @description Get all Organization + */ + get: operations["getAllOrganization"]; + /** + * Add Organization + * @description Add a new Organization + */ + post: operations["addOrganization"]; + }; + "/organizations/{organizationId}": { + /** + * Get the details of an Organization + * + * @description This operation can be used to get the details of an Organization by specifying its id. + */ + get: operations["getOrganizationById"]; + /** + * Update an Organization + * @description Update an Organization by organization Id + */ + put: operations["updateOrganization"]; + /** + * Delete an Organization + * @description Delete an Organization by API Organization Id + */ + delete: operations["removeOrganization"]; + }; + "/organization-info": { + /** + * Authenticate Organization info + * + * @description This operation can be used to authenticate Organization by specifying its claimValue. + */ + get: operations["getOrganizationByClaimValue"]; + }; +} + +export type webhooks = Record; + +export interface components { + schemas: { + /** Error object returned with 4XX HTTP status */ + Error: { + /** + * Format: int64 + * @description Error code + */ + code: number; + /** @description Error message. */ + message: string; + /** @description A detail description about the error message. */ + description?: string; + /** @description Preferably an url with more details about the error. */ + moreInfo?: string; + /** + * @description If there are more than one error list them out. + * For example, list out validation errors by each field. + */ + error?: (components["schemas"]["ErrorListItem"])[]; + }; + /** Description of individual errors that may have occurred during a request. */ + ErrorListItem: { + /** @description Error code */ + code: string; + /** @description Description about individual errors occurred */ + message: string; + }; + /** Policy List */ + PolicyList: { + /** + * @description Number of Policies returned. + * + * @example 1 + */ + count?: number; + list?: (components["schemas"]["Policy"])[]; + pagination?: components["schemas"]["Pagination"]; + }; + /** Policy List */ + PolicyDetailsList: { + /** + * @description Number of Throttling Policies returned. + * + * @example 1 + */ + count?: number; + list?: (components["schemas"]["PolicyDetails"])[]; + }; + /** Generic Policy */ + PolicyDetails: { + /** + * @description Id of policy + * @example 3 + */ + policyId?: number; + /** + * @description UUId of policy + * @example 0c6439fd-9b16-3c2e-be6e-1086e0b9aa93 + */ + uuid?: string; + /** + * @description Name of policy + * @example 30PerMin + */ + policyName: string; + /** + * @description Display name of the policy + * @example 30PerMin + */ + displayName?: string; + /** + * @description Description of the policy + * @example Allows 30 request per minute + */ + description?: string; + /** + * @description Indicates whether the policy is deployed successfully or not. + * @default false + */ + isDeployed?: boolean; + /** @description Indicates the type of throttle policy */ + type?: string; + }; + /** Generic Throttling Policy */ + Policy: { + /** + * @description Id of plan + * @example 0c6439fd-9b16-3c2e-be6e-1086e0b9aa93 + */ + planId?: string; + /** + * @description Name of plan + * @example 30PerMin + */ + planName: string; + /** + * @description Display name of the policy + * @example 30PerMin + */ + displayName?: string; + /** + * @description Description of the policy + * @example Allows 30 request per minute + */ + description?: string; + /** + * @description Indicates whether the policy is deployed successfully or not. + * @default false + */ + isDeployed?: boolean; + /** @description Indicates the type of throttle policy */ + type?: string; + }; + /** Export Policy */ + ExportPolicy: { + type?: string; + subtype?: string; + version?: string; + data?: Record; + }; + /** Advanced Throttling Policy */ + AdvancedThrottlePolicyInfo: { + type: "AdvancedThrottlePolicyInfo"; + } & Omit & { + defaultLimit?: components["schemas"]["ThrottleLimit"]; + }; + /** Advanced Throttling Policy */ + AdvancedThrottlePolicy: { + type: "AdvancedThrottlePolicy"; + } & Omit & { + defaultLimit: components["schemas"]["ThrottleLimit"]; + /** @description Group of conditions which allow adding different parameter conditions to the throttling limit. */ + conditionalGroups?: (components["schemas"]["ConditionalGroup"])[]; + }; + /** Advanced Throttling Policy List */ + AdvancedThrottlePolicyList: { + /** + * @description Number of Advanced Throttling Policies returned. + * + * @example 1 + */ + count?: number; + list?: (components["schemas"]["AdvancedThrottlePolicyInfo"])[]; + }; + /** Application Throttling Policy */ + ApplicationRatePlan: { + type: "ApplicationRatePlan"; + } & Omit & { + defaultLimit: components["schemas"]["ThrottleLimit"]; + }; + /** Application level Rate Plan List */ + ApplicationRatePlanList: { + /** + * @description Number of Application Rate Plans returned. + * + * @example 1 + */ + count?: number; + list?: (components["schemas"]["ApplicationRatePlan"])[]; + }; + /** Business Plan */ + BusinessPlan: { + type: "BusinessPlan"; + } & Omit & components["schemas"]["GraphQLQuery"] & { + defaultLimit: components["schemas"]["ThrottleLimit"]; + /** + * @description Burst control request count + * @example 10 + */ + rateLimitCount?: number; + /** + * @description Burst control time unit + * @example min + */ + rateLimitTimeUnit?: string; + /** + * @description Number of subscriptions allowed + * @example 10 + */ + subscriberCount?: number; + /** + * @description Custom attributes added to the Subscription Throttling Policy + * + * @example [] + */ + customAttributes?: (components["schemas"]["CustomAttribute"])[]; + permissions?: components["schemas"]["BusinessPlanPermission"]; + }; + /** Business Plan Permission */ + BusinessPlanPermission: { + /** + * @example deny + * @enum {string} + */ + permissionType: "ALLOW" | "DENY"; + /** + * @example [ + * "Internal/everyone" + * ] + */ + roles: (string)[]; + }; + /** GraphQL Query */ + GraphQLQuery: { + /** + * @description Maximum Complexity of the GraphQL query + * @example 400 + */ + graphQLMaxComplexity?: number; + /** + * @description Maximum Depth of the GraphQL query + * @example 10 + */ + graphQLMaxDepth?: number; + }; + /** Business Plan List */ + BusinessPlanList: { + /** + * @description Number of Business Plans returned. + * + * @example 1 + */ + count?: number; + list?: (components["schemas"]["BusinessPlan"])[]; + }; + /** Conditional Groups for Throttling */ + ConditionalGroup: { + /** @description Description of the Conditional Group */ + description?: string; + /** + * @description Individual throttling conditions. They can be defined as either HeaderCondition, IPCondition, JWTClaimsCondition, QueryParameterCondition + * Please see schemas of each of those throttling condition in Definitions section. + * + * @example [ + * { + * "type": "HEADERCONDITION", + * "invertCondition": false, + * "headerCondition": + * { + * "headerName": "Host", + * "headerValue": "10.100.7.77" + * } + * }, + * { + * "type": "IPCONDITION", + * "invertCondition": false, + * "ipCondition": + * { + * "ipConditionType": "IPSPECIFIC", + * "specificIP": "10.100.1.22", + * "startingIP": null, + * "endingIP": null + * } + * }, + * { + * "type": "QUERYPARAMETERCONDITION", + * "invertCondition": false, + * "queryParameterCondition": + * { + * "parameterName": "name", + * "parameterValue": "admin" + * } + * }, + * { + * "type": "JWTCLAIMSCONDITION", + * "invertCondition": true, + * "jwtClaimsCondition": + * { + * "claimUrl": "claimUrl0", + * "attribute": "claimAttr0" + * } + * } + * ] + */ + conditions: (components["schemas"]["ThrottleCondition"])[]; + limit: components["schemas"]["ThrottleLimit"]; + }; + /** + * Throttling Conditions + * @description Conditions used for Throttling + */ + ThrottleCondition: { + /** + * @description Type of the throttling condition. Allowed values are "HEADERCONDITION", "IPCONDITION", "JWTCLAIMSCONDITION" + * and "QUERYPARAMETERCONDITION". + * + * @enum {string} + */ + type: "HEADERCONDITION" | "IPCONDITION" | "JWTCLAIMSCONDITION" | "QUERYPARAMETERCONDITION"; + /** + * @description Specifies whether inversion of the condition to be matched against the request. + * + * **Note:** When you add conditional groups for advanced throttling policies, this parameter should have the + * same value ('true' or 'false') for the same type of conditional group. + * + * @default false + */ + invertCondition?: boolean; + headerCondition?: components["schemas"]["HeaderCondition"]; + ipCondition?: components["schemas"]["IPCondition"]; + jwtClaimsCondition?: components["schemas"]["JWTClaimsCondition"]; + queryParameterCondition?: components["schemas"]["QueryParameterCondition"]; + }; + /** HTTP Header based throttling condition */ + HeaderCondition: { + /** @description Name of the header */ + headerName: string; + /** @description Value of the header */ + headerValue: string; + }; + /** IP based throttling condition */ + IPCondition: { + /** + * @description Type of the IP condition. Allowed values are "IPRANGE" and "IPSPECIFIC" + * @enum {string} + */ + ipConditionType?: "IPRANGE" | "IPSPECIFIC"; + /** @description Specific IP when "IPSPECIFIC" is used as the ipConditionType */ + specificIP?: string; + /** @description Staring IP when "IPRANGE" is used as the ipConditionType */ + startingIP?: string; + /** @description Ending IP when "IPRANGE" is used as the ipConditionType */ + endingIP?: string; + }; + /** JWT claim attribute based throttling condition */ + JWTClaimsCondition: { + /** @description JWT claim URL */ + claimUrl: string; + /** @description Attribute to be matched */ + attribute: string; + }; + /** Query parameter based throttling condition */ + QueryParameterCondition: { + /** @description Name of the query parameter */ + parameterName: string; + /** @description Value of the query parameter to be matched */ + parameterValue: string; + }; + /** Throttle Limit Base */ + ThrottleLimitBase: { + /** + * @description Unit of the time. Allowed values are "sec", "min", "hour", "day" + * @example min + */ + timeUnit: string; + /** + * @description Time limit that the throttling limit applies. + * @example 10 + */ + unitTime: number; + }; + /** Throttle Limit */ + ThrottleLimit: { + /** + * @description Type of the throttling limit. Allowed values are "REQUESTCOUNTLIMIT" and "BANDWIDTHLIMIT". + * Please see schemas of "RequestCountLimit" and "BandwidthLimit" throttling limit types in + * Definitions section. + * + * @example REQUESTCOUNTLIMIT + * @enum {string} + */ + type: "REQUESTCOUNTLIMIT" | "BANDWIDTHLIMIT" | "EVENTCOUNTLIMIT"; + requestCount?: components["schemas"]["RequestCountLimit"]; + bandwidth?: components["schemas"]["BandwidthLimit"]; + eventCount?: components["schemas"]["EventCountLimit"]; + }; + /** API monetization details object */ + MonetizationInfo: { + /** + * @description Flag to indicate the monetization plan + * @example FixedRate + * @enum {string} + */ + monetizationPlan?: "FIXEDRATE" | "DYNAMICRATE"; + /** @description Map of custom properties related to each monetization plan */ + properties: { + [key: string]: string | undefined; + }; + }; + /** Bandwidth Limit object */ + BandwidthLimit: components["schemas"]["ThrottleLimitBase"] & { + /** + * Format: int64 + * @description Amount of data allowed to be transferred + * @example 1000 + */ + dataAmount: number; + /** + * @description Unit of data allowed to be transferred. Allowed values are "KB", "MB" and "GB" + * @example KB + */ + dataUnit: string; + }; + /** Request Count Limit object */ + RequestCountLimit: components["schemas"]["ThrottleLimitBase"] & { + /** + * Format: int64 + * @description Maximum number of requests allowed + * @example 30 + */ + requestCount: number; + }; + /** Event Count Limit object */ + EventCountLimit: components["schemas"]["ThrottleLimitBase"] & { + /** + * Format: int64 + * @description Maximum number of events allowed + * @example 3000 + */ + eventCount: number; + }; + /** + * Blocking Conditions + * @description Blocking Conditions + */ + BlockingCondition: { + /** + * @description Id of the blocking condition + * @example b513eb68-69e8-4c32-92cf-852c101363cf + */ + policyId?: string; + /** + * @description Type of the blocking condition + * @example IP + * @enum {string} + */ + conditionType: "API" | "APPLICATION" | "IP" | "IPRANGE" | "USER"; + /** + * @description Value of the blocking condition + * @example { + * "fixedIp": "192.168.1.1", + * "invert": false + * } + */ + conditionValue: Record; + /** + * @description Status of the blocking condition + * @example true + */ + conditionStatus?: boolean; + }; + /** Blocking Conditions List */ + BlockingConditionList: { + /** + * @description Number of Blocking Conditions returned. + * + * @example 1 + */ + count?: number; + list?: (components["schemas"]["BlockingCondition"])[]; + }; + /** + * Blocking Conditions Status + * @description Blocking Conditions Status + */ + BlockingConditionStatus: { + /** + * @description Id of the blocking condition + * @example b513eb68-69e8-4c32-92cf-852c101363cf + */ + policyId?: string; + /** + * @description Status of the blocking condition + * @example true + */ + conditionStatus: boolean; + }; + /** Name-Value pair */ + CustomAttribute: { + /** + * @description Name of the custom attribute + * @example customAttr1 + */ + name: string; + /** + * @description Value of the custom attribute + * @example value1 + */ + value: string; + }; + /** Application List */ + ApplicationList: { + /** + * @description Number of applications returned. + * + * @example 1 + */ + count?: number; + list?: (components["schemas"]["ApplicationInfo"])[]; + pagination?: components["schemas"]["Pagination"]; + }; + /** Application info object with basic application details */ + ApplicationInfo: { + /** @example 01234567-0123-0123-0123-012345678901 */ + applicationId?: string; + /** @example CalculatorApp */ + name?: string; + /** @example admin */ + owner?: string; + /** @example APPROVED */ + status?: string; + /** @example */ + groupId?: string; + }; + /** Application object with all the application details */ + Application: { + /** @example 01234567-0123-0123-0123-012345678901 */ + applicationId?: string; + /** @example CalculatorApp */ + name?: string; + /** @example Unlimited */ + throttlingPolicy?: string; + /** @example Sample calculator application */ + description?: string; + /** + * @description Type of the access token generated for this application. + * **OAUTH:** A UUID based access token which is issued by default. + * **JWT:** A self-contained, signed JWT based access token. **Note:** This can be only used in Microgateway environments. + * + * @default JWT + * @example JWT + * @enum {string} + */ + tokenType?: "OAUTH" | "JWT"; + /** + * @default + * @example APPROVED + */ + status?: string; + /** @example */ + groups?: (string)[]; + subscriptionCount?: number; + /** @example External Reference ID, Billing Tier */ + attributes?: { + [key: string]: string | undefined; + }; + subscriptionScopes?: (components["schemas"]["ScopeInfo"])[]; + /** + * @description Application created user + * + * @example admin + */ + owner?: string; + }; + /** API Scope info object with scope details */ + ScopeInfo: { + /** @example admin_scope */ + key?: string; + /** @example admin scope */ + name?: string; + /** + * @description Allowed roles for the scope + * @example [ + * "manager", + * "developer" + * ] + */ + roles?: (string)[]; + /** @description Description of the scope */ + description?: string; + }; + /** Environment */ + Environment: { + /** @example ece92bdc-e1e6-325c-b6f4-656208a041e9 */ + id?: string; + /** @example us-region */ + name: string; + /** @example US Region */ + displayName?: string; + /** @example wso2 */ + provider?: string; + /** @example Gateway environment in US Region */ + description?: string; + /** @example false */ + isReadOnly?: boolean; + vhosts: (components["schemas"]["VHost"])[]; + endpointURIs?: (components["schemas"]["GatewayEnvironmentProtocolURI"])[]; + additionalProperties?: (components["schemas"]["AdditionalProperty"])[]; + }; + /** Environment List */ + EnvironmentList: { + /** + * @description Number of Environments returned. + * + * @example 1 + */ + count?: number; + list?: (components["schemas"]["Environment"])[]; + }; + /** Virtual Host */ + VHost: { + /** @example mg.wso2.com */ + host: string; + /** @example pets */ + httpContext?: string; + /** @example 80 */ + httpPort?: number; + /** @example 443 */ + httpsPort?: number; + /** @example 9099 */ + wsPort?: number; + /** @example 8099 */ + wssPort?: number; + }; + /** Additional Gateway Properties */ + AdditionalProperty: { + /** @example Organization */ + key?: string; + /** @example wso2 */ + value?: string; + }; + /** Gateway Environment protocols and URIs */ + GatewayEnvironmentProtocolURI: { + /** @example default */ + protocol: string; + /** @example default */ + endpointURI: string; + }; + /** Usage publish status */ + PublishStatus: { + /** + * @description Status of the usage publish request + * @example successful + */ + status?: string; + /** + * @description detailed message of the status + * @example Records published successfully + */ + message?: string; + }; + /** Usage publish status */ + MonetizationUsagePublishInfo: { + /** + * @description State of usage publish job + * @example RUNNING + */ + state?: string; + /** + * @description Status of usage publish job + * @example SUCCESSFULL + */ + status?: string; + /** + * @description Timestamp of the started time of the Job + * @example 1599196134000 + */ + startedTime?: string; + /** + * @description Timestamp of the last published time + * @example 1599196134000 + */ + lastPublsihedTime?: string; + }; + /** workflow */ + Workflow: { + /** + * @description This attribute declares whether this workflow task is approved or rejected. + * + * @example APPROVED + * @enum {string} + */ + status: "APPROVED" | "REJECTED"; + /** + * @description Custom attributes to complete the workflow task + * + * @example {} + */ + attributes?: { + [key: string]: string | undefined; + }; + /** @example Approve workflow request. */ + description?: string; + }; + /** + * Tenant information + * @description The tenant information of the user + */ + TenantInfo: { + /** @example john */ + username?: string; + /** @example carbon.super */ + tenantDomain?: string; + /** @example -1234 */ + tenantId?: number; + }; + /** + * Custom url information + * @description The custom url information of the tenant domain + */ + CustomUrlInfo: { + /** @example carbon.super */ + tenantDomain?: string; + /** @example john@foo.com */ + tenantAdminUsername?: string; + /** @example true */ + enabled?: boolean; + devPortal?: { + /** @example http://example.com */ + url?: string; + }; + }; + /** Organization */ + Organization: { + /** @example 01234567-0123-0123-0123-012345678901 */ + id?: string; + /** @example Finance */ + name: string; + /** @example Finance */ + displayName: string; + /** @example 01234567-0123-0123-0123 */ + organizationClaimValue?: string; + /** @default true */ + enabled?: boolean; + /** + * @default [ + * "*" + * ] + */ + serviceNamespaces?: (string)[]; + production?: (string)[]; + sandbox?: (string)[]; + }; + /** Organization List */ + OrganizationList: { + /** + * @description Number of Organization returned. + * + * @example 1 + */ + count?: number; + list?: (components["schemas"]["Organization"])[]; + }; + /** API Category */ + APICategory: { + /** @example 01234567-0123-0123-0123-012345678901 */ + id?: string; + /** @example Finance */ + name: string; + /** @example Finance related APIs */ + description?: string; + /** @example 1 */ + numberOfAPIs?: number; + }; + /** API Category List */ + APICategoryList: { + /** + * @description Number of API categories returned. + * + * @example 1 + */ + count?: number; + list?: (components["schemas"]["APICategory"])[]; + }; + /** File Information including meta data */ + FileInfo: { + /** + * @description relative location of the file (excluding the base context and host of the Admin API) + * @example api-categories/01234567-0123-0123-0123-012345678901/thumbnail + */ + relativePath?: string; + /** + * @description media-type of the file + * @example image/jpeg + */ + mediaType?: string; + }; + /** Settings */ + Settings: { + scopes?: (string)[]; + keyManagerConfiguration?: ({ + /** @example default */ + type?: string; + /** @example default */ + displayName?: string; + /** @example azp */ + defaultConsumerKeyClaim?: string; + /** @example scope */ + defaultScopesClaim?: string; + configurations?: (components["schemas"]["KeyManagerConfiguration"])[]; + endpointConfigurations?: (components["schemas"]["KeyManagerConfiguration"])[]; + })[]; + /** + * @description To determine whether analytics is enabled or not + * @example false + */ + analyticsEnabled?: boolean; + }; + /** Scope Role Mapping List */ + ScopeList: { + /** + * @description Number of scopes available for tenant. + * + * @example 60 + */ + count?: number; + list?: (components["schemas"]["Scope"])[]; + }; + /** Scope Role */ + Scope: { + /** + * @description Portal name. + * + * @example publisher + */ + tag?: string; + /** + * @description Scope name. + * + * @example apk:api_publish + */ + name?: string; + /** + * @description About scope. + * + * @example Publish API + */ + description?: string; + /** + * @description Roles for the particular scope. + * + * @example [ + * "admin", + * "Internal/publisher" + * ] + */ + roles?: (string)[]; + }; + /** Key Manager Well-Known Response. */ + KeyManagerWellKnownResponse: { + /** + * @default false + * @example true + */ + valid?: boolean; + value?: components["schemas"]["KeyManager"]; + }; + /** Key Manager */ + KeyManager: { + /** @example 01234567-0123-0123-0123-012345678901 */ + id?: string; + /** @example WSO2 Identity Server */ + name: string; + /** + * @description display name of Key Manager to show in UI + * + * @example WSO2 Identity Server + */ + displayName?: string; + /** @example WSO2-IS */ + type: string; + /** @example This is a key manager for Developers */ + description?: string; + /** + * @description Well-Known Endpoint of Identity Provider. + * + * @example + */ + wellKnownEndpoint?: string; + /** + * @deprecated + * @example https://localhost:9444/oauth2/introspect + */ + introspectionEndpoint?: string; + /** + * @deprecated + * @example https://localhost:9444/keymanager-operations/dcr/register + */ + clientRegistrationEndpoint?: string; + /** + * @deprecated + * @example https://localhost:9444/oauth2/token + */ + tokenEndpoint?: string; + /** + * @deprecated + * @example https://localhost:9444/oauth2/token + */ + displayTokenEndpoint?: string; + /** + * @deprecated + * @example https://localhost:9444/oauth2/revoke + */ + revokeEndpoint?: string; + /** + * @deprecated + * @example https://localhost:9444/oauth2/revoke + */ + displayRevokeEndpoint?: string; + /** + * @deprecated + * @example https://localhost:9444/oauth2/userinfo?schema=openid + */ + userInfoEndpoint?: string; + /** + * @deprecated + * @example https://localhost:9444/oauth2/authorize + */ + authorizeEndpoint?: string; + endpoints?: (components["schemas"]["KeyManagerEndpoint"])[]; + certificates?: { + /** @enum {string} */ + type?: "JWKS" | "PEM"; + value?: string; + }; + /** @example https://localhost:9444/services */ + issuer?: string; + /** + * @description The alias of Identity Provider. + * If the tokenType is EXCHANGED, the alias value should be inclusive in the audience values of the JWT token + * + * @example https://localhost:9443/oauth2/token + */ + alias?: string; + /** + * @deprecated + * @example https://wso2is.com:9444/api/identity/oauth2/v1.0/scopes + */ + scopeManagementEndpoint?: string; + availableGrantTypes?: (string)[]; + /** @example true */ + enableTokenGeneration?: boolean; + /** + * @default false + * @example false + */ + enableTokenEncryption?: boolean; + /** + * @default false + * @example false + */ + enableTokenHashing?: boolean; + /** + * @default false + * @example false + */ + enableMapOAuthConsumerApps?: boolean; + /** + * @default false + * @example false + */ + enableOAuthAppCreation?: boolean; + /** + * @default true + * @example true + */ + enableSelfValidationJWT?: boolean; + claimMapping?: (components["schemas"]["ClaimMappingEntry"])[]; + /** @example azp */ + consumerKeyClaim?: string; + /** @example scp */ + scopesClaim?: string; + tokenValidation?: (components["schemas"]["TokenValidation"])[]; + /** @example true */ + enabled?: boolean; + /** + * @example { + * "self_validate_jwt": true, + * "Username": "admin", + * "Password": "admin" + * } + */ + additionalProperties?: Record; + /** + * @description The type of the tokens to be used (exchanged or without exchanged). Accepted values are EXCHANGED, DIRECT and BOTH. + * @default DIRECT + * @example EXCHANGED + * @enum {string} + */ + tokenType?: "EXCHANGED" | "DIRECT" | "BOTH"; + }; + /** Key Manager Endpoint. */ + KeyManagerEndpoint: { + /** @example token_endpoint */ + name: string; + /** @example https://localhost:9443/oauth2/token */ + value: string; + }; + /** Key Manager Info */ + KeyManagerInfo: { + /** @example 01234567-0123-0123-0123-012345678901 */ + id?: string; + /** @example WSO2 IS */ + name: string; + /** @example IS */ + type: string; + /** @example This is a key manager for Developers */ + description?: string; + /** @example true */ + enabled?: boolean; + /** + * @description The type of the tokens to be used (exchanged or without exchanged). Accepted values are EXCHANGED, DIRECT and BOTH. + * @default DIRECT + * @example EXCHANGED + * @enum {string} + */ + tokenType?: "EXCHANGED" | "DIRECT" | "BOTH"; + }; + /** Key Manager Configuration */ + KeyManagerConfiguration: { + /** @example consumer_key */ + name?: string; + /** @example Consumer Key */ + label?: string; + /** @example select */ + type?: string; + /** @example true */ + required?: boolean; + /** @example true */ + mask?: boolean; + /** @example true */ + multiple?: boolean; + /** @example Enter username to connect to key manager */ + tooltip?: string; + /** @example admin */ + default?: Record; + values?: (Record)[]; + }; + /** Key Manager List */ + KeyManagerList: { + /** + * @description Number of Key managers returned. + * + * @example 1 + */ + count?: number; + list?: (components["schemas"]["KeyManagerInfo"])[]; + }; + /** Claim Mapping Configuration */ + ClaimMappingEntry: { + /** @example http://idp.org/username */ + remoteClaim?: string; + /** @example http://wso2.org/username */ + localClaim?: string; + }; + /** Token handling Configuration */ + TokenValidation: { + id?: number; + /** + * @default true + * @example false + */ + enable?: boolean; + /** @enum {string} */ + type?: "REFERENCE" | "JWT" | "CUSTOM"; + value?: Record; + }; + /** Settings */ + ScopeSettings: { + /** @example apk:subscribe */ + name?: string; + }; + /** WorkflowList */ + WorkflowList: { + /** + * @description Number of workflow processes returned. + * + * @example 1 + */ + count?: number; + /** + * @description Link to the next subset of resources qualified. + * Empty if no more resources are to be returned. + * + * @example /workflows?limit=1&offset=2&user= + */ + next?: string; + /** + * @description Link to the previous subset of resources qualified. + * Empty if current subset is the first subset returned. + * + * @example /workflows?limit=1&offset=0&user= + */ + previous?: string; + list?: (components["schemas"]["WorkflowInfo"])[]; + }; + /** Workflow info object with basic workflow details */ + WorkflowInfo: { + /** + * @description Type of the Workflow Request. It shows which type of request is it. + * + * @example APPLICATION_CREATION + * @enum {string} + */ + workflowType?: "APPLICATION_CREATION" | "SUBSCRIPTION_CREATION" | "USER_SIGNUP" | "APPLICATION_REGISTRATION_PRODUCTION" | "APPLICATION_REGISTRATION_SANDBOX" | "APPLICATION_DELETION" | "API_STATE" | "API_PRODUCT_STATE" | "SUBSCRIPTION_DELETION" | "SUBSCRIPTION_UPDATE"; + /** + * @description Show the Status of the the workflow request whether it is approved or created. + * + * @example APPROVED + * @enum {string} + */ + workflowStatus?: "APPROVED" | "CREATED"; + /** + * @description Time of the the workflow request created. + * + * @example "2020-02-10T10:10:19.704Z" + */ + createdTime?: string; + /** + * @description Time of the the workflow request updated. + * + * @example "2020-02-10T10:10:19.704Z" + */ + updatedTime?: string; + /** + * @description Workflow external reference is used to identify the workflow requests uniquely. + * + * @example 5871244b-d6f3-466e-8995-8accd1e64303 + */ + referenceId?: string; + properties?: Record; + /** + * @description description is a message with basic details about the workflow request. + * + * @example Approve application [APP1] creation request from application creator - admin with throttling tier - 10MinPer + */ + description?: string; + }; + /** workflow Response */ + WorkflowResponse: { + /** + * @description This attribute declares whether this workflow task is approved or rejected. + * + * @example APPROVED + * @enum {string} + */ + workflowStatus: "CREATED" | "APPROVED" | "REJECTED" | "REGISTERED"; + /** @description Attributes that returned after the workflow execution */ + jsonPayload?: string; + }; + /** Bot Detection Data List */ + BotDetectionDataList: { + /** + * @description Number of Bot Detection Data returned. + * + * @example 1 + */ + count?: number; + list?: (components["schemas"]["BotDetectionData"])[]; + }; + /** Bot Detection Data */ + BotDetectionData: { + /** + * Format: int64 + * @description The time of detection + * @example 1591734138413 + */ + recordedTime?: number; + /** + * @description The message ID + * @example urn:uuid:1ed6d2de-29df-4fed-a96a-46d2329dce65 + */ + messageID?: string; + /** + * @description The api method + * @example GET + */ + apiMethod?: string; + /** + * @description The header set + * @example [Accept=*\/*, Host=localhost:8243, User-Agent=curl/7.58.0] + */ + headerSet?: string; + /** + * @description The content of the message body + * @example + */ + messageBody?: string; + /** + * @description The IP of the client + * @example 127.0.0.1 + */ + clientIp?: string; + }; + /** Role alias list */ + RoleAliasList: { + /** + * @description The number of role aliases + * @example 1 + */ + count?: number; + list?: (components["schemas"]["RoleAlias"])[]; + }; + /** Role alias */ + RoleAlias: { + /** + * @description The original role + * @example Internal/subscriber + */ + role?: string; + /** + * @description The role mapping for role alias + * @example [ + * "Subscriber", + * "Internal/subscriber" + * ] + */ + aliases?: (string)[]; + }; + /** Pagination */ + Pagination: { + /** @example 0 */ + offset?: number; + /** @example 1 */ + limit?: number; + /** @example 10 */ + total?: number; + /** + * @description Link to the next subset of resources qualified. + * Empty if no more resources are to be returned. + * example: "" + */ + next?: string; + /** + * @description Link to the previous subset of resources qualified. + * Empty if current subset is the first subset returned. + * example: "" + */ + previous?: string; + }; + }; + responses: { + /** @description Bad Request. Invalid request or validation error. */ + BadRequest: { + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Conflict. Specified resource already exists. */ + Conflict: { + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Forbidden. The request must be conditional but no condition has been specified. */ + Forbidden: { + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Internal Server Error. */ + InternalServerError: { + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Not Acceptable. The requested media type is not supported. */ + NotAcceptable: { + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Not Found. The specified resource does not exist. */ + NotFound: { + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Payload Too Large. Request entity is larger than limits defined by server. */ + PayloadTooLarge: { + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Precondition Failed. The request has not been performed because one of the preconditions is not met. */ + PreconditionFailed: { + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Unauthorized. The user is not authorized. */ + Unauthorized: { + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + /** @description Unsupported Media Type. The entity of the request was not in a supported format. */ + UnsupportedMediaType: { + content: { + "application/json": components["schemas"]["Error"]; + }; + }; + }; + parameters: { + /** + * @description Validator for conditional requests; based on the ETag of the formerly retrieved + * variant of the resource. + */ + "If-None-Match": string; + /** + * @description For cross-tenant invocations, this is used to specify the tenant domain, where the resource need to be + * retirieved from. + */ + requestedTenant: string; + /** @description Criteria for sorting. */ + sortBy: "apiName" | "version" | "createdTime" | "status"; + /** @description Order of sorting(ascending/descending). */ + sortOrder: "asc" | "desc"; + /** @description username of the new application owner */ + username: string; + /** @description Base64 URL encoded value of the scope name to be validated */ + scopeName: string; + /** @description Environment UUID (or Environment name defined in config) */ + environmentId: string; + /** @description Policy UUID */ + policyId: string; + /** @description Policy UUID */ + planId: string; + /** @description Custom rule UUID */ + ruleId: string; + /** @description Application UUID */ + applicationId: string; + /** @description Media types acceptable for the response. Default is application/json. */ + Accept: string; + /** @description Media type of the entity in the body. Default is application/json. */ + "Content-Type": string; + /** @description Maximum size of resource array to return. */ + limit: number; + /** @description Starting point within the complete list of items qualified. */ + offset: number; + /** @description username of the application creator */ + user: string; + /** @description Workflow reference id */ + "workflowReferenceId-Q": string; + /** @description API Category UUID */ + apiCategoryId: string; + /** @description Organization UUID */ + organizationId: string; + /** @description Key Manager UUID */ + keyManagerId: string; + /** + * @description The Base 64 URL encoded role name with domain. If the given role is in PRIMARY user-store, role ID should be + * derived as Base64URLEncode(role-name). If the given role is in secondary user-store, role ID should be + * derived as Base64URLEncode({user-store-name}/{role-name}). + */ + roleId: string; + }; + requestBodies: never; + headers: never; + pathItems: never; +} + +export type external = Record; + +export interface operations { + + policySearch: { + /** + * Retrieve/Search Policies + * + * @description This operation provides you a list of available Policies qualifying the given keyword match. + */ + parameters?: { + /** + * @description **Search**. + * You can search by providing a keyword. Allowed to search by type and name only. + */ + query?: { + query?: string; + }; + }; + responses: { + /** + * @description OK. + * List of qualifying Policies is returned. + */ + 200: { + headers: { + /** @description The content type of the body. */ + "Content-Type"?: string; + }; + content: { + "application/json": components["schemas"]["PolicyDetailsList"]; + }; + }; + }; + }; + getApplicationRatePlans: { + /** + * Get all Application Rate Plans + * @description Retrieves all existing application rate plans. + */ + responses: { + /** + * @description OK. + * Policies returned + */ + 200: { + headers: { + /** @description The content type of the body. */ + "Content-Type"?: string; + }; + content: { + "application/json": components["schemas"]["ApplicationRatePlanList"]; + }; + }; + 406: components["responses"]["NotAcceptable"]; + }; + }; + addApplicationRatePlan: { + /** + * Add an Application Rate Plan + * @description This operation can be used to add a new application level rate plan. + */ + /** @description Application level policy object that should to be added */ + requestBody: { + content: { + "application/json": components["schemas"]["ApplicationRatePlan"]; + }; + }; + responses: { + /** + * @description Created. + * Successful response with the newly created object as entity in the body. + * Location header contains URL of newly created entity. + */ + 201: { + headers: { + /** @description Location of the newly created Policy object. */ + Location?: string; + /** @description The content type of the body. */ + "Content-Type"?: string; + }; + content: { + "application/json": components["schemas"]["ApplicationRatePlan"]; + }; + }; + 400: components["responses"]["BadRequest"]; + 415: components["responses"]["UnsupportedMediaType"]; + }; + }; + getApplicationRatePlanById: { + /** + * Get an Application Rate Plan + * @description Retrieves an application rate plan. + */ + responses: { + /** + * @description OK. + * Plan returned + */ + 200: { + headers: { + /** @description The content type of the body. */ + "Content-Type"?: string; + }; + content: { + "application/json": components["schemas"]["ApplicationRatePlan"]; + }; + }; + 404: components["responses"]["NotFound"]; + 406: components["responses"]["NotAcceptable"]; + }; + }; + updateApplicationRatePlan: { + /** + * Update an Application Rate Plan + * @description Updates an existing application level rate plan. Upon a successful update, you will receive the updated application plan as the response. + */ + /** @description Policy object that needs to be modified */ + requestBody: { + content: { + "application/json": components["schemas"]["ApplicationRatePlan"]; + }; + }; + responses: { + /** + * @description OK. + * Plan updated. + */ + 200: { + headers: { + /** @description The URL of the newly created resource. */ + Location?: string; + /** @description The content type of the body. */ + "Content-Type"?: string; + }; + content: { + "application/json": components["schemas"]["ApplicationRatePlan"]; + }; + }; + 400: components["responses"]["BadRequest"]; + 404: components["responses"]["NotFound"]; + }; + }; + removeApplicationRatePlan: { + /** + * Delete an Application Rate Plan + * @description Deletes an application level rate plan. + */ + responses: { + /** + * @description OK. + * Resource successfully deleted. + */ + 200: { + content: { + }; + }; + 404: components["responses"]["NotFound"]; + }; + }; + getAllBusinessPlans: { + /** + * Get all Business Plans + * @description This operation can be used to retrieve all Business Plans. + */ + responses: { + /** + * @description OK. + * Plans returned + */ + 200: { + headers: { + /** @description The content type of the body. */ + "Content-Type"?: string; + }; + content: { + "application/json": components["schemas"]["BusinessPlanList"]; + }; + }; + 406: components["responses"]["NotAcceptable"]; + }; + }; + addBusinessPlan: { + /** + * Add a Business Plan + * @description This operation can be used to add a Business Plan specifying the details of the plan in the payload. + */ + /** @description Business Plan object that should to be added */ + requestBody: { + content: { + "application/json": components["schemas"]["BusinessPlan"]; + }; + }; + responses: { + /** + * @description Created. + * Successful response with the newly created object as entity in the body. + * Location header contains URL of newly created entity. + */ + 201: { + headers: { + /** @description Location of the newly created Plan object. */ + Location?: string; + /** @description The content type of the body. */ + "Content-Type"?: string; + }; + content: { + "application/json": components["schemas"]["BusinessPlan"]; + }; + }; + 400: components["responses"]["BadRequest"]; + 415: components["responses"]["UnsupportedMediaType"]; + }; + }; + getBusinessPlanById: { + /** + * Get a Business Plan + * @description This operation can be used to retrieves Business Plan by specifying the Id of the plan as a path parameter + */ + responses: { + /** + * @description OK. + * Plan returned + */ + 200: { + headers: { + /** @description The content type of the body. */ + "Content-Type"?: string; + }; + content: { + "application/json": components["schemas"]["BusinessPlan"]; + }; + }; + 404: components["responses"]["NotFound"]; + 406: components["responses"]["NotAcceptable"]; + }; + }; + updateBusinessPlan: { + /** + * Update a Business Plan + * @description Updates an existing Business Plan. + */ + /** @description Plan object that needs to be modified */ + requestBody: { + content: { + "application/json": components["schemas"]["BusinessPlan"]; + }; + }; + responses: { + /** + * @description OK. + * Plan updated. + */ + 200: { + headers: { + /** @description The URL of the newly created resource. */ + Location?: string; + /** @description The content type of the body. */ + "Content-Type"?: string; + }; + content: { + "application/json": components["schemas"]["BusinessPlan"]; + }; + }; + 400: components["responses"]["BadRequest"]; + 404: components["responses"]["NotFound"]; + }; + }; + removeBusinessPlan: { + /** + * Delete a Business Plan + * @description This operation can be used to delete a business plan by specifying the Id of the plan as a path parameter. + */ + responses: { + /** + * @description OK. + * Resource successfully deleted. + */ + 200: { + content: { + }; + }; + 404: components["responses"]["NotFound"]; + }; + }; + getAllAdvancedPolicy: { + /** + * Get all Advanced Throttling Policies + * @description Retrieves all existing advanced throttling policies. + */ + responses: { + /** + * @description OK. + * Policies returned + */ + 200: { + headers: { + /** @description The content type of the body. */ + "Content-Type"?: string; + }; + content: { + "application/json": components["schemas"]["AdvancedThrottlePolicyList"]; + }; + }; + 406: components["responses"]["NotAcceptable"]; + }; + }; + addAdvancedPolicy: { + /** + * Add an Advanced Throttling Policy + * @description Add a new advanced throttling policy. + */ + /** @description Advanced level policy object that should to be added */ + requestBody: { + content: { + "application/json": components["schemas"]["AdvancedThrottlePolicy"]; + }; + }; + responses: { + /** + * @description Created. + * Successful response with the newly created object as entity in the body. + * Location header contains URL of newly created entity. + */ + 201: { + headers: { + /** @description Location of the newly created Advanced Throttling Policy. */ + Location?: string; + /** @description The content type of the body. */ + "Content-Type"?: string; + }; + content: { + "application/json": components["schemas"]["AdvancedThrottlePolicy"]; + }; + }; + 400: components["responses"]["BadRequest"]; + 415: components["responses"]["UnsupportedMediaType"]; + }; + }; + getAdvancedPolicyById: { + /** + * Get an Advanced Throttling Policy + * @description Retrieves an advanced throttling policy. + */ + responses: { + /** + * @description OK. + * Policy returned + */ + 200: { + headers: { + /** @description The content type of the body. */ + "Content-Type"?: string; + }; + content: { + "application/json": components["schemas"]["AdvancedThrottlePolicy"]; + }; + }; + 404: components["responses"]["NotFound"]; + 406: components["responses"]["NotAcceptable"]; + }; + }; + updateAdvancedPolicy: { + /** + * Update an Advanced Throttling Policy + * @description Updates an existing Advanced throttling policy. + */ + /** @description Policy object that needs to be modified */ + requestBody: { + content: { + "application/json": components["schemas"]["AdvancedThrottlePolicy"]; + }; + }; + responses: { + /** + * @description OK. + * Policy updated. + */ + 200: { + headers: { + /** @description The URL of the newly created resource. */ + Location?: string; + /** @description The content type of the body. */ + "Content-Type"?: string; + }; + content: { + "application/json": components["schemas"]["AdvancedThrottlePolicy"]; + }; + }; + 400: components["responses"]["BadRequest"]; + 404: components["responses"]["NotFound"]; + }; + }; + removeAdvancedPolicy: { + /** + * Delete an Advanced Throttling Policy + * @description Deletes an advanced throttling policy. + */ + responses: { + /** + * @description OK. + * Resource successfully deleted. + */ + 200: { + content: { + }; + }; + 404: components["responses"]["NotFound"]; + }; + }; + exportThrottlingPolicy: { + /** + * Export a Throttling Policy + * @description This operation can be used to export the details of a particular Throttling Policy. + */ + parameters?: { + /** @description UUID of the ThrottlingPolicy */ + /** @description Throttling Policy Name */ + /** @description Type of the Throttling Policy */ + /** @description Format of output documents. Can be YAML or JSON. */ + query?: { + policyId?: string; + name?: string; + type?: "sub" | "app" | "api" | "global"; + format?: "JSON" | "YAML"; + }; + }; + responses: { + /** + * @description OK. + * Export Successful. + */ + 200: { + headers: { + /** @description The content type of the body. */ + "Content-Type"?: string; + }; + content: { + "application/json": components["schemas"]["ExportPolicy"]; + }; + }; + 404: components["responses"]["NotFound"]; + 500: components["responses"]["InternalServerError"]; + }; + }; + importThrottlingPolicy: { + /** + * Import a Throttling Policy + * @description This operation can be used to import a Throttling Policy. + */ + parameters?: { + /** @description Update an existing throttling policy with the same name. */ + query?: { + overwrite?: boolean; + }; + }; + requestBody: { + content: { + "multipart/form-data": { + /** + * Format: binary + * @description Json File + */ + file: string; + }; + }; + }; + responses: { + /** + * @description Created. + * Throttling Policy Imported Successfully. + */ + 200: never; + 403: components["responses"]["Forbidden"]; + 404: components["responses"]["NotFound"]; + 409: components["responses"]["Conflict"]; + 500: components["responses"]["InternalServerError"]; + }; + }; + getAllDenyPolicies: { + /** + * Get all Deny Policies + * @description Retrieves all existing deny policies. + */ + responses: { + /** + * @description OK. + * Deny Policies returned + */ + 200: { + headers: { + /** @description The content type of the body. */ + "Content-Type"?: string; + }; + content: { + "application/json": components["schemas"]["BlockingConditionList"]; + }; + }; + 406: components["responses"]["NotAcceptable"]; + }; + }; + addDenyPolicy: { + /** + * Add a deny policy + * @description Adds a new deny policy + */ + /** @description Blocking condition object that should to be added */ + requestBody: { + content: { + "application/json": components["schemas"]["BlockingCondition"]; + }; + }; + responses: { + /** + * @description Created. + * Successful response with the newly created object as entity in the body. + * Location header contains URL of newly created entity. + */ + 201: { + headers: { + /** @description Location of the newly created resource. */ + Location?: string; + /** @description The content type of the body. */ + "Content-Type"?: string; + }; + content: { + "application/json": components["schemas"]["BlockingCondition"]; + }; + }; + 400: components["responses"]["BadRequest"]; + 415: components["responses"]["UnsupportedMediaType"]; + }; + }; + getDenyPolicyById: { + /** + * Get a Deny Policy + * @description Retrieves a Deny policy providing the policy Id + */ + responses: { + /** + * @description OK. + * Condition returned + */ + 200: { + headers: { + /** @description The content type of the body. */ + "Content-Type"?: string; + }; + content: { + "application/json": components["schemas"]["BlockingCondition"]; + }; + }; + 404: components["responses"]["NotFound"]; + 406: components["responses"]["NotAcceptable"]; + }; + }; + removeDenyPolicy: { + /** + * Delete a Deny Policy + * @description Deletes an existing deny policy + */ + responses: { + /** + * @description OK. + * Resource successfully deleted. + */ + 200: { + content: { + }; + }; + 404: components["responses"]["NotFound"]; + }; + }; + updateDenyPolicy: { + /** + * Update a Deny Policy + * @description Update a deny policy by Id + */ + /** @description Blocking condition with updated status */ + requestBody: { + content: { + "application/json": components["schemas"]["BlockingConditionStatus"]; + }; + }; + responses: { + /** + * @description OK. + * Resource successfully updated. + */ + 200: { + content: { + "application/json": components["schemas"]["BlockingCondition"]; + }; + }; + 400: components["responses"]["BadRequest"]; + 404: components["responses"]["NotFound"]; + }; + }; + getApplicationsByUser: { + /** + * Retrieve/Search Applications + * + * @description This operation can be used to retrieve list of applications owned by the given user, If no user + * is provided, the applications owned by the user associated with the provided access token will be returned. + */ + parameters?: { + /** @description Application Name */ + /** + * @description Tenant domain of the applications to get. This has to be specified only if it is required to get applications of + * a tenant other than the requester's tenant. So, if not specified, the default will be set as the + * requester's tenant domain. This cross tenant Application access is allowed only for super tenant admin + * users **only at a migration process**. + */ + query?: { + name?: string; + tenantDomain?: string; + sortBy?: "name" | "owner"; + sortOrder?: "asc" | "desc"; + }; + }; + responses: { + /** + * @description OK. + * Application list returned. + */ + 200: { + headers: { + /** @description The content type of the body. */ + "Content-Type"?: string; + }; + content: { + "application/json": components["schemas"]["ApplicationList"]; + }; + }; + 400: components["responses"]["BadRequest"]; + 406: components["responses"]["NotAcceptable"]; + }; + }; + getApplicationById: { + /** + * Get the details of an Application + * + * @description This operation can be used to get the details of an application by specifying its id. + */ + responses: { + /** + * @description OK. + * Application details returned. + */ + 200: { + content: { + "application/json": components["schemas"]["Application"]; + }; + }; + 400: components["responses"]["BadRequest"]; + 404: components["responses"]["NotFound"]; + 406: components["responses"]["NotAcceptable"]; + }; + }; + removeApplication: { + /** + * Delete an Application + * + * @description This operation can be used to delete an application by specifying its id. + */ + responses: { + /** + * @description OK. + * Resource successfully deleted. + */ + 200: { + content: { + }; + }; + /** + * @description Accepted. + * The request has been accepted. + */ + 202: { + headers: { + /** @description Location of the existing Application. */ + Location?: string; + }; + content: { + "application/json": components["schemas"]["WorkflowResponse"]; + }; + }; + 404: components["responses"]["NotFound"]; + }; + }; + changeApplicationOwner: { + /** + * Change Application Owner + * @description This operation is used to change the owner of an Application. + * In order to change the owner of an application, we need to pass the new application owner as a query parameter + */ + parameters: { + query: { + owner: string; + }; + }; + responses: { + /** + * @description OK. + * Application owner changed successfully. + */ + 200: { + content: { + }; + }; + 400: components["responses"]["BadRequest"]; + 404: components["responses"]["NotFound"]; + }; + }; + getEnvironments: { + /** + * Get all registered Environments + * @description Get all Registered Environments + */ + responses: { + /** + * @description OK. + * Environments returned + */ + 200: { + content: { + "application/json": components["schemas"]["EnvironmentList"]; + }; + }; + }; + }; + addEnvironment: { + /** + * Add an Environment + * @description Add a new gateway environment + */ + /** @description Environment object that should to be added */ + requestBody: { + content: { + "application/json": components["schemas"]["Environment"]; + }; + }; + responses: { + /** + * @description Created. + * Successful response with the newly created environment as entity in the body. + */ + 201: { + content: { + "application/json": components["schemas"]["Environment"]; + }; + }; + 400: components["responses"]["BadRequest"]; + }; + }; + updateEnvironment: { + /** + * Update an Environment + * @description Update a gateway Environment by environment Id + */ + /** @description Environment object with updated information */ + requestBody: { + content: { + "application/json": components["schemas"]["Environment"]; + }; + }; + responses: { + /** + * @description OK. + * Environment updated. + */ + 200: { + content: { + "application/json": components["schemas"]["Environment"]; + }; + }; + 400: components["responses"]["BadRequest"]; + 404: components["responses"]["NotFound"]; + }; + }; + removeEnvironment: { + /** + * Delete an Environment + * @description Delete a Environment by Environment Id + */ + responses: { + /** + * @description OK. + * Environment successfully deleted. + */ + 200: { + content: { + }; + }; + 404: components["responses"]["NotFound"]; + }; + }; + getBotDetectionData: { + /** + * Get all Bot Detected Data + * + * @description Get all bot detected data + */ + responses: { + /** + * @description OK. + * Bot detected data returned. + */ + 200: { + headers: { + /** @description The content type of the body. */ + "Content-Type"?: string; + }; + content: { + "application/json": components["schemas"]["BotDetectionDataList"]; + }; + }; + 404: components["responses"]["NotFound"]; + }; + }; + publishMonetizationRecords: { + /** + * Publish Usage Records + * @description Publish usage records of monetized APIs + */ + responses: { + /** @description Usage records successfully published. */ + 200: { + content: { + "application/json": components["schemas"]["PublishStatus"]; + }; + }; + /** @description Request is sucessfully accepted for processing. */ + 202: { + content: { + "application/json": components["schemas"]["PublishStatus"]; + }; + }; + 404: components["responses"]["NotFound"]; + 500: components["responses"]["InternalServerError"]; + }; + }; + getMonetizationUsagePublisherStatus: { + /** + * Get the Status of Monetization Usage Publisher + * @description Get the status of monetization usage publisher + */ + responses: { + /** + * @description OK. + * Status returned + */ + 200: { + content: { + "application/json": components["schemas"]["MonetizationUsagePublishInfo"]; + }; + }; + }; + }; + getAllPendingWorkflows: { + /** + * Retrieve All Pending Workflow Processes + * + * @description This operation can be used to retrieve list of workflow pending processes. + */ + parameters?: { + /** + * @description We need to show the values of each workflow process separately .for that we use workflow type. + * Workflow type can be AM_APPLICATION_CREATION, AM_SUBSCRIPTION_CREATION, AM_USER_SIGNUP, AM_APPLICATION_REGISTRATION_PRODUCTION, AM_APPLICATION_REGISTRATION_SANDBOX. + */ + query?: { + workflowType?: "AM_APPLICATION_CREATION" | "AM_SUBSCRIPTION_CREATION" | "AM_USER_SIGNUP" | "AM_APPLICATION_REGISTRATION_PRODUCTION" | "AM_APPLICATION_REGISTRATION_SANDBOX" | "AM_SUBSCRIPTION_DELETION" | "AM_APPLICATION_DELETION" | "AM_API_STATE" | "AM_API_PRODUCT_STATE"; + }; + }; + responses: { + /** + * @description OK. + * Workflow pending process list returned. + */ + 200: { + headers: { + /** @description The content type of the body. */ + "Content-Type"?: string; + }; + content: { + "application/json": components["schemas"]["WorkflowList"]; + }; + }; + 400: components["responses"]["BadRequest"]; + 404: components["responses"]["NotFound"]; + 406: components["responses"]["NotAcceptable"]; + }; + }; + getWorkflowByExternalRef: { + /** + * Get Pending Workflow Details by External Workflow Reference + * + * @description Using this operation, you can retrieve complete details of a pending workflow request that either belongs to application creation, application subscription, application registration, api state change, user self sign up.. You need to provide the External_Workflow_Reference of the workflow Request to retrieve it. + */ + parameters: { + /** @description from the external workflow reference we decide what is the the pending request that the are requesting. */ + path: { + externalWorkflowRef: string; + }; + }; + responses: { + /** + * @description OK. + * Requested Workflow Pending is returned + */ + 200: { + content: { + "application/json": components["schemas"]["WorkflowInfo"]; + }; + }; + /** + * @description Not Modified. + * Empty body because the client has already the latest version of the requested resource. + */ + 304: { + content: { + }; + }; + 404: components["responses"]["NotFound"]; + 406: components["responses"]["NotAcceptable"]; + }; + }; + updateWorkflowStatus: { + /** + * Update Workflow Status + * @description This operation can be used to approve or reject a workflow task. + */ + /** @description Workflow event that need to be updated */ + requestBody: { + content: { + "application/json": components["schemas"]["Workflow"]; + }; + }; + responses: { + /** + * @description OK. + * Workflow request information is returned. + */ + 200: { + headers: { + /** @description The content type of the body. */ + "Content-Type"?: string; + }; + content: { + "application/json": components["schemas"]["Workflow"]; + }; + }; + 400: components["responses"]["BadRequest"]; + 404: components["responses"]["NotFound"]; + }; + }; + getTenantInfoByUsername: { + /** + * Get Tenant Id of User + * + * @description This operation is to get tenant id of the provided user + */ + parameters: { + /** @description The state represents the current state of the tenant. Supported states are [ active, inactive] */ + path: { + username: string; + }; + }; + responses: { + /** + * @description OK. + * Tenant id of the user retrieved. + */ + 200: { + headers: { + /** @description The content type of the body. */ + "Content-Type"?: string; + }; + content: { + "application/json": components["schemas"]["TenantInfo"]; + }; + }; + 404: components["responses"]["NotFound"]; + 406: components["responses"]["NotAcceptable"]; + }; + }; + getCustomUrlInfoByTenantDomain: { + /** + * Get Custom URL Info of a Tenant Domain + * + * @description This operation is to get custom-url information of the provided tenant-domain + */ + parameters: { + /** @description The tenant domain name. */ + path: { + tenantDomain: string; + }; + }; + responses: { + /** + * @description OK. + * Custom url info of the tenant is retrieved. + */ + 200: { + headers: { + /** @description The content type of the body. */ + "Content-Type"?: string; + }; + content: { + "application/json": components["schemas"]["CustomUrlInfo"]; + }; + }; + 404: components["responses"]["NotFound"]; + 406: components["responses"]["NotAcceptable"]; + }; + }; + getAllCategories: { + /** + * Get all API Categories + * @description Get all API categories + */ + responses: { + /** + * @description OK. + * Categories returned + */ + 200: { + content: { + "application/json": components["schemas"]["APICategoryList"]; + }; + }; + }; + }; + addCategory: { + /** + * Add API Category + * @description Add a new API category + */ + /** @description API Category object that should to be added */ + requestBody: { + content: { + "application/json": components["schemas"]["APICategory"]; + }; + }; + responses: { + /** + * @description Created. + * Successful response with the newly created object as entity in the body. + */ + 201: { + content: { + "application/json": components["schemas"]["APICategory"]; + }; + }; + 400: components["responses"]["BadRequest"]; + }; + }; + updateCategory: { + /** + * Update an API Category + * @description Update an API Category by category Id + */ + /** @description API Category object with updated information */ + requestBody: { + content: { + "application/json": components["schemas"]["APICategory"]; + }; + }; + responses: { + /** + * @description OK. + * Label updated. + */ + 200: { + content: { + "application/json": components["schemas"]["APICategory"]; + }; + }; + 400: components["responses"]["BadRequest"]; + 404: components["responses"]["NotFound"]; + }; + }; + removeCategory: { + /** + * Delete an API Category + * @description Delete an API Category by API Category Id + */ + responses: { + /** + * @description OK. + * API Category successfully deleted. + */ + 200: { + content: { + }; + }; + 404: components["responses"]["NotFound"]; + }; + }; + getAdminSettings: { + /** + * Retrieve Admin Settings + * @description Retrieve admin settings + */ + responses: { + /** + * @description OK. + * Settings returned + */ + 200: { + content: { + "application/json": components["schemas"]["Settings"]; + }; + }; + 404: components["responses"]["NotFound"]; + }; + }; + systemScopesScopeNameGet: { + /** + * Retrieve Scopes for a Particular User + * @description This operation will return the scope list of particular user + * In order to get it, we need to pass the userId as a query parameter + */ + parameters?: { + query?: { + username?: string; + }; + }; + responses: { + /** + * @description OK. + * Particular scope exists for the given user. + */ + 200: { + content: { + "application/json": components["schemas"]["ScopeSettings"]; + }; + }; + 400: components["responses"]["BadRequest"]; + 404: components["responses"]["NotFound"]; + }; + }; + systemScopesGet: { + /** + * Get Role Scope Mappings + * + * @description This operation is used to get the list of role scope mapping from tenant-conf for the APK admin dashboard + */ + responses: { + /** + * @description OK. + * The list of role scope mappings are returned. + */ + 200: { + headers: { + /** @description The content type of the body. */ + "Content-Type"?: string; + }; + content: { + "application/json": components["schemas"]["ScopeList"]; + }; + }; + 500: components["responses"]["InternalServerError"]; + }; + }; + updateRolesForScope: { + /** + * Update Roles For Scope + * + * @description This operation is used to update the roles for all scopes + */ + /** @description Scope list object with updated scope to role mappings */ + requestBody: { + content: { + "application/json": components["schemas"]["ScopeList"]; + }; + }; + responses: { + /** + * @description OK. + * Successful response with the newly added roles. + */ + 200: { + headers: { + /** @description The content type of the body. */ + "Content-Type"?: string; + }; + content: { + "application/json": components["schemas"]["ScopeList"]; + }; + }; + 400: components["responses"]["BadRequest"]; + 500: components["responses"]["InternalServerError"]; + }; + }; + getRoleAliasMappings: { + /** + * Retrieve Role Alias Mappings + * @description This operation can be used to retrieve role alias mapping + */ + responses: { + /** + * @description OK. + * The list of role mappings are returned. + */ + 200: { + headers: { + /** @description The content type of the body. */ + "Content-Type"?: string; + }; + content: { + "application/json": components["schemas"]["RoleAliasList"]; + }; + }; + 404: components["responses"]["NotFound"]; + }; + }; + addRoleAliasMapping: { + /** + * Add a New Role Alias + * @description This operation can be used to add a new role alias mapping for system scope roles + */ + /** @description role-alias mapping */ + requestBody: { + content: { + "application/json": components["schemas"]["RoleAliasList"]; + }; + }; + responses: { + /** + * @description OK. + * Role mapping alias returned + */ + 200: { + content: { + "application/json": components["schemas"]["RoleAliasList"]; + }; + }; + 400: components["responses"]["BadRequest"]; + 500: components["responses"]["InternalServerError"]; + }; + }; + validateSystemRole: { + /** + * Check Whether Given Role Name already Exist + * @description Using this operation, user can check a given role name exists or not. + */ + responses: { + /** @description OK. Requested role name exists. */ + 200: { + content: { + }; + }; + 404: components["responses"]["NotFound"]; + 500: components["responses"]["InternalServerError"]; + }; + }; + exportTenantTheme: { + /** + * Export a DevPortal Tenant Theme + * @description This operation can be used to export a DevPortal tenant theme as a zip file. + */ + responses: { + /** + * @description OK. + * Tenant Theme Exported Successfully. + */ + 200: { + headers: { + /** @description The content type of the body. */ + "Content-Type"?: string; + }; + content: { + "application/zip": string; + }; + }; + 403: components["responses"]["Forbidden"]; + 404: components["responses"]["NotFound"]; + 500: components["responses"]["InternalServerError"]; + }; + }; + importTenantTheme: { + /** + * Import a DevPortal Tenant Theme + * @description This operation can be used to import a DevPortal tenant theme. + */ + requestBody: { + content: { + "multipart/form-data": { + /** + * Format: binary + * @description Zip archive consisting of tenant theme configuration + */ + file: string; + }; + }; + }; + responses: { + /** + * @description Ok. + * Tenant Theme Imported Successfully. + */ + 200: { + content: { + }; + }; + 403: components["responses"]["Forbidden"]; + 413: components["responses"]["PayloadTooLarge"]; + 500: components["responses"]["InternalServerError"]; + }; + }; + exportTenantConfig: { + /** + * Export a tenant-Config. + * @description This operation can be used to export a tenant-config.json used in deployment. + */ + responses: { + /** + * @description OK. + * Tenant config Exported Successfully. + */ + 200: { + headers: { + /** @description The content type of the body. */ + "Content-Type"?: string; + }; + content: { + "application/json": string; + }; + }; + 403: components["responses"]["Forbidden"]; + 404: components["responses"]["NotFound"]; + 500: components["responses"]["InternalServerError"]; + }; + }; + updateTenantConfig: { + /** + * Update a tenant-config. + * @description This operation can be used to update tenant-config. + */ + /** @description tenant-config */ + requestBody: { + content: { + "application/json": string; + }; + }; + responses: { + /** + * @description OK. + * Role mapping alias returned + */ + 200: { + content: { + "application/json": string; + }; + }; + 403: components["responses"]["Forbidden"]; + 413: components["responses"]["PayloadTooLarge"]; + 500: components["responses"]["InternalServerError"]; + }; + }; + exportTenantConfigSchema: { + /** + * Export a tenant-Config-Schema. + * @description This operation can be used to export a tenant-config-schema.json used in deployment. + */ + responses: { + /** + * @description OK. + * Tenant config schema exported successfully. + */ + 200: { + headers: { + /** @description The content type of the body. */ + "Content-Type"?: string; + }; + content: { + "application/json": string; + }; + }; + 403: components["responses"]["Forbidden"]; + 404: components["responses"]["NotFound"]; + 500: components["responses"]["InternalServerError"]; + }; + }; + getAllKeyManagers: { + /** + * Get all Key managers + * @description Get all Key managers + */ + responses: { + /** + * @description OK. + * KeyManagers returned + */ + 200: { + content: { + "application/json": components["schemas"]["KeyManagerList"]; + }; + }; + }; + }; + addNewKeyManager: { + /** + * Add a new API Key Manager + * @description Add a new API Key Manager + */ + /** @description Key Manager object that should to be added */ + requestBody: { + content: { + "application/json": components["schemas"]["KeyManager"]; + }; + }; + responses: { + /** + * @description Created. + * Successful response with the newly created object as entity in the body. + */ + 201: { + content: { + "application/json": components["schemas"]["KeyManager"]; + }; + }; + 400: components["responses"]["BadRequest"]; + }; + }; + getKeyManagerConfiguration: { + /** + * Get a Key Manager Configuration + * @description Retrieve a single Key Manager Configuration. We should provide the Id of the KeyManager as a path parameter. + */ + responses: { + /** + * @description OK. + * KeyManager Configuration returned + */ + 200: { + headers: { + /** @description The content type of the body. */ + "Content-Type"?: string; + }; + content: { + "application/json": components["schemas"]["KeyManager"]; + }; + }; + 404: components["responses"]["NotFound"]; + 406: components["responses"]["NotAcceptable"]; + }; + }; + updateKeyManager: { + /** + * Update a Key Manager + * @description Update a Key Manager by keyManager ID + */ + /** @description Key Manager object with updated information */ + requestBody: { + content: { + "application/json": components["schemas"]["KeyManager"]; + }; + }; + responses: { + /** + * @description OK. + * Label updated. + */ + 200: { + content: { + "application/json": components["schemas"]["KeyManager"]; + }; + }; + 400: components["responses"]["BadRequest"]; + 404: components["responses"]["NotFound"]; + }; + }; + removeKeyManager: { + /** + * Delete a Key Manager + * @description Delete a Key Manager by keyManager id + */ + responses: { + /** + * @description OK. + * Key Manager successfully deleted. + */ + 200: { + content: { + }; + }; + 404: components["responses"]["NotFound"]; + }; + }; + getWellKnownInfoKeyManager: { + /** + * Retrieve Well-known information from Key Manager Well-known Endpoint + * @description Retrieve well-known information from key manager's well-known endpoint + */ + requestBody?: { + content: { + "multipart/form-data": { + /** @description Well-Known Endpoint */ + url?: string; + /** + * @description Key Manager Type + * + * @default false + */ + type?: string; + }; + }; + }; + responses: { + /** + * @description OK. + * KeyManagers returned + */ + 200: { + content: { + "application/json": components["schemas"]["KeyManagerWellKnownResponse"]; + }; + }; + }; + }; + getAllOrganization: { + /** + * Get all Organization + * @description Get all Organization + */ + responses: { + /** + * @description OK. + * Organization returned + */ + 200: { + content: { + "application/json": components["schemas"]["OrganizationList"]; + }; + }; + }; + }; + addOrganization: { + /** + * Add Organization + * @description Add a new Organization + */ + /** @description Organization object that should to be added */ + requestBody: { + content: { + "application/json": components["schemas"]["Organization"]; + }; + }; + responses: { + /** + * @description Created. + * Successful response with the newly created object as entity in the body. + */ + 201: { + content: { + "application/json": components["schemas"]["Organization"]; + }; + }; + 400: components["responses"]["BadRequest"]; + }; + }; + getOrganizationById: { + /** + * Get the details of an Organization + * + * @description This operation can be used to get the details of an Organization by specifying its id. + */ + responses: { + /** + * @description OK. + * Application details returned. + */ + 200: { + content: { + "application/json": components["schemas"]["Organization"]; + }; + }; + 400: components["responses"]["BadRequest"]; + 404: components["responses"]["NotFound"]; + 406: components["responses"]["NotAcceptable"]; + }; + }; + updateOrganization: { + /** + * Update an Organization + * @description Update an Organization by organization Id + */ + /** @description Organization object with updated information */ + requestBody: { + content: { + "application/json": components["schemas"]["Organization"]; + }; + }; + responses: { + /** + * @description OK. + * Label updated. + */ + 200: { + content: { + "application/json": components["schemas"]["Organization"]; + }; + }; + 400: components["responses"]["BadRequest"]; + 404: components["responses"]["NotFound"]; + }; + }; + removeOrganization: { + /** + * Delete an Organization + * @description Delete an Organization by API Organization Id + */ + responses: { + /** + * @description OK. + * Organization successfully deleted. + */ + 200: { + content: { + }; + }; + 404: components["responses"]["NotFound"]; + }; + }; + getOrganizationByClaimValue: { + /** + * Authenticate Organization info + * + * @description This operation can be used to authenticate Organization by specifying its claimValue. + */ + responses: { + /** + * @description OK. + * Application details returned. + */ + 200: { + content: { + "application/json": components["schemas"]["Organization"]; + }; + }; + 400: components["responses"]["BadRequest"]; + 404: components["responses"]["NotFound"]; + }; + }; +} diff --git a/admin/admin-ui/gradle.properties b/admin/admin-ui/gradle.properties new file mode 100644 index 000000000..15a900025 --- /dev/null +++ b/admin/admin-ui/gradle.properties @@ -0,0 +1,3 @@ +group=org.wso2.apk +version=0.0.1-SNAPSHOT +docker_image_name = "admin-ui" diff --git a/admin/admin-ui/gradle/wrapper/gradle-wrapper.properties b/admin/admin-ui/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..ae04661ee --- /dev/null +++ b/admin/admin-ui/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/admin/admin-ui/gradlew b/admin/admin-ui/gradlew new file mode 100755 index 000000000..a69d9cb6c --- /dev/null +++ b/admin/admin-ui/gradlew @@ -0,0 +1,240 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# 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 +# +# https://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. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/admin/admin-ui/gradlew.bat b/admin/admin-ui/gradlew.bat new file mode 100644 index 000000000..f127cfd49 --- /dev/null +++ b/admin/admin-ui/gradlew.bat @@ -0,0 +1,91 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/admin/admin-ui/jsconfig.json b/admin/admin-ui/jsconfig.json new file mode 100644 index 000000000..190c5a0fb --- /dev/null +++ b/admin/admin-ui/jsconfig.json @@ -0,0 +1,6 @@ +{ + "compilerOptions": { + "baseUrl": "./client/source", + }, + "exclude": ["node_modules", "client/public/build"] +} \ No newline at end of file diff --git a/admin/admin-ui/package-lock.json b/admin/admin-ui/package-lock.json new file mode 100644 index 000000000..122e98e26 --- /dev/null +++ b/admin/admin-ui/package-lock.json @@ -0,0 +1,20653 @@ +{ + "name": "apps", + "version": "0.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "apps", + "version": "0.0.0", + "dependencies": { + "@ant-design/colors": "^6.0.0", + "@ant-design/icons": "^5.0.1", + "@auth0/auth0-react": "^1.11.0", + "@emotion/react": "^11.10.4", + "@emotion/styled": "^11.10.4", + "@fortawesome/fontawesome-svg-core": "^6.2.0", + "@fortawesome/free-brands-svg-icons": "^6.2.0", + "@fortawesome/free-solid-svg-icons": "^6.2.0", + "@fortawesome/react-fontawesome": "^0.2.0", + "@mui/material": "^5.10.11", + "@types/crypto-js": "^4.1.1", + "@types/node": "^18.8.2", + "@types/react": "^18.0.21", + "@types/react-dom": "^18.0.6", + "await-semaphore": "^0.1.3", + "crypto-js": "^4.1.1", + "debug": "~2.6.9", + "dotenv": "^16.0.3", + "express": "~4.16.1", + "framer-motion": "^7.6.1", + "http-errors": "~1.6.3", + "jsrsasign": "^10.5.27", + "jwt-decode": "^3.1.2", + "moment": "^2.29.4", + "morgan": "~1.9.1", + "react": "^18.2.0", + "react-copy-to-clipboard": "^5.1.0", + "react-device-detect": "^2.2.2", + "react-dom": "^18.2.0", + "react-hot-toast": "^2.4.0", + "react-router-dom": "^6.4.1", + "react-table": "^7.8.0", + "simplebar": "^5.3.9", + "simplebar-react": "^2.4.3", + "tss-react": "^4.4.1", + "url": "^0.11.0" + }, + "devDependencies": { + "@babel/core": "^7.19.3", + "@babel/plugin-proposal-class-properties": "^7.18.6", + "@babel/plugin-proposal-object-rest-spread": "^7.19.4", + "@babel/plugin-transform-arrow-functions": "^7.18.6", + "@babel/plugin-transform-async-to-generator": "^7.18.6", + "@babel/plugin-transform-runtime": "^7.19.6", + "@babel/plugin-transform-typescript": "^7.20.0", + "@babel/preset-env": "^7.19.4", + "@babel/preset-react": "^7.18.6", + "@babel/preset-typescript": "^7.18.6", + "@types/jsrsasign": "^10.5.4", + "@typescript-eslint/eslint-plugin": "^5.42.1", + "@typescript-eslint/parser": "^5.42.1", + "axios": "^1.3.4", + "babel-loader": "^8.2.5", + "connect-livereload": "^0.6.1", + "cookie-parser": "^1.4.6", + "css-loader": "^6.7.1", + "eslint": "^8.27.0", + "eslint-plugin-react": "^7.31.10", + "file-loader": "^6.2.0", + "html-webpack-plugin": "^5.5.0", + "install": "^0.13.0", + "jsonwebtoken": "^9.0.0", + "livereload": "^0.9.3", + "node-fetch": "^3.3.0", + "nodemon": "^2.0.20", + "npm": "^9.5.1", + "react-intl": "^6.2.1", + "style-loader": "^3.3.1", + "ts-loader": "^9.4.1", + "typescript": "^4.8.4", + "webpack": "^5.74.0", + "webpack-cli": "^4.10.0" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", + "dependencies": { + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@ant-design/colors": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@ant-design/colors/-/colors-6.0.0.tgz", + "integrity": "sha512-qAZRvPzfdWHtfameEGP2Qvuf838NhergR35o+EuVyB5XvSA98xod5r4utvi4TJ3ywmevm290g9nsCG5MryrdWQ==", + "dependencies": { + "@ctrl/tinycolor": "^3.4.0" + } + }, + "node_modules/@ant-design/icons": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@ant-design/icons/-/icons-5.0.1.tgz", + "integrity": "sha512-ZyF4ksXCcdtwA/1PLlnFLcF/q8/MhwxXhKHh4oCHDA4Ip+ZzAHoICtyp4wZWfiCVDP0yuz3HsjyvuldHFb3wjA==", + "dependencies": { + "@ant-design/colors": "^7.0.0", + "@ant-design/icons-svg": "^4.2.1", + "@babel/runtime": "^7.11.2", + "classnames": "^2.2.6", + "rc-util": "^5.9.4" + }, + "engines": { + "node": ">=8" + }, + "peerDependencies": { + "react": ">=16.0.0", + "react-dom": ">=16.0.0" + } + }, + "node_modules/@ant-design/icons-svg": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@ant-design/icons-svg/-/icons-svg-4.2.1.tgz", + "integrity": "sha512-EB0iwlKDGpG93hW8f85CTJTs4SvMX7tt5ceupvhALp1IF44SeUFOMhKUOYqpsoYWQKAOuTRDMqn75rEaKDp0Xw==" + }, + "node_modules/@ant-design/icons/node_modules/@ant-design/colors": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@ant-design/colors/-/colors-7.0.0.tgz", + "integrity": "sha512-iVm/9PfGCbC0dSMBrz7oiEXZaaGH7ceU40OJEfKmyuzR9R5CRimJYPlRiFtMQGQcbNMea/ePcoIebi4ASGYXtg==", + "dependencies": { + "@ctrl/tinycolor": "^3.4.0" + } + }, + "node_modules/@auth0/auth0-react": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/@auth0/auth0-react/-/auth0-react-1.12.0.tgz", + "integrity": "sha512-Cny2RyHvr0GrKKKV8PMh6GU0vkWNSgd6mp/YHYJynnYCs9yFduNo9hdpHPxXbdDX5CB6wc2PqK6aL8leDlnl/A==", + "dependencies": { + "@auth0/auth0-spa-js": "^1.22.4" + }, + "peerDependencies": { + "react": "^16.11.0 || ^17 || ^18", + "react-dom": "^16.11.0 || ^17 || ^18" + } + }, + "node_modules/@auth0/auth0-spa-js": { + "version": "1.22.5", + "resolved": "https://registry.npmjs.org/@auth0/auth0-spa-js/-/auth0-spa-js-1.22.5.tgz", + "integrity": "sha512-6gaQcd+Eb8ZBcdQkrrm9undM7dY/rPvVdQN8s7rxxrviUCs7OopEygsfSkHf67IP4HtlCiE8dSW5/AipRUOw/A==", + "dependencies": { + "abortcontroller-polyfill": "^1.7.3", + "browser-tabs-lock": "^1.2.15", + "core-js": "^3.25.1", + "es-cookie": "~1.3.2", + "fast-text-encoding": "^1.0.6", + "promise-polyfill": "^8.2.3", + "unfetch": "^4.2.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "dependencies": { + "@babel/highlight": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.19.4.tgz", + "integrity": "sha512-CHIGpJcUQ5lU9KrPHTjBMhVwQG6CQjxfg36fGXl3qk/Gik1WwWachaXFuo0uCWJT/mStOKtcbFJCaVLihC1CMw==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.6.tgz", + "integrity": "sha512-D2Ue4KHpc6Ys2+AxpIx1BZ8+UegLLLE2p3KJEuJRKmokHOtl49jQ5ny1773KsGLZs8MQvBidAF6yWUJxRqtKtg==", + "dependencies": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.19.6", + "@babel/helper-compilation-targets": "^7.19.3", + "@babel/helper-module-transforms": "^7.19.6", + "@babel/helpers": "^7.19.4", + "@babel/parser": "^7.19.6", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.6", + "@babel/types": "^7.19.4", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.1", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@babel/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==" + }, + "node_modules/@babel/generator": { + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.6.tgz", + "integrity": "sha512-oHGRUQeoX1QrKeJIKVe0hwjGqNnVYsM5Nep5zo0uE0m42sLH+Fsd2pStJ5sRM1bNyTUUoz0pe2lTeMJrb/taTA==", + "dependencies": { + "@babel/types": "^7.19.4", + "@jridgewell/gen-mapping": "^0.3.2", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz", + "integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "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/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.19.3", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.19.3.tgz", + "integrity": "sha512-65ESqLGyGmLvgR0mst5AdW1FkNlj9rQsCKduzEoEPhBCDFGXvz2jW6bXFG6i0/MrV2s7hhXjjb2yAzcPuQlLwg==", + "dependencies": { + "@babel/compat-data": "^7.19.3", + "@babel/helper-validator-option": "^7.18.6", + "browserslist": "^4.21.3", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.19.0.tgz", + "integrity": "sha512-NRz8DwF4jT3UfrmUoZjd0Uph9HQnP30t7Ash+weACcyNkiYTywpIjDBgReJMKgr+n86sn2nPVVmJ28Dm053Kqw==", + "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.18.9", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/helper-replace-supers": "^7.18.9", + "@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.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.19.0.tgz", + "integrity": "sha512-htnV+mHX32DF81amCDrwIDr8nrp1PTm+3wfBN9/v8QJOLEioOCOG7qNyq0nHeFiWbT3Eb7gsPwEmV64UCQ1jzw==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "regexpu-core": "^5.1.0" + }, + "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-environment-visitor": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", + "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", + "engines": { + "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", + "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", + "dependencies": { + "@babel/template": "^7.18.10", + "@babel/types": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", + "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.18.9.tgz", + "integrity": "sha512-RxifAh2ZoVU67PyKIO4AMi1wTenGfMR/O/ae0CCRqwgBAt5v7xjdtRw7UoSbsreKrQn5t7r89eruK/9JjYHuDg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.9" + }, + "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", + "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.19.6.tgz", + "integrity": "sha512-fCmcfQo/KYr/VXXDIyd3CBGZ6AFhPFy1TfSEJ+PilGVlQT6jcbqtHAM4C1EciRqMza7/TpOUZliuSH+U6HAhJw==", + "dependencies": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-simple-access": "^7.19.4", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/helper-validator-identifier": "^7.19.1", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.6", + "@babel/types": "^7.19.4" + }, + "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==", + "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.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.19.1.tgz", + "integrity": "sha512-T7ahH7wV0Hfs46SFh5Jz3s0B6+o8g3c+7TMxu7xKfmHikg7EAZ3I2Qk9LFhjxXq8sL7UkP5JflezNwoZa8WvWw==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-member-expression-to-functions": "^7.18.9", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/traverse": "^7.19.1", + "@babel/types": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.19.4.tgz", + "integrity": "sha512-f9Xq6WqBFqaDfbCzn2w85hwklswz5qsKlh7f08w4Y9yhJHpnNC0QemtSkK5YyOY8kPGvyiwdzZksGUhnGdaUIg==", + "dependencies": { + "@babel/types": "^7.19.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.18.9.tgz", + "integrity": "sha512-imytd2gHi3cJPsybLRbmFrF7u5BIEuI2cNheyKi3/iOBC63kNn3q8Crn2xVuESli0aM4KYsyEqKyS7lFL8YVtw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.9" + }, + "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", + "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", + "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "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==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.19.0.tgz", + "integrity": "sha512-txX8aN8CZyYGTwcLhlk87KRqncAzhh5TpQamZUa0/u3an36NtDpUP6bQgBCBcLeBs09R/OwQu3OjK0k/HwfNDg==", + "dev": true, + "dependencies": { + "@babel/helper-function-name": "^7.19.0", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.0", + "@babel/types": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.19.4.tgz", + "integrity": "sha512-G+z3aOx2nfDHwX/kyVii5fJq+bgscg89/dJNWpYeKeBv3v9xX8EIabmx1k6u9LS04H7nROFVRVK+e3k0VHp+sw==", + "dependencies": { + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.4", + "@babel/types": "^7.19.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "dependencies": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.6.tgz", + "integrity": "sha512-h1IUp81s2JYJ3mRkdxJgs4UvmSsRvDrx5ICSJbPvtWYv5i1nTBGcBpnog+89rAFMwvvru6E5NUHdBe01UeSzYA==", + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "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.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.18.9.tgz", + "integrity": "sha512-AHrP9jadvH7qlOj6PINbgSuphjQUAK7AOT7DPjBo9EHoLhQTnnK5u45e1Hd4DbSQEO9nqPWtQ89r+XEOWFScKg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9", + "@babel/plugin-proposal-optional-chaining": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-proposal-async-generator-functions": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.19.1.tgz", + "integrity": "sha512-0yu8vNATgLy4ivqMNBIwb1HebCelqN7YX8SL3FDXORv/RqT0zEEWUCH4GH44JsSrvCu6GqnAdR5EBFAPeNBB4Q==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-plugin-utils": "^7.19.0", + "@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.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.18.6.tgz", + "integrity": "sha512-+I3oIiNxrCpup3Gi8n5IGMwj0gOCAjcJUSQEcotNnCCPMEnixawOQ+KeJPlgfjzx+FKQ1QSyZOWe7wmoJp7vhw==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@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.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.18.9.tgz", + "integrity": "sha512-128YbMpjCrP35IOExw2Fq+x55LMP42DzhOhX2aNNIdI9avSWl2PI0yuBWarr3RYpZBSPtabfadkH2yeRiMD61Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9", + "@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.19.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.19.4.tgz", + "integrity": "sha512-wHmj6LDxVDnL+3WhXteUBaoM1aVILZODAUjg11kHqG4cOlfgMQGxw6aCgvrXrmaJR3Bn14oZhImyCPZzRpC93Q==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.19.4", + "@babel/helper-compilation-targets": "^7.19.3", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.18.8" + }, + "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.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.18.9.tgz", + "integrity": "sha512-v5nwt4IqBXihxGsW2QmCWMDS3B3bzGIk/EQVZz2ei7f3NJl8NzAJVvUmpDW5q1CRNY+Beb/k58UAH1Km1N411w==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9", + "@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.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.18.6.tgz", + "integrity": "sha512-9Rysx7FOctvT5ouj5JODjAFAkgGoudQuLPamZb0v1TGLpapdNaftzifU8NTWQm0IRjqoYypdrSmyWgkocDQ8Dw==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@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-import-assertions": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.18.6.tgz", + "integrity": "sha512-/DU3RXad9+bZwrgWJQKbr39gYbJpLJHezqEzRzi/BHRlJ9zsQb4CK2CA/5apllXNomwA1qHwzvHl+AdEmC5krQ==", + "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-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", + "integrity": "sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==", + "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-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": { + "@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/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": { + "@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.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.18.6.tgz", + "integrity": "sha512-9S9X9RUefzrsHZmKMbDXxweEH+YlE8JJEuat9FdvW9Qh1cw7W64jELCtWNkPBPX5En45uy28KGvA/AySqUh8CQ==", + "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-async-to-generator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.18.6.tgz", + "integrity": "sha512-ARE5wZLKnTgPW7/1ftQmSi1CmkqqHo2DNmtztFhvgtOWSDfq0Cq9/9L+KnZNYSNrydBekhW3rwShduf59RoXag==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-remap-async-to-generator": "^7.18.6" + }, + "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.19.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.19.4.tgz", + "integrity": "sha512-934S2VLLlt2hRJwPf4MczaOr4hYF0z+VKPwqTNxyKX7NthTiPfhuKFWQZHXRM0vh/wo/VyXB3s4bZUNA08l+tQ==", + "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-classes": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.19.0.tgz", + "integrity": "sha512-YfeEE9kCjqTS9IitkgfJuxjcEtLUHMqa8yUJ6zdz8vR7hKuo6mOy2C05P0F1tdMmDCeuyidKnlrw/iTppHcr2A==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-compilation-targets": "^7.19.0", + "@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.19.0", + "@babel/helper-replace-supers": "^7.18.9", + "@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.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.18.9.tgz", + "integrity": "sha512-+i0ZU1bCDymKakLxn5srGHrsAPRELC2WIbzwjLhHW9SIE1cPYkLCL0NlnXMZaM1vhfgA2+M7hySk42VBvrkBRw==", + "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-destructuring": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.19.4.tgz", + "integrity": "sha512-t0j0Hgidqf0aM86dF8U+vXYReUgJnlv4bZLsyoPnwZNrGY+7/38o8YjaELrvHeVfTZao15kjR0PVv0nju2iduA==", + "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-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-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.19.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.19.6.tgz", + "integrity": "sha512-uG3od2mXvAtIFQIh0xrpLH6r5fpSQN04gIVovl+ODLdUMANokxQLZnPBHcjmv3GxRjnqwLuHvppjjcelqUFZvg==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.19.6", + "@babel/helper-plugin-utils": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.19.6.tgz", + "integrity": "sha512-8PIa1ym4XRTKuSsOUXqDG0YaOlEuTVvHMe5JCfgBMOtHvJKw/4NGovEGN33viISshG/rZNVrACiBmPQLvWN8xQ==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.19.6", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-simple-access": "^7.19.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.19.6.tgz", + "integrity": "sha512-fqGLBepcc3kErfR9R3DnVpURmckXP7gj7bAlrTQyBxrigFqszZCkFkcoxzCp2v32XmwXLvbw+8Yq9/b+QqksjQ==", + "dev": true, + "dependencies": { + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-module-transforms": "^7.19.6", + "@babel/helper-plugin-utils": "^7.19.0", + "@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.19.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.19.1.tgz", + "integrity": "sha512-oWk9l9WItWBQYS4FgXD4Uyy5kq898lvkXpXQxoJEY1RnvPk4R/Dvu2ebXU9q8lP+rlMwUQTFf2Ok6d78ODa0kw==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.19.0", + "@babel/helper-plugin-utils": "^7.19.0" + }, + "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.18.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.18.8.tgz", + "integrity": "sha512-ivfbE3X2Ss+Fj8nnXvKJS6sjRG4gzwPMsP+taZC+ZzEGjAYlvENixmt1sZ5Ca6tWls+BlKSGKPJ6OOXvXCbkFg==", + "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-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.19.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.19.0.tgz", + "integrity": "sha512-UVEvX3tXie3Szm3emi1+G63jyw1w5IcMY0FSKM+CRnKRI5Mr1YbCNgsSTwoTwKphQEG9P+QqmuRFneJPZuHNhg==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/plugin-syntax-jsx": "^7.18.6", + "@babel/types": "^7.19.0" + }, + "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.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.18.6.tgz", + "integrity": "sha512-poqRI2+qiSdeldcz4wTSTXBRryoq3Gc70ye7m7UD5Ww0nE29IXqMl6r7Nd15WBgRd74vloEMlShtH6CKxVzfmQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "regenerator-transform": "^0.15.0" + }, + "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-runtime": { + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.19.6.tgz", + "integrity": "sha512-PRH37lz4JU156lYFW1p8OxE5i7d6Sl/zV58ooyr+q1J1lnQPyg5tIiXlIwNVhJaY4W3TmOtdc8jqdXQcB1v5Yw==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.19.0", + "babel-plugin-polyfill-corejs2": "^0.3.3", + "babel-plugin-polyfill-corejs3": "^0.6.0", + "babel-plugin-polyfill-regenerator": "^0.4.1", + "semver": "^6.3.0" + }, + "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.19.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.19.0.tgz", + "integrity": "sha512-RsuMk7j6n+r752EtzyScnWkQyuJdli6LdO5Klv8Yx0OfPVTcQkIUfS8clx5e9yHXzlnhOZF3CbQ8C2uP5j074w==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9" + }, + "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.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.20.0.tgz", + "integrity": "sha512-xOAsAFaun3t9hCwZ13Qe7gq423UgMZ6zAgmLxeGGapFqlT/X3L5qT2btjiVLlFn7gWtMaVyceS5VxGAuKbgizw==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.19.0", + "@babel/helper-plugin-utils": "^7.19.0", + "@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.19.4", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.19.4.tgz", + "integrity": "sha512-5QVOTXUdqTCjQuh2GGtdd7YEhoRXBMVGROAtsBeLGIbIz3obCBIfRMT1I3ZKkMgNzwkyCkftDXSSkHxnfVf4qg==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.19.4", + "@babel/helper-compilation-targets": "^7.19.3", + "@babel/helper-plugin-utils": "^7.19.0", + "@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.19.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.19.4", + "@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.18.6", + "@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.19.4", + "@babel/plugin-transform-classes": "^7.19.0", + "@babel/plugin-transform-computed-properties": "^7.18.9", + "@babel/plugin-transform-destructuring": "^7.19.4", + "@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.18.6", + "@babel/plugin-transform-modules-commonjs": "^7.18.6", + "@babel/plugin-transform-modules-systemjs": "^7.19.0", + "@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.18.8", + "@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.19.4", + "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-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/runtime": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.19.4.tgz", + "integrity": "sha512-EXpLCrk55f+cYqmHsSR+yD/0gAIMxxA9QK9lnQWzhMCvt+YmoBN7Zx94s++Kv0+unHk39vxNO8t+CMA2WSS3wA==", + "dependencies": { + "regenerator-runtime": "^0.13.4" + }, + "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==", + "dependencies": { + "@babel/code-frame": "^7.18.6", + "@babel/parser": "^7.18.10", + "@babel/types": "^7.18.10" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.19.6.tgz", + "integrity": "sha512-6l5HrUCzFM04mfbG09AagtYyR2P0B71B1wN7PfSPiksDPz2k5H9CBC1tcZpz2M8OxbKTPccByoOJ22rUKbpmQQ==", + "dependencies": { + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.19.6", + "@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.19.6", + "@babel/types": "^7.19.4", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@babel/traverse/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==" + }, + "node_modules/@babel/types": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.4.tgz", + "integrity": "sha512-M5LK7nAeS6+9j7hAq+b3fQs+pNfUtTGq+yFFfHnauFA8zQtLRfmuipmsKDKKLuyG+wC8ABW43A153YNawNTEtw==", + "dependencies": { + "@babel/helper-string-parser": "^7.19.4", + "@babel/helper-validator-identifier": "^7.19.1", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@ctrl/tinycolor": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.4.1.tgz", + "integrity": "sha512-ej5oVy6lykXsvieQtqZxCOaLT+xD4+QNarq78cIYISHmZXshCvROLudpQN3lfL8G0NL7plMSSK+zlyvCaIJ4Iw==", + "engines": { + "node": ">=10" + } + }, + "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", + "integrity": "sha512-xNQ57njWTFVfPAc3cjfuaPdsgLp5QOSuRsj9MA6ndEhH/AzuZM86qIQzt6rq+aGBwj3n5/TkLmU5lhAfdRmogA==", + "dependencies": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/plugin-syntax-jsx": "^7.17.12", + "@babel/runtime": "^7.18.3", + "@emotion/hash": "^0.9.0", + "@emotion/memoize": "^0.8.0", + "@emotion/serialize": "^1.1.0", + "babel-plugin-macros": "^3.1.0", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^4.0.0", + "find-root": "^1.1.0", + "source-map": "^0.5.7", + "stylis": "4.0.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@emotion/cache": { + "version": "11.10.3", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.10.3.tgz", + "integrity": "sha512-Psmp/7ovAa8appWh3g51goxu/z3iVms7JXOreq136D8Bbn6dYraPnmL6mdM8GThEx9vwSn92Fz+mGSjBzN8UPQ==", + "dependencies": { + "@emotion/memoize": "^0.8.0", + "@emotion/sheet": "^1.2.0", + "@emotion/utils": "^1.2.0", + "@emotion/weak-memoize": "^0.3.0", + "stylis": "4.0.13" + } + }, + "node_modules/@emotion/hash": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.0.tgz", + "integrity": "sha512-14FtKiHhy2QoPIzdTcvh//8OyBlknNs2nXRwIhG904opCby3l+9Xaf/wuPvICBF0rc1ZCNBd3nKe9cd2mecVkQ==" + }, + "node_modules/@emotion/is-prop-valid": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.0.tgz", + "integrity": "sha512-3aDpDprjM0AwaxGE09bOPkNxHpBd+kA6jty3RnaEXdweX1DF1U3VQpPYb0g1IStAuK7SVQ1cy+bNBBKp4W3Fjg==", + "dependencies": { + "@emotion/memoize": "^0.8.0" + } + }, + "node_modules/@emotion/memoize": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.0.tgz", + "integrity": "sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA==" + }, + "node_modules/@emotion/react": { + "version": "11.10.4", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.10.4.tgz", + "integrity": "sha512-j0AkMpr6BL8gldJZ6XQsQ8DnS9TxEQu1R+OGmDZiWjBAJtCcbt0tS3I/YffoqHXxH6MjgI7KdMbYKw3MEiU9eA==", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.10.0", + "@emotion/cache": "^11.10.0", + "@emotion/serialize": "^1.1.0", + "@emotion/use-insertion-effect-with-fallbacks": "^1.0.0", + "@emotion/utils": "^1.2.0", + "@emotion/weak-memoize": "^0.3.0", + "hoist-non-react-statics": "^3.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.0.0", + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/serialize": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.0.tgz", + "integrity": "sha512-F1ZZZW51T/fx+wKbVlwsfchr5q97iW8brAnXmsskz4d0hVB4O3M/SiA3SaeH06x02lSNzkkQv+n3AX3kCXKSFA==", + "dependencies": { + "@emotion/hash": "^0.9.0", + "@emotion/memoize": "^0.8.0", + "@emotion/unitless": "^0.8.0", + "@emotion/utils": "^1.2.0", + "csstype": "^3.0.2" + } + }, + "node_modules/@emotion/sheet": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.0.tgz", + "integrity": "sha512-OiTkRgpxescko+M51tZsMq7Puu/KP55wMT8BgpcXVG2hqXc0Vo0mfymJ/Uj24Hp0i083ji/o0aLddh08UEjq8w==" + }, + "node_modules/@emotion/styled": { + "version": "11.10.4", + "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.10.4.tgz", + "integrity": "sha512-pRl4R8Ez3UXvOPfc2bzIoV8u9P97UedgHS4FPX594ntwEuAMA114wlaHvOK24HB48uqfXiGlYIZYCxVJ1R1ttQ==", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.10.0", + "@emotion/is-prop-valid": "^1.2.0", + "@emotion/serialize": "^1.1.0", + "@emotion/use-insertion-effect-with-fallbacks": "^1.0.0", + "@emotion/utils": "^1.2.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0", + "@emotion/react": "^11.0.0-rc.0", + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/unitless": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.0.tgz", + "integrity": "sha512-VINS5vEYAscRl2ZUDiT3uMPlrFQupiKgHz5AA4bCH1miKBg4qtwkim1qPmJj/4WG6TreYMY111rEFsjupcOKHw==" + }, + "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==", + "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", + "integrity": "sha512-sn3WH53Kzpw8oQ5mgMmIzzyAaH2ZqFEbozVVBSYp538E06OSE6ytOp7pRAjNQR+Q/orwqdQYJSe2m3hCOeznkw==" + }, + "node_modules/@emotion/weak-memoize": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.0.tgz", + "integrity": "sha512-AHPmaAx+RYfZz0eYu6Gviiagpmiyw98ySSlQvCUhVGDRtDFe4DBS0x1bSjdF3gqUDYOczB+yYvBTtEylYSdRhg==" + }, + "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==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.4.0", + "globals": "^13.15.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/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/@eslint/eslintrc/node_modules/globals": { + "version": "13.17.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz", + "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/eslintrc/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/@formatjs/ecma402-abstract": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-1.13.0.tgz", + "integrity": "sha512-CQ8Ykd51jYD1n05dtoX6ns6B9n/+6ZAxnWUAonvHC4kkuAemROYBhHkEB4tm1uVrRlE7gLDqXkAnY51Y0pRCWQ==", + "dev": true, + "dependencies": { + "@formatjs/intl-localematcher": "0.2.31", + "tslib": "2.4.0" + } + }, + "node_modules/@formatjs/fast-memoize": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@formatjs/fast-memoize/-/fast-memoize-1.2.6.tgz", + "integrity": "sha512-9CWZ3+wCkClKHX+i5j+NyoBVqGf0pIskTo6Xl6ihGokYM2yqSSS68JIgeo+99UIHc+7vi9L3/SDSz/dWI9SNlA==", + "dev": true, + "dependencies": { + "tslib": "2.4.0" + } + }, + "node_modules/@formatjs/icu-messageformat-parser": { + "version": "2.1.10", + "resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.1.10.tgz", + "integrity": "sha512-KkRMxhifWkRC45dhM9tqm0GXbb6NPYTGVYY3xx891IKc6p++DQrZTnmkVSNNO47OEERLfuP2KkPFPJBuu8z/wg==", + "dev": true, + "dependencies": { + "@formatjs/ecma402-abstract": "1.13.0", + "@formatjs/icu-skeleton-parser": "1.3.14", + "tslib": "2.4.0" + } + }, + "node_modules/@formatjs/icu-skeleton-parser": { + "version": "1.3.14", + "resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.3.14.tgz", + "integrity": "sha512-7bv60HQQcBb3+TSj+45tOb/CHV5z1hOpwdtS50jsSBXfB+YpGhnoRsZxSRksXeCxMy6xn6tA6VY2601BrrK+OA==", + "dev": true, + "dependencies": { + "@formatjs/ecma402-abstract": "1.13.0", + "tslib": "2.4.0" + } + }, + "node_modules/@formatjs/intl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@formatjs/intl/-/intl-2.5.1.tgz", + "integrity": "sha512-P01ZGuDDlcN8bHHBCEHspJPvs8WJeO8SXlUIcVGWhS3IN5vUgz0QKUXcKBFnJbEHhONJ+azlObVwvlDKsE+kUg==", + "dev": true, + "dependencies": { + "@formatjs/ecma402-abstract": "1.13.0", + "@formatjs/fast-memoize": "1.2.6", + "@formatjs/icu-messageformat-parser": "2.1.10", + "@formatjs/intl-displaynames": "6.1.4", + "@formatjs/intl-listformat": "7.1.3", + "intl-messageformat": "10.2.1", + "tslib": "2.4.0" + }, + "peerDependencies": { + "typescript": "^4.7" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@formatjs/intl-displaynames": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/@formatjs/intl-displaynames/-/intl-displaynames-6.1.4.tgz", + "integrity": "sha512-sEbziGLsWQo6nA8ZUBcsDRlZzPg+uMVjDmbTalgGqRWLbdXuxMldTYdaCK+UptyJhkmNVM/erz3csTiyqamXHQ==", + "dev": true, + "dependencies": { + "@formatjs/ecma402-abstract": "1.13.0", + "@formatjs/intl-localematcher": "0.2.31", + "tslib": "2.4.0" + } + }, + "node_modules/@formatjs/intl-listformat": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@formatjs/intl-listformat/-/intl-listformat-7.1.3.tgz", + "integrity": "sha512-rs0Kxl78PeRCedx2cmFoBqcun2Kf0bCQrF8ycna54sfePpDhMskvODWeI4G/xBioW01FjK7CJSvtJJ87hrr79A==", + "dev": true, + "dependencies": { + "@formatjs/ecma402-abstract": "1.13.0", + "@formatjs/intl-localematcher": "0.2.31", + "tslib": "2.4.0" + } + }, + "node_modules/@formatjs/intl-localematcher": { + "version": "0.2.31", + "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.2.31.tgz", + "integrity": "sha512-9QTjdSBpQ7wHShZgsNzNig5qT3rCPvmZogS/wXZzKotns5skbXgs0I7J8cuN0PPqXyynvNVuN+iOKhNS2eb+ZA==", + "dev": true, + "dependencies": { + "tslib": "2.4.0" + } + }, + "node_modules/@fortawesome/fontawesome-common-types": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.2.0.tgz", + "integrity": "sha512-rBevIsj2nclStJ7AxTdfsa3ovHb1H+qApwrxcTVo+NNdeJiB9V75hsKfrkG5AwNcRUNxrPPiScGYCNmLMoh8pg==", + "hasInstallScript": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/fontawesome-svg-core": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.2.0.tgz", + "integrity": "sha512-Cf2mAAeMWFMzpLC7Y9H1I4o3wEU+XovVJhTiNG8ZNgSQj53yl7OCJaS80K4YjrABWZzbAHVaoHE1dVJ27AAYXw==", + "hasInstallScript": true, + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/free-brands-svg-icons": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-6.2.0.tgz", + "integrity": "sha512-fm1y4NyZ2qKYNmYhdMz9VAWRw1Et7PMHNunSw3W0SVAwKwv6o0qiJworLH3Y9SnmhHzAymXJwCX1op22FFvGiA==", + "hasInstallScript": true, + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/free-solid-svg-icons": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.2.0.tgz", + "integrity": "sha512-UjCILHIQ4I8cN46EiQn0CZL/h8AwCGgR//1c4R96Q5viSRwuKVo0NdQEc4bm+69ZwC0dUvjbDqAHF1RR5FA3XA==", + "hasInstallScript": true, + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/react-fontawesome": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.0.tgz", + "integrity": "sha512-uHg75Rb/XORTtVt7OS9WoK8uM276Ufi7gCzshVWkUJbHhh3svsUUeqXerrM96Wm7fRiDzfKRwSoahhMIkGAYHw==", + "dependencies": { + "prop-types": "^15.8.1" + }, + "peerDependencies": { + "@fortawesome/fontawesome-svg-core": "~1 || ~6", + "react": ">=16.3" + } + }, + "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==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/config-array/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/@humanwhocodes/config-array/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/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", + "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", + "dependencies": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "engines": { + "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/source-map/node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", + "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", + "dependencies": { + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + } + }, + "node_modules/@juggle/resize-observer": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/@juggle/resize-observer/-/resize-observer-3.4.0.tgz", + "integrity": "sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA==" + }, + "node_modules/@motionone/animation": { + "version": "10.14.0", + "resolved": "https://registry.npmjs.org/@motionone/animation/-/animation-10.14.0.tgz", + "integrity": "sha512-h+1sdyBP8vbxEBW5gPFDnj+m2DCqdlAuf2g6Iafb1lcMnqjsRXWlPw1AXgvUMXmreyhqmPbJqoNfIKdytampRQ==", + "dependencies": { + "@motionone/easing": "^10.14.0", + "@motionone/types": "^10.14.0", + "@motionone/utils": "^10.14.0", + "tslib": "^2.3.1" + } + }, + "node_modules/@motionone/dom": { + "version": "10.13.1", + "resolved": "https://registry.npmjs.org/@motionone/dom/-/dom-10.13.1.tgz", + "integrity": "sha512-zjfX+AGMIt/fIqd/SL1Lj93S6AiJsEA3oc5M9VkUr+Gz+juRmYN1vfvZd6MvEkSqEjwPQgcjN7rGZHrDB9APfQ==", + "dependencies": { + "@motionone/animation": "^10.13.1", + "@motionone/generators": "^10.13.1", + "@motionone/types": "^10.13.0", + "@motionone/utils": "^10.13.1", + "hey-listen": "^1.0.8", + "tslib": "^2.3.1" + } + }, + "node_modules/@motionone/easing": { + "version": "10.14.0", + "resolved": "https://registry.npmjs.org/@motionone/easing/-/easing-10.14.0.tgz", + "integrity": "sha512-2vUBdH9uWTlRbuErhcsMmt1jvMTTqvGmn9fHq8FleFDXBlHFs5jZzHJT9iw+4kR1h6a4SZQuCf72b9ji92qNYA==", + "dependencies": { + "@motionone/utils": "^10.14.0", + "tslib": "^2.3.1" + } + }, + "node_modules/@motionone/generators": { + "version": "10.14.0", + "resolved": "https://registry.npmjs.org/@motionone/generators/-/generators-10.14.0.tgz", + "integrity": "sha512-6kRHezoFfIjFN7pPpaxmkdZXD36tQNcyJe3nwVqwJ+ZfC0e3rFmszR8kp9DEVFs9QL/akWjuGPSLBI1tvz+Vjg==", + "dependencies": { + "@motionone/types": "^10.14.0", + "@motionone/utils": "^10.14.0", + "tslib": "^2.3.1" + } + }, + "node_modules/@motionone/types": { + "version": "10.14.0", + "resolved": "https://registry.npmjs.org/@motionone/types/-/types-10.14.0.tgz", + "integrity": "sha512-3bNWyYBHtVd27KncnJLhksMFQ5o2MSdk1cA/IZqsHtA9DnRM1SYgN01CTcJ8Iw8pCXF5Ocp34tyAjY7WRpOJJQ==" + }, + "node_modules/@motionone/utils": { + "version": "10.14.0", + "resolved": "https://registry.npmjs.org/@motionone/utils/-/utils-10.14.0.tgz", + "integrity": "sha512-sLWBLPzRqkxmOTRzSaD3LFQXCPHvDzyHJ1a3VP9PRzBxyVd2pv51/gMOsdAcxQ9n+MIeGJnxzXBYplUHKj4jkw==", + "dependencies": { + "@motionone/types": "^10.14.0", + "hey-listen": "^1.0.8", + "tslib": "^2.3.1" + } + }, + "node_modules/@mui/base": { + "version": "5.0.0-alpha.103", + "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-alpha.103.tgz", + "integrity": "sha512-fJIyB2df3CHn7D26WHnutnY7vew6aytTlhmRJz6GX7ag19zU2GcOUhJAzY5qwWcrXKnlYgzimhEjaEnuiUWU4g==", + "dependencies": { + "@babel/runtime": "^7.19.0", + "@emotion/is-prop-valid": "^1.2.0", + "@mui/types": "^7.2.0", + "@mui/utils": "^5.10.9", + "@popperjs/core": "^2.11.6", + "clsx": "^1.2.1", + "prop-types": "^15.8.1", + "react-is": "^18.2.0" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0", + "react-dom": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/core-downloads-tracker": { + "version": "5.10.11", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.10.11.tgz", + "integrity": "sha512-u5ff+UCFDHcR8MoQ8tuJR4c35vt7T/ki3aMEE2O3XQoGs8KJSrBiisFpFKyldg9/W2NSyoZxN+kxEGIfRxh+9Q==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui" + } + }, + "node_modules/@mui/material": { + "version": "5.10.11", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.10.11.tgz", + "integrity": "sha512-KJ0wPCTbv6sFzwA3dgg0gowdfF+SRl7D510J9l6Nl/KFX0EawcewQudqKY4slYGFXniKa5PykqokpaWXsCCPqg==", + "dependencies": { + "@babel/runtime": "^7.19.0", + "@mui/base": "5.0.0-alpha.103", + "@mui/core-downloads-tracker": "^5.10.11", + "@mui/system": "^5.10.10", + "@mui/types": "^7.2.0", + "@mui/utils": "^5.10.9", + "@types/react-transition-group": "^4.4.5", + "clsx": "^1.2.1", + "csstype": "^3.1.1", + "prop-types": "^15.8.1", + "react-is": "^18.2.0", + "react-transition-group": "^4.4.5" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0", + "react-dom": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/private-theming": { + "version": "5.10.9", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.10.9.tgz", + "integrity": "sha512-BN7/CnsVPVyBaQpDTij4uV2xGYHHHhOgpdxeYLlIu+TqnsVM7wUeF+37kXvHovxM6xmL5qoaVUD98gDC0IZnHg==", + "dependencies": { + "@babel/runtime": "^7.19.0", + "@mui/utils": "^5.10.9", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/styled-engine": { + "version": "5.10.8", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.10.8.tgz", + "integrity": "sha512-w+y8WI18EJV6zM/q41ug19cE70JTeO6sWFsQ7tgePQFpy6ToCVPh0YLrtqxUZXSoMStW5FMw0t9fHTFAqPbngw==", + "dependencies": { + "@babel/runtime": "^7.19.0", + "@emotion/cache": "^11.10.3", + "csstype": "^3.1.1", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui" + }, + "peerDependencies": { + "@emotion/react": "^11.4.1", + "@emotion/styled": "^11.3.0", + "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + } + } + }, + "node_modules/@mui/system": { + "version": "5.10.10", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.10.10.tgz", + "integrity": "sha512-TXwtKN0adKpBrZmO+eilQWoPf2veh050HLYrN78Kps9OhlvO70v/2Kya0+mORFhu9yhpAwjHXO8JII/R4a5ZLA==", + "dependencies": { + "@babel/runtime": "^7.19.0", + "@mui/private-theming": "^5.10.9", + "@mui/styled-engine": "^5.10.8", + "@mui/types": "^7.2.0", + "@mui/utils": "^5.10.9", + "clsx": "^1.2.1", + "csstype": "^3.1.1", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/types": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.0.tgz", + "integrity": "sha512-lGXtFKe5lp3UxTBGqKI1l7G8sE2xBik8qCfrLHD5olwP/YU0/ReWoWT7Lp1//ri32dK39oPMrJN8TgbkCSbsNA==", + "peerDependencies": { + "@types/react": "*" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/utils": { + "version": "5.10.9", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.10.9.tgz", + "integrity": "sha512-2tdHWrq3+WCy+G6TIIaFx3cg7PorXZ71P375ExuX61od1NOAJP1mK90VxQ8N4aqnj2vmO3AQDkV4oV2Ktvt4bA==", + "dependencies": { + "@babel/runtime": "^7.19.0", + "@types/prop-types": "^15.7.5", + "@types/react-is": "^16.7.1 || ^17.0.0", + "prop-types": "^15.8.1", + "react-is": "^18.2.0" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui" + }, + "peerDependencies": { + "react": "^17.0.0 || ^18.0.0" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@popperjs/core": { + "version": "2.11.6", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.6.tgz", + "integrity": "sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@remix-run/router": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.0.2.tgz", + "integrity": "sha512-GRSOFhJzjGN+d4sKHTMSvNeUPoZiDHWmRnXfzaxrqe7dE/Nzlc8BiMSJdLDESZlndM7jIUrZ/F4yWqVYlI0rwQ==", + "engines": { + "node": ">=14" + } + }, + "node_modules/@types/crypto-js": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@types/crypto-js/-/crypto-js-4.1.1.tgz", + "integrity": "sha512-BG7fQKZ689HIoc5h+6D2Dgq1fABRa0RbBWKBd9SP/MVRVXROflpm5fhwyATX5duFmbStzyzyycPB8qUYKDH3NA==" + }, + "node_modules/@types/eslint": { + "version": "8.4.8", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.8.tgz", + "integrity": "sha512-zUCKQI1bUCTi+0kQs5ZQzQ/XILWRLIlh15FXWNykJ+NG3TMKMVvwwC6GP3DR1Ylga15fB7iAExSzc4PNlR5i3w==", + "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/hoist-non-react-statics": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz", + "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==", + "dev": true, + "dependencies": { + "@types/react": "*", + "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/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true + }, + "node_modules/@types/jsrsasign": { + "version": "10.5.4", + "resolved": "https://registry.npmjs.org/@types/jsrsasign/-/jsrsasign-10.5.4.tgz", + "integrity": "sha512-05S2f4lGaWgCwFHsa3OEirc4VJf/sJRfhofzxUbuFbmm6NbffPXZrnJqquQAtS3g4C8Z0L9NHgW0znmtDxNoTQ==", + "dev": true + }, + "node_modules/@types/node": { + "version": "18.11.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.5.tgz", + "integrity": "sha512-3JRwhbjI+cHLAkUorhf8RnqUbFXajvzX4q6fMn5JwkgtuwfYtRQYI3u4V92vI6NJuTsbBQWWh3RZjFsuevyMGQ==" + }, + "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/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/react": { + "version": "18.0.23", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.23.tgz", + "integrity": "sha512-R1wTULtCiJkudAN2DJGoYYySbGtOdzZyUWAACYinKdiQC8auxso4kLDUhQ7AJ2kh3F6A6z4v69U6tNY39hihVQ==", + "dependencies": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.0.7", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.7.tgz", + "integrity": "sha512-HaXc+BbqAZE1RdsK3tC8SbkFy6UL2xF76lT9rQs5JkPrJg3rWA3Ou/Lhw3YJQzEDkBpmJ79nBsfnd05WrBd2QQ==", + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/react-is": { + "version": "17.0.3", + "resolved": "https://registry.npmjs.org/@types/react-is/-/react-is-17.0.3.tgz", + "integrity": "sha512-aBTIWg1emtu95bLTLx0cpkxwGW3ueZv71nE2YFBpL8k/z5czEW8yYpOo8Dp+UUAFAtKwNaOsh/ioSeQnWlZcfw==", + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-juKD/eiSM3/xZYzjuzH6ZwpP+/lejltmiS3QEzV/vmb/Q8+HfDmxu+Baga8UEMGBqV88Nbg4l2hY/K2DkyaLLA==", + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/scheduler": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", + "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" + }, + "node_modules/@types/semver": { + "version": "7.3.13", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", + "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", + "dev": true + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "5.51.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.51.0.tgz", + "integrity": "sha512-wcAwhEWm1RgNd7dxD/o+nnLW8oH+6RK1OGnmbmkj/GGoDPV1WWMVP0FXYQBivKHdwM1pwii3bt//RC62EriIUQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.51.0", + "@typescript-eslint/type-utils": "5.51.0", + "@typescript-eslint/utils": "5.51.0", + "debug": "^4.3.4", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "natural-compare-lite": "^1.4.0", + "regexpp": "^3.2.0", + "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" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-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/@typescript-eslint/eslint-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/@typescript-eslint/eslint-plugin/node_modules/semver": { + "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" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "5.51.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.51.0.tgz", + "integrity": "sha512-fEV0R9gGmfpDeRzJXn+fGQKcl0inIeYobmmUWijZh9zA7bxJ8clPhV9up2ZQzATxAiFAECqPQyMDB4o4B81AaA==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.51.0", + "@typescript-eslint/types": "5.51.0", + "@typescript-eslint/typescript-estree": "5.51.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser/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/parser/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/scope-manager": { + "version": "5.51.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.51.0.tgz", + "integrity": "sha512-gNpxRdlx5qw3yaHA0SFuTjW4rxeYhpHxt491PEcKF8Z6zpq0kMhe0Tolxt0qjlojS+/wArSDlj/LtE69xUJphQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.51.0", + "@typescript-eslint/visitor-keys": "5.51.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": { + "version": "5.51.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.51.0.tgz", + "integrity": "sha512-QHC5KKyfV8sNSyHqfNa0UbTbJ6caB8uhcx2hYcWVvJAZYJRBo5HyyZfzMdRx8nvS+GyMg56fugMzzWnojREuQQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "5.51.0", + "@typescript-eslint/utils": "5.51.0", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/type-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/type-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/types": { + "version": "5.51.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.51.0.tgz", + "integrity": "sha512-SqOn0ANn/v6hFn0kjvLwiDi4AzR++CBZz0NV5AnusT2/3y32jdc0G4woXPWHCumWtUXZKPAS27/9vziSsC9jnw==", + "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/typescript-estree": { + "version": "5.51.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.51.0.tgz", + "integrity": "sha512-TSkNupHvNRkoH9FMA3w7TazVFcBPveAAmb7Sz+kArY6sLT86PA5Vx80cKlYmd8m3Ha2SwofM1KwraF24lM9FvA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.51.0", + "@typescript-eslint/visitor-keys": "5.51.0", + "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/typescript-estree/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/typescript-estree/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/typescript-estree/node_modules/semver": { + "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" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "5.51.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.51.0.tgz", + "integrity": "sha512-76qs+5KWcaatmwtwsDJvBk4H76RJQBFe+Gext0EfJdC3Vd2kpY2Pf//OHHzHp84Ciw0/rYoGTDnIAr3uWhhJYw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.51.0", + "@typescript-eslint/types": "5.51.0", + "@typescript-eslint/typescript-estree": "5.51.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0", + "semver": "^7.3.7" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/semver": { + "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" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "5.51.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.51.0.tgz", + "integrity": "sha512-Oh2+eTdjHjOFjKA27sxESlA87YPSOJafGCR0md5oeMdh1ZcCfAGCIOL216uTBAkAIptvLIfKQhl7lHxMJet4GQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.51.0", + "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/@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/@webpack-cli/configtest": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.2.0.tgz", + "integrity": "sha512-4FB8Tj6xyVkyqjj1OaTqCjXYULB9FMkqQ8yGrZjRDrYh0nOE+7Lhs45WioWQQMV+ceFlE368Ukhe6xdvJM9Egg==", + "dev": true, + "peerDependencies": { + "webpack": "4.x.x || 5.x.x", + "webpack-cli": "4.x.x" + } + }, + "node_modules/@webpack-cli/info": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.5.0.tgz", + "integrity": "sha512-e8tSXZpw2hPl2uMJY6fsMswaok5FdlGNRTktvFk2sD8RjH0hE2+XistawJx1vmKteh4NmGmNUrp+Tb2w+udPcQ==", + "dev": true, + "dependencies": { + "envinfo": "^7.7.3" + }, + "peerDependencies": { + "webpack-cli": "4.x.x" + } + }, + "node_modules/@webpack-cli/serve": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.7.0.tgz", + "integrity": "sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q==", + "dev": true, + "peerDependencies": { + "webpack-cli": "4.x.x" + }, + "peerDependenciesMeta": { + "webpack-dev-server": { + "optional": true + } + } + }, + "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/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 + }, + "node_modules/abortcontroller-polyfill": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.5.tgz", + "integrity": "sha512-JMJ5soJWP18htbbxJjG7bG6yuI6pRhgJ0scHHTfkUjf6wjP912xZWvM+A4sJK3gqd9E8fcPbDnOefbA9Th/FIQ==" + }, + "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==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "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/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/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/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-regex": { + "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" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "node_modules/array-includes": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz", + "integrity": "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "get-intrinsic": "^1.1.3", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz", + "integrity": "sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.tosorted": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.1.tgz", + "integrity": "sha512-pZYPXPRl2PqWcsUs6LOMn+1f1532nEoPTYowBtqLwAW+W8vSVhkIGnmOX1t/UQjD6YGI0vcD2B1U7ZFGQH9jnQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0", + "get-intrinsic": "^1.1.3" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true + }, + "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/await-semaphore": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/await-semaphore/-/await-semaphore-0.1.3.tgz", + "integrity": "sha512-d1W2aNSYcz/sxYO4pMGX9vq65qOTu0P800epMud+6cYYX0QcT7zyqcxec3VWzpgvdXo57UWmVbZpLMjX2m1I7Q==" + }, + "node_modules/axios": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.3.4.tgz", + "integrity": "sha512-toYm+Bsyl6VC5wSkfkbbNB6ROv7KY93PEBBL6xyDczaIHasAiv4wPqQ/c4RjoQzipxRD2W5g21cOqQulZ7rHwQ==", + "dev": true, + "dependencies": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/babel-loader": { + "version": "8.2.5", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.5.tgz", + "integrity": "sha512-OSiFfH89LrEMiWd4pLNqGz4CwJDtbs2ZVc+iGu2HrkRfPxId9F2anQj38IxWpmRfsUY0aBZYi1EFcd3mhtRMLQ==", + "dev": true, + "dependencies": { + "find-cache-dir": "^3.3.1", + "loader-utils": "^2.0.0", + "make-dir": "^3.1.0", + "schema-utils": "^2.6.5" + }, + "engines": { + "node": ">= 8.9" + }, + "peerDependencies": { + "@babel/core": "^7.0.0", + "webpack": ">=2" + } + }, + "node_modules/babel-plugin-macros": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", + "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", + "dependencies": { + "@babel/runtime": "^7.12.5", + "cosmiconfig": "^7.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + } + }, + "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-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/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/basic-auth": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", + "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", + "dependencies": { + "safe-buffer": "5.1.2" + }, + "engines": { + "node": ">= 0.8" + } + }, + "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", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/body-parser": { + "version": "1.18.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz", + "integrity": "sha512-YQyoqQG3sO8iCmf8+hyVpgHHOv0/hCEFiS4zTGUwTA1HjAFX66wRcNQrVCeJq9pgESMRvUAOvSil5MJlmccuKQ==", + "dependencies": { + "bytes": "3.0.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "~1.6.3", + "iconv-lite": "0.4.23", + "on-finished": "~2.3.0", + "qs": "6.5.2", + "raw-body": "2.3.3", + "type-is": "~1.6.16" + }, + "engines": { + "node": ">= 0.8" + } + }, + "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/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browser-tabs-lock": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/browser-tabs-lock/-/browser-tabs-lock-1.2.15.tgz", + "integrity": "sha512-J8K9vdivK0Di+b8SBdE7EZxDr88TnATing7XoLw6+nFkXMQ6sVBh92K3NQvZlZU91AIkFRi0w3sztk5Z+vsswA==", + "hasInstallScript": true, + "dependencies": { + "lodash": ">=4.17.21" + } + }, + "node_modules/browserslist": { + "version": "4.21.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", + "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001400", + "electron-to-chromium": "^1.4.251", + "node-releases": "^2.0.6", + "update-browserslist-db": "^1.0.9" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "dev": true + }, + "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/bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "engines": { + "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/can-use-dom": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/can-use-dom/-/can-use-dom-0.1.0.tgz", + "integrity": "sha512-ceOhN1DL7Y4O6M0j9ICgmTYziV89WMd96SvSl0REd8PMgrY0B/WBOPoed5S1KUmJqXgUXh8gzSe6E3ae27upsQ==" + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001425", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001425.tgz", + "integrity": "sha512-/pzFv0OmNG6W0ym80P3NtapU0QEiDS3VuYAZMGoLLqiC7f6FJFe1MjpQDREGApeenD9wloeytmVDj+JLXPC6qw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + } + ] + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "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/classnames": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz", + "integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==" + }, + "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/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/clsx": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", + "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", + "engines": { + "node": ">=6" + } + }, + "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-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/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", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "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/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/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/connect-livereload": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/connect-livereload/-/connect-livereload-0.6.1.tgz", + "integrity": "sha512-3R0kMOdL7CjJpU66fzAkCe6HNtd3AavCS4m+uW4KtJjrdGPT0SQEZieAYd+cm+lJoBznNQ4lqipYWkhBMgk00g==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/content-disposition": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha512-kRGRZw3bLlFISDBgwTSA1TMBFN6J6GWDeubmDE3AF+3+yXL8hTWv8r5rkLbqYXY4RjPk/EzHnClI3zQf1cFmHA==", + "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==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" + }, + "node_modules/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-parser": { + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.6.tgz", + "integrity": "sha512-z3IzaNjdwUC2olLIB5/ITd0/setiaFMLYiZJle7xg5Fe9KWAceil7xszYfHHBtDFYLSgJduS2Ty0P1uJdPDJeA==", + "dev": true, + "dependencies": { + "cookie": "0.4.1", + "cookie-signature": "1.0.6" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "node_modules/copy-to-clipboard": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.2.tgz", + "integrity": "sha512-Vme1Z6RUDzrb6xAI7EZlVZ5uvOk2F//GaxKUxajDqm9LhOVM1inxNAD2vy+UZDYsd0uyA9s7b3/FVZPSxqrCfg==", + "dependencies": { + "toggle-selection": "^1.0.6" + } + }, + "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, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-js-compat": { + "version": "3.26.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.26.0.tgz", + "integrity": "sha512-piOX9Go+Z4f9ZiBFLnZ5VrOpBl0h7IGCkiFUN11QTe6LjAvOT3ifL/5TdoizMh99hcGy5SoLyWbapIY/PIb/3A==", + "dev": true, + "dependencies": { + "browserslist": "^4.21.4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/cosmiconfig": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", + "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crypto-js": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.1.1.tgz", + "integrity": "sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw==" + }, + "node_modules/css-loader": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.7.1.tgz", + "integrity": "sha512-yB5CNFa14MbPJcomwNh3wLThtkZgcNyI2bNMRt8iE5Z8Vwl7f8vQXFAzn2HDOJvtDq2NTZBUGMSUNNyrv3/+cw==", + "dev": true, + "dependencies": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.7", + "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.5" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/css-loader/node_modules/semver": { + "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" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "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-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", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/csstype": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", + "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==" + }, + "node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "dev": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/define-properties": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", + "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", + "dev": true, + "dependencies": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha512-3NdhDuEXnfun/z7x9GOElY49LoqVHoGScmOKwmxhsS8N5Y+Z8KyPPDnaSzqWgYt/ji4mqwfTS34Htrk0zPIXVg==" + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "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-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, + "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/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/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": "16.0.3", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz", + "integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "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==" + }, + "node_modules/electron-to-chromium": { + "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==" + }, + "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==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz", + "integrity": "sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "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/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", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.21.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.1.tgz", + "integrity": "sha512-QudMsPOz86xYz/1dG1OuGBKOELjCh99IIWHLzy5znUB6j8xG2yMA7bfTV86VSqKF+Y/H08vQPR+9jyXpuC6hfg==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "es-set-tostringtag": "^2.0.1", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "function.prototype.name": "^1.1.5", + "get-intrinsic": "^1.1.3", + "get-symbol-description": "^1.0.0", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.4", + "is-array-buffer": "^3.0.1", + "is-callable": "^1.2.7", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.10", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.2", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.4.3", + "safe-regex-test": "^1.0.0", + "string.prototype.trimend": "^1.0.6", + "string.prototype.trimstart": "^1.0.6", + "typed-array-length": "^1.0.4", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-cookie": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/es-cookie/-/es-cookie-1.3.2.tgz", + "integrity": "sha512-UTlYYhXGLOy05P/vKVT2Ui7WtC7NiRzGtJyAKKn32g5Gvcjn7KAClLPWlipCtxIus934dFg9o9jXiBL0nP+t9Q==" + }, + "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-set-tostringtag": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", + "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3", + "has": "^1.0.3", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "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==" + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.27.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.27.0.tgz", + "integrity": "sha512-0y1bfG2ho7mty+SiILVf9PfuRA49ek4Nc60Wmmu62QlobNR+CeXa4xXIJgcuwSQgZiWaPH+5BDsctpIW0PR/wQ==", + "dev": true, + "dependencies": { + "@eslint/eslintrc": "^1.3.3", + "@humanwhocodes/config-array": "^0.11.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.4.0", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.15.0", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-sdsl": "^4.1.4", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-plugin-react": { + "version": "7.32.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.32.2.tgz", + "integrity": "sha512-t2fBMa+XzonrrNkyVirzKlvn5RXzzPwRHtMvLAtVZrt8oxgnTQaYbU6SXTOO1mwQgp1y5+toMSKInnzGr0Knqg==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flatmap": "^1.3.1", + "array.prototype.tosorted": "^1.1.1", + "doctrine": "^2.1.0", + "estraverse": "^5.3.0", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.6", + "object.fromentries": "^2.0.6", + "object.hasown": "^1.1.2", + "object.values": "^1.1.6", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.4", + "semver": "^6.3.0", + "string.prototype.matchall": "^4.0.8" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/eslint-plugin-react/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-react/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint-plugin-react/node_modules/resolve": { + "version": "2.0.0-next.4", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz", + "integrity": "sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==", + "dev": true, + "dependencies": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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/eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "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/eslint/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/eslint/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/eslint/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/eslint/node_modules/eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/eslint/node_modules/globals": { + "version": "13.17.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz", + "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/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/eslint/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/espree": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", + "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", + "dev": true, + "dependencies": { + "acorn": "^8.8.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/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/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "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==", + "engines": { + "node": ">= 0.6" + } + }, + "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/express": { + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/express/-/express-4.16.4.tgz", + "integrity": "sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg==", + "dependencies": { + "accepts": "~1.3.5", + "array-flatten": "1.1.1", + "body-parser": "1.18.3", + "content-disposition": "0.5.2", + "content-type": "~1.0.4", + "cookie": "0.3.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.1.1", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.4", + "qs": "6.5.2", + "range-parser": "~1.2.0", + "safe-buffer": "5.1.2", + "send": "0.16.2", + "serve-static": "1.13.2", + "setprototypeof": "1.1.0", + "statuses": "~1.4.0", + "type-is": "~1.6.16", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express/node_modules/cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha512-+IJOX0OqlHCszo2mBUq+SrEbCj6w7Kpffqx60zYbPTFaO4+yYgRjHwcZNpWvaTylDHaV7PPmBHzSecZiMhtPgw==", + "engines": { + "node": ">= 0.6" + } + }, + "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-glob": { + "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", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fast-text-encoding": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.6.tgz", + "integrity": "sha512-VhXlQgj9ioXCqGstD37E/HBeqEGV/qOD/kmbVG8h5xKBYvM1L3lR1Zn4555cQ8GkYbJa8aJSipLPndE1k6zK2w==" + }, + "node_modules/fastest-levenshtein": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "dev": true, + "engines": { + "node": ">= 4.9.1" + } + }, + "node_modules/fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/file-loader": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz", + "integrity": "sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==", + "dev": true, + "dependencies": { + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/file-loader/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/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", + "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "statuses": "~1.4.0", + "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-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==" + }, + "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/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "dev": true + }, + "node_modules/follow-redirects": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "dev": true, + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/framer-motion": { + "version": "7.6.1", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-7.6.1.tgz", + "integrity": "sha512-8US03IWJKrLoSb81l5OahNzB9Sv7Jo1RhIwUoTG/25BRUdO9lOqq/klsdZqNmNG0ua9IEJJQ8hkYpETJ4N6VSw==", + "dependencies": { + "@motionone/dom": "10.13.1", + "framesync": "6.1.2", + "hey-listen": "^1.0.8", + "popmotion": "11.0.5", + "style-value-types": "5.1.2", + "tslib": "2.4.0" + }, + "optionalDependencies": { + "@emotion/is-prop-valid": "^0.8.2" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/framer-motion/node_modules/@emotion/is-prop-valid": { + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz", + "integrity": "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==", + "optional": true, + "dependencies": { + "@emotion/memoize": "0.7.4" + } + }, + "node_modules/framer-motion/node_modules/@emotion/memoize": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz", + "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==", + "optional": true + }, + "node_modules/framesync": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/framesync/-/framesync-6.1.2.tgz", + "integrity": "sha512-jBTqhX6KaQVDyus8muwZbBeGGP0XgujBRbQ7gM7BRdS3CadCZIHiawyzYLnafYcvZIh5j8WE7cxZKFn7dXhu9g==", + "dependencies": { + "tslib": "2.4.0" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "node_modules/function.prototype.name": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", + "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", + "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "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/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/goober": { + "version": "2.1.11", + "resolved": "https://registry.npmjs.org/goober/-/goober-2.1.11.tgz", + "integrity": "sha512-5SS2lmxbhqH0u9ABEWq7WPU69a4i2pYcHeCxqaNq6Cw3mnrF0ghWNM4tEGid4dKy8XNIAUbuThuozDHHKJVh3A==", + "peerDependencies": { + "csstype": "^3.0.10" + } + }, + "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", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true + }, + "node_modules/grapheme-splitter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "dev": true + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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/hey-listen": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/hey-listen/-/hey-listen-1.0.8.tgz", + "integrity": "sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q==" + }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hoist-non-react-statics/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "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-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/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/http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", + "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", + "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/ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==" + }, + "node_modules/install": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/install/-/install-0.13.0.tgz", + "integrity": "sha512-zDml/jzr2PKU9I8J/xyZBQn8rPCAY//UOYNmR01XwNwyfhEWObo2SWfSl1+0tm1u6PhxLwDnfsT/6jB7OUxqFA==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/internal-slot": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", + "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/interpret": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", + "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/intl-messageformat": { + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-10.2.1.tgz", + "integrity": "sha512-1lrJG2qKzcC1TVzYu1VuB1yiY68LU5rwpbHa2THCzA67Vutkz7+1lv5U20K3Lz5RAiH78zxNztMEtchokMWv8A==", + "dev": true, + "dependencies": { + "@formatjs/ecma402-abstract": "1.13.0", + "@formatjs/fast-memoize": "1.2.6", + "@formatjs/icu-messageformat-parser": "2.1.10", + "tslib": "2.4.0" + } + }, + "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==", + "engines": { + "node": ">= 0.10" + } + }, + "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.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "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", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "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-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "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-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "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/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/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.1.5", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.5.tgz", + "integrity": "sha512-08bOAKweV2NUC1wqTtf3qZlnpOX/R2DU9ikpjOHs0H+ibQv3zpncVQg6um4uYtRtrwIX8M4Nh3ytK4HGlYAq7Q==", + "dev": true + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/json5": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", + "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonwebtoken": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz", + "integrity": "sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw==", + "dev": true, + "dependencies": { + "jws": "^3.2.2", + "lodash": "^4.17.21", + "ms": "^2.1.1", + "semver": "^7.3.8" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jsonwebtoken/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/jsonwebtoken/node_modules/semver": { + "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" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jsrsasign": { + "version": "10.5.27", + "resolved": "https://registry.npmjs.org/jsrsasign/-/jsrsasign-10.5.27.tgz", + "integrity": "sha512-1F4LmDeJZHYwoVvB44jEo2uZL3XuwYNzXCDOu53Ui6vqofGQ/gCYDmaxfVZtN0TGd92UKXr/BONcfrPonUIcQQ==", + "funding": { + "url": "https://github.com/kjur/jsrsasign#donations" + } + }, + "node_modules/jsx-ast-utils": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz", + "integrity": "sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.5", + "object.assign": "^4.1.3" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "dev": true, + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "dev": true, + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jwt-decode": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz", + "integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==" + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.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", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" + }, + "node_modules/livereload": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/livereload/-/livereload-0.9.3.tgz", + "integrity": "sha512-q7Z71n3i4X0R9xthAryBdNGVGAO2R5X+/xXpmKeuPMrteg+W2U8VusTKV3YiJbXZwKsOlFlHe+go6uSNjfxrZw==", + "dev": true, + "dependencies": { + "chokidar": "^3.5.0", + "livereload-js": "^3.3.1", + "opts": ">= 1.2.0", + "ws": "^7.4.3" + }, + "bin": { + "livereload": "bin/livereload.js" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/livereload-js": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/livereload-js/-/livereload-js-3.4.1.tgz", + "integrity": "sha512-5MP0uUeVCec89ZbNOT/i97Mc+q3SxXmiUGhRFOTmhrGPn//uWVQdCvcLJDy64MSBR5MidFdOR7B9viumoavy6g==", + "dev": true + }, + "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": "2.0.3", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.3.tgz", + "integrity": "sha512-THWqIsn8QRnvLl0shHYVBN9syumU8pYWEHPTmkiVGd+7K5eFNVSY6AJhRvgGF70gg1Dz+l/k8WicvFCxdEs60A==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "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/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" + }, + "node_modules/lodash.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==" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/lodash.throttle": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", + "integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/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", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "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/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==", + "engines": { + "node": ">= 0.6" + } + }, + "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==" + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "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==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==", + "bin": { + "mime": "cli.js" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/moment": { + "version": "2.29.4", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", + "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", + "engines": { + "node": "*" + } + }, + "node_modules/morgan": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.9.1.tgz", + "integrity": "sha512-HQStPIV4y3afTiCYVxirakhlCfGkI161c76kKFca7Fk1JusM//Qeo1ej2XaMniiNeaZklMVrh3vTtIzpzwbpmA==", + "dependencies": { + "basic-auth": "~2.0.0", + "debug": "2.6.9", + "depd": "~1.1.2", + "on-finished": "~2.3.0", + "on-headers": "~1.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/nanoid": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "dev": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "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==", + "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/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-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-fetch": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.0.tgz", + "integrity": "sha512-BKwRP/O0UvoMKp7GNdwPlObhYGB5DQqwhEDQlNKuoqwVYSxkSZCSbHjnFFmUEtwSKRPU4kNK8PbDYYitwaE3QA==", + "dev": true, + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, + "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==" + }, + "node_modules/nodemon": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.20.tgz", + "integrity": "sha512-Km2mWHKKY5GzRg6i1j5OxOHQtuvVsgskLfigG25yTtbyfRGn/GNvIbRyOf1PSCKJ2aT/58TiuUsuOU5UToVViw==", + "dev": true, + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^3.2.7", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", + "semver": "^5.7.1", + "simple-update-notifier": "^1.0.7", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=8.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/nodemon/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/nodemon/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/nodemon/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/nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", + "dev": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm": { + "version": "9.5.1", + "resolved": "https://registry.npmjs.org/npm/-/npm-9.5.1.tgz", + "integrity": "sha512-MzULm9eEWPuPyHmRBxjcKm47KKYYT1gteVOXPlNJbfdaXNtp+sO4y2X3v5g375KudEAGJVDVCoFuk7bFnuuvNg==", + "bundleDependencies": [ + "@isaacs/string-locale-compare", + "@npmcli/arborist", + "@npmcli/config", + "@npmcli/map-workspaces", + "@npmcli/package-json", + "@npmcli/run-script", + "abbrev", + "archy", + "cacache", + "chalk", + "ci-info", + "cli-columns", + "cli-table3", + "columnify", + "fastest-levenshtein", + "fs-minipass", + "glob", + "graceful-fs", + "hosted-git-info", + "ini", + "init-package-json", + "is-cidr", + "json-parse-even-better-errors", + "libnpmaccess", + "libnpmdiff", + "libnpmexec", + "libnpmfund", + "libnpmhook", + "libnpmorg", + "libnpmpack", + "libnpmpublish", + "libnpmsearch", + "libnpmteam", + "libnpmversion", + "make-fetch-happen", + "minimatch", + "minipass", + "minipass-pipeline", + "ms", + "node-gyp", + "nopt", + "npm-audit-report", + "npm-install-checks", + "npm-package-arg", + "npm-pick-manifest", + "npm-profile", + "npm-registry-fetch", + "npm-user-validate", + "npmlog", + "p-map", + "pacote", + "parse-conflict-json", + "proc-log", + "qrcode-terminal", + "read", + "read-package-json", + "read-package-json-fast", + "semver", + "ssri", + "tar", + "text-table", + "tiny-relative-date", + "treeverse", + "validate-npm-package-name", + "which", + "write-file-atomic" + ], + "dev": true, + "dependencies": { + "@isaacs/string-locale-compare": "^1.1.0", + "@npmcli/arborist": "^6.2.3", + "@npmcli/config": "^6.1.3", + "@npmcli/map-workspaces": "^3.0.2", + "@npmcli/package-json": "^3.0.0", + "@npmcli/run-script": "^6.0.0", + "abbrev": "^2.0.0", + "archy": "~1.0.0", + "cacache": "^17.0.4", + "chalk": "^4.1.2", + "ci-info": "^3.8.0", + "cli-columns": "^4.0.0", + "cli-table3": "^0.6.3", + "columnify": "^1.6.0", + "fastest-levenshtein": "^1.0.16", + "fs-minipass": "^3.0.1", + "glob": "^8.1.0", + "graceful-fs": "^4.2.10", + "hosted-git-info": "^6.1.1", + "ini": "^3.0.1", + "init-package-json": "^5.0.0", + "is-cidr": "^4.0.2", + "json-parse-even-better-errors": "^3.0.0", + "libnpmaccess": "^7.0.2", + "libnpmdiff": "^5.0.11", + "libnpmexec": "^5.0.11", + "libnpmfund": "^4.0.11", + "libnpmhook": "^9.0.3", + "libnpmorg": "^5.0.3", + "libnpmpack": "^5.0.11", + "libnpmpublish": "^7.1.0", + "libnpmsearch": "^6.0.2", + "libnpmteam": "^5.0.3", + "libnpmversion": "^4.0.2", + "make-fetch-happen": "^11.0.3", + "minimatch": "^6.2.0", + "minipass": "^4.0.3", + "minipass-pipeline": "^1.2.4", + "ms": "^2.1.2", + "node-gyp": "^9.3.1", + "nopt": "^7.0.0", + "npm-audit-report": "^4.0.0", + "npm-install-checks": "^6.0.0", + "npm-package-arg": "^10.1.0", + "npm-pick-manifest": "^8.0.1", + "npm-profile": "^7.0.1", + "npm-registry-fetch": "^14.0.3", + "npm-user-validate": "^2.0.0", + "npmlog": "^7.0.1", + "p-map": "^4.0.0", + "pacote": "^15.1.1", + "parse-conflict-json": "^3.0.0", + "proc-log": "^3.0.0", + "qrcode-terminal": "^0.12.0", + "read": "^2.0.0", + "read-package-json": "^6.0.0", + "read-package-json-fast": "^3.0.2", + "semver": "^7.3.8", + "ssri": "^10.0.1", + "tar": "^6.1.13", + "text-table": "~0.2.0", + "tiny-relative-date": "^1.3.0", + "treeverse": "^3.0.0", + "validate-npm-package-name": "^5.0.0", + "which": "^3.0.0", + "write-file-atomic": "^5.0.0" + }, + "bin": { + "npm": "bin/npm-cli.js", + "npx": "bin/npx-cli.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@colors/colors": { + "version": "1.5.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/npm/node_modules/@gar/promisify": { + "version": "1.1.3", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/@isaacs/string-locale-compare": { + "version": "1.1.0", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/@npmcli/arborist": { + "version": "6.2.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@isaacs/string-locale-compare": "^1.1.0", + "@npmcli/fs": "^3.1.0", + "@npmcli/installed-package-contents": "^2.0.0", + "@npmcli/map-workspaces": "^3.0.2", + "@npmcli/metavuln-calculator": "^5.0.0", + "@npmcli/name-from-folder": "^2.0.0", + "@npmcli/node-gyp": "^3.0.0", + "@npmcli/package-json": "^3.0.0", + "@npmcli/query": "^3.0.0", + "@npmcli/run-script": "^6.0.0", + "bin-links": "^4.0.1", + "cacache": "^17.0.4", + "common-ancestor-path": "^1.0.1", + "hosted-git-info": "^6.1.1", + "json-parse-even-better-errors": "^3.0.0", + "json-stringify-nice": "^1.1.4", + "minimatch": "^6.1.6", + "nopt": "^7.0.0", + "npm-install-checks": "^6.0.0", + "npm-package-arg": "^10.1.0", + "npm-pick-manifest": "^8.0.1", + "npm-registry-fetch": "^14.0.3", + "npmlog": "^7.0.1", + "pacote": "^15.0.8", + "parse-conflict-json": "^3.0.0", + "proc-log": "^3.0.0", + "promise-all-reject-late": "^1.0.0", + "promise-call-limit": "^1.0.1", + "read-package-json-fast": "^3.0.2", + "semver": "^7.3.7", + "ssri": "^10.0.1", + "treeverse": "^3.0.0", + "walk-up-path": "^1.0.0" + }, + "bin": { + "arborist": "bin/index.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@npmcli/config": { + "version": "6.1.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/map-workspaces": "^3.0.2", + "ini": "^3.0.0", + "nopt": "^7.0.0", + "proc-log": "^3.0.0", + "read-package-json-fast": "^3.0.2", + "semver": "^7.3.5", + "walk-up-path": "^1.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@npmcli/disparity-colors": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "ansi-styles": "^4.3.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@npmcli/fs": { + "version": "3.1.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@npmcli/git": { + "version": "4.0.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/promise-spawn": "^6.0.0", + "lru-cache": "^7.4.4", + "mkdirp": "^1.0.4", + "npm-pick-manifest": "^8.0.0", + "proc-log": "^3.0.0", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@npmcli/installed-package-contents": { + "version": "2.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-bundled": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "bin": { + "installed-package-contents": "lib/index.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@npmcli/map-workspaces": { + "version": "3.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/name-from-folder": "^2.0.0", + "glob": "^8.0.1", + "minimatch": "^6.1.6", + "read-package-json-fast": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@npmcli/metavuln-calculator": { + "version": "5.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "cacache": "^17.0.0", + "json-parse-even-better-errors": "^3.0.0", + "pacote": "^15.0.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@npmcli/move-file": { + "version": "2.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/npm/node_modules/@npmcli/name-from-folder": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@npmcli/node-gyp": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@npmcli/package-json": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "json-parse-even-better-errors": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@npmcli/promise-spawn": { + "version": "6.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "which": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@npmcli/query": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@npmcli/run-script": { + "version": "6.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/node-gyp": "^3.0.0", + "@npmcli/promise-spawn": "^6.0.0", + "node-gyp": "^9.0.0", + "read-package-json-fast": "^3.0.0", + "which": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@tootallnate/once": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/npm/node_modules/abbrev": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/abort-controller": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/npm/node_modules/agent-base": { + "version": "6.0.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/npm/node_modules/agentkeepalive": { + "version": "4.2.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.0", + "depd": "^1.1.2", + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/npm/node_modules/aggregate-error": { + "version": "3.1.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/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, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/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, + "inBundle": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/npm/node_modules/aproba": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/archy": { + "version": "1.0.0", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/are-we-there-yet": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^4.1.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/base64-js": { + "version": "1.5.1", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/bin-links": { + "version": "4.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "cmd-shim": "^6.0.0", + "npm-normalize-package-bin": "^3.0.0", + "read-cmd-shim": "^4.0.0", + "write-file-atomic": "^5.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/binary-extensions": { + "version": "2.2.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/brace-expansion": { + "version": "2.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/npm/node_modules/buffer": { + "version": "6.0.3", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "inBundle": true, + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/npm/node_modules/builtins": { + "version": "5.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "semver": "^7.0.0" + } + }, + "node_modules/npm/node_modules/cacache": { + "version": "17.0.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/fs": "^3.1.0", + "fs-minipass": "^3.0.0", + "glob": "^8.0.1", + "lru-cache": "^7.7.1", + "minipass": "^4.0.0", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "ssri": "^10.0.0", + "tar": "^6.1.11", + "unique-filename": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/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, + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/npm/node_modules/chownr": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/ci-info": { + "version": "3.8.0", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/cidr-regex": { + "version": "3.1.1", + "dev": true, + "inBundle": true, + "license": "BSD-2-Clause", + "dependencies": { + "ip-regex": "^4.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/clean-stack": { + "version": "2.2.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/npm/node_modules/cli-columns": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/npm/node_modules/cli-table3": { + "version": "0.6.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "string-width": "^4.2.0" + }, + "engines": { + "node": "10.* || >= 12.*" + }, + "optionalDependencies": { + "@colors/colors": "1.5.0" + } + }, + "node_modules/npm/node_modules/clone": { + "version": "1.0.4", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/npm/node_modules/cmd-shim": { + "version": "6.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/npm/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, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/color-support": { + "version": "1.1.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "bin": { + "color-support": "bin.js" + } + }, + "node_modules/npm/node_modules/columnify": { + "version": "1.6.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "strip-ansi": "^6.0.1", + "wcwidth": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/npm/node_modules/common-ancestor-path": { + "version": "1.0.1", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/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, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/console-control-strings": { + "version": "1.1.0", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "inBundle": true, + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/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, + "inBundle": true, + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/npm/node_modules/debug/node_modules/ms": { + "version": "2.1.2", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/defaults": { + "version": "1.0.4", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm/node_modules/delegates": { + "version": "1.0.0", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/depd": { + "version": "1.1.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/npm/node_modules/diff": { + "version": "5.1.0", + "dev": true, + "inBundle": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/npm/node_modules/emoji-regex": { + "version": "8.0.0", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/encoding": { + "version": "0.1.13", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, + "node_modules/npm/node_modules/env-paths": { + "version": "2.2.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/npm/node_modules/err-code": { + "version": "2.0.3", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/event-target-shim": { + "version": "5.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/npm/node_modules/events": { + "version": "3.3.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/npm/node_modules/fastest-levenshtein": { + "version": "1.0.16", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 4.9.1" + } + }, + "node_modules/npm/node_modules/fs-minipass": { + "version": "3.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^4.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/gauge": { + "version": "5.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.3", + "console-control-strings": "^1.1.0", + "has-unicode": "^2.0.1", + "signal-exit": "^3.0.7", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.5" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/glob": { + "version": "8.1.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/glob/node_modules/minimatch": { + "version": "5.1.6", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/graceful-fs": { + "version": "4.2.10", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/npm/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, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/has-unicode": { + "version": "2.0.1", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/hosted-git-info": { + "version": "6.1.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^7.5.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/http-cache-semantics": { + "version": "4.1.1", + "dev": true, + "inBundle": true, + "license": "BSD-2-Clause" + }, + "node_modules/npm/node_modules/http-proxy-agent": { + "version": "5.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/npm/node_modules/https-proxy-agent": { + "version": "5.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/npm/node_modules/humanize-ms": { + "version": "1.2.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "ms": "^2.0.0" + } + }, + "node_modules/npm/node_modules/iconv-lite": { + "version": "0.6.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm/node_modules/ieee754": { + "version": "1.2.1", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "inBundle": true, + "license": "BSD-3-Clause" + }, + "node_modules/npm/node_modules/ignore-walk": { + "version": "6.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minimatch": "^6.1.6" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/npm/node_modules/indent-string": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/infer-owner": { + "version": "1.0.4", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/npm/node_modules/inherits": { + "version": "2.0.4", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/ini": { + "version": "3.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/npm/node_modules/init-package-json": { + "version": "5.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-package-arg": "^10.0.0", + "promzard": "^1.0.0", + "read": "^2.0.0", + "read-package-json": "^6.0.0", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4", + "validate-npm-package-name": "^5.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/ip": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/ip-regex": { + "version": "4.3.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/is-cidr": { + "version": "4.0.2", + "dev": true, + "inBundle": true, + "license": "BSD-2-Clause", + "dependencies": { + "cidr-regex": "^3.1.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/is-core-module": { + "version": "2.11.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/npm/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/is-lambda": { + "version": "1.0.1", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/json-parse-even-better-errors": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/json-stringify-nice": { + "version": "1.1.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/jsonparse": { + "version": "1.3.1", + "dev": true, + "engines": [ + "node >= 0.2.0" + ], + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/just-diff": { + "version": "5.2.0", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/just-diff-apply": { + "version": "5.5.0", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/libnpmaccess": { + "version": "7.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-package-arg": "^10.1.0", + "npm-registry-fetch": "^14.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/libnpmdiff": { + "version": "5.0.11", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/arborist": "^6.2.3", + "@npmcli/disparity-colors": "^3.0.0", + "@npmcli/installed-package-contents": "^2.0.0", + "binary-extensions": "^2.2.0", + "diff": "^5.1.0", + "minimatch": "^6.1.6", + "npm-package-arg": "^10.1.0", + "pacote": "^15.0.8", + "tar": "^6.1.13" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/libnpmexec": { + "version": "5.0.11", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/arborist": "^6.2.3", + "@npmcli/run-script": "^6.0.0", + "chalk": "^4.1.0", + "ci-info": "^3.7.1", + "npm-package-arg": "^10.1.0", + "npmlog": "^7.0.1", + "pacote": "^15.0.8", + "proc-log": "^3.0.0", + "read": "^2.0.0", + "read-package-json-fast": "^3.0.2", + "semver": "^7.3.7", + "walk-up-path": "^1.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/libnpmfund": { + "version": "4.0.11", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/arborist": "^6.2.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/libnpmhook": { + "version": "9.0.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "aproba": "^2.0.0", + "npm-registry-fetch": "^14.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/libnpmorg": { + "version": "5.0.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "aproba": "^2.0.0", + "npm-registry-fetch": "^14.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/libnpmpack": { + "version": "5.0.11", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/arborist": "^6.2.3", + "@npmcli/run-script": "^6.0.0", + "npm-package-arg": "^10.1.0", + "pacote": "^15.0.8" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/libnpmpublish": { + "version": "7.1.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "ci-info": "^3.6.1", + "normalize-package-data": "^5.0.0", + "npm-package-arg": "^10.1.0", + "npm-registry-fetch": "^14.0.3", + "semver": "^7.3.7", + "sigstore": "^1.0.0", + "ssri": "^10.0.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/libnpmsearch": { + "version": "6.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-registry-fetch": "^14.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/libnpmteam": { + "version": "5.0.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "aproba": "^2.0.0", + "npm-registry-fetch": "^14.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/libnpmversion": { + "version": "4.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/git": "^4.0.1", + "@npmcli/run-script": "^6.0.0", + "json-parse-even-better-errors": "^3.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.7" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/lru-cache": { + "version": "7.16.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/npm/node_modules/make-fetch-happen": { + "version": "11.0.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "agentkeepalive": "^4.2.1", + "cacache": "^17.0.0", + "http-cache-semantics": "^4.1.1", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.7.1", + "minipass": "^4.0.0", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^10.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/minimatch": { + "version": "6.2.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/minipass": { + "version": "4.0.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/minipass-collect": { + "version": "1.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/npm/node_modules/minipass-collect/node_modules/minipass": { + "version": "3.3.6", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/minipass-fetch": { + "version": "3.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "minipass": "^4.0.0", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/npm/node_modules/minipass-flush": { + "version": "1.0.5", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/npm/node_modules/minipass-flush/node_modules/minipass": { + "version": "3.3.6", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/minipass-json-stream": { + "version": "1.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "jsonparse": "^1.3.1", + "minipass": "^3.0.0" + } + }, + "node_modules/npm/node_modules/minipass-json-stream/node_modules/minipass": { + "version": "3.3.6", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/minipass-pipeline": { + "version": "1.2.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/minipass-pipeline/node_modules/minipass": { + "version": "3.3.6", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/minipass-sized": { + "version": "1.0.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/minipass-sized/node_modules/minipass": { + "version": "3.3.6", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/minizlib": { + "version": "2.1.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/npm/node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/mkdirp": { + "version": "1.0.4", + "dev": true, + "inBundle": true, + "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/ms": { + "version": "2.1.3", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/mute-stream": { + "version": "1.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/negotiator": { + "version": "0.6.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/npm/node_modules/node-gyp": { + "version": "9.3.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.0", + "glob": "^7.1.4", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^10.0.3", + "nopt": "^6.0.0", + "npmlog": "^6.0.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^2.0.2" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": "^12.13 || ^14.13 || >=16" + } + }, + "node_modules/npm/node_modules/node-gyp/node_modules/@npmcli/fs": { + "version": "2.1.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@gar/promisify": "^1.1.3", + "semver": "^7.3.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/npm/node_modules/node-gyp/node_modules/abbrev": { + "version": "1.1.1", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/node-gyp/node_modules/are-we-there-yet": { + "version": "3.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/npm/node_modules/node-gyp/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/npm/node_modules/node-gyp/node_modules/cacache": { + "version": "16.1.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/fs": "^2.1.0", + "@npmcli/move-file": "^2.0.0", + "chownr": "^2.0.0", + "fs-minipass": "^2.1.0", + "glob": "^8.0.1", + "infer-owner": "^1.0.4", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "mkdirp": "^1.0.4", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^9.0.0", + "tar": "^6.1.11", + "unique-filename": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/npm/node_modules/node-gyp/node_modules/cacache/node_modules/brace-expansion": { + "version": "2.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/npm/node_modules/node-gyp/node_modules/cacache/node_modules/glob": { + "version": "8.1.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/node-gyp/node_modules/cacache/node_modules/minimatch": { + "version": "5.1.6", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/node-gyp/node_modules/fs-minipass": { + "version": "2.1.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/npm/node_modules/node-gyp/node_modules/gauge": { + "version": "4.0.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.3", + "console-control-strings": "^1.1.0", + "has-unicode": "^2.0.1", + "signal-exit": "^3.0.7", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/npm/node_modules/node-gyp/node_modules/glob": { + "version": "7.2.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/node-gyp/node_modules/make-fetch-happen": { + "version": "10.2.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "agentkeepalive": "^4.2.1", + "cacache": "^16.1.0", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^2.0.3", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^9.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/npm/node_modules/node-gyp/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/npm/node_modules/node-gyp/node_modules/minipass": { + "version": "3.3.6", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/node-gyp/node_modules/minipass-fetch": { + "version": "2.1.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "minipass": "^3.1.6", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/npm/node_modules/node-gyp/node_modules/nopt": { + "version": "6.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "abbrev": "^1.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/npm/node_modules/node-gyp/node_modules/npmlog": { + "version": "6.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "are-we-there-yet": "^3.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^4.0.3", + "set-blocking": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/npm/node_modules/node-gyp/node_modules/readable-stream": { + "version": "3.6.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/npm/node_modules/node-gyp/node_modules/ssri": { + "version": "9.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.1.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/npm/node_modules/node-gyp/node_modules/unique-filename": { + "version": "2.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "unique-slug": "^3.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/npm/node_modules/node-gyp/node_modules/unique-slug": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/npm/node_modules/node-gyp/node_modules/which": { + "version": "2.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/npm/node_modules/nopt": { + "version": "7.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "abbrev": "^2.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/normalize-package-data": { + "version": "5.0.0", + "dev": true, + "inBundle": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^6.0.0", + "is-core-module": "^2.8.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/npm-audit-report": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/npm-bundled": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/npm-install-checks": { + "version": "6.0.0", + "dev": true, + "inBundle": true, + "license": "BSD-2-Clause", + "dependencies": { + "semver": "^7.1.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/npm-normalize-package-bin": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/npm-package-arg": { + "version": "10.1.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "hosted-git-info": "^6.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^5.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/npm-packlist": { + "version": "7.0.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "ignore-walk": "^6.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/npm-pick-manifest": { + "version": "8.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-install-checks": "^6.0.0", + "npm-normalize-package-bin": "^3.0.0", + "npm-package-arg": "^10.0.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/npm-profile": { + "version": "7.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-registry-fetch": "^14.0.0", + "proc-log": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/npm-registry-fetch": { + "version": "14.0.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "make-fetch-happen": "^11.0.0", + "minipass": "^4.0.0", + "minipass-fetch": "^3.0.0", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.1.2", + "npm-package-arg": "^10.0.0", + "proc-log": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/npm-user-validate": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "BSD-2-Clause", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/npmlog": { + "version": "7.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "are-we-there-yet": "^4.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^5.0.0", + "set-blocking": "^2.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/npm/node_modules/p-map": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm/node_modules/pacote": { + "version": "15.1.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/git": "^4.0.0", + "@npmcli/installed-package-contents": "^2.0.1", + "@npmcli/promise-spawn": "^6.0.1", + "@npmcli/run-script": "^6.0.0", + "cacache": "^17.0.0", + "fs-minipass": "^3.0.0", + "minipass": "^4.0.0", + "npm-package-arg": "^10.0.0", + "npm-packlist": "^7.0.0", + "npm-pick-manifest": "^8.0.0", + "npm-registry-fetch": "^14.0.0", + "proc-log": "^3.0.0", + "promise-retry": "^2.0.1", + "read-package-json": "^6.0.0", + "read-package-json-fast": "^3.0.0", + "sigstore": "^1.0.0", + "ssri": "^10.0.0", + "tar": "^6.1.11" + }, + "bin": { + "pacote": "lib/bin.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/parse-conflict-json": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "json-parse-even-better-errors": "^3.0.0", + "just-diff": "^5.0.1", + "just-diff-apply": "^5.2.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm/node_modules/postcss-selector-parser": { + "version": "6.0.11", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/proc-log": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/process": { + "version": "0.11.10", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/npm/node_modules/promise-all-reject-late": { + "version": "1.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/promise-call-limit": { + "version": "1.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/promise-inflight": { + "version": "1.0.1", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/promise-retry": { + "version": "2.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/promzard": { + "version": "1.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "read": "^2.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/qrcode-terminal": { + "version": "0.12.0", + "dev": true, + "inBundle": true, + "bin": { + "qrcode-terminal": "bin/qrcode-terminal.js" + } + }, + "node_modules/npm/node_modules/read": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "mute-stream": "~1.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/read-cmd-shim": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/read-package-json": { + "version": "6.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "glob": "^8.0.1", + "json-parse-even-better-errors": "^3.0.0", + "normalize-package-data": "^5.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/read-package-json-fast": { + "version": "3.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "json-parse-even-better-errors": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/readable-stream": { + "version": "4.3.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/npm/node_modules/retry": { + "version": "0.12.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/npm/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/rimraf/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/npm/node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/rimraf/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/npm/node_modules/safe-buffer": { + "version": "5.1.2", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/safer-buffer": { + "version": "2.1.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true + }, + "node_modules/npm/node_modules/semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/semver/node_modules/lru-cache": { + "version": "6.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/set-blocking": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/signal-exit": { + "version": "3.0.7", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/sigstore": { + "version": "1.0.0", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "make-fetch-happen": "^11.0.1", + "tuf-js": "^1.0.0" + }, + "bin": { + "sigstore": "bin/sigstore.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/smart-buffer": { + "version": "4.2.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/npm/node_modules/socks": { + "version": "2.7.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "ip": "^2.0.0", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.13.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/npm/node_modules/socks-proxy-agent": { + "version": "7.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/npm/node_modules/spdx-correct": { + "version": "3.1.1", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/npm/node_modules/spdx-exceptions": { + "version": "2.3.0", + "dev": true, + "inBundle": true, + "license": "CC-BY-3.0" + }, + "node_modules/npm/node_modules/spdx-expression-parse": { + "version": "3.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/npm/node_modules/spdx-license-ids": { + "version": "3.0.12", + "dev": true, + "inBundle": true, + "license": "CC0-1.0" + }, + "node_modules/npm/node_modules/ssri": { + "version": "10.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^4.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/string_decoder": { + "version": "1.1.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/npm/node_modules/string-width": { + "version": "4.2.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/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, + "inBundle": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/tar": { + "version": "6.1.13", + "dev": true, + "inBundle": true, + "license": "ISC", + "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/npm/node_modules/tar/node_modules/fs-minipass": { + "version": "2.1.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/npm/node_modules/tar/node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/text-table": { + "version": "0.2.0", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/tiny-relative-date": { + "version": "1.3.0", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/treeverse": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/tuf-js": { + "version": "1.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "make-fetch-happen": "^11.0.1", + "minimatch": "^6.1.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/unique-filename": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "unique-slug": "^4.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/unique-slug": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/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==", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/validate-npm-package-license": { + "version": "3.0.4", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/npm/node_modules/validate-npm-package-name": { + "version": "5.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "builtins": "^5.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/walk-up-path": { + "version": "1.0.0", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/wcwidth": { + "version": "1.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/npm/node_modules/which": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/wide-align": { + "version": "1.1.5", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "node_modules/npm/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==", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/write-file-atomic": { + "version": "5.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/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, + "inBundle": true, + "license": "ISC" + }, + "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", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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/object.assign": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.6.tgz", + "integrity": "sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.6.tgz", + "integrity": "sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.hasown": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.2.tgz", + "integrity": "sha512-B5UIT3J1W+WuWIU55h0mjlwaqxiE5vYENJXIXZ4VFe05pNYrkKuK0U/6aFcb0pKywYJh7IhfoqUfKVmrJJHZHw==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.values": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz", + "integrity": "sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "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==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/opts": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/opts/-/opts-2.0.2.tgz", + "integrity": "sha512-k41FwbcLnlgnFh69f4qdUfvDQ+5vaSDnVPFI/y5XuhKRq97EnVVneO9F1ESVCdiVu4fCS2L8usX3mU331hB7pg==", + "dev": true + }, + "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/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/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", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "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==", + "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/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "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==" + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "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/popmotion": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/popmotion/-/popmotion-11.0.5.tgz", + "integrity": "sha512-la8gPM1WYeFznb/JqF4GiTkRRPZsfaj2+kCxqQgr2MJylMmIKUwBfWW8Wa5fml/8gmtlD5yI01MP1QCZPWmppA==", + "dependencies": { + "framesync": "6.1.2", + "hey-listen": "^1.0.8", + "style-value-types": "5.1.2", + "tslib": "2.4.0" + } + }, + "node_modules/postcss": { + "version": "8.4.18", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.18.tgz", + "integrity": "sha512-Wi8mWhncLJm11GATDaQKobXSNEYGUHeQLiQqDFG1qQ5UTDPTEvKw0Xt5NsTpktGTwLps3ByrWsBrG0rB8YQ9oA==", + "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/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-selector-parser": { + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", + "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/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/promise-polyfill": { + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/promise-polyfill/-/promise-polyfill-8.2.3.tgz", + "integrity": "sha512-Og0+jCRQetV84U8wVjMNccfGCnMQ9mGs9Hv78QFe+pSDD3gWTpz0y+1QCuxy5d/vBFuZ3iwP2eycAkvqIMPmWg==" + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "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==", + "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/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true + }, + "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==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==", + "deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.", + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz", + "integrity": "sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==", + "dependencies": { + "bytes": "3.0.0", + "http-errors": "1.6.3", + "iconv-lite": "0.4.23", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/rc-util": { + "version": "5.27.2", + "resolved": "https://registry.npmjs.org/rc-util/-/rc-util-5.27.2.tgz", + "integrity": "sha512-8XHRbeJOWlTR2Hk1K2xLaPOf7lZu+3taskAGuqOPccA676vB3ygrz3ZgdrA3wml40CzR9RlIEHDWwI7FZT3wBQ==", + "dependencies": { + "@babel/runtime": "^7.18.3", + "react-is": "^16.12.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-util/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "node_modules/react": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-copy-to-clipboard": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/react-copy-to-clipboard/-/react-copy-to-clipboard-5.1.0.tgz", + "integrity": "sha512-k61RsNgAayIJNoy9yDsYzDe/yAZAzEbEgcz3DZMhF686LEyukcE1hzurxe85JandPUG+yTfGVFzuEw3xt8WP/A==", + "dependencies": { + "copy-to-clipboard": "^3.3.1", + "prop-types": "^15.8.1" + }, + "peerDependencies": { + "react": "^15.3.0 || 16 || 17 || 18" + } + }, + "node_modules/react-device-detect": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/react-device-detect/-/react-device-detect-2.2.2.tgz", + "integrity": "sha512-zSN1gIAztUekp5qUT/ybHwQ9fmOqVT1psxpSlTn1pe0CO+fnJHKRLOWWac5nKxOxvOpD/w84hk1I+EydrJp7SA==", + "dependencies": { + "ua-parser-js": "^1.0.2" + }, + "peerDependencies": { + "react": ">= 0.14.0", + "react-dom": ">= 0.14.0" + } + }, + "node_modules/react-dom": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", + "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.0" + }, + "peerDependencies": { + "react": "^18.2.0" + } + }, + "node_modules/react-hot-toast": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/react-hot-toast/-/react-hot-toast-2.4.0.tgz", + "integrity": "sha512-qnnVbXropKuwUpriVVosgo8QrB+IaPJCpL8oBI6Ov84uvHZ5QQcTp2qg6ku2wNfgJl6rlQXJIQU5q+5lmPOutA==", + "dependencies": { + "goober": "^2.1.10" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "react": ">=16", + "react-dom": ">=16" + } + }, + "node_modules/react-intl": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/react-intl/-/react-intl-6.2.1.tgz", + "integrity": "sha512-hYxcSamgoA3Mvc55nwhTF1v15T0NUSkaV/EScMNVZXg0kRyaMAoNHkCi9/9H+TnXWNiWrcWH9bjlMlJwrG2V7g==", + "dev": true, + "dependencies": { + "@formatjs/ecma402-abstract": "1.13.0", + "@formatjs/icu-messageformat-parser": "2.1.10", + "@formatjs/intl": "2.5.1", + "@formatjs/intl-displaynames": "6.1.4", + "@formatjs/intl-listformat": "7.1.3", + "@types/hoist-non-react-statics": "^3.3.1", + "@types/react": "16 || 17 || 18", + "hoist-non-react-statics": "^3.3.2", + "intl-messageformat": "10.2.1", + "tslib": "2.4.0" + }, + "peerDependencies": { + "react": "^16.6.0 || 17 || 18", + "typescript": "^4.7" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" + }, + "node_modules/react-router": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.4.2.tgz", + "integrity": "sha512-Rb0BAX9KHhVzT1OKhMvCDMw776aTYM0DtkxqUBP8dNBom3mPXlfNs76JNGK8wKJ1IZEY1+WGj+cvZxHVk/GiKw==", + "dependencies": { + "@remix-run/router": "1.0.2" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.4.2.tgz", + "integrity": "sha512-yM1kjoTkpfjgczPrcyWrp+OuQMyB1WleICiiGfstnQYo/S8hPEEnVjr/RdmlH6yKK4Tnj1UGXFSa7uwAtmDoLQ==", + "dependencies": { + "@remix-run/router": "1.0.2", + "react-router": "6.4.2" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, + "node_modules/react-table": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/react-table/-/react-table-7.8.0.tgz", + "integrity": "sha512-hNaz4ygkZO4bESeFfnfOft73iBUj8K5oKi1EcSHPAibEydfsX2MyU6Z8KCr3mv3C9Kqqh71U+DhZkFvibbnPbA==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^16.8.3 || ^17.0.0-0 || ^18.0.0" + } + }, + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/rechoir": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz", + "integrity": "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==", + "dev": true, + "dependencies": { + "resolve": "^1.9.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "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.10", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.10.tgz", + "integrity": "sha512-KepLsg4dU12hryUO7bp/axHAKvwGOCV0sGloQtpagJ12ai+ojVDqkeGSiRX1zlq+kjIMZ1t7gpze+26QqtdGqw==" + }, + "node_modules/regenerator-transform": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.0.tgz", + "integrity": "sha512-LsrGtPmbYg19bcPHwdtmXwbW+TqNvtY4riE3P83foeHRroMbH6/2ddFBfab3t7kbzc7v7p4wbkIecHImqt0QNg==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.8.4" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", + "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "functions-have-names": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/regexpu-core": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.2.1.tgz", + "integrity": "sha512-HrnlNtpvqP1Xkb28tMhBUO2EbyUHdQlsnlAhzWcwHy8WJR53UWr7/MAvqrsQKMbV4qdpv03oTMG8iIhfsPFktQ==", + "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.0.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/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/resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dependencies": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-cwd/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/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "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==" + }, + "node_modules/safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "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/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/send": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", + "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", + "dependencies": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.6.2", + "mime": "1.4.1", + "ms": "2.0.0", + "on-finished": "~2.3.0", + "range-parser": "~1.2.0", + "statuses": "~1.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-static": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", + "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.2", + "send": "0.16.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" + }, + "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/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/simple-update-notifier": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.0.7.tgz", + "integrity": "sha512-BBKgR84BJQJm6WjWFMHgLVuo61FBDSj1z/xSFUIozqO6wO7ii0JxCqlIud7Enr/+LhlbNI0whErq96P2qHNWew==", + "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/simplebar": { + "version": "5.3.9", + "resolved": "https://registry.npmjs.org/simplebar/-/simplebar-5.3.9.tgz", + "integrity": "sha512-1vIIpjDvY9sVH14e0LGeiCiTFU3ILqAghzO6OI9axeG+mvU/vMSrvXeAXkBolqFFz3XYaY8n5ahH9MeP3sp2Ag==", + "dependencies": { + "@juggle/resize-observer": "^3.3.1", + "can-use-dom": "^0.1.0", + "core-js": "^3.0.1", + "lodash.debounce": "^4.0.8", + "lodash.memoize": "^4.1.2", + "lodash.throttle": "^4.1.1" + } + }, + "node_modules/simplebar-react": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/simplebar-react/-/simplebar-react-2.4.3.tgz", + "integrity": "sha512-Ep8gqAUZAS5IC2lT5RE4t1ZFUIVACqbrSRQvFV9a6NbVUzXzOMnc4P82Hl8Ak77AnPQvmgUwZS7aUKLyBoMAcg==", + "dependencies": { + "prop-types": "^15.6.1", + "simplebar": "^5.3.9" + }, + "peerDependencies": { + "react": "^0.14.9 || ^15.3.0 || ^16.0.0-rc || ^16.0 || ^17.0 || ^18.0.0", + "react-dom": "^0.14.9 || ^15.3.0 || ^16.0.0-rc || ^16.0 || ^17.0 || ^18.0.0" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "dev": true, + "engines": { + "node": ">=0.10.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/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/statuses": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", + "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/string.prototype.matchall": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.8.tgz", + "integrity": "sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "get-intrinsic": "^1.1.3", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.3", + "regexp.prototype.flags": "^1.4.3", + "side-channel": "^1.0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", + "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", + "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "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" + }, + "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", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "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-value-types": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/style-value-types/-/style-value-types-5.1.2.tgz", + "integrity": "sha512-Vs9fNreYF9j6W2VvuDTP7kepALi7sk0xtk2Tu8Yxi9UoajJdEVpNpCov0HsLTqXvNGKX+Uv09pkozVITi1jf3Q==", + "dependencies": { + "hey-listen": "^1.0.8", + "tslib": "2.4.0" + } + }, + "node_modules/stylis": { + "version": "4.0.13", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.0.13.tgz", + "integrity": "sha512-xGPXiFVl4YED9Jh7Euv2V220mriG9u4B2TA6Ybjc1catrstKD2PpIdU3U0RKpkVBC2EhmL/F0sPCr9vrFTNRag==" + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/terser": { + "version": "5.15.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.15.1.tgz", + "integrity": "sha512-K1faMUvpm/FBxjBXud0LWVAGxmvoPbZbfTCYbSgaaYQaIXI3/TdI7a7ZGA73Zrou6Q8Zmz3oeUTsp/dj+ag2Xw==", + "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/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/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/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/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==", + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toggle-selection": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz", + "integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==" + }, + "node_modules/touch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", + "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "dev": true, + "dependencies": { + "nopt": "~1.0.10" + }, + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/ts-loader": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.4.1.tgz", + "integrity": "sha512-384TYAqGs70rn9F0VBnh6BPTfhga7yFNdC5gXbQpDrBj9/KsT4iRkGqKXhziofHOlE2j6YEaiTYVGKKvPhGWvw==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "enhanced-resolve": "^5.0.0", + "micromatch": "^4.0.0", + "semver": "^7.3.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "typescript": "*", + "webpack": "^5.0.0" + } + }, + "node_modules/ts-loader/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/ts-loader/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "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/ts-loader/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/ts-loader/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/ts-loader/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/ts-loader/node_modules/semver": { + "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" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ts-loader/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + }, + "node_modules/tss-react": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/tss-react/-/tss-react-4.4.2.tgz", + "integrity": "sha512-typ6yVmBGz1GIHmWaN+bmwHaAfxZLImfiNTiGIfJCFgas3rEpdYSty2/JENXAFvzKFl53CHc/6Z/FM2EkE2ZTQ==", + "dependencies": { + "@emotion/cache": "*", + "@emotion/serialize": "*", + "@emotion/utils": "*" + }, + "peerDependencies": { + "@emotion/react": "^11.4.1", + "@emotion/server": "^11.4.0", + "react": "^16.8.0 || ^17.0.2 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/server": { + "optional": true + } + } + }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, + "node_modules/tsutils/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", + "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "is-typed-array": "^1.1.9" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typescript": { + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", + "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/ua-parser-js": { + "version": "1.0.32", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.32.tgz", + "integrity": "sha512-dXVsz3M4j+5tTiovFVyVqssXBu5HM47//YSOeZ9fQkdDKkfzv2v3PP1jmH6FUyPW+yCSn7aBVK1fGGKNhowdDA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/ua-parser-js" + }, + { + "type": "paypal", + "url": "https://paypal.me/faisalman" + } + ], + "engines": { + "node": "*" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true + }, + "node_modules/unfetch": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/unfetch/-/unfetch-4.2.0.tgz", + "integrity": "sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA==" + }, + "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.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz", + "integrity": "sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw==", + "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/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", + "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "browserslist-lint": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "integrity": "sha512-kbailJa29QrtXnxgq+DdCEGlbTeYM2eJUxsz6vjZavrCYPMIFHMKQmSKYAIuUK2i7hgPm28a8piX5NTUtM/LKQ==", + "dependencies": { + "punycode": "1.3.2", + "querystring": "0.2.0" + } + }, + "node_modules/url/node_modules/punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==" + }, + "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==", + "dev": true + }, + "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==", + "engines": { + "node": ">= 0.4.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==", + "engines": { + "node": ">= 0.8" + } + }, + "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/web-streams-polyfill": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", + "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/webpack": { + "version": "5.74.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.74.0.tgz", + "integrity": "sha512-A2InDwnhhGN4LYctJj6M1JEaGL7Luj6LOmyBHjcI8529cm5p6VXiTIW2sn6ffvEAKmveLzvu4jrihwXtPojlAA==", + "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-cli": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.10.0.tgz", + "integrity": "sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w==", + "dev": true, + "dependencies": { + "@discoveryjs/json-ext": "^0.5.0", + "@webpack-cli/configtest": "^1.2.0", + "@webpack-cli/info": "^1.5.0", + "@webpack-cli/serve": "^1.7.0", + "colorette": "^2.0.14", + "commander": "^7.0.0", + "cross-spawn": "^7.0.3", + "fastest-levenshtein": "^1.0.12", + "import-local": "^3.0.2", + "interpret": "^2.2.0", + "rechoir": "^0.7.0", + "webpack-merge": "^5.7.3" + }, + "bin": { + "webpack-cli": "bin/cli.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "4.x.x || 5.x.x" + }, + "peerDependenciesMeta": { + "@webpack-cli/generators": { + "optional": true + }, + "@webpack-cli/migrate": { + "optional": true + }, + "webpack-bundle-analyzer": { + "optional": true + }, + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/webpack-cli/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/webpack-merge": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz", + "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==", + "dev": true, + "dependencies": { + "clone-deep": "^4.0.1", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.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/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/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "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/wildcard": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", + "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==", + "dev": true + }, + "node_modules/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, + "engines": { + "node": ">=0.10.0" + } + }, + "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==", + "dev": true + }, + "node_modules/ws": { + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "dev": true, + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/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/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + }, + "dependencies": { + "@ampproject/remapping": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", + "requires": { + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@ant-design/colors": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@ant-design/colors/-/colors-6.0.0.tgz", + "integrity": "sha512-qAZRvPzfdWHtfameEGP2Qvuf838NhergR35o+EuVyB5XvSA98xod5r4utvi4TJ3ywmevm290g9nsCG5MryrdWQ==", + "requires": { + "@ctrl/tinycolor": "^3.4.0" + } + }, + "@ant-design/icons": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@ant-design/icons/-/icons-5.0.1.tgz", + "integrity": "sha512-ZyF4ksXCcdtwA/1PLlnFLcF/q8/MhwxXhKHh4oCHDA4Ip+ZzAHoICtyp4wZWfiCVDP0yuz3HsjyvuldHFb3wjA==", + "requires": { + "@ant-design/colors": "^7.0.0", + "@ant-design/icons-svg": "^4.2.1", + "@babel/runtime": "^7.11.2", + "classnames": "^2.2.6", + "rc-util": "^5.9.4" + }, + "dependencies": { + "@ant-design/colors": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@ant-design/colors/-/colors-7.0.0.tgz", + "integrity": "sha512-iVm/9PfGCbC0dSMBrz7oiEXZaaGH7ceU40OJEfKmyuzR9R5CRimJYPlRiFtMQGQcbNMea/ePcoIebi4ASGYXtg==", + "requires": { + "@ctrl/tinycolor": "^3.4.0" + } + } + } + }, + "@ant-design/icons-svg": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@ant-design/icons-svg/-/icons-svg-4.2.1.tgz", + "integrity": "sha512-EB0iwlKDGpG93hW8f85CTJTs4SvMX7tt5ceupvhALp1IF44SeUFOMhKUOYqpsoYWQKAOuTRDMqn75rEaKDp0Xw==" + }, + "@auth0/auth0-react": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/@auth0/auth0-react/-/auth0-react-1.12.0.tgz", + "integrity": "sha512-Cny2RyHvr0GrKKKV8PMh6GU0vkWNSgd6mp/YHYJynnYCs9yFduNo9hdpHPxXbdDX5CB6wc2PqK6aL8leDlnl/A==", + "requires": { + "@auth0/auth0-spa-js": "^1.22.4" + } + }, + "@auth0/auth0-spa-js": { + "version": "1.22.5", + "resolved": "https://registry.npmjs.org/@auth0/auth0-spa-js/-/auth0-spa-js-1.22.5.tgz", + "integrity": "sha512-6gaQcd+Eb8ZBcdQkrrm9undM7dY/rPvVdQN8s7rxxrviUCs7OopEygsfSkHf67IP4HtlCiE8dSW5/AipRUOw/A==", + "requires": { + "abortcontroller-polyfill": "^1.7.3", + "browser-tabs-lock": "^1.2.15", + "core-js": "^3.25.1", + "es-cookie": "~1.3.2", + "fast-text-encoding": "^1.0.6", + "promise-polyfill": "^8.2.3", + "unfetch": "^4.2.0" + } + }, + "@babel/code-frame": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "requires": { + "@babel/highlight": "^7.18.6" + } + }, + "@babel/compat-data": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.19.4.tgz", + "integrity": "sha512-CHIGpJcUQ5lU9KrPHTjBMhVwQG6CQjxfg36fGXl3qk/Gik1WwWachaXFuo0uCWJT/mStOKtcbFJCaVLihC1CMw==" + }, + "@babel/core": { + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.6.tgz", + "integrity": "sha512-D2Ue4KHpc6Ys2+AxpIx1BZ8+UegLLLE2p3KJEuJRKmokHOtl49jQ5ny1773KsGLZs8MQvBidAF6yWUJxRqtKtg==", + "requires": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.19.6", + "@babel/helper-compilation-targets": "^7.19.3", + "@babel/helper-module-transforms": "^7.19.6", + "@babel/helpers": "^7.19.4", + "@babel/parser": "^7.19.6", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.6", + "@babel/types": "^7.19.4", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.1", + "semver": "^6.3.0" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "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==" + } + } + }, + "@babel/generator": { + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.6.tgz", + "integrity": "sha512-oHGRUQeoX1QrKeJIKVe0hwjGqNnVYsM5Nep5zo0uE0m42sLH+Fsd2pStJ5sRM1bNyTUUoz0pe2lTeMJrb/taTA==", + "requires": { + "@babel/types": "^7.19.4", + "@jridgewell/gen-mapping": "^0.3.2", + "jsesc": "^2.5.1" + }, + "dependencies": { + "@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + } + } + }, + "@babel/helper-annotate-as-pure": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz", + "integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==", + "dev": true, + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@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/helper-explode-assignable-expression": "^7.18.6", + "@babel/types": "^7.18.9" + } + }, + "@babel/helper-compilation-targets": { + "version": "7.19.3", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.19.3.tgz", + "integrity": "sha512-65ESqLGyGmLvgR0mst5AdW1FkNlj9rQsCKduzEoEPhBCDFGXvz2jW6bXFG6i0/MrV2s7hhXjjb2yAzcPuQlLwg==", + "requires": { + "@babel/compat-data": "^7.19.3", + "@babel/helper-validator-option": "^7.18.6", + "browserslist": "^4.21.3", + "semver": "^6.3.0" + } + }, + "@babel/helper-create-class-features-plugin": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.19.0.tgz", + "integrity": "sha512-NRz8DwF4jT3UfrmUoZjd0Uph9HQnP30t7Ash+weACcyNkiYTywpIjDBgReJMKgr+n86sn2nPVVmJ28Dm053Kqw==", + "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.18.9", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/helper-replace-supers": "^7.18.9", + "@babel/helper-split-export-declaration": "^7.18.6" + } + }, + "@babel/helper-create-regexp-features-plugin": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.19.0.tgz", + "integrity": "sha512-htnV+mHX32DF81amCDrwIDr8nrp1PTm+3wfBN9/v8QJOLEioOCOG7qNyq0nHeFiWbT3Eb7gsPwEmV64UCQ1jzw==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "regexpu-core": "^5.1.0" + } + }, + "@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 + } + } + }, + "@babel/helper-environment-visitor": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", + "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==" + }, + "@babel/helper-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", + "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", + "requires": { + "@babel/template": "^7.18.10", + "@babel/types": "^7.19.0" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", + "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.18.9.tgz", + "integrity": "sha512-RxifAh2ZoVU67PyKIO4AMi1wTenGfMR/O/ae0CCRqwgBAt5v7xjdtRw7UoSbsreKrQn5t7r89eruK/9JjYHuDg==", + "dev": true, + "requires": { + "@babel/types": "^7.18.9" + } + }, + "@babel/helper-module-imports": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", + "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-module-transforms": { + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.19.6.tgz", + "integrity": "sha512-fCmcfQo/KYr/VXXDIyd3CBGZ6AFhPFy1TfSEJ+PilGVlQT6jcbqtHAM4C1EciRqMza7/TpOUZliuSH+U6HAhJw==", + "requires": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-simple-access": "^7.19.4", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/helper-validator-identifier": "^7.19.1", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.6", + "@babel/types": "^7.19.4" + } + }, + "@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==" + }, + "@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.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.19.1.tgz", + "integrity": "sha512-T7ahH7wV0Hfs46SFh5Jz3s0B6+o8g3c+7TMxu7xKfmHikg7EAZ3I2Qk9LFhjxXq8sL7UkP5JflezNwoZa8WvWw==", + "dev": true, + "requires": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-member-expression-to-functions": "^7.18.9", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/traverse": "^7.19.1", + "@babel/types": "^7.19.0" + } + }, + "@babel/helper-simple-access": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.19.4.tgz", + "integrity": "sha512-f9Xq6WqBFqaDfbCzn2w85hwklswz5qsKlh7f08w4Y9yhJHpnNC0QemtSkK5YyOY8kPGvyiwdzZksGUhnGdaUIg==", + "requires": { + "@babel/types": "^7.19.4" + } + }, + "@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.18.9.tgz", + "integrity": "sha512-imytd2gHi3cJPsybLRbmFrF7u5BIEuI2cNheyKi3/iOBC63kNn3q8Crn2xVuESli0aM4KYsyEqKyS7lFL8YVtw==", + "dev": true, + "requires": { + "@babel/types": "^7.18.9" + } + }, + "@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", + "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-string-parser": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", + "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==" + }, + "@babel/helper-validator-identifier": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==" + }, + "@babel/helper-validator-option": { + "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==" + }, + "@babel/helper-wrap-function": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.19.0.tgz", + "integrity": "sha512-txX8aN8CZyYGTwcLhlk87KRqncAzhh5TpQamZUa0/u3an36NtDpUP6bQgBCBcLeBs09R/OwQu3OjK0k/HwfNDg==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.19.0", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.0", + "@babel/types": "^7.19.0" + } + }, + "@babel/helpers": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.19.4.tgz", + "integrity": "sha512-G+z3aOx2nfDHwX/kyVii5fJq+bgscg89/dJNWpYeKeBv3v9xX8EIabmx1k6u9LS04H7nROFVRVK+e3k0VHp+sw==", + "requires": { + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.4", + "@babel/types": "^7.19.4" + } + }, + "@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "requires": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.6.tgz", + "integrity": "sha512-h1IUp81s2JYJ3mRkdxJgs4UvmSsRvDrx5ICSJbPvtWYv5i1nTBGcBpnog+89rAFMwvvru6E5NUHdBe01UeSzYA==" + }, + "@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.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.18.9.tgz", + "integrity": "sha512-AHrP9jadvH7qlOj6PINbgSuphjQUAK7AOT7DPjBo9EHoLhQTnnK5u45e1Hd4DbSQEO9nqPWtQ89r+XEOWFScKg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9", + "@babel/plugin-proposal-optional-chaining": "^7.18.9" + } + }, + "@babel/plugin-proposal-async-generator-functions": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.19.1.tgz", + "integrity": "sha512-0yu8vNATgLy4ivqMNBIwb1HebCelqN7YX8SL3FDXORv/RqT0zEEWUCH4GH44JsSrvCu6GqnAdR5EBFAPeNBB4Q==", + "dev": true, + "requires": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-plugin-utils": "^7.19.0", + "@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.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.18.6.tgz", + "integrity": "sha512-+I3oIiNxrCpup3Gi8n5IGMwj0gOCAjcJUSQEcotNnCCPMEnixawOQ+KeJPlgfjzx+FKQ1QSyZOWe7wmoJp7vhw==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@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.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.18.9.tgz", + "integrity": "sha512-128YbMpjCrP35IOExw2Fq+x55LMP42DzhOhX2aNNIdI9avSWl2PI0yuBWarr3RYpZBSPtabfadkH2yeRiMD61Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9", + "@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.19.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.19.4.tgz", + "integrity": "sha512-wHmj6LDxVDnL+3WhXteUBaoM1aVILZODAUjg11kHqG4cOlfgMQGxw6aCgvrXrmaJR3Bn14oZhImyCPZzRpC93Q==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.19.4", + "@babel/helper-compilation-targets": "^7.19.3", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.18.8" + } + }, + "@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.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.18.9.tgz", + "integrity": "sha512-v5nwt4IqBXihxGsW2QmCWMDS3B3bzGIk/EQVZz2ei7f3NJl8NzAJVvUmpDW5q1CRNY+Beb/k58UAH1Km1N411w==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9", + "@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.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.18.6.tgz", + "integrity": "sha512-9Rysx7FOctvT5ouj5JODjAFAkgGoudQuLPamZb0v1TGLpapdNaftzifU8NTWQm0IRjqoYypdrSmyWgkocDQ8Dw==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@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-import-assertions": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.18.6.tgz", + "integrity": "sha512-/DU3RXad9+bZwrgWJQKbr39gYbJpLJHezqEzRzi/BHRlJ9zsQb4CK2CA/5apllXNomwA1qHwzvHl+AdEmC5krQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@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", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz", + "integrity": "sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==", + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "requires": { + "@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.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.18.6.tgz", + "integrity": "sha512-9S9X9RUefzrsHZmKMbDXxweEH+YlE8JJEuat9FdvW9Qh1cw7W64jELCtWNkPBPX5En45uy28KGvA/AySqUh8CQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-async-to-generator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.18.6.tgz", + "integrity": "sha512-ARE5wZLKnTgPW7/1ftQmSi1CmkqqHo2DNmtztFhvgtOWSDfq0Cq9/9L+KnZNYSNrydBekhW3rwShduf59RoXag==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-remap-async-to-generator": "^7.18.6" + } + }, + "@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.19.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.19.4.tgz", + "integrity": "sha512-934S2VLLlt2hRJwPf4MczaOr4hYF0z+VKPwqTNxyKX7NthTiPfhuKFWQZHXRM0vh/wo/VyXB3s4bZUNA08l+tQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.19.0" + } + }, + "@babel/plugin-transform-classes": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.19.0.tgz", + "integrity": "sha512-YfeEE9kCjqTS9IitkgfJuxjcEtLUHMqa8yUJ6zdz8vR7hKuo6mOy2C05P0F1tdMmDCeuyidKnlrw/iTppHcr2A==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-compilation-targets": "^7.19.0", + "@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.19.0", + "@babel/helper-replace-supers": "^7.18.9", + "@babel/helper-split-export-declaration": "^7.18.6", + "globals": "^11.1.0" + } + }, + "@babel/plugin-transform-computed-properties": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.18.9.tgz", + "integrity": "sha512-+i0ZU1bCDymKakLxn5srGHrsAPRELC2WIbzwjLhHW9SIE1cPYkLCL0NlnXMZaM1vhfgA2+M7hySk42VBvrkBRw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9" + } + }, + "@babel/plugin-transform-destructuring": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.19.4.tgz", + "integrity": "sha512-t0j0Hgidqf0aM86dF8U+vXYReUgJnlv4bZLsyoPnwZNrGY+7/38o8YjaELrvHeVfTZao15kjR0PVv0nju2iduA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.19.0" + } + }, + "@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-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.19.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.19.6.tgz", + "integrity": "sha512-uG3od2mXvAtIFQIh0xrpLH6r5fpSQN04gIVovl+ODLdUMANokxQLZnPBHcjmv3GxRjnqwLuHvppjjcelqUFZvg==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.19.6", + "@babel/helper-plugin-utils": "^7.19.0" + } + }, + "@babel/plugin-transform-modules-commonjs": { + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.19.6.tgz", + "integrity": "sha512-8PIa1ym4XRTKuSsOUXqDG0YaOlEuTVvHMe5JCfgBMOtHvJKw/4NGovEGN33viISshG/rZNVrACiBmPQLvWN8xQ==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.19.6", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-simple-access": "^7.19.4" + } + }, + "@babel/plugin-transform-modules-systemjs": { + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.19.6.tgz", + "integrity": "sha512-fqGLBepcc3kErfR9R3DnVpURmckXP7gj7bAlrTQyBxrigFqszZCkFkcoxzCp2v32XmwXLvbw+8Yq9/b+QqksjQ==", + "dev": true, + "requires": { + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-module-transforms": "^7.19.6", + "@babel/helper-plugin-utils": "^7.19.0", + "@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.19.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.19.1.tgz", + "integrity": "sha512-oWk9l9WItWBQYS4FgXD4Uyy5kq898lvkXpXQxoJEY1RnvPk4R/Dvu2ebXU9q8lP+rlMwUQTFf2Ok6d78ODa0kw==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.19.0", + "@babel/helper-plugin-utils": "^7.19.0" + } + }, + "@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.18.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.18.8.tgz", + "integrity": "sha512-ivfbE3X2Ss+Fj8nnXvKJS6sjRG4gzwPMsP+taZC+ZzEGjAYlvENixmt1sZ5Ca6tWls+BlKSGKPJ6OOXvXCbkFg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@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.19.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.19.0.tgz", + "integrity": "sha512-UVEvX3tXie3Szm3emi1+G63jyw1w5IcMY0FSKM+CRnKRI5Mr1YbCNgsSTwoTwKphQEG9P+QqmuRFneJPZuHNhg==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/plugin-syntax-jsx": "^7.18.6", + "@babel/types": "^7.19.0" + } + }, + "@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.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.18.6.tgz", + "integrity": "sha512-poqRI2+qiSdeldcz4wTSTXBRryoq3Gc70ye7m7UD5Ww0nE29IXqMl6r7Nd15WBgRd74vloEMlShtH6CKxVzfmQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "regenerator-transform": "^0.15.0" + } + }, + "@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-runtime": { + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.19.6.tgz", + "integrity": "sha512-PRH37lz4JU156lYFW1p8OxE5i7d6Sl/zV58ooyr+q1J1lnQPyg5tIiXlIwNVhJaY4W3TmOtdc8jqdXQcB1v5Yw==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.19.0", + "babel-plugin-polyfill-corejs2": "^0.3.3", + "babel-plugin-polyfill-corejs3": "^0.6.0", + "babel-plugin-polyfill-regenerator": "^0.4.1", + "semver": "^6.3.0" + } + }, + "@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.19.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.19.0.tgz", + "integrity": "sha512-RsuMk7j6n+r752EtzyScnWkQyuJdli6LdO5Klv8Yx0OfPVTcQkIUfS8clx5e9yHXzlnhOZF3CbQ8C2uP5j074w==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9" + } + }, + "@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.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.20.0.tgz", + "integrity": "sha512-xOAsAFaun3t9hCwZ13Qe7gq423UgMZ6zAgmLxeGGapFqlT/X3L5qT2btjiVLlFn7gWtMaVyceS5VxGAuKbgizw==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.19.0", + "@babel/helper-plugin-utils": "^7.19.0", + "@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.19.4", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.19.4.tgz", + "integrity": "sha512-5QVOTXUdqTCjQuh2GGtdd7YEhoRXBMVGROAtsBeLGIbIz3obCBIfRMT1I3ZKkMgNzwkyCkftDXSSkHxnfVf4qg==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.19.4", + "@babel/helper-compilation-targets": "^7.19.3", + "@babel/helper-plugin-utils": "^7.19.0", + "@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.19.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.19.4", + "@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.18.6", + "@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.19.4", + "@babel/plugin-transform-classes": "^7.19.0", + "@babel/plugin-transform-computed-properties": "^7.18.9", + "@babel/plugin-transform-destructuring": "^7.19.4", + "@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.18.6", + "@babel/plugin-transform-modules-commonjs": "^7.18.6", + "@babel/plugin-transform-modules-systemjs": "^7.19.0", + "@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.18.8", + "@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.19.4", + "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" + } + }, + "@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/runtime": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.19.4.tgz", + "integrity": "sha512-EXpLCrk55f+cYqmHsSR+yD/0gAIMxxA9QK9lnQWzhMCvt+YmoBN7Zx94s++Kv0+unHk39vxNO8t+CMA2WSS3wA==", + "requires": { + "regenerator-runtime": "^0.13.4" + } + }, + "@babel/template": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", + "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", + "requires": { + "@babel/code-frame": "^7.18.6", + "@babel/parser": "^7.18.10", + "@babel/types": "^7.18.10" + } + }, + "@babel/traverse": { + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.19.6.tgz", + "integrity": "sha512-6l5HrUCzFM04mfbG09AagtYyR2P0B71B1wN7PfSPiksDPz2k5H9CBC1tcZpz2M8OxbKTPccByoOJ22rUKbpmQQ==", + "requires": { + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.19.6", + "@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.19.6", + "@babel/types": "^7.19.4", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "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==" + } + } + }, + "@babel/types": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.4.tgz", + "integrity": "sha512-M5LK7nAeS6+9j7hAq+b3fQs+pNfUtTGq+yFFfHnauFA8zQtLRfmuipmsKDKKLuyG+wC8ABW43A153YNawNTEtw==", + "requires": { + "@babel/helper-string-parser": "^7.19.4", + "@babel/helper-validator-identifier": "^7.19.1", + "to-fast-properties": "^2.0.0" + } + }, + "@ctrl/tinycolor": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.4.1.tgz", + "integrity": "sha512-ej5oVy6lykXsvieQtqZxCOaLT+xD4+QNarq78cIYISHmZXshCvROLudpQN3lfL8G0NL7plMSSK+zlyvCaIJ4Iw==" + }, + "@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", + "integrity": "sha512-xNQ57njWTFVfPAc3cjfuaPdsgLp5QOSuRsj9MA6ndEhH/AzuZM86qIQzt6rq+aGBwj3n5/TkLmU5lhAfdRmogA==", + "requires": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/plugin-syntax-jsx": "^7.17.12", + "@babel/runtime": "^7.18.3", + "@emotion/hash": "^0.9.0", + "@emotion/memoize": "^0.8.0", + "@emotion/serialize": "^1.1.0", + "babel-plugin-macros": "^3.1.0", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^4.0.0", + "find-root": "^1.1.0", + "source-map": "^0.5.7", + "stylis": "4.0.13" + } + }, + "@emotion/cache": { + "version": "11.10.3", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.10.3.tgz", + "integrity": "sha512-Psmp/7ovAa8appWh3g51goxu/z3iVms7JXOreq136D8Bbn6dYraPnmL6mdM8GThEx9vwSn92Fz+mGSjBzN8UPQ==", + "requires": { + "@emotion/memoize": "^0.8.0", + "@emotion/sheet": "^1.2.0", + "@emotion/utils": "^1.2.0", + "@emotion/weak-memoize": "^0.3.0", + "stylis": "4.0.13" + } + }, + "@emotion/hash": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.0.tgz", + "integrity": "sha512-14FtKiHhy2QoPIzdTcvh//8OyBlknNs2nXRwIhG904opCby3l+9Xaf/wuPvICBF0rc1ZCNBd3nKe9cd2mecVkQ==" + }, + "@emotion/is-prop-valid": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.0.tgz", + "integrity": "sha512-3aDpDprjM0AwaxGE09bOPkNxHpBd+kA6jty3RnaEXdweX1DF1U3VQpPYb0g1IStAuK7SVQ1cy+bNBBKp4W3Fjg==", + "requires": { + "@emotion/memoize": "^0.8.0" + } + }, + "@emotion/memoize": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.0.tgz", + "integrity": "sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA==" + }, + "@emotion/react": { + "version": "11.10.4", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.10.4.tgz", + "integrity": "sha512-j0AkMpr6BL8gldJZ6XQsQ8DnS9TxEQu1R+OGmDZiWjBAJtCcbt0tS3I/YffoqHXxH6MjgI7KdMbYKw3MEiU9eA==", + "requires": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.10.0", + "@emotion/cache": "^11.10.0", + "@emotion/serialize": "^1.1.0", + "@emotion/use-insertion-effect-with-fallbacks": "^1.0.0", + "@emotion/utils": "^1.2.0", + "@emotion/weak-memoize": "^0.3.0", + "hoist-non-react-statics": "^3.3.1" + } + }, + "@emotion/serialize": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.0.tgz", + "integrity": "sha512-F1ZZZW51T/fx+wKbVlwsfchr5q97iW8brAnXmsskz4d0hVB4O3M/SiA3SaeH06x02lSNzkkQv+n3AX3kCXKSFA==", + "requires": { + "@emotion/hash": "^0.9.0", + "@emotion/memoize": "^0.8.0", + "@emotion/unitless": "^0.8.0", + "@emotion/utils": "^1.2.0", + "csstype": "^3.0.2" + } + }, + "@emotion/sheet": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.0.tgz", + "integrity": "sha512-OiTkRgpxescko+M51tZsMq7Puu/KP55wMT8BgpcXVG2hqXc0Vo0mfymJ/Uj24Hp0i083ji/o0aLddh08UEjq8w==" + }, + "@emotion/styled": { + "version": "11.10.4", + "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.10.4.tgz", + "integrity": "sha512-pRl4R8Ez3UXvOPfc2bzIoV8u9P97UedgHS4FPX594ntwEuAMA114wlaHvOK24HB48uqfXiGlYIZYCxVJ1R1ttQ==", + "requires": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.10.0", + "@emotion/is-prop-valid": "^1.2.0", + "@emotion/serialize": "^1.1.0", + "@emotion/use-insertion-effect-with-fallbacks": "^1.0.0", + "@emotion/utils": "^1.2.0" + } + }, + "@emotion/unitless": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.0.tgz", + "integrity": "sha512-VINS5vEYAscRl2ZUDiT3uMPlrFQupiKgHz5AA4bCH1miKBg4qtwkim1qPmJj/4WG6TreYMY111rEFsjupcOKHw==" + }, + "@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==", + "requires": {} + }, + "@emotion/utils": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.0.tgz", + "integrity": "sha512-sn3WH53Kzpw8oQ5mgMmIzzyAaH2ZqFEbozVVBSYp538E06OSE6ytOp7pRAjNQR+Q/orwqdQYJSe2m3hCOeznkw==" + }, + "@emotion/weak-memoize": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.0.tgz", + "integrity": "sha512-AHPmaAx+RYfZz0eYu6Gviiagpmiyw98ySSlQvCUhVGDRtDFe4DBS0x1bSjdF3gqUDYOczB+yYvBTtEylYSdRhg==" + }, + "@eslint/eslintrc": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.3.tgz", + "integrity": "sha512-uj3pT6Mg+3t39fvLrj8iuCIJ38zKO9FpGtJ4BBJebJhEwjoT+KLVNCcHT5QC9NGRIEi7fZ0ZR8YRb884auB4Lg==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.4.0", + "globals": "^13.15.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "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" + } + }, + "globals": { + "version": "13.17.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz", + "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==", + "dev": true, + "requires": { + "type-fest": "^0.20.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 + } + } + }, + "@formatjs/ecma402-abstract": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-1.13.0.tgz", + "integrity": "sha512-CQ8Ykd51jYD1n05dtoX6ns6B9n/+6ZAxnWUAonvHC4kkuAemROYBhHkEB4tm1uVrRlE7gLDqXkAnY51Y0pRCWQ==", + "dev": true, + "requires": { + "@formatjs/intl-localematcher": "0.2.31", + "tslib": "2.4.0" + } + }, + "@formatjs/fast-memoize": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@formatjs/fast-memoize/-/fast-memoize-1.2.6.tgz", + "integrity": "sha512-9CWZ3+wCkClKHX+i5j+NyoBVqGf0pIskTo6Xl6ihGokYM2yqSSS68JIgeo+99UIHc+7vi9L3/SDSz/dWI9SNlA==", + "dev": true, + "requires": { + "tslib": "2.4.0" + } + }, + "@formatjs/icu-messageformat-parser": { + "version": "2.1.10", + "resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.1.10.tgz", + "integrity": "sha512-KkRMxhifWkRC45dhM9tqm0GXbb6NPYTGVYY3xx891IKc6p++DQrZTnmkVSNNO47OEERLfuP2KkPFPJBuu8z/wg==", + "dev": true, + "requires": { + "@formatjs/ecma402-abstract": "1.13.0", + "@formatjs/icu-skeleton-parser": "1.3.14", + "tslib": "2.4.0" + } + }, + "@formatjs/icu-skeleton-parser": { + "version": "1.3.14", + "resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.3.14.tgz", + "integrity": "sha512-7bv60HQQcBb3+TSj+45tOb/CHV5z1hOpwdtS50jsSBXfB+YpGhnoRsZxSRksXeCxMy6xn6tA6VY2601BrrK+OA==", + "dev": true, + "requires": { + "@formatjs/ecma402-abstract": "1.13.0", + "tslib": "2.4.0" + } + }, + "@formatjs/intl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@formatjs/intl/-/intl-2.5.1.tgz", + "integrity": "sha512-P01ZGuDDlcN8bHHBCEHspJPvs8WJeO8SXlUIcVGWhS3IN5vUgz0QKUXcKBFnJbEHhONJ+azlObVwvlDKsE+kUg==", + "dev": true, + "requires": { + "@formatjs/ecma402-abstract": "1.13.0", + "@formatjs/fast-memoize": "1.2.6", + "@formatjs/icu-messageformat-parser": "2.1.10", + "@formatjs/intl-displaynames": "6.1.4", + "@formatjs/intl-listformat": "7.1.3", + "intl-messageformat": "10.2.1", + "tslib": "2.4.0" + } + }, + "@formatjs/intl-displaynames": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/@formatjs/intl-displaynames/-/intl-displaynames-6.1.4.tgz", + "integrity": "sha512-sEbziGLsWQo6nA8ZUBcsDRlZzPg+uMVjDmbTalgGqRWLbdXuxMldTYdaCK+UptyJhkmNVM/erz3csTiyqamXHQ==", + "dev": true, + "requires": { + "@formatjs/ecma402-abstract": "1.13.0", + "@formatjs/intl-localematcher": "0.2.31", + "tslib": "2.4.0" + } + }, + "@formatjs/intl-listformat": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@formatjs/intl-listformat/-/intl-listformat-7.1.3.tgz", + "integrity": "sha512-rs0Kxl78PeRCedx2cmFoBqcun2Kf0bCQrF8ycna54sfePpDhMskvODWeI4G/xBioW01FjK7CJSvtJJ87hrr79A==", + "dev": true, + "requires": { + "@formatjs/ecma402-abstract": "1.13.0", + "@formatjs/intl-localematcher": "0.2.31", + "tslib": "2.4.0" + } + }, + "@formatjs/intl-localematcher": { + "version": "0.2.31", + "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.2.31.tgz", + "integrity": "sha512-9QTjdSBpQ7wHShZgsNzNig5qT3rCPvmZogS/wXZzKotns5skbXgs0I7J8cuN0PPqXyynvNVuN+iOKhNS2eb+ZA==", + "dev": true, + "requires": { + "tslib": "2.4.0" + } + }, + "@fortawesome/fontawesome-common-types": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.2.0.tgz", + "integrity": "sha512-rBevIsj2nclStJ7AxTdfsa3ovHb1H+qApwrxcTVo+NNdeJiB9V75hsKfrkG5AwNcRUNxrPPiScGYCNmLMoh8pg==" + }, + "@fortawesome/fontawesome-svg-core": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.2.0.tgz", + "integrity": "sha512-Cf2mAAeMWFMzpLC7Y9H1I4o3wEU+XovVJhTiNG8ZNgSQj53yl7OCJaS80K4YjrABWZzbAHVaoHE1dVJ27AAYXw==", + "requires": { + "@fortawesome/fontawesome-common-types": "6.2.0" + } + }, + "@fortawesome/free-brands-svg-icons": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-6.2.0.tgz", + "integrity": "sha512-fm1y4NyZ2qKYNmYhdMz9VAWRw1Et7PMHNunSw3W0SVAwKwv6o0qiJworLH3Y9SnmhHzAymXJwCX1op22FFvGiA==", + "requires": { + "@fortawesome/fontawesome-common-types": "6.2.0" + } + }, + "@fortawesome/free-solid-svg-icons": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.2.0.tgz", + "integrity": "sha512-UjCILHIQ4I8cN46EiQn0CZL/h8AwCGgR//1c4R96Q5viSRwuKVo0NdQEc4bm+69ZwC0dUvjbDqAHF1RR5FA3XA==", + "requires": { + "@fortawesome/fontawesome-common-types": "6.2.0" + } + }, + "@fortawesome/react-fontawesome": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.0.tgz", + "integrity": "sha512-uHg75Rb/XORTtVt7OS9WoK8uM276Ufi7gCzshVWkUJbHhh3svsUUeqXerrM96Wm7fRiDzfKRwSoahhMIkGAYHw==", + "requires": { + "prop-types": "^15.8.1" + } + }, + "@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==", + "dev": true, + "requires": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + }, + "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 + } + } + }, + "@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true + }, + "@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "@jridgewell/gen-mapping": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", + "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", + "requires": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==" + }, + "@jridgewell/set-array": { + "version": "1.1.2", + "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" + }, + "dependencies": { + "@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + } + } + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" + }, + "@jridgewell/trace-mapping": { + "version": "0.3.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.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + } + }, + "@juggle/resize-observer": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/@juggle/resize-observer/-/resize-observer-3.4.0.tgz", + "integrity": "sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA==" + }, + "@motionone/animation": { + "version": "10.14.0", + "resolved": "https://registry.npmjs.org/@motionone/animation/-/animation-10.14.0.tgz", + "integrity": "sha512-h+1sdyBP8vbxEBW5gPFDnj+m2DCqdlAuf2g6Iafb1lcMnqjsRXWlPw1AXgvUMXmreyhqmPbJqoNfIKdytampRQ==", + "requires": { + "@motionone/easing": "^10.14.0", + "@motionone/types": "^10.14.0", + "@motionone/utils": "^10.14.0", + "tslib": "^2.3.1" + } + }, + "@motionone/dom": { + "version": "10.13.1", + "resolved": "https://registry.npmjs.org/@motionone/dom/-/dom-10.13.1.tgz", + "integrity": "sha512-zjfX+AGMIt/fIqd/SL1Lj93S6AiJsEA3oc5M9VkUr+Gz+juRmYN1vfvZd6MvEkSqEjwPQgcjN7rGZHrDB9APfQ==", + "requires": { + "@motionone/animation": "^10.13.1", + "@motionone/generators": "^10.13.1", + "@motionone/types": "^10.13.0", + "@motionone/utils": "^10.13.1", + "hey-listen": "^1.0.8", + "tslib": "^2.3.1" + } + }, + "@motionone/easing": { + "version": "10.14.0", + "resolved": "https://registry.npmjs.org/@motionone/easing/-/easing-10.14.0.tgz", + "integrity": "sha512-2vUBdH9uWTlRbuErhcsMmt1jvMTTqvGmn9fHq8FleFDXBlHFs5jZzHJT9iw+4kR1h6a4SZQuCf72b9ji92qNYA==", + "requires": { + "@motionone/utils": "^10.14.0", + "tslib": "^2.3.1" + } + }, + "@motionone/generators": { + "version": "10.14.0", + "resolved": "https://registry.npmjs.org/@motionone/generators/-/generators-10.14.0.tgz", + "integrity": "sha512-6kRHezoFfIjFN7pPpaxmkdZXD36tQNcyJe3nwVqwJ+ZfC0e3rFmszR8kp9DEVFs9QL/akWjuGPSLBI1tvz+Vjg==", + "requires": { + "@motionone/types": "^10.14.0", + "@motionone/utils": "^10.14.0", + "tslib": "^2.3.1" + } + }, + "@motionone/types": { + "version": "10.14.0", + "resolved": "https://registry.npmjs.org/@motionone/types/-/types-10.14.0.tgz", + "integrity": "sha512-3bNWyYBHtVd27KncnJLhksMFQ5o2MSdk1cA/IZqsHtA9DnRM1SYgN01CTcJ8Iw8pCXF5Ocp34tyAjY7WRpOJJQ==" + }, + "@motionone/utils": { + "version": "10.14.0", + "resolved": "https://registry.npmjs.org/@motionone/utils/-/utils-10.14.0.tgz", + "integrity": "sha512-sLWBLPzRqkxmOTRzSaD3LFQXCPHvDzyHJ1a3VP9PRzBxyVd2pv51/gMOsdAcxQ9n+MIeGJnxzXBYplUHKj4jkw==", + "requires": { + "@motionone/types": "^10.14.0", + "hey-listen": "^1.0.8", + "tslib": "^2.3.1" + } + }, + "@mui/base": { + "version": "5.0.0-alpha.103", + "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-alpha.103.tgz", + "integrity": "sha512-fJIyB2df3CHn7D26WHnutnY7vew6aytTlhmRJz6GX7ag19zU2GcOUhJAzY5qwWcrXKnlYgzimhEjaEnuiUWU4g==", + "requires": { + "@babel/runtime": "^7.19.0", + "@emotion/is-prop-valid": "^1.2.0", + "@mui/types": "^7.2.0", + "@mui/utils": "^5.10.9", + "@popperjs/core": "^2.11.6", + "clsx": "^1.2.1", + "prop-types": "^15.8.1", + "react-is": "^18.2.0" + } + }, + "@mui/core-downloads-tracker": { + "version": "5.10.11", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.10.11.tgz", + "integrity": "sha512-u5ff+UCFDHcR8MoQ8tuJR4c35vt7T/ki3aMEE2O3XQoGs8KJSrBiisFpFKyldg9/W2NSyoZxN+kxEGIfRxh+9Q==" + }, + "@mui/material": { + "version": "5.10.11", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.10.11.tgz", + "integrity": "sha512-KJ0wPCTbv6sFzwA3dgg0gowdfF+SRl7D510J9l6Nl/KFX0EawcewQudqKY4slYGFXniKa5PykqokpaWXsCCPqg==", + "requires": { + "@babel/runtime": "^7.19.0", + "@mui/base": "5.0.0-alpha.103", + "@mui/core-downloads-tracker": "^5.10.11", + "@mui/system": "^5.10.10", + "@mui/types": "^7.2.0", + "@mui/utils": "^5.10.9", + "@types/react-transition-group": "^4.4.5", + "clsx": "^1.2.1", + "csstype": "^3.1.1", + "prop-types": "^15.8.1", + "react-is": "^18.2.0", + "react-transition-group": "^4.4.5" + } + }, + "@mui/private-theming": { + "version": "5.10.9", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.10.9.tgz", + "integrity": "sha512-BN7/CnsVPVyBaQpDTij4uV2xGYHHHhOgpdxeYLlIu+TqnsVM7wUeF+37kXvHovxM6xmL5qoaVUD98gDC0IZnHg==", + "requires": { + "@babel/runtime": "^7.19.0", + "@mui/utils": "^5.10.9", + "prop-types": "^15.8.1" + } + }, + "@mui/styled-engine": { + "version": "5.10.8", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.10.8.tgz", + "integrity": "sha512-w+y8WI18EJV6zM/q41ug19cE70JTeO6sWFsQ7tgePQFpy6ToCVPh0YLrtqxUZXSoMStW5FMw0t9fHTFAqPbngw==", + "requires": { + "@babel/runtime": "^7.19.0", + "@emotion/cache": "^11.10.3", + "csstype": "^3.1.1", + "prop-types": "^15.8.1" + } + }, + "@mui/system": { + "version": "5.10.10", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.10.10.tgz", + "integrity": "sha512-TXwtKN0adKpBrZmO+eilQWoPf2veh050HLYrN78Kps9OhlvO70v/2Kya0+mORFhu9yhpAwjHXO8JII/R4a5ZLA==", + "requires": { + "@babel/runtime": "^7.19.0", + "@mui/private-theming": "^5.10.9", + "@mui/styled-engine": "^5.10.8", + "@mui/types": "^7.2.0", + "@mui/utils": "^5.10.9", + "clsx": "^1.2.1", + "csstype": "^3.1.1", + "prop-types": "^15.8.1" + } + }, + "@mui/types": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.0.tgz", + "integrity": "sha512-lGXtFKe5lp3UxTBGqKI1l7G8sE2xBik8qCfrLHD5olwP/YU0/ReWoWT7Lp1//ri32dK39oPMrJN8TgbkCSbsNA==", + "requires": {} + }, + "@mui/utils": { + "version": "5.10.9", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.10.9.tgz", + "integrity": "sha512-2tdHWrq3+WCy+G6TIIaFx3cg7PorXZ71P375ExuX61od1NOAJP1mK90VxQ8N4aqnj2vmO3AQDkV4oV2Ktvt4bA==", + "requires": { + "@babel/runtime": "^7.19.0", + "@types/prop-types": "^15.7.5", + "@types/react-is": "^16.7.1 || ^17.0.0", + "prop-types": "^15.8.1", + "react-is": "^18.2.0" + } + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@popperjs/core": { + "version": "2.11.6", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.6.tgz", + "integrity": "sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==" + }, + "@remix-run/router": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.0.2.tgz", + "integrity": "sha512-GRSOFhJzjGN+d4sKHTMSvNeUPoZiDHWmRnXfzaxrqe7dE/Nzlc8BiMSJdLDESZlndM7jIUrZ/F4yWqVYlI0rwQ==" + }, + "@types/crypto-js": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@types/crypto-js/-/crypto-js-4.1.1.tgz", + "integrity": "sha512-BG7fQKZ689HIoc5h+6D2Dgq1fABRa0RbBWKBd9SP/MVRVXROflpm5fhwyATX5duFmbStzyzyycPB8qUYKDH3NA==" + }, + "@types/eslint": { + "version": "8.4.8", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.8.tgz", + "integrity": "sha512-zUCKQI1bUCTi+0kQs5ZQzQ/XILWRLIlh15FXWNykJ+NG3TMKMVvwwC6GP3DR1Ylga15fB7iAExSzc4PNlR5i3w==", + "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/hoist-non-react-statics": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz", + "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==", + "dev": true, + "requires": { + "@types/react": "*", + "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/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true + }, + "@types/jsrsasign": { + "version": "10.5.4", + "resolved": "https://registry.npmjs.org/@types/jsrsasign/-/jsrsasign-10.5.4.tgz", + "integrity": "sha512-05S2f4lGaWgCwFHsa3OEirc4VJf/sJRfhofzxUbuFbmm6NbffPXZrnJqquQAtS3g4C8Z0L9NHgW0znmtDxNoTQ==", + "dev": true + }, + "@types/node": { + "version": "18.11.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.5.tgz", + "integrity": "sha512-3JRwhbjI+cHLAkUorhf8RnqUbFXajvzX4q6fMn5JwkgtuwfYtRQYI3u4V92vI6NJuTsbBQWWh3RZjFsuevyMGQ==" + }, + "@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/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/react": { + "version": "18.0.23", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.23.tgz", + "integrity": "sha512-R1wTULtCiJkudAN2DJGoYYySbGtOdzZyUWAACYinKdiQC8auxso4kLDUhQ7AJ2kh3F6A6z4v69U6tNY39hihVQ==", + "requires": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, + "@types/react-dom": { + "version": "18.0.7", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.7.tgz", + "integrity": "sha512-HaXc+BbqAZE1RdsK3tC8SbkFy6UL2xF76lT9rQs5JkPrJg3rWA3Ou/Lhw3YJQzEDkBpmJ79nBsfnd05WrBd2QQ==", + "requires": { + "@types/react": "*" + } + }, + "@types/react-is": { + "version": "17.0.3", + "resolved": "https://registry.npmjs.org/@types/react-is/-/react-is-17.0.3.tgz", + "integrity": "sha512-aBTIWg1emtu95bLTLx0cpkxwGW3ueZv71nE2YFBpL8k/z5czEW8yYpOo8Dp+UUAFAtKwNaOsh/ioSeQnWlZcfw==", + "requires": { + "@types/react": "*" + } + }, + "@types/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-juKD/eiSM3/xZYzjuzH6ZwpP+/lejltmiS3QEzV/vmb/Q8+HfDmxu+Baga8UEMGBqV88Nbg4l2hY/K2DkyaLLA==", + "requires": { + "@types/react": "*" + } + }, + "@types/scheduler": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", + "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" + }, + "@types/semver": { + "version": "7.3.13", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", + "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", + "dev": true + }, + "@typescript-eslint/eslint-plugin": { + "version": "5.51.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.51.0.tgz", + "integrity": "sha512-wcAwhEWm1RgNd7dxD/o+nnLW8oH+6RK1OGnmbmkj/GGoDPV1WWMVP0FXYQBivKHdwM1pwii3bt//RC62EriIUQ==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "5.51.0", + "@typescript-eslint/type-utils": "5.51.0", + "@typescript-eslint/utils": "5.51.0", + "debug": "^4.3.4", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "natural-compare-lite": "^1.4.0", + "regexpp": "^3.2.0", + "semver": "^7.3.7", + "tsutils": "^3.21.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 + }, + "semver": { + "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" + } + } + } + }, + "@typescript-eslint/parser": { + "version": "5.51.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.51.0.tgz", + "integrity": "sha512-fEV0R9gGmfpDeRzJXn+fGQKcl0inIeYobmmUWijZh9zA7bxJ8clPhV9up2ZQzATxAiFAECqPQyMDB4o4B81AaA==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "5.51.0", + "@typescript-eslint/types": "5.51.0", + "@typescript-eslint/typescript-estree": "5.51.0", + "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 + } + } + }, + "@typescript-eslint/scope-manager": { + "version": "5.51.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.51.0.tgz", + "integrity": "sha512-gNpxRdlx5qw3yaHA0SFuTjW4rxeYhpHxt491PEcKF8Z6zpq0kMhe0Tolxt0qjlojS+/wArSDlj/LtE69xUJphQ==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.51.0", + "@typescript-eslint/visitor-keys": "5.51.0" + } + }, + "@typescript-eslint/type-utils": { + "version": "5.51.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.51.0.tgz", + "integrity": "sha512-QHC5KKyfV8sNSyHqfNa0UbTbJ6caB8uhcx2hYcWVvJAZYJRBo5HyyZfzMdRx8nvS+GyMg56fugMzzWnojREuQQ==", + "dev": true, + "requires": { + "@typescript-eslint/typescript-estree": "5.51.0", + "@typescript-eslint/utils": "5.51.0", + "debug": "^4.3.4", + "tsutils": "^3.21.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 + } + } + }, + "@typescript-eslint/types": { + "version": "5.51.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.51.0.tgz", + "integrity": "sha512-SqOn0ANn/v6hFn0kjvLwiDi4AzR++CBZz0NV5AnusT2/3y32jdc0G4woXPWHCumWtUXZKPAS27/9vziSsC9jnw==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "5.51.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.51.0.tgz", + "integrity": "sha512-TSkNupHvNRkoH9FMA3w7TazVFcBPveAAmb7Sz+kArY6sLT86PA5Vx80cKlYmd8m3Ha2SwofM1KwraF24lM9FvA==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.51.0", + "@typescript-eslint/visitor-keys": "5.51.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.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 + }, + "semver": { + "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" + } + } + } + }, + "@typescript-eslint/utils": { + "version": "5.51.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.51.0.tgz", + "integrity": "sha512-76qs+5KWcaatmwtwsDJvBk4H76RJQBFe+Gext0EfJdC3Vd2kpY2Pf//OHHzHp84Ciw0/rYoGTDnIAr3uWhhJYw==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.51.0", + "@typescript-eslint/types": "5.51.0", + "@typescript-eslint/typescript-estree": "5.51.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0", + "semver": "^7.3.7" + }, + "dependencies": { + "semver": { + "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" + } + } + } + }, + "@typescript-eslint/visitor-keys": { + "version": "5.51.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.51.0.tgz", + "integrity": "sha512-Oh2+eTdjHjOFjKA27sxESlA87YPSOJafGCR0md5oeMdh1ZcCfAGCIOL216uTBAkAIptvLIfKQhl7lHxMJet4GQ==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.51.0", + "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" + } + }, + "@webpack-cli/configtest": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.2.0.tgz", + "integrity": "sha512-4FB8Tj6xyVkyqjj1OaTqCjXYULB9FMkqQ8yGrZjRDrYh0nOE+7Lhs45WioWQQMV+ceFlE368Ukhe6xdvJM9Egg==", + "dev": true, + "requires": {} + }, + "@webpack-cli/info": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.5.0.tgz", + "integrity": "sha512-e8tSXZpw2hPl2uMJY6fsMswaok5FdlGNRTktvFk2sD8RjH0hE2+XistawJx1vmKteh4NmGmNUrp+Tb2w+udPcQ==", + "dev": true, + "requires": { + "envinfo": "^7.7.3" + } + }, + "@webpack-cli/serve": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.7.0.tgz", + "integrity": "sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q==", + "dev": true, + "requires": {} + }, + "@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 + }, + "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 + }, + "abortcontroller-polyfill": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.5.tgz", + "integrity": "sha512-JMJ5soJWP18htbbxJjG7bG6yuI6pRhgJ0scHHTfkUjf6wjP912xZWvM+A4sJK3gqd9E8fcPbDnOefbA9Th/FIQ==" + }, + "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==", + "requires": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + } + }, + "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, + "requires": {} + }, + "acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "requires": {} + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "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, + "requires": {} + }, + "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 + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "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 + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "array-includes": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz", + "integrity": "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "get-intrinsic": "^1.1.3", + "is-string": "^1.0.7" + } + }, + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true + }, + "array.prototype.flatmap": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz", + "integrity": "sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" + } + }, + "array.prototype.tosorted": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.1.tgz", + "integrity": "sha512-pZYPXPRl2PqWcsUs6LOMn+1f1532nEoPTYowBtqLwAW+W8vSVhkIGnmOX1t/UQjD6YGI0vcD2B1U7ZFGQH9jnQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0", + "get-intrinsic": "^1.1.3" + } + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true + }, + "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 + }, + "await-semaphore": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/await-semaphore/-/await-semaphore-0.1.3.tgz", + "integrity": "sha512-d1W2aNSYcz/sxYO4pMGX9vq65qOTu0P800epMud+6cYYX0QcT7zyqcxec3VWzpgvdXo57UWmVbZpLMjX2m1I7Q==" + }, + "axios": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.3.4.tgz", + "integrity": "sha512-toYm+Bsyl6VC5wSkfkbbNB6ROv7KY93PEBBL6xyDczaIHasAiv4wPqQ/c4RjoQzipxRD2W5g21cOqQulZ7rHwQ==", + "dev": true, + "requires": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "babel-loader": { + "version": "8.2.5", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.5.tgz", + "integrity": "sha512-OSiFfH89LrEMiWd4pLNqGz4CwJDtbs2ZVc+iGu2HrkRfPxId9F2anQj38IxWpmRfsUY0aBZYi1EFcd3mhtRMLQ==", + "dev": true, + "requires": { + "find-cache-dir": "^3.3.1", + "loader-utils": "^2.0.0", + "make-dir": "^3.1.0", + "schema-utils": "^2.6.5" + } + }, + "babel-plugin-macros": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", + "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", + "requires": { + "@babel/runtime": "^7.12.5", + "cosmiconfig": "^7.0.0", + "resolve": "^1.19.0" + } + }, + "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" + } + }, + "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" + } + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "basic-auth": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", + "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", + "requires": { + "safe-buffer": "5.1.2" + } + }, + "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", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true + }, + "body-parser": { + "version": "1.18.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz", + "integrity": "sha512-YQyoqQG3sO8iCmf8+hyVpgHHOv0/hCEFiS4zTGUwTA1HjAFX66wRcNQrVCeJq9pgESMRvUAOvSil5MJlmccuKQ==", + "requires": { + "bytes": "3.0.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "~1.6.3", + "iconv-lite": "0.4.23", + "on-finished": "~2.3.0", + "qs": "6.5.2", + "raw-body": "2.3.3", + "type-is": "~1.6.16" + } + }, + "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 + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "browser-tabs-lock": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/browser-tabs-lock/-/browser-tabs-lock-1.2.15.tgz", + "integrity": "sha512-J8K9vdivK0Di+b8SBdE7EZxDr88TnATing7XoLw6+nFkXMQ6sVBh92K3NQvZlZU91AIkFRi0w3sztk5Z+vsswA==", + "requires": { + "lodash": ">=4.17.21" + } + }, + "browserslist": { + "version": "4.21.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", + "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", + "requires": { + "caniuse-lite": "^1.0.30001400", + "electron-to-chromium": "^1.4.251", + "node-releases": "^2.0.6", + "update-browserslist-db": "^1.0.9" + } + }, + "buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "dev": true + }, + "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 + }, + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==" + }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "callsites": { + "version": "3.1.0", + "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" + } + }, + "can-use-dom": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/can-use-dom/-/can-use-dom-0.1.0.tgz", + "integrity": "sha512-ceOhN1DL7Y4O6M0j9ICgmTYziV89WMd96SvSl0REd8PMgrY0B/WBOPoed5S1KUmJqXgUXh8gzSe6E3ae27upsQ==" + }, + "caniuse-lite": { + "version": "1.0.30001425", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001425.tgz", + "integrity": "sha512-/pzFv0OmNG6W0ym80P3NtapU0QEiDS3VuYAZMGoLLqiC7f6FJFe1MjpQDREGApeenD9wloeytmVDj+JLXPC6qw==" + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "dependencies": { + "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==" + } + } + }, + "chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + } + }, + "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 + }, + "classnames": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz", + "integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==" + }, + "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 + } + } + }, + "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" + } + }, + "clsx": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", + "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==" + }, + "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==" + }, + "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", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "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 + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "connect-livereload": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/connect-livereload/-/connect-livereload-0.6.1.tgz", + "integrity": "sha512-3R0kMOdL7CjJpU66fzAkCe6HNtd3AavCS4m+uW4KtJjrdGPT0SQEZieAYd+cm+lJoBznNQ4lqipYWkhBMgk00g==", + "dev": true + }, + "content-disposition": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha512-kRGRZw3bLlFISDBgwTSA1TMBFN6J6GWDeubmDE3AF+3+yXL8hTWv8r5rkLbqYXY4RjPk/EzHnClI3zQf1cFmHA==" + }, + "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==" + }, + "convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" + }, + "cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==", + "dev": true + }, + "cookie-parser": { + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.6.tgz", + "integrity": "sha512-z3IzaNjdwUC2olLIB5/ITd0/setiaFMLYiZJle7xg5Fe9KWAceil7xszYfHHBtDFYLSgJduS2Ty0P1uJdPDJeA==", + "dev": true, + "requires": { + "cookie": "0.4.1", + "cookie-signature": "1.0.6" + } + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "copy-to-clipboard": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.2.tgz", + "integrity": "sha512-Vme1Z6RUDzrb6xAI7EZlVZ5uvOk2F//GaxKUxajDqm9LhOVM1inxNAD2vy+UZDYsd0uyA9s7b3/FVZPSxqrCfg==", + "requires": { + "toggle-selection": "^1.0.6" + } + }, + "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==" + }, + "core-js-compat": { + "version": "3.26.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.26.0.tgz", + "integrity": "sha512-piOX9Go+Z4f9ZiBFLnZ5VrOpBl0h7IGCkiFUN11QTe6LjAvOT3ifL/5TdoizMh99hcGy5SoLyWbapIY/PIb/3A==", + "dev": true, + "requires": { + "browserslist": "^4.21.4" + } + }, + "cosmiconfig": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", + "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==", + "requires": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + } + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "crypto-js": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.1.1.tgz", + "integrity": "sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw==" + }, + "css-loader": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.7.1.tgz", + "integrity": "sha512-yB5CNFa14MbPJcomwNh3wLThtkZgcNyI2bNMRt8iE5Z8Vwl7f8vQXFAzn2HDOJvtDq2NTZBUGMSUNNyrv3/+cw==", + "dev": true, + "requires": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.7", + "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.5" + }, + "dependencies": { + "semver": { + "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" + } + } + } + }, + "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-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", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true + }, + "csstype": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", + "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==" + }, + "data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "dev": true + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "define-properties": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", + "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", + "dev": true, + "requires": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==" + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha512-3NdhDuEXnfun/z7x9GOElY49LoqVHoGScmOKwmxhsS8N5Y+Z8KyPPDnaSzqWgYt/ji4mqwfTS34Htrk0zPIXVg==" + }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "requires": { + "path-type": "^4.0.0" + } + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "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-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "requires": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, + "dom-serializer": { + "version": "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" + } + }, + "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" + } + }, + "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": "16.0.3", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz", + "integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==" + }, + "ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "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==" + }, + "electron-to-chromium": { + "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==" + }, + "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==" + }, + "enhanced-resolve": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz", + "integrity": "sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + } + }, + "entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true + }, + "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", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-abstract": { + "version": "1.21.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.1.tgz", + "integrity": "sha512-QudMsPOz86xYz/1dG1OuGBKOELjCh99IIWHLzy5znUB6j8xG2yMA7bfTV86VSqKF+Y/H08vQPR+9jyXpuC6hfg==", + "dev": true, + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "es-set-tostringtag": "^2.0.1", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "function.prototype.name": "^1.1.5", + "get-intrinsic": "^1.1.3", + "get-symbol-description": "^1.0.0", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.4", + "is-array-buffer": "^3.0.1", + "is-callable": "^1.2.7", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.10", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.2", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.4.3", + "safe-regex-test": "^1.0.0", + "string.prototype.trimend": "^1.0.6", + "string.prototype.trimstart": "^1.0.6", + "typed-array-length": "^1.0.4", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.9" + } + }, + "es-cookie": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/es-cookie/-/es-cookie-1.3.2.tgz", + "integrity": "sha512-UTlYYhXGLOy05P/vKVT2Ui7WtC7NiRzGtJyAKKn32g5Gvcjn7KAClLPWlipCtxIus934dFg9o9jXiBL0nP+t9Q==" + }, + "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-set-tostringtag": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", + "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.3", + "has": "^1.0.3", + "has-tostringtag": "^1.0.0" + } + }, + "es-shim-unscopables": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" + }, + "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==" + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" + }, + "eslint": { + "version": "8.27.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.27.0.tgz", + "integrity": "sha512-0y1bfG2ho7mty+SiILVf9PfuRA49ek4Nc60Wmmu62QlobNR+CeXa4xXIJgcuwSQgZiWaPH+5BDsctpIW0PR/wQ==", + "dev": true, + "requires": { + "@eslint/eslintrc": "^1.3.3", + "@humanwhocodes/config-array": "^0.11.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.4.0", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.15.0", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-sdsl": "^4.1.4", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "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": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + } + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + }, + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "requires": { + "is-glob": "^4.0.3" + } + }, + "globals": { + "version": "13.17.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz", + "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "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 + }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } + }, + "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 + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "requires": { + "p-limit": "^3.0.2" + } + }, + "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" + } + } + } + }, + "eslint-plugin-react": { + "version": "7.32.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.32.2.tgz", + "integrity": "sha512-t2fBMa+XzonrrNkyVirzKlvn5RXzzPwRHtMvLAtVZrt8oxgnTQaYbU6SXTOO1mwQgp1y5+toMSKInnzGr0Knqg==", + "dev": true, + "requires": { + "array-includes": "^3.1.6", + "array.prototype.flatmap": "^1.3.1", + "array.prototype.tosorted": "^1.1.1", + "doctrine": "^2.1.0", + "estraverse": "^5.3.0", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.6", + "object.fromentries": "^2.0.6", + "object.hasown": "^1.1.2", + "object.values": "^1.1.6", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.4", + "semver": "^6.3.0", + "string.prototype.matchall": "^4.0.8" + }, + "dependencies": { + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + }, + "resolve": { + "version": "2.0.0-next.4", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz", + "integrity": "sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==", + "dev": true, + "requires": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + } + } + }, + "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" + } + }, + "eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^2.0.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true + } + } + }, + "eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true + }, + "espree": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", + "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", + "dev": true, + "requires": { + "acorn": "^8.8.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.3.0" + } + }, + "esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + } + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + } + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "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==" + }, + "events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true + }, + "express": { + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/express/-/express-4.16.4.tgz", + "integrity": "sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg==", + "requires": { + "accepts": "~1.3.5", + "array-flatten": "1.1.1", + "body-parser": "1.18.3", + "content-disposition": "0.5.2", + "content-type": "~1.0.4", + "cookie": "0.3.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.1.1", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.4", + "qs": "6.5.2", + "range-parser": "~1.2.0", + "safe-buffer": "5.1.2", + "send": "0.16.2", + "serve-static": "1.13.2", + "setprototypeof": "1.1.0", + "statuses": "~1.4.0", + "type-is": "~1.6.16", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "dependencies": { + "cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha512-+IJOX0OqlHCszo2mBUq+SrEbCj6w7Kpffqx60zYbPTFaO4+yYgRjHwcZNpWvaTylDHaV7PPmBHzSecZiMhtPgw==" + } + } + }, + "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-glob": { + "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", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + } + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "fast-text-encoding": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.6.tgz", + "integrity": "sha512-VhXlQgj9ioXCqGstD37E/HBeqEGV/qOD/kmbVG8h5xKBYvM1L3lR1Zn4555cQ8GkYbJa8aJSipLPndE1k6zK2w==" + }, + "fastest-levenshtein": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "dev": true + }, + "fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "dev": true, + "requires": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + } + }, + "file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "requires": { + "flat-cache": "^3.0.4" + } + }, + "file-loader": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz", + "integrity": "sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==", + "dev": true, + "requires": { + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" + }, + "dependencies": { + "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" + } + } + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "finalhandler": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", + "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "statuses": "~1.4.0", + "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" + } + }, + "find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==" + }, + "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" + } + }, + "flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "requires": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + } + }, + "flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "dev": true + }, + "follow-redirects": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "dev": true + }, + "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" + } + }, + "form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, + "formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "dev": true, + "requires": { + "fetch-blob": "^3.1.2" + } + }, + "forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" + }, + "framer-motion": { + "version": "7.6.1", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-7.6.1.tgz", + "integrity": "sha512-8US03IWJKrLoSb81l5OahNzB9Sv7Jo1RhIwUoTG/25BRUdO9lOqq/klsdZqNmNG0ua9IEJJQ8hkYpETJ4N6VSw==", + "requires": { + "@emotion/is-prop-valid": "^0.8.2", + "@motionone/dom": "10.13.1", + "framesync": "6.1.2", + "hey-listen": "^1.0.8", + "popmotion": "11.0.5", + "style-value-types": "5.1.2", + "tslib": "2.4.0" + }, + "dependencies": { + "@emotion/is-prop-valid": { + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz", + "integrity": "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==", + "optional": true, + "requires": { + "@emotion/memoize": "0.7.4" + } + }, + "@emotion/memoize": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz", + "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==", + "optional": true + } + } + }, + "framesync": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/framesync/-/framesync-6.1.2.tgz", + "integrity": "sha512-jBTqhX6KaQVDyus8muwZbBeGGP0XgujBRbQ7gM7BRdS3CadCZIHiawyzYLnafYcvZIh5j8WE7cxZKFn7dXhu9g==", + "requires": { + "tslib": "2.4.0" + } + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "function.prototype.name": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", + "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" + } + }, + "functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true + }, + "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==" + }, + "get-intrinsic": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", + "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + } + }, + "get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + } + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "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 + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" + }, + "globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3" + } + }, + "globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + } + }, + "goober": { + "version": "2.1.11", + "resolved": "https://registry.npmjs.org/goober/-/goober-2.1.11.tgz", + "integrity": "sha512-5SS2lmxbhqH0u9ABEWq7WPU69a4i2pYcHeCxqaNq6Cw3mnrF0ghWNM4tEGid4dKy8XNIAUbuThuozDHHKJVh3A==", + "requires": {} + }, + "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", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true + }, + "grapheme-splitter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "dev": true + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" + }, + "has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.1" + } + }, + "has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "dev": true + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true + }, + "has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "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 + }, + "hey-listen": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/hey-listen/-/hey-listen-1.0.8.tgz", + "integrity": "sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q==" + }, + "hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "requires": { + "react-is": "^16.7.0" + }, + "dependencies": { + "react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + } + } + }, + "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-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" + } + }, + "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" + } + }, + "http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + } + }, + "iconv-lite": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", + "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", + "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, + "requires": {} + }, + "ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "dev": true + }, + "ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "requires": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==" + }, + "install": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/install/-/install-0.13.0.tgz", + "integrity": "sha512-zDml/jzr2PKU9I8J/xyZBQn8rPCAY//UOYNmR01XwNwyfhEWObo2SWfSl1+0tm1u6PhxLwDnfsT/6jB7OUxqFA==", + "dev": true + }, + "internal-slot": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", + "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", + "dev": true, + "requires": { + "get-intrinsic": "^1.2.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + } + }, + "interpret": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", + "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==", + "dev": true + }, + "intl-messageformat": { + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-10.2.1.tgz", + "integrity": "sha512-1lrJG2qKzcC1TVzYu1VuB1yiY68LU5rwpbHa2THCzA67Vutkz7+1lv5U20K3Lz5RAiH78zxNztMEtchokMWv8A==", + "dev": true, + "requires": { + "@formatjs/ecma402-abstract": "1.13.0", + "@formatjs/fast-memoize": "1.2.6", + "@formatjs/icu-messageformat-parser": "2.1.10", + "tslib": "2.4.0" + } + }, + "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==" + }, + "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.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" + }, + "is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "requires": { + "has-bigints": "^1.0.1" + } + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true + }, + "is-core-module": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "requires": { + "has": "^1.0.3" + } + }, + "is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "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", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, + "is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "requires": { + "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-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "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 + }, + "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" + }, + "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.1.5", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.5.tgz", + "integrity": "sha512-08bOAKweV2NUC1wqTtf3qZlnpOX/R2DU9ikpjOHs0H+ibQv3zpncVQg6um4uYtRtrwIX8M4Nh3ytK4HGlYAq7Q==", + "dev": true + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "js-yaml": { + "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" + } + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" + }, + "json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "json5": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", + "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==" + }, + "jsonwebtoken": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz", + "integrity": "sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw==", + "dev": true, + "requires": { + "jws": "^3.2.2", + "lodash": "^4.17.21", + "ms": "^2.1.1", + "semver": "^7.3.8" + }, + "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 + }, + "semver": { + "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" + } + } + } + }, + "jsrsasign": { + "version": "10.5.27", + "resolved": "https://registry.npmjs.org/jsrsasign/-/jsrsasign-10.5.27.tgz", + "integrity": "sha512-1F4LmDeJZHYwoVvB44jEo2uZL3XuwYNzXCDOu53Ui6vqofGQ/gCYDmaxfVZtN0TGd92UKXr/BONcfrPonUIcQQ==" + }, + "jsx-ast-utils": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz", + "integrity": "sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw==", + "dev": true, + "requires": { + "array-includes": "^3.1.5", + "object.assign": "^4.1.3" + } + }, + "jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "dev": true, + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "dev": true, + "requires": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, + "jwt-decode": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz", + "integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==" + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" + }, + "livereload": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/livereload/-/livereload-0.9.3.tgz", + "integrity": "sha512-q7Z71n3i4X0R9xthAryBdNGVGAO2R5X+/xXpmKeuPMrteg+W2U8VusTKV3YiJbXZwKsOlFlHe+go6uSNjfxrZw==", + "dev": true, + "requires": { + "chokidar": "^3.5.0", + "livereload-js": "^3.3.1", + "opts": ">= 1.2.0", + "ws": "^7.4.3" + } + }, + "livereload-js": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/livereload-js/-/livereload-js-3.4.1.tgz", + "integrity": "sha512-5MP0uUeVCec89ZbNOT/i97Mc+q3SxXmiUGhRFOTmhrGPn//uWVQdCvcLJDy64MSBR5MidFdOR7B9viumoavy6g==", + "dev": true + }, + "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": "2.0.3", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.3.tgz", + "integrity": "sha512-THWqIsn8QRnvLl0shHYVBN9syumU8pYWEHPTmkiVGd+7K5eFNVSY6AJhRvgGF70gg1Dz+l/k8WicvFCxdEs60A==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + }, + "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" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" + }, + "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==" + }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "lodash.throttle": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", + "integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==" + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "requires": { + "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", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "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" + } + }, + "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==" + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + }, + "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==" + }, + "micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "requires": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + } + }, + "mime": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==" + }, + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "requires": { + "mime-db": "1.52.0" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "moment": { + "version": "2.29.4", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", + "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==" + }, + "morgan": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.9.1.tgz", + "integrity": "sha512-HQStPIV4y3afTiCYVxirakhlCfGkI161c76kKFca7Fk1JusM//Qeo1ej2XaMniiNeaZklMVrh3vTtIzpzwbpmA==", + "requires": { + "basic-auth": "~2.0.0", + "debug": "2.6.9", + "depd": "~1.1.2", + "on-finished": "~2.3.0", + "on-headers": "~1.0.1" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "nanoid": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "dev": true + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "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==" + }, + "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 + }, + "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-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "dev": true + }, + "node-fetch": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.0.tgz", + "integrity": "sha512-BKwRP/O0UvoMKp7GNdwPlObhYGB5DQqwhEDQlNKuoqwVYSxkSZCSbHjnFFmUEtwSKRPU4kNK8PbDYYitwaE3QA==", + "dev": true, + "requires": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + } + }, + "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==" + }, + "nodemon": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.20.tgz", + "integrity": "sha512-Km2mWHKKY5GzRg6i1j5OxOHQtuvVsgskLfigG25yTtbyfRGn/GNvIbRyOf1PSCKJ2aT/58TiuUsuOU5UToVViw==", + "dev": true, + "requires": { + "chokidar": "^3.5.2", + "debug": "^3.2.7", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", + "semver": "^5.7.1", + "simple-update-notifier": "^1.0.7", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "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" + } + }, + "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": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", + "dev": true, + "requires": { + "abbrev": "1" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "npm": { + "version": "9.5.1", + "resolved": "https://registry.npmjs.org/npm/-/npm-9.5.1.tgz", + "integrity": "sha512-MzULm9eEWPuPyHmRBxjcKm47KKYYT1gteVOXPlNJbfdaXNtp+sO4y2X3v5g375KudEAGJVDVCoFuk7bFnuuvNg==", + "dev": true, + "requires": { + "@isaacs/string-locale-compare": "^1.1.0", + "@npmcli/arborist": "^6.2.3", + "@npmcli/config": "^6.1.3", + "@npmcli/map-workspaces": "^3.0.2", + "@npmcli/package-json": "^3.0.0", + "@npmcli/run-script": "^6.0.0", + "abbrev": "^2.0.0", + "archy": "~1.0.0", + "cacache": "^17.0.4", + "chalk": "^4.1.2", + "ci-info": "^3.8.0", + "cli-columns": "^4.0.0", + "cli-table3": "^0.6.3", + "columnify": "^1.6.0", + "fastest-levenshtein": "^1.0.16", + "fs-minipass": "^3.0.1", + "glob": "^8.1.0", + "graceful-fs": "^4.2.10", + "hosted-git-info": "^6.1.1", + "ini": "^3.0.1", + "init-package-json": "^5.0.0", + "is-cidr": "^4.0.2", + "json-parse-even-better-errors": "^3.0.0", + "libnpmaccess": "^7.0.2", + "libnpmdiff": "^5.0.11", + "libnpmexec": "^5.0.11", + "libnpmfund": "^4.0.11", + "libnpmhook": "^9.0.3", + "libnpmorg": "^5.0.3", + "libnpmpack": "^5.0.11", + "libnpmpublish": "^7.1.0", + "libnpmsearch": "^6.0.2", + "libnpmteam": "^5.0.3", + "libnpmversion": "^4.0.2", + "make-fetch-happen": "^11.0.3", + "minimatch": "^6.2.0", + "minipass": "^4.0.3", + "minipass-pipeline": "^1.2.4", + "ms": "^2.1.2", + "node-gyp": "^9.3.1", + "nopt": "^7.0.0", + "npm-audit-report": "^4.0.0", + "npm-install-checks": "^6.0.0", + "npm-package-arg": "^10.1.0", + "npm-pick-manifest": "^8.0.1", + "npm-profile": "^7.0.1", + "npm-registry-fetch": "^14.0.3", + "npm-user-validate": "^2.0.0", + "npmlog": "^7.0.1", + "p-map": "^4.0.0", + "pacote": "^15.1.1", + "parse-conflict-json": "^3.0.0", + "proc-log": "^3.0.0", + "qrcode-terminal": "^0.12.0", + "read": "^2.0.0", + "read-package-json": "^6.0.0", + "read-package-json-fast": "^3.0.2", + "semver": "^7.3.8", + "ssri": "^10.0.1", + "tar": "^6.1.13", + "text-table": "~0.2.0", + "tiny-relative-date": "^1.3.0", + "treeverse": "^3.0.0", + "validate-npm-package-name": "^5.0.0", + "which": "^3.0.0", + "write-file-atomic": "^5.0.0" + }, + "dependencies": { + "@colors/colors": { + "version": "1.5.0", + "bundled": true, + "dev": true, + "optional": true + }, + "@gar/promisify": { + "version": "1.1.3", + "bundled": true, + "dev": true + }, + "@isaacs/string-locale-compare": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "@npmcli/arborist": { + "version": "6.2.3", + "bundled": true, + "dev": true, + "requires": { + "@isaacs/string-locale-compare": "^1.1.0", + "@npmcli/fs": "^3.1.0", + "@npmcli/installed-package-contents": "^2.0.0", + "@npmcli/map-workspaces": "^3.0.2", + "@npmcli/metavuln-calculator": "^5.0.0", + "@npmcli/name-from-folder": "^2.0.0", + "@npmcli/node-gyp": "^3.0.0", + "@npmcli/package-json": "^3.0.0", + "@npmcli/query": "^3.0.0", + "@npmcli/run-script": "^6.0.0", + "bin-links": "^4.0.1", + "cacache": "^17.0.4", + "common-ancestor-path": "^1.0.1", + "hosted-git-info": "^6.1.1", + "json-parse-even-better-errors": "^3.0.0", + "json-stringify-nice": "^1.1.4", + "minimatch": "^6.1.6", + "nopt": "^7.0.0", + "npm-install-checks": "^6.0.0", + "npm-package-arg": "^10.1.0", + "npm-pick-manifest": "^8.0.1", + "npm-registry-fetch": "^14.0.3", + "npmlog": "^7.0.1", + "pacote": "^15.0.8", + "parse-conflict-json": "^3.0.0", + "proc-log": "^3.0.0", + "promise-all-reject-late": "^1.0.0", + "promise-call-limit": "^1.0.1", + "read-package-json-fast": "^3.0.2", + "semver": "^7.3.7", + "ssri": "^10.0.1", + "treeverse": "^3.0.0", + "walk-up-path": "^1.0.0" + } + }, + "@npmcli/config": { + "version": "6.1.3", + "bundled": true, + "dev": true, + "requires": { + "@npmcli/map-workspaces": "^3.0.2", + "ini": "^3.0.0", + "nopt": "^7.0.0", + "proc-log": "^3.0.0", + "read-package-json-fast": "^3.0.2", + "semver": "^7.3.5", + "walk-up-path": "^1.0.0" + } + }, + "@npmcli/disparity-colors": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "ansi-styles": "^4.3.0" + } + }, + "@npmcli/fs": { + "version": "3.1.0", + "bundled": true, + "dev": true, + "requires": { + "semver": "^7.3.5" + } + }, + "@npmcli/git": { + "version": "4.0.3", + "bundled": true, + "dev": true, + "requires": { + "@npmcli/promise-spawn": "^6.0.0", + "lru-cache": "^7.4.4", + "mkdirp": "^1.0.4", + "npm-pick-manifest": "^8.0.0", + "proc-log": "^3.0.0", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^3.0.0" + } + }, + "@npmcli/installed-package-contents": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "npm-bundled": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" + } + }, + "@npmcli/map-workspaces": { + "version": "3.0.2", + "bundled": true, + "dev": true, + "requires": { + "@npmcli/name-from-folder": "^2.0.0", + "glob": "^8.0.1", + "minimatch": "^6.1.6", + "read-package-json-fast": "^3.0.0" + } + }, + "@npmcli/metavuln-calculator": { + "version": "5.0.0", + "bundled": true, + "dev": true, + "requires": { + "cacache": "^17.0.0", + "json-parse-even-better-errors": "^3.0.0", + "pacote": "^15.0.0", + "semver": "^7.3.5" + } + }, + "@npmcli/move-file": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + } + }, + "@npmcli/name-from-folder": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "@npmcli/node-gyp": { + "version": "3.0.0", + "bundled": true, + "dev": true + }, + "@npmcli/package-json": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "json-parse-even-better-errors": "^3.0.0" + } + }, + "@npmcli/promise-spawn": { + "version": "6.0.2", + "bundled": true, + "dev": true, + "requires": { + "which": "^3.0.0" + } + }, + "@npmcli/query": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "postcss-selector-parser": "^6.0.10" + } + }, + "@npmcli/run-script": { + "version": "6.0.0", + "bundled": true, + "dev": true, + "requires": { + "@npmcli/node-gyp": "^3.0.0", + "@npmcli/promise-spawn": "^6.0.0", + "node-gyp": "^9.0.0", + "read-package-json-fast": "^3.0.0", + "which": "^3.0.0" + } + }, + "@tootallnate/once": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "abbrev": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "abort-controller": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "event-target-shim": "^5.0.0" + } + }, + "agent-base": { + "version": "6.0.2", + "bundled": true, + "dev": true, + "requires": { + "debug": "4" + } + }, + "agentkeepalive": { + "version": "4.2.1", + "bundled": true, + "dev": true, + "requires": { + "debug": "^4.1.0", + "depd": "^1.1.2", + "humanize-ms": "^1.2.1" + } + }, + "aggregate-error": { + "version": "3.1.0", + "bundled": true, + "dev": true, + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + } + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "bundled": true, + "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==", + "bundled": true, + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "aproba": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "archy": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "are-we-there-yet": { + "version": "4.0.0", + "bundled": true, + "dev": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^4.1.0" + } + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "bundled": true, + "dev": true + }, + "base64-js": { + "version": "1.5.1", + "bundled": true, + "dev": true + }, + "bin-links": { + "version": "4.0.1", + "bundled": true, + "dev": true, + "requires": { + "cmd-shim": "^6.0.0", + "npm-normalize-package-bin": "^3.0.0", + "read-cmd-shim": "^4.0.0", + "write-file-atomic": "^5.0.0" + } + }, + "binary-extensions": { + "version": "2.2.0", + "bundled": true, + "dev": true + }, + "brace-expansion": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "buffer": { + "version": "6.0.3", + "bundled": true, + "dev": true, + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "builtins": { + "version": "5.0.1", + "bundled": true, + "dev": true, + "requires": { + "semver": "^7.0.0" + } + }, + "cacache": { + "version": "17.0.4", + "bundled": true, + "dev": true, + "requires": { + "@npmcli/fs": "^3.1.0", + "fs-minipass": "^3.0.0", + "glob": "^8.0.1", + "lru-cache": "^7.7.1", + "minipass": "^4.0.0", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "ssri": "^10.0.0", + "tar": "^6.1.11", + "unique-filename": "^3.0.0" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "bundled": true, + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "chownr": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "ci-info": { + "version": "3.8.0", + "bundled": true, + "dev": true + }, + "cidr-regex": { + "version": "3.1.1", + "bundled": true, + "dev": true, + "requires": { + "ip-regex": "^4.1.0" + } + }, + "clean-stack": { + "version": "2.2.0", + "bundled": true, + "dev": true + }, + "cli-columns": { + "version": "4.0.0", + "bundled": true, + "dev": true, + "requires": { + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + } + }, + "cli-table3": { + "version": "0.6.3", + "bundled": true, + "dev": true, + "requires": { + "@colors/colors": "1.5.0", + "string-width": "^4.2.0" + } + }, + "clone": { + "version": "1.0.4", + "bundled": true, + "dev": true + }, + "cmd-shim": { + "version": "6.0.1", + "bundled": true, + "dev": true + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "bundled": true, + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "bundled": true, + "dev": true + }, + "color-support": { + "version": "1.1.3", + "bundled": true, + "dev": true + }, + "columnify": { + "version": "1.6.0", + "bundled": true, + "dev": true, + "requires": { + "strip-ansi": "^6.0.1", + "wcwidth": "^1.0.0" + } + }, + "common-ancestor-path": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "bundled": true, + "dev": true + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "bundled": true, + "dev": true + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "bundled": true, + "dev": true, + "requires": { + "ms": "2.1.2" + }, + "dependencies": { + "ms": { + "version": "2.1.2", + "bundled": true, + "dev": true + } + } + }, + "defaults": { + "version": "1.0.4", + "bundled": true, + "dev": true, + "requires": { + "clone": "^1.0.2" + } + }, + "delegates": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "depd": { + "version": "1.1.2", + "bundled": true, + "dev": true + }, + "diff": { + "version": "5.1.0", + "bundled": true, + "dev": true + }, + "emoji-regex": { + "version": "8.0.0", + "bundled": true, + "dev": true + }, + "encoding": { + "version": "0.1.13", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "iconv-lite": "^0.6.2" + } + }, + "env-paths": { + "version": "2.2.1", + "bundled": true, + "dev": true + }, + "err-code": { + "version": "2.0.3", + "bundled": true, + "dev": true + }, + "event-target-shim": { + "version": "5.0.1", + "bundled": true, + "dev": true + }, + "events": { + "version": "3.3.0", + "bundled": true, + "dev": true + }, + "fastest-levenshtein": { + "version": "1.0.16", + "bundled": true, + "dev": true + }, + "fs-minipass": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "requires": { + "minipass": "^4.0.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "bundled": true, + "dev": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "bundled": true, + "dev": true + }, + "gauge": { + "version": "5.0.0", + "bundled": true, + "dev": true, + "requires": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.3", + "console-control-strings": "^1.1.0", + "has-unicode": "^2.0.1", + "signal-exit": "^3.0.7", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.5" + } + }, + "glob": { + "version": "8.1.0", + "bundled": true, + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "dependencies": { + "minimatch": { + "version": "5.1.6", + "bundled": true, + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, + "graceful-fs": { + "version": "4.2.10", + "bundled": true, + "dev": true + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "bundled": true, + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "bundled": true, + "dev": true + }, + "has-unicode": { + "version": "2.0.1", + "bundled": true, + "dev": true + }, + "hosted-git-info": { + "version": "6.1.1", + "bundled": true, + "dev": true, + "requires": { + "lru-cache": "^7.5.1" + } + }, + "http-cache-semantics": { + "version": "4.1.1", + "bundled": true, + "dev": true + }, + "http-proxy-agent": { + "version": "5.0.0", + "bundled": true, + "dev": true, + "requires": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + } + }, + "https-proxy-agent": { + "version": "5.0.1", + "bundled": true, + "dev": true, + "requires": { + "agent-base": "6", + "debug": "4" + } + }, + "humanize-ms": { + "version": "1.2.1", + "bundled": true, + "dev": true, + "requires": { + "ms": "^2.0.0" + } + }, + "iconv-lite": { + "version": "0.6.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + }, + "ieee754": { + "version": "1.2.1", + "bundled": true, + "dev": true + }, + "ignore-walk": { + "version": "6.0.1", + "bundled": true, + "dev": true, + "requires": { + "minimatch": "^6.1.6" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "bundled": true, + "dev": true + }, + "indent-string": { + "version": "4.0.0", + "bundled": true, + "dev": true + }, + "infer-owner": { + "version": "1.0.4", + "bundled": true, + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "bundled": true, + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "bundled": true, + "dev": true + }, + "ini": { + "version": "3.0.1", + "bundled": true, + "dev": true + }, + "init-package-json": { + "version": "5.0.0", + "bundled": true, + "dev": true, + "requires": { + "npm-package-arg": "^10.0.0", + "promzard": "^1.0.0", + "read": "^2.0.0", + "read-package-json": "^6.0.0", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4", + "validate-npm-package-name": "^5.0.0" + } + }, + "ip": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "ip-regex": { + "version": "4.3.0", + "bundled": true, + "dev": true + }, + "is-cidr": { + "version": "4.0.2", + "bundled": true, + "dev": true, + "requires": { + "cidr-regex": "^3.1.1" + } + }, + "is-core-module": { + "version": "2.11.0", + "bundled": true, + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "bundled": true, + "dev": true + }, + "is-lambda": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "bundled": true, + "dev": true + }, + "json-parse-even-better-errors": { + "version": "3.0.0", + "bundled": true, + "dev": true + }, + "json-stringify-nice": { + "version": "1.1.4", + "bundled": true, + "dev": true + }, + "jsonparse": { + "version": "1.3.1", + "bundled": true, + "dev": true + }, + "just-diff": { + "version": "5.2.0", + "bundled": true, + "dev": true + }, + "just-diff-apply": { + "version": "5.5.0", + "bundled": true, + "dev": true + }, + "libnpmaccess": { + "version": "7.0.2", + "bundled": true, + "dev": true, + "requires": { + "npm-package-arg": "^10.1.0", + "npm-registry-fetch": "^14.0.3" + } + }, + "libnpmdiff": { + "version": "5.0.11", + "bundled": true, + "dev": true, + "requires": { + "@npmcli/arborist": "^6.2.3", + "@npmcli/disparity-colors": "^3.0.0", + "@npmcli/installed-package-contents": "^2.0.0", + "binary-extensions": "^2.2.0", + "diff": "^5.1.0", + "minimatch": "^6.1.6", + "npm-package-arg": "^10.1.0", + "pacote": "^15.0.8", + "tar": "^6.1.13" + } + }, + "libnpmexec": { + "version": "5.0.11", + "bundled": true, + "dev": true, + "requires": { + "@npmcli/arborist": "^6.2.3", + "@npmcli/run-script": "^6.0.0", + "chalk": "^4.1.0", + "ci-info": "^3.7.1", + "npm-package-arg": "^10.1.0", + "npmlog": "^7.0.1", + "pacote": "^15.0.8", + "proc-log": "^3.0.0", + "read": "^2.0.0", + "read-package-json-fast": "^3.0.2", + "semver": "^7.3.7", + "walk-up-path": "^1.0.0" + } + }, + "libnpmfund": { + "version": "4.0.11", + "bundled": true, + "dev": true, + "requires": { + "@npmcli/arborist": "^6.2.3" + } + }, + "libnpmhook": { + "version": "9.0.3", + "bundled": true, + "dev": true, + "requires": { + "aproba": "^2.0.0", + "npm-registry-fetch": "^14.0.3" + } + }, + "libnpmorg": { + "version": "5.0.3", + "bundled": true, + "dev": true, + "requires": { + "aproba": "^2.0.0", + "npm-registry-fetch": "^14.0.3" + } + }, + "libnpmpack": { + "version": "5.0.11", + "bundled": true, + "dev": true, + "requires": { + "@npmcli/arborist": "^6.2.3", + "@npmcli/run-script": "^6.0.0", + "npm-package-arg": "^10.1.0", + "pacote": "^15.0.8" + } + }, + "libnpmpublish": { + "version": "7.1.0", + "bundled": true, + "dev": true, + "requires": { + "ci-info": "^3.6.1", + "normalize-package-data": "^5.0.0", + "npm-package-arg": "^10.1.0", + "npm-registry-fetch": "^14.0.3", + "semver": "^7.3.7", + "sigstore": "^1.0.0", + "ssri": "^10.0.1" + } + }, + "libnpmsearch": { + "version": "6.0.2", + "bundled": true, + "dev": true, + "requires": { + "npm-registry-fetch": "^14.0.3" + } + }, + "libnpmteam": { + "version": "5.0.3", + "bundled": true, + "dev": true, + "requires": { + "aproba": "^2.0.0", + "npm-registry-fetch": "^14.0.3" + } + }, + "libnpmversion": { + "version": "4.0.2", + "bundled": true, + "dev": true, + "requires": { + "@npmcli/git": "^4.0.1", + "@npmcli/run-script": "^6.0.0", + "json-parse-even-better-errors": "^3.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.7" + } + }, + "lru-cache": { + "version": "7.16.2", + "bundled": true, + "dev": true + }, + "make-fetch-happen": { + "version": "11.0.3", + "bundled": true, + "dev": true, + "requires": { + "agentkeepalive": "^4.2.1", + "cacache": "^17.0.0", + "http-cache-semantics": "^4.1.1", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.7.1", + "minipass": "^4.0.0", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^10.0.0" + } + }, + "minimatch": { + "version": "6.2.0", + "bundled": true, + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + }, + "minipass": { + "version": "4.0.3", + "bundled": true, + "dev": true + }, + "minipass-collect": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "minipass": "^3.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "bundled": true, + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "minipass-fetch": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "requires": { + "encoding": "^0.1.13", + "minipass": "^4.0.0", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + } + }, + "minipass-flush": { + "version": "1.0.5", + "bundled": true, + "dev": true, + "requires": { + "minipass": "^3.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "bundled": true, + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "minipass-json-stream": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "jsonparse": "^1.3.1", + "minipass": "^3.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "bundled": true, + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "minipass-pipeline": { + "version": "1.2.4", + "bundled": true, + "dev": true, + "requires": { + "minipass": "^3.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "bundled": true, + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "minipass-sized": { + "version": "1.0.3", + "bundled": true, + "dev": true, + "requires": { + "minipass": "^3.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "bundled": true, + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "minizlib": { + "version": "2.1.2", + "bundled": true, + "dev": true, + "requires": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "bundled": true, + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "mkdirp": { + "version": "1.0.4", + "bundled": true, + "dev": true + }, + "ms": { + "version": "2.1.3", + "bundled": true, + "dev": true + }, + "mute-stream": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "negotiator": { + "version": "0.6.3", + "bundled": true, + "dev": true + }, + "node-gyp": { + "version": "9.3.1", + "bundled": true, + "dev": true, + "requires": { + "env-paths": "^2.2.0", + "glob": "^7.1.4", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^10.0.3", + "nopt": "^6.0.0", + "npmlog": "^6.0.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^2.0.2" + }, + "dependencies": { + "@npmcli/fs": { + "version": "2.1.2", + "bundled": true, + "dev": true, + "requires": { + "@gar/promisify": "^1.1.3", + "semver": "^7.3.5" + } + }, + "abbrev": { + "version": "1.1.1", + "bundled": true, + "dev": true + }, + "are-we-there-yet": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "bundled": true, + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "cacache": { + "version": "16.1.3", + "bundled": true, + "dev": true, + "requires": { + "@npmcli/fs": "^2.1.0", + "@npmcli/move-file": "^2.0.0", + "chownr": "^2.0.0", + "fs-minipass": "^2.1.0", + "glob": "^8.0.1", + "infer-owner": "^1.0.4", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "mkdirp": "^1.0.4", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^9.0.0", + "tar": "^6.1.11", + "unique-filename": "^2.0.0" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "glob": { + "version": "8.1.0", + "bundled": true, + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + } + }, + "minimatch": { + "version": "5.1.6", + "bundled": true, + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, + "fs-minipass": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "gauge": { + "version": "4.0.4", + "bundled": true, + "dev": true, + "requires": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.3", + "console-control-strings": "^1.1.0", + "has-unicode": "^2.0.1", + "signal-exit": "^3.0.7", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.5" + } + }, + "glob": { + "version": "7.2.3", + "bundled": true, + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "make-fetch-happen": { + "version": "10.2.1", + "bundled": true, + "dev": true, + "requires": { + "agentkeepalive": "^4.2.1", + "cacache": "^16.1.0", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^2.0.3", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^9.0.0" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "bundled": true, + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minipass": { + "version": "3.3.6", + "bundled": true, + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "minipass-fetch": { + "version": "2.1.2", + "bundled": true, + "dev": true, + "requires": { + "encoding": "^0.1.13", + "minipass": "^3.1.6", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + } + }, + "nopt": { + "version": "6.0.0", + "bundled": true, + "dev": true, + "requires": { + "abbrev": "^1.0.0" + } + }, + "npmlog": { + "version": "6.0.2", + "bundled": true, + "dev": true, + "requires": { + "are-we-there-yet": "^3.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^4.0.3", + "set-blocking": "^2.0.0" + } + }, + "readable-stream": { + "version": "3.6.0", + "bundled": true, + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "ssri": { + "version": "9.0.1", + "bundled": true, + "dev": true, + "requires": { + "minipass": "^3.1.1" + } + }, + "unique-filename": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "unique-slug": "^3.0.0" + } + }, + "unique-slug": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "imurmurhash": "^0.1.4" + } + }, + "which": { + "version": "2.0.2", + "bundled": true, + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "nopt": { + "version": "7.0.0", + "bundled": true, + "dev": true, + "requires": { + "abbrev": "^2.0.0" + } + }, + "normalize-package-data": { + "version": "5.0.0", + "bundled": true, + "dev": true, + "requires": { + "hosted-git-info": "^6.0.0", + "is-core-module": "^2.8.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + } + }, + "npm-audit-report": { + "version": "4.0.0", + "bundled": true, + "dev": true, + "requires": { + "chalk": "^4.0.0" + } + }, + "npm-bundled": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "npm-normalize-package-bin": "^3.0.0" + } + }, + "npm-install-checks": { + "version": "6.0.0", + "bundled": true, + "dev": true, + "requires": { + "semver": "^7.1.1" + } + }, + "npm-normalize-package-bin": { + "version": "3.0.0", + "bundled": true, + "dev": true + }, + "npm-package-arg": { + "version": "10.1.0", + "bundled": true, + "dev": true, + "requires": { + "hosted-git-info": "^6.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^5.0.0" + } + }, + "npm-packlist": { + "version": "7.0.4", + "bundled": true, + "dev": true, + "requires": { + "ignore-walk": "^6.0.0" + } + }, + "npm-pick-manifest": { + "version": "8.0.1", + "bundled": true, + "dev": true, + "requires": { + "npm-install-checks": "^6.0.0", + "npm-normalize-package-bin": "^3.0.0", + "npm-package-arg": "^10.0.0", + "semver": "^7.3.5" + } + }, + "npm-profile": { + "version": "7.0.1", + "bundled": true, + "dev": true, + "requires": { + "npm-registry-fetch": "^14.0.0", + "proc-log": "^3.0.0" + } + }, + "npm-registry-fetch": { + "version": "14.0.3", + "bundled": true, + "dev": true, + "requires": { + "make-fetch-happen": "^11.0.0", + "minipass": "^4.0.0", + "minipass-fetch": "^3.0.0", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.1.2", + "npm-package-arg": "^10.0.0", + "proc-log": "^3.0.0" + } + }, + "npm-user-validate": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "npmlog": { + "version": "7.0.1", + "bundled": true, + "dev": true, + "requires": { + "are-we-there-yet": "^4.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^5.0.0", + "set-blocking": "^2.0.0" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "bundled": true, + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "p-map": { + "version": "4.0.0", + "bundled": true, + "dev": true, + "requires": { + "aggregate-error": "^3.0.0" + } + }, + "pacote": { + "version": "15.1.1", + "bundled": true, + "dev": true, + "requires": { + "@npmcli/git": "^4.0.0", + "@npmcli/installed-package-contents": "^2.0.1", + "@npmcli/promise-spawn": "^6.0.1", + "@npmcli/run-script": "^6.0.0", + "cacache": "^17.0.0", + "fs-minipass": "^3.0.0", + "minipass": "^4.0.0", + "npm-package-arg": "^10.0.0", + "npm-packlist": "^7.0.0", + "npm-pick-manifest": "^8.0.0", + "npm-registry-fetch": "^14.0.0", + "proc-log": "^3.0.0", + "promise-retry": "^2.0.1", + "read-package-json": "^6.0.0", + "read-package-json-fast": "^3.0.0", + "sigstore": "^1.0.0", + "ssri": "^10.0.0", + "tar": "^6.1.11" + } + }, + "parse-conflict-json": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "json-parse-even-better-errors": "^3.0.0", + "just-diff": "^5.0.1", + "just-diff-apply": "^5.2.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "bundled": true, + "dev": true + }, + "postcss-selector-parser": { + "version": "6.0.11", + "bundled": true, + "dev": true, + "requires": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + } + }, + "proc-log": { + "version": "3.0.0", + "bundled": true, + "dev": true + }, + "process": { + "version": "0.11.10", + "bundled": true, + "dev": true + }, + "promise-all-reject-late": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "promise-call-limit": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "promise-inflight": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "promise-retry": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + } + }, + "promzard": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "read": "^2.0.0" + } + }, + "qrcode-terminal": { + "version": "0.12.0", + "bundled": true, + "dev": true + }, + "read": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "requires": { + "mute-stream": "~1.0.0" + } + }, + "read-cmd-shim": { + "version": "4.0.0", + "bundled": true, + "dev": true + }, + "read-package-json": { + "version": "6.0.0", + "bundled": true, + "dev": true, + "requires": { + "glob": "^8.0.1", + "json-parse-even-better-errors": "^3.0.0", + "normalize-package-data": "^5.0.0", + "npm-normalize-package-bin": "^3.0.0" + } + }, + "read-package-json-fast": { + "version": "3.0.2", + "bundled": true, + "dev": true, + "requires": { + "json-parse-even-better-errors": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" + } + }, + "readable-stream": { + "version": "4.3.0", + "bundled": true, + "dev": true, + "requires": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10" + } + }, + "retry": { + "version": "0.12.0", + "bundled": true, + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "bundled": true, + "dev": true, + "requires": { + "glob": "^7.1.3" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "bundled": true, + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "glob": { + "version": "7.2.3", + "bundled": true, + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "bundled": true, + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, + "safe-buffer": { + "version": "5.1.2", + "bundled": true, + "dev": true + }, + "safer-buffer": { + "version": "2.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "bundled": true, + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + }, + "dependencies": { + "lru-cache": { + "version": "6.0.0", + "bundled": true, + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "signal-exit": { + "version": "3.0.7", + "bundled": true, + "dev": true + }, + "sigstore": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "make-fetch-happen": "^11.0.1", + "tuf-js": "^1.0.0" + } + }, + "smart-buffer": { + "version": "4.2.0", + "bundled": true, + "dev": true + }, + "socks": { + "version": "2.7.1", + "bundled": true, + "dev": true, + "requires": { + "ip": "^2.0.0", + "smart-buffer": "^4.2.0" + } + }, + "socks-proxy-agent": { + "version": "7.0.0", + "bundled": true, + "dev": true, + "requires": { + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" + } + }, + "spdx-correct": { + "version": "3.1.1", + "bundled": true, + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.3.0", + "bundled": true, + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.12", + "bundled": true, + "dev": true + }, + "ssri": { + "version": "10.0.1", + "bundled": true, + "dev": true, + "requires": { + "minipass": "^4.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "string-width": { + "version": "4.2.3", + "bundled": true, + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "bundled": true, + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "bundled": true, + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "tar": { + "version": "6.1.13", + "bundled": true, + "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": { + "fs-minipass": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "requires": { + "minipass": "^3.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "bundled": true, + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + } + } + } + } + }, + "text-table": { + "version": "0.2.0", + "bundled": true, + "dev": true + }, + "tiny-relative-date": { + "version": "1.3.0", + "bundled": true, + "dev": true + }, + "treeverse": { + "version": "3.0.0", + "bundled": true, + "dev": true + }, + "tuf-js": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "make-fetch-happen": "^11.0.1", + "minimatch": "^6.1.0" + } + }, + "unique-filename": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "unique-slug": "^4.0.0" + } + }, + "unique-slug": { + "version": "4.0.0", + "bundled": true, + "dev": true, + "requires": { + "imurmurhash": "^0.1.4" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "bundled": true, + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.4", + "bundled": true, + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "validate-npm-package-name": { + "version": "5.0.0", + "bundled": true, + "dev": true, + "requires": { + "builtins": "^5.0.0" + } + }, + "walk-up-path": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "wcwidth": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "defaults": "^1.0.3" + } + }, + "which": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "wide-align": { + "version": "1.1.5", + "bundled": true, + "dev": true, + "requires": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "bundled": true, + "dev": true + }, + "write-file-atomic": { + "version": "5.0.0", + "bundled": true, + "dev": true, + "requires": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "bundled": true, + "dev": true + } + } + }, + "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-inspect": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "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 + }, + "object.assign": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + } + }, + "object.entries": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.6.tgz", + "integrity": "sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "object.fromentries": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.6.tgz", + "integrity": "sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "object.hasown": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.2.tgz", + "integrity": "sha512-B5UIT3J1W+WuWIU55h0mjlwaqxiE5vYENJXIXZ4VFe05pNYrkKuK0U/6aFcb0pKywYJh7IhfoqUfKVmrJJHZHw==", + "dev": true, + "requires": { + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "object.values": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz", + "integrity": "sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "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==" + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + } + }, + "opts": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/opts/-/opts-2.0.2.tgz", + "integrity": "sha512-k41FwbcLnlgnFh69f4qdUfvDQ+5vaSDnVPFI/y5XuhKRq97EnVVneO9F1ESVCdiVu4fCS2L8usX3mU331hB7pg==", + "dev": true + }, + "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" + } + }, + "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", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "requires": { + "callsites": "^3.0.0" + } + }, + "parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + } + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + }, + "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" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "path-parse": { + "version": "1.0.7", + "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==" + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==" + }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + }, + "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" + } + }, + "popmotion": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/popmotion/-/popmotion-11.0.5.tgz", + "integrity": "sha512-la8gPM1WYeFznb/JqF4GiTkRRPZsfaj2+kCxqQgr2MJylMmIKUwBfWW8Wa5fml/8gmtlD5yI01MP1QCZPWmppA==", + "requires": { + "framesync": "6.1.2", + "hey-listen": "^1.0.8", + "style-value-types": "5.1.2", + "tslib": "2.4.0" + } + }, + "postcss": { + "version": "8.4.18", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.18.tgz", + "integrity": "sha512-Wi8mWhncLJm11GATDaQKobXSNEYGUHeQLiQqDFG1qQ5UTDPTEvKw0Xt5NsTpktGTwLps3ByrWsBrG0rB8YQ9oA==", + "dev": true, + "requires": { + "nanoid": "^3.3.4", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + } + }, + "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, + "requires": {} + }, + "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-selector-parser": { + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", + "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", + "dev": true, + "requires": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + } + }, + "postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "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" + } + }, + "promise-polyfill": { + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/promise-polyfill/-/promise-polyfill-8.2.3.tgz", + "integrity": "sha512-Og0+jCRQetV84U8wVjMNccfGCnMQ9mGs9Hv78QFe+pSDD3gWTpz0y+1QCuxy5d/vBFuZ3iwP2eycAkvqIMPmWg==" + }, + "prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "requires": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + }, + "dependencies": { + "react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + } + } + }, + "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==", + "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 + }, + "pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" + }, + "querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==" + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + }, + "raw-body": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz", + "integrity": "sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==", + "requires": { + "bytes": "3.0.0", + "http-errors": "1.6.3", + "iconv-lite": "0.4.23", + "unpipe": "1.0.0" + } + }, + "rc-util": { + "version": "5.27.2", + "resolved": "https://registry.npmjs.org/rc-util/-/rc-util-5.27.2.tgz", + "integrity": "sha512-8XHRbeJOWlTR2Hk1K2xLaPOf7lZu+3taskAGuqOPccA676vB3ygrz3ZgdrA3wml40CzR9RlIEHDWwI7FZT3wBQ==", + "requires": { + "@babel/runtime": "^7.18.3", + "react-is": "^16.12.0" + }, + "dependencies": { + "react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + } + } + }, + "react": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "requires": { + "loose-envify": "^1.1.0" + } + }, + "react-copy-to-clipboard": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/react-copy-to-clipboard/-/react-copy-to-clipboard-5.1.0.tgz", + "integrity": "sha512-k61RsNgAayIJNoy9yDsYzDe/yAZAzEbEgcz3DZMhF686LEyukcE1hzurxe85JandPUG+yTfGVFzuEw3xt8WP/A==", + "requires": { + "copy-to-clipboard": "^3.3.1", + "prop-types": "^15.8.1" + } + }, + "react-device-detect": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/react-device-detect/-/react-device-detect-2.2.2.tgz", + "integrity": "sha512-zSN1gIAztUekp5qUT/ybHwQ9fmOqVT1psxpSlTn1pe0CO+fnJHKRLOWWac5nKxOxvOpD/w84hk1I+EydrJp7SA==", + "requires": { + "ua-parser-js": "^1.0.2" + } + }, + "react-dom": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", + "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "requires": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.0" + } + }, + "react-hot-toast": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/react-hot-toast/-/react-hot-toast-2.4.0.tgz", + "integrity": "sha512-qnnVbXropKuwUpriVVosgo8QrB+IaPJCpL8oBI6Ov84uvHZ5QQcTp2qg6ku2wNfgJl6rlQXJIQU5q+5lmPOutA==", + "requires": { + "goober": "^2.1.10" + } + }, + "react-intl": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/react-intl/-/react-intl-6.2.1.tgz", + "integrity": "sha512-hYxcSamgoA3Mvc55nwhTF1v15T0NUSkaV/EScMNVZXg0kRyaMAoNHkCi9/9H+TnXWNiWrcWH9bjlMlJwrG2V7g==", + "dev": true, + "requires": { + "@formatjs/ecma402-abstract": "1.13.0", + "@formatjs/icu-messageformat-parser": "2.1.10", + "@formatjs/intl": "2.5.1", + "@formatjs/intl-displaynames": "6.1.4", + "@formatjs/intl-listformat": "7.1.3", + "@types/hoist-non-react-statics": "^3.3.1", + "@types/react": "16 || 17 || 18", + "hoist-non-react-statics": "^3.3.2", + "intl-messageformat": "10.2.1", + "tslib": "2.4.0" + } + }, + "react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" + }, + "react-router": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.4.2.tgz", + "integrity": "sha512-Rb0BAX9KHhVzT1OKhMvCDMw776aTYM0DtkxqUBP8dNBom3mPXlfNs76JNGK8wKJ1IZEY1+WGj+cvZxHVk/GiKw==", + "requires": { + "@remix-run/router": "1.0.2" + } + }, + "react-router-dom": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.4.2.tgz", + "integrity": "sha512-yM1kjoTkpfjgczPrcyWrp+OuQMyB1WleICiiGfstnQYo/S8hPEEnVjr/RdmlH6yKK4Tnj1UGXFSa7uwAtmDoLQ==", + "requires": { + "@remix-run/router": "1.0.2", + "react-router": "6.4.2" + } + }, + "react-table": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/react-table/-/react-table-7.8.0.tgz", + "integrity": "sha512-hNaz4ygkZO4bESeFfnfOft73iBUj8K5oKi1EcSHPAibEydfsX2MyU6Z8KCr3mv3C9Kqqh71U+DhZkFvibbnPbA==", + "requires": {} + }, + "react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "requires": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + } + }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "rechoir": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz", + "integrity": "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==", + "dev": true, + "requires": { + "resolve": "^1.9.0" + } + }, + "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.10", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.10.tgz", + "integrity": "sha512-KepLsg4dU12hryUO7bp/axHAKvwGOCV0sGloQtpagJ12ai+ojVDqkeGSiRX1zlq+kjIMZ1t7gpze+26QqtdGqw==" + }, + "regenerator-transform": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.0.tgz", + "integrity": "sha512-LsrGtPmbYg19bcPHwdtmXwbW+TqNvtY4riE3P83foeHRroMbH6/2ddFBfab3t7kbzc7v7p4wbkIecHImqt0QNg==", + "dev": true, + "requires": { + "@babel/runtime": "^7.8.4" + } + }, + "regexp.prototype.flags": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", + "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "functions-have-names": "^1.2.2" + } + }, + "regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true + }, + "regexpu-core": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.2.1.tgz", + "integrity": "sha512-HrnlNtpvqP1Xkb28tMhBUO2EbyUHdQlsnlAhzWcwHy8WJR53UWr7/MAvqrsQKMbV4qdpv03oTMG8iIhfsPFktQ==", + "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.0.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 + }, + "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" + } + }, + "resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "requires": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "requires": { + "resolve-from": "^5.0.0" + }, + "dependencies": { + "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 + } + } + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "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==" + }, + "safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "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==" + }, + "scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "requires": { + "loose-envify": "^1.1.0" + } + }, + "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==" + }, + "send": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", + "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.6.2", + "mime": "1.4.1", + "ms": "2.0.0", + "on-finished": "~2.3.0", + "range-parser": "~1.2.0", + "statuses": "~1.4.0" + } + }, + "serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, + "serve-static": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", + "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.2", + "send": "0.16.2" + } + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" + }, + "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" + } + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, + "simple-update-notifier": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.0.7.tgz", + "integrity": "sha512-BBKgR84BJQJm6WjWFMHgLVuo61FBDSj1z/xSFUIozqO6wO7ii0JxCqlIud7Enr/+LhlbNI0whErq96P2qHNWew==", + "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 + } + } + }, + "simplebar": { + "version": "5.3.9", + "resolved": "https://registry.npmjs.org/simplebar/-/simplebar-5.3.9.tgz", + "integrity": "sha512-1vIIpjDvY9sVH14e0LGeiCiTFU3ILqAghzO6OI9axeG+mvU/vMSrvXeAXkBolqFFz3XYaY8n5ahH9MeP3sp2Ag==", + "requires": { + "@juggle/resize-observer": "^3.3.1", + "can-use-dom": "^0.1.0", + "core-js": "^3.0.1", + "lodash.debounce": "^4.0.8", + "lodash.memoize": "^4.1.2", + "lodash.throttle": "^4.1.1" + } + }, + "simplebar-react": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/simplebar-react/-/simplebar-react-2.4.3.tgz", + "integrity": "sha512-Ep8gqAUZAS5IC2lT5RE4t1ZFUIVACqbrSRQvFV9a6NbVUzXzOMnc4P82Hl8Ak77AnPQvmgUwZS7aUKLyBoMAcg==", + "requires": { + "prop-types": "^15.6.1", + "simplebar": "^5.3.9" + } + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==" + }, + "source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "dev": true + }, + "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": { + "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 + } + } + }, + "statuses": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", + "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" + }, + "string.prototype.matchall": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.8.tgz", + "integrity": "sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "get-intrinsic": "^1.1.3", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.3", + "regexp.prototype.flags": "^1.4.3", + "side-channel": "^1.0.4" + } + }, + "string.prototype.trimend": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", + "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "string.prototype.trimstart": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", + "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "strip-ansi": { + "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" + } + }, + "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, + "requires": {} + }, + "style-value-types": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/style-value-types/-/style-value-types-5.1.2.tgz", + "integrity": "sha512-Vs9fNreYF9j6W2VvuDTP7kepALi7sk0xtk2Tu8Yxi9UoajJdEVpNpCov0HsLTqXvNGKX+Uv09pkozVITi1jf3Q==", + "requires": { + "hey-listen": "^1.0.8", + "tslib": "2.4.0" + } + }, + "stylis": { + "version": "4.0.13", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.0.13.tgz", + "integrity": "sha512-xGPXiFVl4YED9Jh7Euv2V220mriG9u4B2TA6Ybjc1catrstKD2PpIdU3U0RKpkVBC2EhmL/F0sPCr9vrFTNRag==" + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" + }, + "tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true + }, + "terser": { + "version": "5.15.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.15.1.tgz", + "integrity": "sha512-K1faMUvpm/FBxjBXud0LWVAGxmvoPbZbfTCYbSgaaYQaIXI3/TdI7a7ZGA73Zrou6Q8Zmz3oeUTsp/dj+ag2Xw==", + "dev": true, + "requires": { + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "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 + } + } + }, + "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": { + "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" + } + } + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "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-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "toggle-selection": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz", + "integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==" + }, + "touch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", + "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "dev": true, + "requires": { + "nopt": "~1.0.10" + } + }, + "ts-loader": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.4.1.tgz", + "integrity": "sha512-384TYAqGs70rn9F0VBnh6BPTfhga7yFNdC5gXbQpDrBj9/KsT4iRkGqKXhziofHOlE2j6YEaiTYVGKKvPhGWvw==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "enhanced-resolve": "^5.0.0", + "micromatch": "^4.0.0", + "semver": "^7.3.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" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "semver": { + "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" + } + }, + "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", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + }, + "tss-react": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/tss-react/-/tss-react-4.4.2.tgz", + "integrity": "sha512-typ6yVmBGz1GIHmWaN+bmwHaAfxZLImfiNTiGIfJCFgas3rEpdYSty2/JENXAFvzKFl53CHc/6Z/FM2EkE2ZTQ==", + "requires": { + "@emotion/cache": "*", + "@emotion/serialize": "*", + "@emotion/utils": "*" + } + }, + "tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "typed-array-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", + "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "is-typed-array": "^1.1.9" + } + }, + "typescript": { + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", + "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==", + "dev": true + }, + "ua-parser-js": { + "version": "1.0.32", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.32.tgz", + "integrity": "sha512-dXVsz3M4j+5tTiovFVyVqssXBu5HM47//YSOeZ9fQkdDKkfzv2v3PP1jmH6FUyPW+yCSn7aBVK1fGGKNhowdDA==" + }, + "unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + } + }, + "undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true + }, + "unfetch": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/unfetch/-/unfetch-4.2.0.tgz", + "integrity": "sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA==" + }, + "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.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz", + "integrity": "sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw==", + "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 + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==" + }, + "update-browserslist-db": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", + "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", + "requires": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + } + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "url": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "integrity": "sha512-kbailJa29QrtXnxgq+DdCEGlbTeYM2eJUxsz6vjZavrCYPMIFHMKQmSKYAIuUK2i7hgPm28a8piX5NTUtM/LKQ==", + "requires": { + "punycode": "1.3.2", + "querystring": "0.2.0" + }, + "dependencies": { + "punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==" + } + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "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==" + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" + }, + "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" + } + }, + "web-streams-polyfill": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", + "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==", + "dev": true + }, + "webpack": { + "version": "5.74.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.74.0.tgz", + "integrity": "sha512-A2InDwnhhGN4LYctJj6M1JEaGL7Luj6LOmyBHjcI8529cm5p6VXiTIW2sn6ffvEAKmveLzvu4jrihwXtPojlAA==", + "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": { + "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" + } + } + } + }, + "webpack-cli": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.10.0.tgz", + "integrity": "sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w==", + "dev": true, + "requires": { + "@discoveryjs/json-ext": "^0.5.0", + "@webpack-cli/configtest": "^1.2.0", + "@webpack-cli/info": "^1.5.0", + "@webpack-cli/serve": "^1.7.0", + "colorette": "^2.0.14", + "commander": "^7.0.0", + "cross-spawn": "^7.0.3", + "fastest-levenshtein": "^1.0.12", + "import-local": "^3.0.2", + "interpret": "^2.2.0", + "rechoir": "^0.7.0", + "webpack-merge": "^5.7.3" + }, + "dependencies": { + "commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true + } + } + }, + "webpack-merge": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz", + "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==", + "dev": true, + "requires": { + "clone-deep": "^4.0.1", + "wildcard": "^2.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 + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "requires": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + } + }, + "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" + } + }, + "wildcard": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", + "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==", + "dev": true + }, + "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 + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "ws": { + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "dev": true, + "requires": {} + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==" + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true + } + } +} diff --git a/admin/admin-ui/package.json b/admin/admin-ui/package.json new file mode 100644 index 000000000..a55d1d4ee --- /dev/null +++ b/admin/admin-ui/package.json @@ -0,0 +1,88 @@ +{ + "name": "apps", + "version": "0.0.0", + "private": true, + "scripts": { + "node-prod": "node ./server/bin/www", + "node-dev": "nodemon ./server/bin/www", + "react-dev": "webpack --watch", + "react-prod": "npm run types-gen && webpack", + "types-gen": "npx openapi-typescript ../admin-domain-service/ballerina/resources/admin-api.yaml --output client/source/types/Types.ts" + }, + "dependencies": { + "@ant-design/colors": "^6.0.0", + "@ant-design/icons": "^5.0.1", + "@auth0/auth0-react": "^1.11.0", + "@emotion/react": "^11.10.4", + "@emotion/styled": "^11.10.4", + "@fortawesome/fontawesome-svg-core": "^6.2.0", + "@fortawesome/free-brands-svg-icons": "^6.2.0", + "@fortawesome/free-solid-svg-icons": "^6.2.0", + "@fortawesome/react-fontawesome": "^0.2.0", + "@mui/icons-material": "^5.11.16", + "@mui/material": "^5.10.11", + "@types/crypto-js": "^4.1.1", + "@types/node": "^18.8.2", + "@types/react": "^18.0.21", + "@types/react-dom": "^18.0.6", + "await-semaphore": "^0.1.3", + "crypto-js": "^4.1.1", + "debug": "~2.6.9", + "dotenv": "^16.0.3", + "express": "~4.16.1", + "framer-motion": "^7.6.1", + "http-errors": "~1.6.3", + "jsrsasign": "^10.5.27", + "jwt-decode": "^3.1.2", + "moment": "^2.29.4", + "morgan": "~1.9.1", + "mui-chips-input": "^2.0.1", + "react": "^18.2.0", + "react-copy-to-clipboard": "^5.1.0", + "react-device-detect": "^2.2.2", + "react-dom": "^18.2.0", + "react-hot-toast": "^2.4.0", + "react-router-dom": "^6.4.1", + "react-table": "^7.8.0", + "simplebar": "^5.3.9", + "simplebar-react": "^2.4.3", + "tss-react": "^4.4.1", + "url": "^0.11.0" + }, + "devDependencies": { + "@babel/core": "^7.19.3", + "@babel/plugin-proposal-class-properties": "^7.18.6", + "@babel/plugin-proposal-object-rest-spread": "^7.19.4", + "@babel/plugin-transform-arrow-functions": "^7.18.6", + "@babel/plugin-transform-async-to-generator": "^7.18.6", + "@babel/plugin-transform-runtime": "^7.19.6", + "@babel/plugin-transform-typescript": "^7.20.0", + "@babel/preset-env": "^7.19.4", + "@babel/preset-react": "^7.18.6", + "@babel/preset-typescript": "^7.18.6", + "@types/jsrsasign": "^10.5.4", + "@typescript-eslint/eslint-plugin": "^5.42.1", + "@typescript-eslint/parser": "^5.42.1", + "axios": "^1.3.4", + "babel-loader": "^8.2.5", + "connect-livereload": "^0.6.1", + "cookie-parser": "^1.4.6", + "css-loader": "^6.7.1", + "eslint": "^8.27.0", + "eslint-plugin-react": "^7.31.10", + "file-loader": "^6.2.0", + "html-webpack-plugin": "^5.5.0", + "install": "^0.13.0", + "jsonwebtoken": "^9.0.0", + "livereload": "^0.9.3", + "node-fetch": "^3.3.0", + "nodemon": "^2.0.20", + "npm": "^9.5.1", + "react-intl": "^6.2.1", + "style-loader": "^3.3.1", + "ts-loader": "^9.4.1", + "typescript": "^4.8.4", + "webpack": "^5.74.0", + "webpack-cli": "^4.10.0" + } +} diff --git a/admin/admin-ui/server/app.js b/admin/admin-ui/server/app.js new file mode 100644 index 000000000..004f53bd9 --- /dev/null +++ b/admin/admin-ui/server/app.js @@ -0,0 +1,73 @@ +require('dotenv').config(); +var createError = require('http-errors'); +var express = require('express'); +var path = require('path'); +var cookieParser = require('cookie-parser'); +var logger = require('morgan'); +const fs = require('fs'); + +// Live reloading libs import +var livereload = require("livereload"); +const connectLivereload = require("connect-livereload"); + +// Routes +var tokenRoutes = require('./routes/tokenRoutes'); +var serviceRouters = require('./routes/serviceRouters'); +var apiRoutes = require('./routes/apiRoutes'); + +// Initialize express +var app = express(); + +// Live reload browser +const liveReloadServer = livereload.createServer(); +liveReloadServer.watch(path.join(__dirname, '../client/public/build')); +liveReloadServer.server.once("connection", () => { + setTimeout(() => { + liveReloadServer.refresh("/"); + }, 100); +}); +// app.use(connectLivereload()); +// Live reload browser end +app.use(logger('dev')); +app.use(express.json()); +app.use(express.urlencoded({ extended: false })); +app.use(cookieParser()); +app.use(express.static(path.join(__dirname, 'public'))); + +// Server side route definitions +app.use('/token', tokenRoutes); +app.use('/services', serviceRouters); +app.use('/api', apiRoutes); + +// app.use('/specs', specs); + +// Serving the static react files +/* ******************************** */ +/* ******************************** */ +app.use( + express.static(path.join(__dirname, "../client/public")) +); + +app.get("*", (req, res) => { + res.sendFile( + path.join(__dirname, "../client/public/build/index.html") + ); +}); + +// catch 404 and forward to error handler +app.use(function(req, res, next) { + next(createError(404)); +}); + +// error handler +app.use(function(err, req, res, next) { + // set locals, only providing error in development + res.locals.message = err.message; + res.locals.error = req.app.get('env') === 'development' ? err : {}; + + // render the error page + res.status(err.status || 500); + res.send(err.message); +}); + +module.exports = app; diff --git a/admin/admin-ui/server/bin/www b/admin/admin-ui/server/bin/www new file mode 100755 index 000000000..4c1eb8b66 --- /dev/null +++ b/admin/admin-ui/server/bin/www @@ -0,0 +1,95 @@ +#!/usr/bin/env node + +/** + * Module dependencies. + */ + +var app = require('../app'); +var debug = require('debug')('apps:server'); +// var http = require('http'); +const https = require("https"); +const fs = require('fs'); +/** + * Get port from environment and store in Express. + */ + +var port = normalizePort(process.env.NODE_PORT || '4000'); +app.set('port', port); + +/** + * Create HTTP server. + */ + +var server = https.createServer({ + key: fs.readFileSync("server/tmpCerts/key.pem"), + cert: fs.readFileSync("server/tmpCerts/cert.pem"), +}, + app); + +/** + * Listen on provided port, on all network interfaces. + */ + +server.listen(port); +server.on('error', onError); +server.on('listening', onListening); + +/** + * Normalize a port into a number, string, or false. + */ + +function normalizePort(val) { + var port = parseInt(val, 10); + + if (isNaN(port)) { + // named pipe + return val; + } + + if (port >= 0) { + // port number + return port; + } + + return false; +} + +/** + * Event listener for HTTP server "error" event. + */ + +function onError(error) { + if (error.syscall !== 'listen') { + throw error; + } + + var bind = typeof port === 'string' + ? 'Pipe ' + port + : 'Port ' + port; + + // handle specific listen errors with friendly messages + switch (error.code) { + case 'EACCES': + console.error(bind + ' requires elevated privileges'); + process.exit(1); + break; + case 'EADDRINUSE': + console.error(bind + ' is already in use'); + process.exit(1); + break; + default: + throw error; + } +} + +/** + * Event listener for HTTP server "listening" event. + */ + +function onListening() { + var addr = server.address(); + var bind = typeof addr === 'string' + ? 'pipe ' + addr + : 'port ' + addr.port; + debug('Listening on ' + bind); +} diff --git a/admin/admin-ui/server/routes/apiRoutes.js b/admin/admin-ui/server/routes/apiRoutes.js new file mode 100644 index 000000000..7449eb69e --- /dev/null +++ b/admin/admin-ui/server/routes/apiRoutes.js @@ -0,0 +1,365 @@ +var express = require('express'); +var router = express.Router(); +const axios = require('axios'); +const https = require('https'); +const Settings = require('../../client/public/conf/Settings.js'); + +/* GET users listing. */ +router.get('/', async function (req, res, next) { + const accessToken = req.cookies.access_token; + + const instance = axios.create({ + httpsAgent: new https.Agent({ + rejectUnauthorized: false + }) + }); + const headers = { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${accessToken}`, + }; + console.log("*****************"); + console.log(headers); + console.log("*****************"); + try { + const response = await instance.get(`${Settings.app.rest_api}/application-rate-plans`, { + headers: headers + }); + const data = response.data; + console.log(data); + res.status(200).json(data); + } catch (error) { + console.log(error); + res.status(500).json({ error: error.message }); + } + const applicationThrottlePoliciesx = { + "count": 2, + "list": [ + { + "defaultLimit": { + "type": "REQUESTCOUNTLIMIT", + "requestCount": { + "requestCount": 41, + "timeUnit": "min", + "unitTime": 1 + } + }, + "policyId": "cbee719f-ea93-4578-91a5-df94df99a008", + "policyName": "42PerMin", + "displayName": "41PerMin", + "description": "Allows 30 request per minute", + "isDeployed": false, + "type": "ApplicationThrottlePolicy" + }, + { + "defaultLimit": { + "type": "REQUESTCOUNTLIMIT", + "requestCount": { + "requestCount": 32, + "timeUnit": "min", + "unitTime": 1 + } + }, + "policyId": "d94c27e8-3867-482d-8218-9dc69e027ebe", + "policyName": "32PerMin", + "displayName": "32PerMin", + "description": "Allows 32 request per minute", + "isDeployed": false, + "type": "ApplicationThrottlePolicy" + } + ] + }; + + // Retrieve the access token from the HTTP-only cookie + + // Make a request to the API server with the access token + // Assuming the API server is located at https://api.example.com/items + +}); + +router.get('/admin/api-categories', async function (req, res, next) { + const accessToken = req.cookies.access_token; + + const instance = axios.create({ + httpsAgent: new https.Agent({ + rejectUnauthorized: false + }) + }); + const headers = { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${accessToken}`, + 'Host': 'api.am.wso2.com' + }; + try { + const response = await instance.get(`${Settings.app.rest_api}/api-categories`, { + headers: headers + }); + const data = response.data; + res.status(200).json(data); + } catch (error) { + console.log(error); + res.status(500).json({ error: error.message }); + } +}); + +router.post('/admin/api-categories', async function (req, res, next) { + const accessToken = req.cookies.access_token; + + const instance = axios.create({ + httpsAgent: new https.Agent({ + rejectUnauthorized: false + }) + }); + const headers = { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${accessToken}`, + 'Host': 'api.am.wso2.com' + }; + + try { + const response = await instance.post(`${Settings.app.rest_api}/api-categories`, req.body, { + headers: headers + }); + const data = response.data; + res.status(201).json(data); + } catch (error) { + console.log(error); + res.status(500).json({ code: error.code, error: error.message }); + } +}); + +router.put('/admin/api-categories/:categoryId', async function (req, res, next) { + const categoryId = req.params.categoryId; + const accessToken = req.cookies.access_token; + + const instance = axios.create({ + httpsAgent: new https.Agent({ + rejectUnauthorized: false + }) + }); + const headers = { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${accessToken}`, + 'Host': 'api.am.wso2.com' + }; + + try { + const response = await instance.put(`${Settings.app.rest_api}/api-categories/${categoryId}`, req.body, { + headers: headers + }); + const data = response.data; + res.status(200).json(data); + } catch (error) { + console.log(error); + res.status(500).json({ code: error.code, error: error.message }); + } +}); + +router.delete('/admin/api-categories/:categoryId', async function (req, res, next) { + const categoryId = req.params.categoryId; + const accessToken = req.cookies.access_token; + + const instance = axios.create({ + httpsAgent: new https.Agent({ + rejectUnauthorized: false + }) + }); + const headers = { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${accessToken}`, + 'Host': 'api.am.wso2.com' + }; + + try { + const response = await instance.delete(`${Settings.app.rest_api}/api-categories/${categoryId}`, { + headers: headers + }); + res.status(200).json({ message: "Successfully deleted" }); + } catch (error) { + console.log(error); + res.status(500).json({ code: error.code, error: error.message }); + } +}); + +router.get('/admin/organizations', async function (req, res, next) { + const accessToken = req.cookies.access_token; + + const instance = axios.create({ + httpsAgent: new https.Agent({ + rejectUnauthorized: false + }) + }); + const headers = { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${accessToken}`, + 'Host': 'api.am.wso2.com' + }; + try { + const response = await instance.get(`${Settings.app.rest_api}/organizations`, { + headers: headers + }); + const data = response.data; + res.status(200).json(data); + } catch (error) { + console.log(error); + res.status(500).json({ error: error.message }); + } +}); + +router.post('/admin/organizations', async function (req, res, next) { + const accessToken = req.cookies.access_token; + + const instance = axios.create({ + httpsAgent: new https.Agent({ + rejectUnauthorized: false + }) + }); + const headers = { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${accessToken}`, + 'Host': 'api.am.wso2.com' + }; + + try { + const response = await instance.post(`${Settings.app.rest_api}/organizations`, req.body, { + headers: headers + }); + const data = response.data; + res.status(200).json(data); + } catch (error) { + console.log(error); + res.status(500).json({ code: error.code, error: error.message }); + } +}); + +router.delete('/admin/organizations/:organizationId', async function (req, res, next) { + const organizationId = req.params.organizationId; + const accessToken = req.cookies.access_token; + + const instance = axios.create({ + httpsAgent: new https.Agent({ + rejectUnauthorized: false + }) + }); + const headers = { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${accessToken}`, + 'Host': 'api.am.wso2.com' + }; + + try { + const response = await instance.delete(`${Settings.app.rest_api}/organizations/${organizationId}`, { + headers: headers + }); + res.status(200).json({ message: "Successfully deleted" }); + } catch (error) { + console.log(error); + res.status(500).json({ code: error.code, error: error.message }); + } +}); + +router.put('/admin/organizations/:organizationId', async function (req, res, next) { + const organizationId = req.params.organizationId; + const accessToken = req.cookies.access_token; + + const instance = axios.create({ + httpsAgent: new https.Agent({ + rejectUnauthorized: false + }) + }); + const headers = { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${accessToken}`, + 'Host': 'api.am.wso2.com' + }; + + try { + const response = await instance.put(`${Settings.app.rest_api}/organizations/${organizationId}`, req.body, { + headers: headers + }); + const data = response.data; + res.status(200).json(data); + } catch (error) { + console.log(error); + res.status(500).json({ code: error.code, error: error.message }); + } +}); + +router.get('/admin/organizations/:organizationId', async function (req, res, next) { + const organizationId = req.params.organizationId; + const accessToken = req.cookies.access_token; + + const instance = axios.create({ + httpsAgent: new https.Agent({ + rejectUnauthorized: false + }) + }); + const headers = { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${accessToken}`, + 'Host': 'api.am.wso2.com' + }; + try { + const response = await instance.get(`${Settings.app.rest_api}/organizations/${organizationId}`, { + headers: headers + }); + const data = response.data; + res.status(200).json(data); + } catch (error) { + console.log(error); + res.status(500).json({ error: error.message }); + } +}); + +router.get('/am/admin/key-managers', async function (req, res, next) { + const accessToken = req.cookies.access_token; + + const instance = axios.create({ + httpsAgent: new https.Agent({ + rejectUnauthorized: false + }) + }); + const headers = { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${accessToken}`, + 'Host': 'api.am.wso2.com' + }; + try { + const response = await instance.get(`${Settings.app.rest_api}/key-managers`, { + headers: headers + }); + const data = response.data; + res.status(200).json(data); + } catch (error) { + console.log(error); + res.status(500).json({ error: error.message }); + } +}); + +router.delete('/am/admin/key-managers/:keyManagerId', async function (req, res, next) { + const keyManagerId = req.params.keyManagerId; + const accessToken = req.cookies.access_token; + + const instance = axios.create({ + httpsAgent: new https.Agent({ + rejectUnauthorized: false + }) + }); + const headers = { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${accessToken}`, + 'Host': 'api.am.wso2.com' + }; + + try { + const response = await instance.delete(`${Settings.app.rest_api}/key-managers/${keyManagerId}`, { + headers: headers + }); + res.status(200).json({ message: "Successfully deleted" }); + } catch (error) { + console.log(error); + res.status(500).json({ code: error.code, error: error.message }); + } +}); + + +module.exports = router; diff --git a/admin/admin-ui/server/routes/index.js b/admin/admin-ui/server/routes/index.js new file mode 100644 index 000000000..ecca96a56 --- /dev/null +++ b/admin/admin-ui/server/routes/index.js @@ -0,0 +1,9 @@ +var express = require('express'); +var router = express.Router(); + +/* GET home page. */ +router.get('/', function(req, res, next) { + res.render('index', { title: 'Express' }); +}); + +module.exports = router; diff --git a/admin/admin-ui/server/routes/serviceRouters.js b/admin/admin-ui/server/routes/serviceRouters.js new file mode 100644 index 000000000..fb732ee14 --- /dev/null +++ b/admin/admin-ui/server/routes/serviceRouters.js @@ -0,0 +1,20 @@ +var express = require('express'); +var router = express.Router(); +const axios = require('axios'); +const https = require('https'); +const jwt = require('jsonwebtoken'); + +const Settings = require('../../client/public/conf/Settings.js'); + +/* GET users listing. */ +router.get('/update-token', async function (req, res, next) { + try { + res.send('respond with a resource'); + } catch (error) { + console.log("Logging the error", error); + next(error); + } +}); + + +module.exports = router; diff --git a/admin/admin-ui/server/routes/tokenRoutes.js b/admin/admin-ui/server/routes/tokenRoutes.js new file mode 100644 index 000000000..e1cf1d145 --- /dev/null +++ b/admin/admin-ui/server/routes/tokenRoutes.js @@ -0,0 +1,69 @@ +var express = require('express'); +var router = express.Router(); +const axios = require('axios'); +const https = require('https'); +const jwt = require('jsonwebtoken'); + +const Settings = require('../../client/public/conf/Settings.js'); + +/* GET users listing. */ +router.get('/', async function (req, res, next) { + process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; + const instance = axios.create({ + httpsAgent: new https.Agent({ + rejectUnauthorized: false + }) + }); + + // Disables SSL verification + // TODO we need to get this client_secret from an Environment variable + /* eslint-disable no-undef */ + const base64EncodedKeyAndSecret = Buffer.from(`${Settings.idp.client_id}:${Settings.idp.client_secret}`).toString('base64'); + // /Send post request to authorization endpoint get the token + const tokenRequestPayload = { + grant_type: 'authorization_code', + code: req.query.code, + redirect_uri: `${Settings.idp.redirect_uri}/token`, + client_id: Settings.idp.client_id + }; + const headers = { + 'Content-Type': 'application/x-www-form-urlencoded', + 'Authorization': `Basic ${base64EncodedKeyAndSecret}`, + 'Host': Settings.idp.host, + }; + try { + console.log('sending token request to', Settings.idp.token_endpoint); + const response = await instance.post(Settings.idp.token_endpoint, tokenRequestPayload, { + headers: headers + }); + const data = response.data; + console.log(data); + const { access_token, expires_in, refresh_token } = data; + const cookieOptions = { + httpOnly: true, + maxAge: expires_in * 1000, // expires_in is the token expiration time in seconds + sameSite: 'strict', + secure: true, //process.env.NODE_ENV === 'production' // Set to true in production + }; + res.cookie('access_token', access_token, cookieOptions); + // decode the token and print the fields + const decodedToken = jwt.decode(access_token, { complete: true }); + + // Extract the fields from the decoded token + const { header, payload } = decodedToken; + const { iss, sub, exp } = payload; + + console.log('Header:', header); + console.log('Issuer:', iss); + console.log('Subject:', sub); + console.log('Expiration Time:', new Date(exp * 1000)); + // redirect to the home page + res.redirect(`/?user=${sub}&exp=${exp}`); + } catch (error) { + console.log("Logging the error", error); + next(error); + } +}); + + +module.exports = router; diff --git a/admin/admin-ui/server/tmpCerts/cert.pem b/admin/admin-ui/server/tmpCerts/cert.pem new file mode 100644 index 000000000..c431a866d --- /dev/null +++ b/admin/admin-ui/server/tmpCerts/cert.pem @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIIC/DCCAeQCCQDN6ihkplbBejANBgkqhkiG9w0BAQUFADA/MQ0wCwYDVQQKDAR3 +c28yMQ0wCwYDVQQLDARhcGltMR8wHQYJKoZIhvcNAQkBFhBjaGFuYWthQHdzbzIu +Y29tMCAXDTIyMDkzMDExNDAwNFoYDzIwNTAwMjE0MTE0MDA0WjA/MQ0wCwYDVQQK +DAR3c28yMQ0wCwYDVQQLDARhcGltMR8wHQYJKoZIhvcNAQkBFhBjaGFuYWthQHdz +bzIuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwoPL8WtTxV03 +crnfaHj5MnR3DNb+vIlGu4uYuznnSDgT0jjaIVs1pX1xU843PWarBo+XpItZ7Apc +tk1Btgwe9ojePTCifsvcr954WjSbtMOOXqXo0nbSZNcYUwWNKYjKboYO0QB1HEfp +/YwomI89OW5EOuA8VnffSygw2cWBg68OckCu6CmOZ6B61TIEaAJQH2l4NXlaUmfk +fpvAGsuI9XeU8HbQMq4lRlNySgEgY1KuUojp7Yg6d88HD9z6vjd3ViUn1udJJiF/ +3EUyt5Ewq2eKwmIHRfJseoghAULEGSgj8USfwy9XWeO/BCvOLqqSgSjJvtuNAxNP +rF+Su6ENJQIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQBFgxCGoECgYW+YxMFoJRoV +UNR5r62pULY04Ebf/QlW0kPMAY45uOn10h8tvY1ev1zC2m+yg3/AfBvaSorfgGtT +WCwMlCmKZwHmb8MRZRSvq7JXgXFqtPeWQShuxfraC2E6+lQX3cysouYYywzqMd98 +OlCQBNL5em6cpv/nqoUcccpd51sEbvJGLTL4s7hsvWcdQ6XCBrJLoFMgsPwmaBWZ +K+JiheLGH36PpiAcT+hF8In56HDbO8dseNbLvBMPdn/amm6akUXNG/mDnYNBqKmu +vKsMM6siT17C+wWju4hzfoiwOCi3kDT4vkCesp/Pi4+rJEGkJ8V1nGW29+Bgpgth +-----END CERTIFICATE----- diff --git a/admin/admin-ui/server/tmpCerts/csr.pem b/admin/admin-ui/server/tmpCerts/csr.pem new file mode 100644 index 000000000..de7dad8bd --- /dev/null +++ b/admin/admin-ui/server/tmpCerts/csr.pem @@ -0,0 +1,16 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIICmTCCAYECAQAwPzENMAsGA1UECgwEd3NvMjENMAsGA1UECwwEYXBpbTEfMB0G +CSqGSIb3DQEJARYQY2hhbmFrYUB3c28yLmNvbTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBAMKDy/FrU8VdN3K532h4+TJ0dwzW/ryJRruLmLs550g4E9I4 +2iFbNaV9cVPONz1mqwaPl6SLWewKXLZNQbYMHvaI3j0won7L3K/eeFo0m7TDjl6l +6NJ20mTXGFMFjSmIym6GDtEAdRxH6f2MKJiPPTluRDrgPFZ330soMNnFgYOvDnJA +rugpjmegetUyBGgCUB9peDV5WlJn5H6bwBrLiPV3lPB20DKuJUZTckoBIGNSrlKI +6e2IOnfPBw/c+r43d1YlJ9bnSSYhf9xFMreRMKtnisJiB0XybHqIIQFCxBkoI/FE +n8MvV1njvwQrzi6qkoEoyb7bjQMTT6xfkruhDSUCAwEAAaAVMBMGCSqGSIb3DQEJ +BzEGDARhcGltMA0GCSqGSIb3DQEBCwUAA4IBAQAJaj0XzGs0RyLuSFFzxl1IK0RS +emWVDkOcjiAv69zEzNhpxTbNZoBExx2jZJkTX2mGO0+BPTUFdF4HkHkvD6x5IDIh +SvfG/4XUZEKE1UBVqCgDKyPbYAmd58IPkJwLUjSnrRoBJuiTOzh0dGE02OBwMV3n +NPjps7KIzHMT7u498ta514/teEjxV+OH9uad+PEqxTZGXjljqViuy8MpUgPOBgQW +r/AVmVjPRD1/tyksSAxNn1N+6nIdVCXmnXF5HWIcbwlxORO17JK0NX5cg0pS7f51 +dSKN8Tw/3jcbtKvl1Qy+1JRCc6vYlTTL7HYy+wXIGyexPDeQ61vjmLf+3GdQ +-----END CERTIFICATE REQUEST----- diff --git a/admin/admin-ui/server/tmpCerts/key.pem b/admin/admin-ui/server/tmpCerts/key.pem new file mode 100644 index 000000000..8754f54bb --- /dev/null +++ b/admin/admin-ui/server/tmpCerts/key.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAwoPL8WtTxV03crnfaHj5MnR3DNb+vIlGu4uYuznnSDgT0jja +IVs1pX1xU843PWarBo+XpItZ7Apctk1Btgwe9ojePTCifsvcr954WjSbtMOOXqXo +0nbSZNcYUwWNKYjKboYO0QB1HEfp/YwomI89OW5EOuA8VnffSygw2cWBg68OckCu +6CmOZ6B61TIEaAJQH2l4NXlaUmfkfpvAGsuI9XeU8HbQMq4lRlNySgEgY1KuUojp +7Yg6d88HD9z6vjd3ViUn1udJJiF/3EUyt5Ewq2eKwmIHRfJseoghAULEGSgj8USf +wy9XWeO/BCvOLqqSgSjJvtuNAxNPrF+Su6ENJQIDAQABAoIBACWMYZMR39Lqgqif +3tOA/sHRn6WX3wawDTpo4SvLKq1TPehH1zu3KqzugTDnTtyIdB1JHMHDsLES8wCx ++yxUPKnkk9oGCGgnnEtKy7rGCwSi91mn90ChdU3IA8cK/Ev3PvSE5llMGE9ERpQO +OUvx4qSyd3NSE/OxIiaU9JElQjIUAyHpfKxkg24HfFZ/4DcofZnYZOP/0NA/iHj5 +hilVQC33dCsFOGC9IMtZUoXPvIrbsJnlNLca1zDJd/gnd4cPXV//qeN14sKiXvIF +/8lVN6IPBdJZtodbjAsVeLKXyzoGDiGOfFnYzobg1uhrNs7Qauk/YTH+gh1kP6js +JH59GiUCgYEA+lK1jnFzif2OhyKgbinpsuOnYTmXQm7Op4B8bkboplA+LL/PwmA8 +WUk80/jYFW5sAkHq6+dcqJFdzvf/ppQw5DvBjTc+VYJRxJTW9m2Y+3WdP3TIY4si +mZ/jCPajIUNnjsQSAHc0Rj1Zu6dmOWukDlnxsijzU/ILwZD1841o3bcCgYEAxu0V +bMtu+UtF+FodYT61i7kOi4hic4Osz8qVG6j1VGzvtNUuE+ntgZfTyHHbEWuEZiOk +ebztLX+2l244mPmAxLFtLX2mCIhekAcVKZWmhIH2u92vzMlHWNIn4XcD97TiT/A3 +LVf6Kz3wyzlGsxgm4OEX1ue5uCsGXDPmz40NLAMCgYEAtIkmTB9itujZ/HhqwEkW +NWCe/S3t+4mzHXc7RsV5UUmaLegAzS1fGP4LEs3r+jjzSQWFirIIT8LXp0eRZ/CE ++nZmd5SaLk2Y73BxQLV2mhUPXg6536EfSTDZK0PGD11vuLWMTi2q0+W3a/GldlA9 +t+QCvv1t0ONGu0nzOL6KHS0CgYB4IphM0vMbNR11ph6WKwQC9OjW1a/3aS9Fcmfo +g3pd2UhOomwodJ8OI74wEKqnc5JLCP180989GiMQgu1FXXEp2KlBzt8lyg2p180t +BwbAgaibvn88ItamyoxxOqo3v5Lpif4YsUgRM2Anq1iKMmzQZMA79kgP9FPr/SBI +ejvZNwKBgHGBtH0VYjSf4wXZDRg/1WSBvntF5bHf4CeIdRw7SFiyeN95POPFVcU5 +Re7aixAuDpKLpYcRnTnM3dTONuJ95hair095Q4LAJb+olkW1iuwzYSu3u7FvWRi7 +EUrj4IOFQU4y+bt25pemXBP/7q0oZjWBwoiDYt1TqfTDhmDdUsZM +-----END RSA PRIVATE KEY----- diff --git a/admin/admin-ui/tsconfig.json b/admin/admin-ui/tsconfig.json new file mode 100644 index 000000000..7a6558150 --- /dev/null +++ b/admin/admin-ui/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "module": "ESNext", + "skipLibCheck": true, + "esModuleInterop": true, + "resolveJsonModule": true, + "outDir": "./dist/", + "sourceMap": true, + "noImplicitThis": true, + "strictNullChecks": true, + "target": "ES6", + "jsx": "react", + "allowJs": true, + "moduleResolution": "node", + "allowSyntheticDefaultImports": true, + "baseUrl": "./client/source", + "typeRoots": [ + "node_modules/@types" + ], + }, + "exclude": [ + "node_modules", + "client/public/build" + ] +} \ No newline at end of file diff --git a/admin/admin-ui/webpack.config.js b/admin/admin-ui/webpack.config.js new file mode 100644 index 000000000..63931ace7 --- /dev/null +++ b/admin/admin-ui/webpack.config.js @@ -0,0 +1,96 @@ +const HtmlWebpackPlugin = require('html-webpack-plugin'); +const path = require('path'); + +module.exports = (env) => { + // const env = dotenv.config().parsed; + + // // reduce it to a nice object, the same as before + // const envKeys = Object.keys(env).reduce((prev, next) => { + // prev[`process.env.${next}`] = JSON.stringify(env[next]); + // return prev; + // }, {}); + const devConfig = { + entry: { + main: path.resolve(__dirname, './client/source/index.tsx'), + }, + module: { + rules: [ + { + test: /\.(js|jsx)$/, + exclude: /node_modules/, + use: { + loader: 'babel-loader', + options: { + presets: ['@babel/preset-react', '@babel/preset-env'] + } + }, + }, + { + test: /\.(ts|tsx)$/, + use: 'ts-loader', + exclude: /node_modules/, + }, + { + test: /\.css$/, + use: ['style-loader', 'css-loader'] + }, + { + test: /\.(woff|woff2|ttf|eot|png|jpg|svg|gif)$/i, + use: ['file-loader'] + } + ] + }, + output: { + filename: '[name].bundle.js', + path: path.resolve(__dirname, './client/public/build'), + }, + optimization: { + splitChunks: { + chunks: 'all', + }, + }, + plugins: [ + new HtmlWebpackPlugin({ + title: 'WSO2 API Manager', + // Load a custom template (lodash by default) + template: './client/pages/index.html', + publicPath: '/build', + templateParameters: { env: env.production ? 'production': 'development'}, + }) + ], + resolve: { + alias: { + assets: path.resolve(__dirname, 'client/source/assets'), + auth: path.resolve(__dirname, 'client/source/auth'), + components: path.resolve(__dirname, 'client/source/components'), + context: path.resolve(__dirname, 'client/source/context'), + layout: path.resolve(__dirname, 'client/source/layout'), + 'menu-items': path.resolve(__dirname, 'client/source/menu-items'), + pages: path.resolve(__dirname, 'client/source/pages'), + routes: path.resolve(__dirname, 'client/source/routes'), + themes: path.resolve(__dirname, 'client/source/themes'), + types: path.resolve(__dirname, 'client/source/types'), + config: path.resolve(__dirname, 'client/source/config.ts'), + + // For the old UIs + client: path.resolve(__dirname, 'client/src'), + AppData: path.resolve(__dirname, 'client/source/data/'), + }, + extensions: ['.tsx', '.ts', '.js', '.jsx'], + }, + externals: { + Settings: 'Settings', + }, + devtool: 'source-map', + } + if (env.production) { + return { + ...devConfig + } + } else { + return { + mode: 'development', + ...devConfig + } + } +}; \ No newline at end of file diff --git a/admin/admin-ui/yarn.lock b/admin/admin-ui/yarn.lock new file mode 100644 index 000000000..0f516ccfc --- /dev/null +++ b/admin/admin-ui/yarn.lock @@ -0,0 +1,6468 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@ampproject/remapping@^2.1.0": + "integrity" "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==" + "resolved" "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz" + "version" "2.2.0" + dependencies: + "@jridgewell/gen-mapping" "^0.1.0" + "@jridgewell/trace-mapping" "^0.3.9" + +"@ant-design/colors@^6.0.0": + "integrity" "sha512-qAZRvPzfdWHtfameEGP2Qvuf838NhergR35o+EuVyB5XvSA98xod5r4utvi4TJ3ywmevm290g9nsCG5MryrdWQ==" + "resolved" "https://registry.npmjs.org/@ant-design/colors/-/colors-6.0.0.tgz" + "version" "6.0.0" + dependencies: + "@ctrl/tinycolor" "^3.4.0" + +"@ant-design/colors@^7.0.0": + "integrity" "sha512-iVm/9PfGCbC0dSMBrz7oiEXZaaGH7ceU40OJEfKmyuzR9R5CRimJYPlRiFtMQGQcbNMea/ePcoIebi4ASGYXtg==" + "resolved" "https://registry.npmjs.org/@ant-design/colors/-/colors-7.0.0.tgz" + "version" "7.0.0" + dependencies: + "@ctrl/tinycolor" "^3.4.0" + +"@ant-design/icons-svg@^4.2.1": + "integrity" "sha512-EB0iwlKDGpG93hW8f85CTJTs4SvMX7tt5ceupvhALp1IF44SeUFOMhKUOYqpsoYWQKAOuTRDMqn75rEaKDp0Xw==" + "resolved" "https://registry.npmjs.org/@ant-design/icons-svg/-/icons-svg-4.2.1.tgz" + "version" "4.2.1" + +"@ant-design/icons@^5.0.1": + "integrity" "sha512-ZyF4ksXCcdtwA/1PLlnFLcF/q8/MhwxXhKHh4oCHDA4Ip+ZzAHoICtyp4wZWfiCVDP0yuz3HsjyvuldHFb3wjA==" + "resolved" "https://registry.npmjs.org/@ant-design/icons/-/icons-5.0.1.tgz" + "version" "5.0.1" + dependencies: + "@ant-design/colors" "^7.0.0" + "@ant-design/icons-svg" "^4.2.1" + "@babel/runtime" "^7.11.2" + "classnames" "^2.2.6" + "rc-util" "^5.9.4" + +"@auth0/auth0-react@^1.11.0": + "integrity" "sha512-Cny2RyHvr0GrKKKV8PMh6GU0vkWNSgd6mp/YHYJynnYCs9yFduNo9hdpHPxXbdDX5CB6wc2PqK6aL8leDlnl/A==" + "resolved" "https://registry.npmjs.org/@auth0/auth0-react/-/auth0-react-1.12.0.tgz" + "version" "1.12.0" + dependencies: + "@auth0/auth0-spa-js" "^1.22.4" + +"@auth0/auth0-spa-js@^1.22.4": + "integrity" "sha512-6gaQcd+Eb8ZBcdQkrrm9undM7dY/rPvVdQN8s7rxxrviUCs7OopEygsfSkHf67IP4HtlCiE8dSW5/AipRUOw/A==" + "resolved" "https://registry.npmjs.org/@auth0/auth0-spa-js/-/auth0-spa-js-1.22.5.tgz" + "version" "1.22.5" + dependencies: + "abortcontroller-polyfill" "^1.7.3" + "browser-tabs-lock" "^1.2.15" + "core-js" "^3.25.1" + "es-cookie" "~1.3.2" + "fast-text-encoding" "^1.0.6" + "promise-polyfill" "^8.2.3" + "unfetch" "^4.2.0" + +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.18.6": + "integrity" "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==" + "resolved" "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/highlight" "^7.18.6" + +"@babel/compat-data@^7.17.7", "@babel/compat-data@^7.19.3", "@babel/compat-data@^7.19.4": + "integrity" "sha512-CHIGpJcUQ5lU9KrPHTjBMhVwQG6CQjxfg36fGXl3qk/Gik1WwWachaXFuo0uCWJT/mStOKtcbFJCaVLihC1CMw==" + "resolved" "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.19.4.tgz" + "version" "7.19.4" + +"@babel/core@^7.0.0", "@babel/core@^7.0.0-0", "@babel/core@^7.12.0", "@babel/core@^7.13.0", "@babel/core@^7.19.3", "@babel/core@^7.4.0-0": + "integrity" "sha512-D2Ue4KHpc6Ys2+AxpIx1BZ8+UegLLLE2p3KJEuJRKmokHOtl49jQ5ny1773KsGLZs8MQvBidAF6yWUJxRqtKtg==" + "resolved" "https://registry.npmjs.org/@babel/core/-/core-7.19.6.tgz" + "version" "7.19.6" + dependencies: + "@ampproject/remapping" "^2.1.0" + "@babel/code-frame" "^7.18.6" + "@babel/generator" "^7.19.6" + "@babel/helper-compilation-targets" "^7.19.3" + "@babel/helper-module-transforms" "^7.19.6" + "@babel/helpers" "^7.19.4" + "@babel/parser" "^7.19.6" + "@babel/template" "^7.18.10" + "@babel/traverse" "^7.19.6" + "@babel/types" "^7.19.4" + "convert-source-map" "^1.7.0" + "debug" "^4.1.0" + "gensync" "^1.0.0-beta.2" + "json5" "^2.2.1" + "semver" "^6.3.0" + +"@babel/generator@^7.19.6": + "integrity" "sha512-oHGRUQeoX1QrKeJIKVe0hwjGqNnVYsM5Nep5zo0uE0m42sLH+Fsd2pStJ5sRM1bNyTUUoz0pe2lTeMJrb/taTA==" + "resolved" "https://registry.npmjs.org/@babel/generator/-/generator-7.19.6.tgz" + "version" "7.19.6" + dependencies: + "@babel/types" "^7.19.4" + "@jridgewell/gen-mapping" "^0.3.2" + "jsesc" "^2.5.1" + +"@babel/helper-annotate-as-pure@^7.18.6": + "integrity" "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==" + "resolved" "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-builder-binary-assignment-operator-visitor@^7.18.6": + "integrity" "sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw==" + "resolved" "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.18.9.tgz" + "version" "7.18.9" + dependencies: + "@babel/helper-explode-assignable-expression" "^7.18.6" + "@babel/types" "^7.18.9" + +"@babel/helper-compilation-targets@^7.17.7", "@babel/helper-compilation-targets@^7.18.9", "@babel/helper-compilation-targets@^7.19.0", "@babel/helper-compilation-targets@^7.19.3": + "integrity" "sha512-65ESqLGyGmLvgR0mst5AdW1FkNlj9rQsCKduzEoEPhBCDFGXvz2jW6bXFG6i0/MrV2s7hhXjjb2yAzcPuQlLwg==" + "resolved" "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.19.3.tgz" + "version" "7.19.3" + dependencies: + "@babel/compat-data" "^7.19.3" + "@babel/helper-validator-option" "^7.18.6" + "browserslist" "^4.21.3" + "semver" "^6.3.0" + +"@babel/helper-create-class-features-plugin@^7.18.6", "@babel/helper-create-class-features-plugin@^7.19.0": + "integrity" "sha512-NRz8DwF4jT3UfrmUoZjd0Uph9HQnP30t7Ash+weACcyNkiYTywpIjDBgReJMKgr+n86sn2nPVVmJ28Dm053Kqw==" + "resolved" "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.19.0.tgz" + "version" "7.19.0" + 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.18.9" + "@babel/helper-optimise-call-expression" "^7.18.6" + "@babel/helper-replace-supers" "^7.18.9" + "@babel/helper-split-export-declaration" "^7.18.6" + +"@babel/helper-create-regexp-features-plugin@^7.18.6", "@babel/helper-create-regexp-features-plugin@^7.19.0": + "integrity" "sha512-htnV+mHX32DF81amCDrwIDr8nrp1PTm+3wfBN9/v8QJOLEioOCOG7qNyq0nHeFiWbT3Eb7gsPwEmV64UCQ1jzw==" + "resolved" "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.19.0.tgz" + "version" "7.19.0" + dependencies: + "@babel/helper-annotate-as-pure" "^7.18.6" + "regexpu-core" "^5.1.0" + +"@babel/helper-define-polyfill-provider@^0.3.3": + "integrity" "sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==" + "resolved" "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz" + "version" "0.3.3" + 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" + +"@babel/helper-environment-visitor@^7.18.9": + "integrity" "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==" + "resolved" "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz" + "version" "7.18.9" + +"@babel/helper-explode-assignable-expression@^7.18.6": + "integrity" "sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg==" + "resolved" "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-function-name@^7.18.9", "@babel/helper-function-name@^7.19.0": + "integrity" "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==" + "resolved" "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz" + "version" "7.19.0" + dependencies: + "@babel/template" "^7.18.10" + "@babel/types" "^7.19.0" + +"@babel/helper-hoist-variables@^7.18.6": + "integrity" "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==" + "resolved" "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-member-expression-to-functions@^7.18.9": + "integrity" "sha512-RxifAh2ZoVU67PyKIO4AMi1wTenGfMR/O/ae0CCRqwgBAt5v7xjdtRw7UoSbsreKrQn5t7r89eruK/9JjYHuDg==" + "resolved" "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.18.9.tgz" + "version" "7.18.9" + dependencies: + "@babel/types" "^7.18.9" + +"@babel/helper-module-imports@^7.16.7", "@babel/helper-module-imports@^7.18.6": + "integrity" "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==" + "resolved" "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-module-transforms@^7.18.6", "@babel/helper-module-transforms@^7.19.6": + "integrity" "sha512-fCmcfQo/KYr/VXXDIyd3CBGZ6AFhPFy1TfSEJ+PilGVlQT6jcbqtHAM4C1EciRqMza7/TpOUZliuSH+U6HAhJw==" + "resolved" "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.19.6.tgz" + "version" "7.19.6" + dependencies: + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-module-imports" "^7.18.6" + "@babel/helper-simple-access" "^7.19.4" + "@babel/helper-split-export-declaration" "^7.18.6" + "@babel/helper-validator-identifier" "^7.19.1" + "@babel/template" "^7.18.10" + "@babel/traverse" "^7.19.6" + "@babel/types" "^7.19.4" + +"@babel/helper-optimise-call-expression@^7.18.6": + "integrity" "sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==" + "resolved" "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.16.7", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.18.9", "@babel/helper-plugin-utils@^7.19.0", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": + "integrity" "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==" + "resolved" "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz" + "version" "7.19.0" + +"@babel/helper-remap-async-to-generator@^7.18.6", "@babel/helper-remap-async-to-generator@^7.18.9": + "integrity" "sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA==" + "resolved" "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz" + "version" "7.18.9" + 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" + +"@babel/helper-replace-supers@^7.18.6", "@babel/helper-replace-supers@^7.18.9": + "integrity" "sha512-T7ahH7wV0Hfs46SFh5Jz3s0B6+o8g3c+7TMxu7xKfmHikg7EAZ3I2Qk9LFhjxXq8sL7UkP5JflezNwoZa8WvWw==" + "resolved" "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.19.1.tgz" + "version" "7.19.1" + dependencies: + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-member-expression-to-functions" "^7.18.9" + "@babel/helper-optimise-call-expression" "^7.18.6" + "@babel/traverse" "^7.19.1" + "@babel/types" "^7.19.0" + +"@babel/helper-simple-access@^7.19.4": + "integrity" "sha512-f9Xq6WqBFqaDfbCzn2w85hwklswz5qsKlh7f08w4Y9yhJHpnNC0QemtSkK5YyOY8kPGvyiwdzZksGUhnGdaUIg==" + "resolved" "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.19.4.tgz" + "version" "7.19.4" + dependencies: + "@babel/types" "^7.19.4" + +"@babel/helper-skip-transparent-expression-wrappers@^7.18.9": + "integrity" "sha512-imytd2gHi3cJPsybLRbmFrF7u5BIEuI2cNheyKi3/iOBC63kNn3q8Crn2xVuESli0aM4KYsyEqKyS7lFL8YVtw==" + "resolved" "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.18.9.tgz" + "version" "7.18.9" + dependencies: + "@babel/types" "^7.18.9" + +"@babel/helper-split-export-declaration@^7.18.6": + "integrity" "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==" + "resolved" "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-string-parser@^7.19.4": + "integrity" "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==" + "resolved" "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz" + "version" "7.19.4" + +"@babel/helper-validator-identifier@^7.18.6", "@babel/helper-validator-identifier@^7.19.1": + "integrity" "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==" + "resolved" "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz" + "version" "7.19.1" + +"@babel/helper-validator-option@^7.18.6": + "integrity" "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==" + "resolved" "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz" + "version" "7.18.6" + +"@babel/helper-wrap-function@^7.18.9": + "integrity" "sha512-txX8aN8CZyYGTwcLhlk87KRqncAzhh5TpQamZUa0/u3an36NtDpUP6bQgBCBcLeBs09R/OwQu3OjK0k/HwfNDg==" + "resolved" "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.19.0.tgz" + "version" "7.19.0" + dependencies: + "@babel/helper-function-name" "^7.19.0" + "@babel/template" "^7.18.10" + "@babel/traverse" "^7.19.0" + "@babel/types" "^7.19.0" + +"@babel/helpers@^7.19.4": + "integrity" "sha512-G+z3aOx2nfDHwX/kyVii5fJq+bgscg89/dJNWpYeKeBv3v9xX8EIabmx1k6u9LS04H7nROFVRVK+e3k0VHp+sw==" + "resolved" "https://registry.npmjs.org/@babel/helpers/-/helpers-7.19.4.tgz" + "version" "7.19.4" + dependencies: + "@babel/template" "^7.18.10" + "@babel/traverse" "^7.19.4" + "@babel/types" "^7.19.4" + +"@babel/highlight@^7.18.6": + "integrity" "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==" + "resolved" "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/helper-validator-identifier" "^7.18.6" + "chalk" "^2.0.0" + "js-tokens" "^4.0.0" + +"@babel/parser@^7.18.10", "@babel/parser@^7.19.6": + "integrity" "sha512-h1IUp81s2JYJ3mRkdxJgs4UvmSsRvDrx5ICSJbPvtWYv5i1nTBGcBpnog+89rAFMwvvru6E5NUHdBe01UeSzYA==" + "resolved" "https://registry.npmjs.org/@babel/parser/-/parser-7.19.6.tgz" + "version" "7.19.6" + +"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.18.6": + "integrity" "sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==" + "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" + "version" "7.18.6" + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.18.9": + "integrity" "sha512-AHrP9jadvH7qlOj6PINbgSuphjQUAK7AOT7DPjBo9EHoLhQTnnK5u45e1Hd4DbSQEO9nqPWtQ89r+XEOWFScKg==" + "resolved" "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.18.9.tgz" + "version" "7.18.9" + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + "@babel/helper-skip-transparent-expression-wrappers" "^7.18.9" + "@babel/plugin-proposal-optional-chaining" "^7.18.9" + +"@babel/plugin-proposal-async-generator-functions@^7.19.1": + "integrity" "sha512-0yu8vNATgLy4ivqMNBIwb1HebCelqN7YX8SL3FDXORv/RqT0zEEWUCH4GH44JsSrvCu6GqnAdR5EBFAPeNBB4Q==" + "resolved" "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.19.1.tgz" + "version" "7.19.1" + dependencies: + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-plugin-utils" "^7.19.0" + "@babel/helper-remap-async-to-generator" "^7.18.9" + "@babel/plugin-syntax-async-generators" "^7.8.4" + +"@babel/plugin-proposal-class-properties@^7.18.6": + "integrity" "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==" + "resolved" "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/helper-create-class-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-proposal-class-static-block@^7.18.6": + "integrity" "sha512-+I3oIiNxrCpup3Gi8n5IGMwj0gOCAjcJUSQEcotNnCCPMEnixawOQ+KeJPlgfjzx+FKQ1QSyZOWe7wmoJp7vhw==" + "resolved" "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/helper-create-class-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + +"@babel/plugin-proposal-dynamic-import@^7.18.6": + "integrity" "sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw==" + "resolved" "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/plugin-syntax-dynamic-import" "^7.8.3" + +"@babel/plugin-proposal-export-namespace-from@^7.18.9": + "integrity" "sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==" + "resolved" "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz" + "version" "7.18.9" + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + "@babel/plugin-syntax-export-namespace-from" "^7.8.3" + +"@babel/plugin-proposal-json-strings@^7.18.6": + "integrity" "sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ==" + "resolved" "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/plugin-syntax-json-strings" "^7.8.3" + +"@babel/plugin-proposal-logical-assignment-operators@^7.18.9": + "integrity" "sha512-128YbMpjCrP35IOExw2Fq+x55LMP42DzhOhX2aNNIdI9avSWl2PI0yuBWarr3RYpZBSPtabfadkH2yeRiMD61Q==" + "resolved" "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.18.9.tgz" + "version" "7.18.9" + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + +"@babel/plugin-proposal-nullish-coalescing-operator@^7.18.6": + "integrity" "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==" + "resolved" "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + +"@babel/plugin-proposal-numeric-separator@^7.18.6": + "integrity" "sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==" + "resolved" "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + +"@babel/plugin-proposal-object-rest-spread@^7.19.4": + "integrity" "sha512-wHmj6LDxVDnL+3WhXteUBaoM1aVILZODAUjg11kHqG4cOlfgMQGxw6aCgvrXrmaJR3Bn14oZhImyCPZzRpC93Q==" + "resolved" "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.19.4.tgz" + "version" "7.19.4" + dependencies: + "@babel/compat-data" "^7.19.4" + "@babel/helper-compilation-targets" "^7.19.3" + "@babel/helper-plugin-utils" "^7.19.0" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-transform-parameters" "^7.18.8" + +"@babel/plugin-proposal-optional-catch-binding@^7.18.6": + "integrity" "sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==" + "resolved" "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + +"@babel/plugin-proposal-optional-chaining@^7.18.9": + "integrity" "sha512-v5nwt4IqBXihxGsW2QmCWMDS3B3bzGIk/EQVZz2ei7f3NJl8NzAJVvUmpDW5q1CRNY+Beb/k58UAH1Km1N411w==" + "resolved" "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.18.9.tgz" + "version" "7.18.9" + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + "@babel/helper-skip-transparent-expression-wrappers" "^7.18.9" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + +"@babel/plugin-proposal-private-methods@^7.18.6": + "integrity" "sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==" + "resolved" "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/helper-create-class-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-proposal-private-property-in-object@^7.18.6": + "integrity" "sha512-9Rysx7FOctvT5ouj5JODjAFAkgGoudQuLPamZb0v1TGLpapdNaftzifU8NTWQm0IRjqoYypdrSmyWgkocDQ8Dw==" + "resolved" "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/helper-annotate-as-pure" "^7.18.6" + "@babel/helper-create-class-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + +"@babel/plugin-proposal-unicode-property-regex@^7.18.6", "@babel/plugin-proposal-unicode-property-regex@^7.4.4": + "integrity" "sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==" + "resolved" "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-syntax-async-generators@^7.8.4": + "integrity" "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==" + "resolved" "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz" + "version" "7.8.4" + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-class-properties@^7.12.13": + "integrity" "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==" + "resolved" "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz" + "version" "7.12.13" + dependencies: + "@babel/helper-plugin-utils" "^7.12.13" + +"@babel/plugin-syntax-class-static-block@^7.14.5": + "integrity" "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==" + "resolved" "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz" + "version" "7.14.5" + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-dynamic-import@^7.8.3": + "integrity" "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==" + "resolved" "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz" + "version" "7.8.3" + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-export-namespace-from@^7.8.3": + "integrity" "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==" + "resolved" "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz" + "version" "7.8.3" + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-syntax-import-assertions@^7.18.6": + "integrity" "sha512-/DU3RXad9+bZwrgWJQKbr39gYbJpLJHezqEzRzi/BHRlJ9zsQb4CK2CA/5apllXNomwA1qHwzvHl+AdEmC5krQ==" + "resolved" "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-syntax-json-strings@^7.8.3": + "integrity" "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==" + "resolved" "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz" + "version" "7.8.3" + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-jsx@^7.17.12", "@babel/plugin-syntax-jsx@^7.18.6": + "integrity" "sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==" + "resolved" "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-syntax-logical-assignment-operators@^7.10.4": + "integrity" "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==" + "resolved" "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz" + "version" "7.10.4" + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": + "integrity" "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==" + "resolved" "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz" + "version" "7.8.3" + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-numeric-separator@^7.10.4": + "integrity" "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==" + "resolved" "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz" + "version" "7.10.4" + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-object-rest-spread@^7.8.3": + "integrity" "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==" + "resolved" "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz" + "version" "7.8.3" + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-catch-binding@^7.8.3": + "integrity" "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==" + "resolved" "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz" + "version" "7.8.3" + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-chaining@^7.8.3": + "integrity" "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==" + "resolved" "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz" + "version" "7.8.3" + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-private-property-in-object@^7.14.5": + "integrity" "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==" + "resolved" "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz" + "version" "7.14.5" + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-top-level-await@^7.14.5": + "integrity" "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==" + "resolved" "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz" + "version" "7.14.5" + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-typescript@^7.20.0": + "integrity" "sha512-rd9TkG+u1CExzS4SM1BlMEhMXwFLKVjOAFFCDx9PbX5ycJWDoWMcwdJH9RhkPu1dOgn5TrxLot/Gx6lWFuAUNQ==" + "resolved" "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.20.0.tgz" + "version" "7.20.0" + dependencies: + "@babel/helper-plugin-utils" "^7.19.0" + +"@babel/plugin-transform-arrow-functions@^7.18.6": + "integrity" "sha512-9S9X9RUefzrsHZmKMbDXxweEH+YlE8JJEuat9FdvW9Qh1cw7W64jELCtWNkPBPX5En45uy28KGvA/AySqUh8CQ==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-async-to-generator@^7.18.6": + "integrity" "sha512-ARE5wZLKnTgPW7/1ftQmSi1CmkqqHo2DNmtztFhvgtOWSDfq0Cq9/9L+KnZNYSNrydBekhW3rwShduf59RoXag==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/helper-module-imports" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-remap-async-to-generator" "^7.18.6" + +"@babel/plugin-transform-block-scoped-functions@^7.18.6": + "integrity" "sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-block-scoping@^7.19.4": + "integrity" "sha512-934S2VLLlt2hRJwPf4MczaOr4hYF0z+VKPwqTNxyKX7NthTiPfhuKFWQZHXRM0vh/wo/VyXB3s4bZUNA08l+tQ==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.19.4.tgz" + "version" "7.19.4" + dependencies: + "@babel/helper-plugin-utils" "^7.19.0" + +"@babel/plugin-transform-classes@^7.19.0": + "integrity" "sha512-YfeEE9kCjqTS9IitkgfJuxjcEtLUHMqa8yUJ6zdz8vR7hKuo6mOy2C05P0F1tdMmDCeuyidKnlrw/iTppHcr2A==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.19.0.tgz" + "version" "7.19.0" + dependencies: + "@babel/helper-annotate-as-pure" "^7.18.6" + "@babel/helper-compilation-targets" "^7.19.0" + "@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.19.0" + "@babel/helper-replace-supers" "^7.18.9" + "@babel/helper-split-export-declaration" "^7.18.6" + "globals" "^11.1.0" + +"@babel/plugin-transform-computed-properties@^7.18.9": + "integrity" "sha512-+i0ZU1bCDymKakLxn5srGHrsAPRELC2WIbzwjLhHW9SIE1cPYkLCL0NlnXMZaM1vhfgA2+M7hySk42VBvrkBRw==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.18.9.tgz" + "version" "7.18.9" + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + +"@babel/plugin-transform-destructuring@^7.19.4": + "integrity" "sha512-t0j0Hgidqf0aM86dF8U+vXYReUgJnlv4bZLsyoPnwZNrGY+7/38o8YjaELrvHeVfTZao15kjR0PVv0nju2iduA==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.19.4.tgz" + "version" "7.19.4" + dependencies: + "@babel/helper-plugin-utils" "^7.19.0" + +"@babel/plugin-transform-dotall-regex@^7.18.6", "@babel/plugin-transform-dotall-regex@^7.4.4": + "integrity" "sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-duplicate-keys@^7.18.9": + "integrity" "sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.9.tgz" + "version" "7.18.9" + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + +"@babel/plugin-transform-exponentiation-operator@^7.18.6": + "integrity" "sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/helper-builder-binary-assignment-operator-visitor" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-for-of@^7.18.8": + "integrity" "sha512-yEfTRnjuskWYo0k1mHUqrVWaZwrdq8AYbfrpqULOJOaucGSp4mNMVps+YtA8byoevxS/urwU75vyhQIxcCgiBQ==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.8.tgz" + "version" "7.18.8" + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-function-name@^7.18.9": + "integrity" "sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.9.tgz" + "version" "7.18.9" + dependencies: + "@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@^7.18.9": + "integrity" "sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.9.tgz" + "version" "7.18.9" + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + +"@babel/plugin-transform-member-expression-literals@^7.18.6": + "integrity" "sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-modules-amd@^7.18.6": + "integrity" "sha512-uG3od2mXvAtIFQIh0xrpLH6r5fpSQN04gIVovl+ODLdUMANokxQLZnPBHcjmv3GxRjnqwLuHvppjjcelqUFZvg==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.19.6.tgz" + "version" "7.19.6" + dependencies: + "@babel/helper-module-transforms" "^7.19.6" + "@babel/helper-plugin-utils" "^7.19.0" + +"@babel/plugin-transform-modules-commonjs@^7.18.6": + "integrity" "sha512-8PIa1ym4XRTKuSsOUXqDG0YaOlEuTVvHMe5JCfgBMOtHvJKw/4NGovEGN33viISshG/rZNVrACiBmPQLvWN8xQ==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.19.6.tgz" + "version" "7.19.6" + dependencies: + "@babel/helper-module-transforms" "^7.19.6" + "@babel/helper-plugin-utils" "^7.19.0" + "@babel/helper-simple-access" "^7.19.4" + +"@babel/plugin-transform-modules-systemjs@^7.19.0": + "integrity" "sha512-fqGLBepcc3kErfR9R3DnVpURmckXP7gj7bAlrTQyBxrigFqszZCkFkcoxzCp2v32XmwXLvbw+8Yq9/b+QqksjQ==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.19.6.tgz" + "version" "7.19.6" + dependencies: + "@babel/helper-hoist-variables" "^7.18.6" + "@babel/helper-module-transforms" "^7.19.6" + "@babel/helper-plugin-utils" "^7.19.0" + "@babel/helper-validator-identifier" "^7.19.1" + +"@babel/plugin-transform-modules-umd@^7.18.6": + "integrity" "sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/helper-module-transforms" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-named-capturing-groups-regex@^7.19.1": + "integrity" "sha512-oWk9l9WItWBQYS4FgXD4Uyy5kq898lvkXpXQxoJEY1RnvPk4R/Dvu2ebXU9q8lP+rlMwUQTFf2Ok6d78ODa0kw==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.19.1.tgz" + "version" "7.19.1" + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.19.0" + "@babel/helper-plugin-utils" "^7.19.0" + +"@babel/plugin-transform-new-target@^7.18.6": + "integrity" "sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-object-super@^7.18.6": + "integrity" "sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-replace-supers" "^7.18.6" + +"@babel/plugin-transform-parameters@^7.18.8": + "integrity" "sha512-ivfbE3X2Ss+Fj8nnXvKJS6sjRG4gzwPMsP+taZC+ZzEGjAYlvENixmt1sZ5Ca6tWls+BlKSGKPJ6OOXvXCbkFg==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.18.8.tgz" + "version" "7.18.8" + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-property-literals@^7.18.6": + "integrity" "sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-react-display-name@^7.18.6": + "integrity" "sha512-TV4sQ+T013n61uMoygyMRm+xf04Bd5oqFpv2jAEQwSZ8NwQA7zeRPg1LMVg2PWi3zWBz+CLKD+v5bcpZ/BS0aA==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-react-jsx-development@^7.18.6": + "integrity" "sha512-SA6HEjwYFKF7WDjWcMcMGUimmw/nhNRDWxr+KaLSCrkD/LMDBvWRmHAYgE1HDeF8KUuI8OAu+RT6EOtKxSW2qA==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/plugin-transform-react-jsx" "^7.18.6" + +"@babel/plugin-transform-react-jsx@^7.18.6": + "integrity" "sha512-UVEvX3tXie3Szm3emi1+G63jyw1w5IcMY0FSKM+CRnKRI5Mr1YbCNgsSTwoTwKphQEG9P+QqmuRFneJPZuHNhg==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.19.0.tgz" + "version" "7.19.0" + dependencies: + "@babel/helper-annotate-as-pure" "^7.18.6" + "@babel/helper-module-imports" "^7.18.6" + "@babel/helper-plugin-utils" "^7.19.0" + "@babel/plugin-syntax-jsx" "^7.18.6" + "@babel/types" "^7.19.0" + +"@babel/plugin-transform-react-pure-annotations@^7.18.6": + "integrity" "sha512-I8VfEPg9r2TRDdvnHgPepTKvuRomzA8+u+nhY7qSI1fR2hRNebasZEETLyM5mAUr0Ku56OkXJ0I7NHJnO6cJiQ==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/helper-annotate-as-pure" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-regenerator@^7.18.6": + "integrity" "sha512-poqRI2+qiSdeldcz4wTSTXBRryoq3Gc70ye7m7UD5Ww0nE29IXqMl6r7Nd15WBgRd74vloEMlShtH6CKxVzfmQ==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + "regenerator-transform" "^0.15.0" + +"@babel/plugin-transform-reserved-words@^7.18.6": + "integrity" "sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-runtime@^7.19.6": + "integrity" "sha512-PRH37lz4JU156lYFW1p8OxE5i7d6Sl/zV58ooyr+q1J1lnQPyg5tIiXlIwNVhJaY4W3TmOtdc8jqdXQcB1v5Yw==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.19.6.tgz" + "version" "7.19.6" + dependencies: + "@babel/helper-module-imports" "^7.18.6" + "@babel/helper-plugin-utils" "^7.19.0" + "babel-plugin-polyfill-corejs2" "^0.3.3" + "babel-plugin-polyfill-corejs3" "^0.6.0" + "babel-plugin-polyfill-regenerator" "^0.4.1" + "semver" "^6.3.0" + +"@babel/plugin-transform-shorthand-properties@^7.18.6": + "integrity" "sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-spread@^7.19.0": + "integrity" "sha512-RsuMk7j6n+r752EtzyScnWkQyuJdli6LdO5Klv8Yx0OfPVTcQkIUfS8clx5e9yHXzlnhOZF3CbQ8C2uP5j074w==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.19.0.tgz" + "version" "7.19.0" + dependencies: + "@babel/helper-plugin-utils" "^7.19.0" + "@babel/helper-skip-transparent-expression-wrappers" "^7.18.9" + +"@babel/plugin-transform-sticky-regex@^7.18.6": + "integrity" "sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-template-literals@^7.18.9": + "integrity" "sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.9.tgz" + "version" "7.18.9" + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + +"@babel/plugin-transform-typeof-symbol@^7.18.9": + "integrity" "sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.9.tgz" + "version" "7.18.9" + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + +"@babel/plugin-transform-typescript@^7.18.6", "@babel/plugin-transform-typescript@^7.20.0": + "integrity" "sha512-xOAsAFaun3t9hCwZ13Qe7gq423UgMZ6zAgmLxeGGapFqlT/X3L5qT2btjiVLlFn7gWtMaVyceS5VxGAuKbgizw==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.20.0.tgz" + "version" "7.20.0" + dependencies: + "@babel/helper-create-class-features-plugin" "^7.19.0" + "@babel/helper-plugin-utils" "^7.19.0" + "@babel/plugin-syntax-typescript" "^7.20.0" + +"@babel/plugin-transform-unicode-escapes@^7.18.10": + "integrity" "sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.10.tgz" + "version" "7.18.10" + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + +"@babel/plugin-transform-unicode-regex@^7.18.6": + "integrity" "sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA==" + "resolved" "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/preset-env@^7.19.4": + "integrity" "sha512-5QVOTXUdqTCjQuh2GGtdd7YEhoRXBMVGROAtsBeLGIbIz3obCBIfRMT1I3ZKkMgNzwkyCkftDXSSkHxnfVf4qg==" + "resolved" "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.19.4.tgz" + "version" "7.19.4" + dependencies: + "@babel/compat-data" "^7.19.4" + "@babel/helper-compilation-targets" "^7.19.3" + "@babel/helper-plugin-utils" "^7.19.0" + "@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.19.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.19.4" + "@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.18.6" + "@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.19.4" + "@babel/plugin-transform-classes" "^7.19.0" + "@babel/plugin-transform-computed-properties" "^7.18.9" + "@babel/plugin-transform-destructuring" "^7.19.4" + "@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.18.6" + "@babel/plugin-transform-modules-commonjs" "^7.18.6" + "@babel/plugin-transform-modules-systemjs" "^7.19.0" + "@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.18.8" + "@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.19.4" + "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" + +"@babel/preset-modules@^0.1.5": + "integrity" "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==" + "resolved" "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz" + "version" "0.1.5" + 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" + +"@babel/preset-react@^7.18.6": + "integrity" "sha512-zXr6atUmyYdiWRVLOZahakYmOBHtWc2WGCkP8PYTgZi0iJXDY2CN180TdrIW4OGOAdLc7TifzDIvtx6izaRIzg==" + "resolved" "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.18.6.tgz" + "version" "7.18.6" + 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" + +"@babel/preset-typescript@^7.18.6": + "integrity" "sha512-s9ik86kXBAnD760aybBucdpnLsAt0jK1xqJn2juOn9lkOvSHV60os5hxoVJsPzMQxvnUJFAlkont2DvvaYEBtQ==" + "resolved" "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.18.6.tgz" + "version" "7.18.6" + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-validator-option" "^7.18.6" + "@babel/plugin-transform-typescript" "^7.18.6" + +"@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.18.3", "@babel/runtime@^7.19.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7": + "integrity" "sha512-EXpLCrk55f+cYqmHsSR+yD/0gAIMxxA9QK9lnQWzhMCvt+YmoBN7Zx94s++Kv0+unHk39vxNO8t+CMA2WSS3wA==" + "resolved" "https://registry.npmjs.org/@babel/runtime/-/runtime-7.19.4.tgz" + "version" "7.19.4" + dependencies: + "regenerator-runtime" "^0.13.4" + +"@babel/template@^7.18.10": + "integrity" "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==" + "resolved" "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz" + "version" "7.18.10" + dependencies: + "@babel/code-frame" "^7.18.6" + "@babel/parser" "^7.18.10" + "@babel/types" "^7.18.10" + +"@babel/traverse@^7.19.0", "@babel/traverse@^7.19.1", "@babel/traverse@^7.19.4", "@babel/traverse@^7.19.6": + "integrity" "sha512-6l5HrUCzFM04mfbG09AagtYyR2P0B71B1wN7PfSPiksDPz2k5H9CBC1tcZpz2M8OxbKTPccByoOJ22rUKbpmQQ==" + "resolved" "https://registry.npmjs.org/@babel/traverse/-/traverse-7.19.6.tgz" + "version" "7.19.6" + dependencies: + "@babel/code-frame" "^7.18.6" + "@babel/generator" "^7.19.6" + "@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.19.6" + "@babel/types" "^7.19.4" + "debug" "^4.1.0" + "globals" "^11.1.0" + +"@babel/types@^7.18.10", "@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.19.0", "@babel/types@^7.19.4", "@babel/types@^7.4.4": + "integrity" "sha512-M5LK7nAeS6+9j7hAq+b3fQs+pNfUtTGq+yFFfHnauFA8zQtLRfmuipmsKDKKLuyG+wC8ABW43A153YNawNTEtw==" + "resolved" "https://registry.npmjs.org/@babel/types/-/types-7.19.4.tgz" + "version" "7.19.4" + dependencies: + "@babel/helper-string-parser" "^7.19.4" + "@babel/helper-validator-identifier" "^7.19.1" + "to-fast-properties" "^2.0.0" + +"@colors/colors@1.5.0": + "version" "1.5.0" + +"@ctrl/tinycolor@^3.4.0": + "integrity" "sha512-ej5oVy6lykXsvieQtqZxCOaLT+xD4+QNarq78cIYISHmZXshCvROLudpQN3lfL8G0NL7plMSSK+zlyvCaIJ4Iw==" + "resolved" "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.4.1.tgz" + "version" "3.4.1" + +"@discoveryjs/json-ext@^0.5.0": + "integrity" "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==" + "resolved" "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz" + "version" "0.5.7" + +"@emotion/babel-plugin@^11.10.0": + "integrity" "sha512-xNQ57njWTFVfPAc3cjfuaPdsgLp5QOSuRsj9MA6ndEhH/AzuZM86qIQzt6rq+aGBwj3n5/TkLmU5lhAfdRmogA==" + "resolved" "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.10.2.tgz" + "version" "11.10.2" + dependencies: + "@babel/helper-module-imports" "^7.16.7" + "@babel/plugin-syntax-jsx" "^7.17.12" + "@babel/runtime" "^7.18.3" + "@emotion/hash" "^0.9.0" + "@emotion/memoize" "^0.8.0" + "@emotion/serialize" "^1.1.0" + "babel-plugin-macros" "^3.1.0" + "convert-source-map" "^1.5.0" + "escape-string-regexp" "^4.0.0" + "find-root" "^1.1.0" + "source-map" "^0.5.7" + "stylis" "4.0.13" + +"@emotion/cache@*", "@emotion/cache@^11.10.0", "@emotion/cache@^11.10.3": + "integrity" "sha512-Psmp/7ovAa8appWh3g51goxu/z3iVms7JXOreq136D8Bbn6dYraPnmL6mdM8GThEx9vwSn92Fz+mGSjBzN8UPQ==" + "resolved" "https://registry.npmjs.org/@emotion/cache/-/cache-11.10.3.tgz" + "version" "11.10.3" + dependencies: + "@emotion/memoize" "^0.8.0" + "@emotion/sheet" "^1.2.0" + "@emotion/utils" "^1.2.0" + "@emotion/weak-memoize" "^0.3.0" + "stylis" "4.0.13" + +"@emotion/hash@^0.9.0": + "integrity" "sha512-14FtKiHhy2QoPIzdTcvh//8OyBlknNs2nXRwIhG904opCby3l+9Xaf/wuPvICBF0rc1ZCNBd3nKe9cd2mecVkQ==" + "resolved" "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.0.tgz" + "version" "0.9.0" + +"@emotion/is-prop-valid@^0.8.2": + "integrity" "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==" + "resolved" "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz" + "version" "0.8.8" + dependencies: + "@emotion/memoize" "0.7.4" + +"@emotion/is-prop-valid@^1.2.0": + "integrity" "sha512-3aDpDprjM0AwaxGE09bOPkNxHpBd+kA6jty3RnaEXdweX1DF1U3VQpPYb0g1IStAuK7SVQ1cy+bNBBKp4W3Fjg==" + "resolved" "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.0.tgz" + "version" "1.2.0" + dependencies: + "@emotion/memoize" "^0.8.0" + +"@emotion/memoize@^0.8.0": + "integrity" "sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA==" + "resolved" "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.0.tgz" + "version" "0.8.0" + +"@emotion/memoize@0.7.4": + "integrity" "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==" + "resolved" "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz" + "version" "0.7.4" + +"@emotion/react@^11.0.0-rc.0", "@emotion/react@^11.10.4", "@emotion/react@^11.4.1", "@emotion/react@^11.5.0": + "integrity" "sha512-j0AkMpr6BL8gldJZ6XQsQ8DnS9TxEQu1R+OGmDZiWjBAJtCcbt0tS3I/YffoqHXxH6MjgI7KdMbYKw3MEiU9eA==" + "resolved" "https://registry.npmjs.org/@emotion/react/-/react-11.10.4.tgz" + "version" "11.10.4" + dependencies: + "@babel/runtime" "^7.18.3" + "@emotion/babel-plugin" "^11.10.0" + "@emotion/cache" "^11.10.0" + "@emotion/serialize" "^1.1.0" + "@emotion/use-insertion-effect-with-fallbacks" "^1.0.0" + "@emotion/utils" "^1.2.0" + "@emotion/weak-memoize" "^0.3.0" + "hoist-non-react-statics" "^3.3.1" + +"@emotion/serialize@*", "@emotion/serialize@^1.1.0": + "integrity" "sha512-F1ZZZW51T/fx+wKbVlwsfchr5q97iW8brAnXmsskz4d0hVB4O3M/SiA3SaeH06x02lSNzkkQv+n3AX3kCXKSFA==" + "resolved" "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.0.tgz" + "version" "1.1.0" + dependencies: + "@emotion/hash" "^0.9.0" + "@emotion/memoize" "^0.8.0" + "@emotion/unitless" "^0.8.0" + "@emotion/utils" "^1.2.0" + "csstype" "^3.0.2" + +"@emotion/sheet@^1.2.0": + "integrity" "sha512-OiTkRgpxescko+M51tZsMq7Puu/KP55wMT8BgpcXVG2hqXc0Vo0mfymJ/Uj24Hp0i083ji/o0aLddh08UEjq8w==" + "resolved" "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.0.tgz" + "version" "1.2.0" + +"@emotion/styled@^11.10.4", "@emotion/styled@^11.3.0": + "integrity" "sha512-pRl4R8Ez3UXvOPfc2bzIoV8u9P97UedgHS4FPX594ntwEuAMA114wlaHvOK24HB48uqfXiGlYIZYCxVJ1R1ttQ==" + "resolved" "https://registry.npmjs.org/@emotion/styled/-/styled-11.10.4.tgz" + "version" "11.10.4" + dependencies: + "@babel/runtime" "^7.18.3" + "@emotion/babel-plugin" "^11.10.0" + "@emotion/is-prop-valid" "^1.2.0" + "@emotion/serialize" "^1.1.0" + "@emotion/use-insertion-effect-with-fallbacks" "^1.0.0" + "@emotion/utils" "^1.2.0" + +"@emotion/unitless@^0.8.0": + "integrity" "sha512-VINS5vEYAscRl2ZUDiT3uMPlrFQupiKgHz5AA4bCH1miKBg4qtwkim1qPmJj/4WG6TreYMY111rEFsjupcOKHw==" + "resolved" "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.0.tgz" + "version" "0.8.0" + +"@emotion/use-insertion-effect-with-fallbacks@^1.0.0": + "integrity" "sha512-1eEgUGmkaljiBnRMTdksDV1W4kUnmwgp7X9G8B++9GYwl1lUdqSndSriIrTJ0N7LQaoauY9JJ2yhiOYK5+NI4A==" + "resolved" "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.0.tgz" + "version" "1.0.0" + +"@emotion/utils@*", "@emotion/utils@^1.2.0": + "integrity" "sha512-sn3WH53Kzpw8oQ5mgMmIzzyAaH2ZqFEbozVVBSYp538E06OSE6ytOp7pRAjNQR+Q/orwqdQYJSe2m3hCOeznkw==" + "resolved" "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.0.tgz" + "version" "1.2.0" + +"@emotion/weak-memoize@^0.3.0": + "integrity" "sha512-AHPmaAx+RYfZz0eYu6Gviiagpmiyw98ySSlQvCUhVGDRtDFe4DBS0x1bSjdF3gqUDYOczB+yYvBTtEylYSdRhg==" + "resolved" "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.0.tgz" + "version" "0.3.0" + +"@eslint/eslintrc@^1.3.3": + "integrity" "sha512-uj3pT6Mg+3t39fvLrj8iuCIJ38zKO9FpGtJ4BBJebJhEwjoT+KLVNCcHT5QC9NGRIEi7fZ0ZR8YRb884auB4Lg==" + "resolved" "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.3.tgz" + "version" "1.3.3" + dependencies: + "ajv" "^6.12.4" + "debug" "^4.3.2" + "espree" "^9.4.0" + "globals" "^13.15.0" + "ignore" "^5.2.0" + "import-fresh" "^3.2.1" + "js-yaml" "^4.1.0" + "minimatch" "^3.1.2" + "strip-json-comments" "^3.1.1" + +"@formatjs/ecma402-abstract@1.13.0": + "integrity" "sha512-CQ8Ykd51jYD1n05dtoX6ns6B9n/+6ZAxnWUAonvHC4kkuAemROYBhHkEB4tm1uVrRlE7gLDqXkAnY51Y0pRCWQ==" + "resolved" "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-1.13.0.tgz" + "version" "1.13.0" + dependencies: + "@formatjs/intl-localematcher" "0.2.31" + "tslib" "2.4.0" + +"@formatjs/fast-memoize@1.2.6": + "integrity" "sha512-9CWZ3+wCkClKHX+i5j+NyoBVqGf0pIskTo6Xl6ihGokYM2yqSSS68JIgeo+99UIHc+7vi9L3/SDSz/dWI9SNlA==" + "resolved" "https://registry.npmjs.org/@formatjs/fast-memoize/-/fast-memoize-1.2.6.tgz" + "version" "1.2.6" + dependencies: + "tslib" "2.4.0" + +"@formatjs/icu-messageformat-parser@2.1.10": + "integrity" "sha512-KkRMxhifWkRC45dhM9tqm0GXbb6NPYTGVYY3xx891IKc6p++DQrZTnmkVSNNO47OEERLfuP2KkPFPJBuu8z/wg==" + "resolved" "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.1.10.tgz" + "version" "2.1.10" + dependencies: + "@formatjs/ecma402-abstract" "1.13.0" + "@formatjs/icu-skeleton-parser" "1.3.14" + "tslib" "2.4.0" + +"@formatjs/icu-skeleton-parser@1.3.14": + "integrity" "sha512-7bv60HQQcBb3+TSj+45tOb/CHV5z1hOpwdtS50jsSBXfB+YpGhnoRsZxSRksXeCxMy6xn6tA6VY2601BrrK+OA==" + "resolved" "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.3.14.tgz" + "version" "1.3.14" + dependencies: + "@formatjs/ecma402-abstract" "1.13.0" + "tslib" "2.4.0" + +"@formatjs/intl-displaynames@6.1.4": + "integrity" "sha512-sEbziGLsWQo6nA8ZUBcsDRlZzPg+uMVjDmbTalgGqRWLbdXuxMldTYdaCK+UptyJhkmNVM/erz3csTiyqamXHQ==" + "resolved" "https://registry.npmjs.org/@formatjs/intl-displaynames/-/intl-displaynames-6.1.4.tgz" + "version" "6.1.4" + dependencies: + "@formatjs/ecma402-abstract" "1.13.0" + "@formatjs/intl-localematcher" "0.2.31" + "tslib" "2.4.0" + +"@formatjs/intl-listformat@7.1.3": + "integrity" "sha512-rs0Kxl78PeRCedx2cmFoBqcun2Kf0bCQrF8ycna54sfePpDhMskvODWeI4G/xBioW01FjK7CJSvtJJ87hrr79A==" + "resolved" "https://registry.npmjs.org/@formatjs/intl-listformat/-/intl-listformat-7.1.3.tgz" + "version" "7.1.3" + dependencies: + "@formatjs/ecma402-abstract" "1.13.0" + "@formatjs/intl-localematcher" "0.2.31" + "tslib" "2.4.0" + +"@formatjs/intl-localematcher@0.2.31": + "integrity" "sha512-9QTjdSBpQ7wHShZgsNzNig5qT3rCPvmZogS/wXZzKotns5skbXgs0I7J8cuN0PPqXyynvNVuN+iOKhNS2eb+ZA==" + "resolved" "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.2.31.tgz" + "version" "0.2.31" + dependencies: + "tslib" "2.4.0" + +"@formatjs/intl@2.5.1": + "integrity" "sha512-P01ZGuDDlcN8bHHBCEHspJPvs8WJeO8SXlUIcVGWhS3IN5vUgz0QKUXcKBFnJbEHhONJ+azlObVwvlDKsE+kUg==" + "resolved" "https://registry.npmjs.org/@formatjs/intl/-/intl-2.5.1.tgz" + "version" "2.5.1" + dependencies: + "@formatjs/ecma402-abstract" "1.13.0" + "@formatjs/fast-memoize" "1.2.6" + "@formatjs/icu-messageformat-parser" "2.1.10" + "@formatjs/intl-displaynames" "6.1.4" + "@formatjs/intl-listformat" "7.1.3" + "intl-messageformat" "10.2.1" + "tslib" "2.4.0" + +"@fortawesome/fontawesome-common-types@6.2.0": + "integrity" "sha512-rBevIsj2nclStJ7AxTdfsa3ovHb1H+qApwrxcTVo+NNdeJiB9V75hsKfrkG5AwNcRUNxrPPiScGYCNmLMoh8pg==" + "resolved" "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.2.0.tgz" + "version" "6.2.0" + +"@fortawesome/fontawesome-svg-core@^6.2.0", "@fortawesome/fontawesome-svg-core@~1 || ~6": + "integrity" "sha512-Cf2mAAeMWFMzpLC7Y9H1I4o3wEU+XovVJhTiNG8ZNgSQj53yl7OCJaS80K4YjrABWZzbAHVaoHE1dVJ27AAYXw==" + "resolved" "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.2.0.tgz" + "version" "6.2.0" + dependencies: + "@fortawesome/fontawesome-common-types" "6.2.0" + +"@fortawesome/free-brands-svg-icons@^6.2.0": + "integrity" "sha512-fm1y4NyZ2qKYNmYhdMz9VAWRw1Et7PMHNunSw3W0SVAwKwv6o0qiJworLH3Y9SnmhHzAymXJwCX1op22FFvGiA==" + "resolved" "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-6.2.0.tgz" + "version" "6.2.0" + dependencies: + "@fortawesome/fontawesome-common-types" "6.2.0" + +"@fortawesome/free-solid-svg-icons@^6.2.0": + "integrity" "sha512-UjCILHIQ4I8cN46EiQn0CZL/h8AwCGgR//1c4R96Q5viSRwuKVo0NdQEc4bm+69ZwC0dUvjbDqAHF1RR5FA3XA==" + "resolved" "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.2.0.tgz" + "version" "6.2.0" + dependencies: + "@fortawesome/fontawesome-common-types" "6.2.0" + +"@fortawesome/react-fontawesome@^0.2.0": + "integrity" "sha512-uHg75Rb/XORTtVt7OS9WoK8uM276Ufi7gCzshVWkUJbHhh3svsUUeqXerrM96Wm7fRiDzfKRwSoahhMIkGAYHw==" + "resolved" "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.0.tgz" + "version" "0.2.0" + dependencies: + "prop-types" "^15.8.1" + +"@gar/promisify@^1.1.3": + "version" "1.1.3" + +"@humanwhocodes/config-array@^0.11.6": + "integrity" "sha512-kBbPWzN8oVMLb0hOUYXhmxggL/1cJE6ydvjDIGi9EnAGUyA7cLVKQg+d/Dsm+KZwx2czGHrCmMVLiyg8s5JPKw==" + "resolved" "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.7.tgz" + "version" "0.11.7" + dependencies: + "@humanwhocodes/object-schema" "^1.2.1" + "debug" "^4.1.1" + "minimatch" "^3.0.5" + +"@humanwhocodes/module-importer@^1.0.1": + "integrity" "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==" + "resolved" "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz" + "version" "1.0.1" + +"@humanwhocodes/object-schema@^1.2.1": + "integrity" "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==" + "resolved" "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz" + "version" "1.2.1" + +"@isaacs/string-locale-compare@^1.1.0": + "version" "1.1.0" + +"@jridgewell/gen-mapping@^0.1.0": + "integrity" "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==" + "resolved" "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz" + "version" "0.1.1" + dependencies: + "@jridgewell/set-array" "^1.0.0" + "@jridgewell/sourcemap-codec" "^1.4.10" + +"@jridgewell/gen-mapping@^0.3.0": + "integrity" "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==" + "resolved" "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz" + "version" "0.3.2" + dependencies: + "@jridgewell/set-array" "^1.0.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/gen-mapping@^0.3.2": + "integrity" "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==" + "resolved" "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz" + "version" "0.3.2" + dependencies: + "@jridgewell/set-array" "^1.0.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/resolve-uri@3.1.0": + "integrity" "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==" + "resolved" "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz" + "version" "3.1.0" + +"@jridgewell/set-array@^1.0.0", "@jridgewell/set-array@^1.0.1": + "integrity" "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==" + "resolved" "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz" + "version" "1.1.2" + +"@jridgewell/source-map@^0.3.2": + "integrity" "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==" + "resolved" "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz" + "version" "0.3.2" + dependencies: + "@jridgewell/gen-mapping" "^0.3.0" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@1.4.14": + "integrity" "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" + "resolved" "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz" + "version" "1.4.14" + +"@jridgewell/trace-mapping@^0.3.14", "@jridgewell/trace-mapping@^0.3.9": + "integrity" "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==" + "resolved" "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz" + "version" "0.3.17" + dependencies: + "@jridgewell/resolve-uri" "3.1.0" + "@jridgewell/sourcemap-codec" "1.4.14" + +"@juggle/resize-observer@^3.3.1": + "integrity" "sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA==" + "resolved" "https://registry.npmjs.org/@juggle/resize-observer/-/resize-observer-3.4.0.tgz" + "version" "3.4.0" + +"@motionone/animation@^10.13.1": + "integrity" "sha512-h+1sdyBP8vbxEBW5gPFDnj+m2DCqdlAuf2g6Iafb1lcMnqjsRXWlPw1AXgvUMXmreyhqmPbJqoNfIKdytampRQ==" + "resolved" "https://registry.npmjs.org/@motionone/animation/-/animation-10.14.0.tgz" + "version" "10.14.0" + dependencies: + "@motionone/easing" "^10.14.0" + "@motionone/types" "^10.14.0" + "@motionone/utils" "^10.14.0" + "tslib" "^2.3.1" + +"@motionone/dom@10.13.1": + "integrity" "sha512-zjfX+AGMIt/fIqd/SL1Lj93S6AiJsEA3oc5M9VkUr+Gz+juRmYN1vfvZd6MvEkSqEjwPQgcjN7rGZHrDB9APfQ==" + "resolved" "https://registry.npmjs.org/@motionone/dom/-/dom-10.13.1.tgz" + "version" "10.13.1" + dependencies: + "@motionone/animation" "^10.13.1" + "@motionone/generators" "^10.13.1" + "@motionone/types" "^10.13.0" + "@motionone/utils" "^10.13.1" + "hey-listen" "^1.0.8" + "tslib" "^2.3.1" + +"@motionone/easing@^10.14.0": + "integrity" "sha512-2vUBdH9uWTlRbuErhcsMmt1jvMTTqvGmn9fHq8FleFDXBlHFs5jZzHJT9iw+4kR1h6a4SZQuCf72b9ji92qNYA==" + "resolved" "https://registry.npmjs.org/@motionone/easing/-/easing-10.14.0.tgz" + "version" "10.14.0" + dependencies: + "@motionone/utils" "^10.14.0" + "tslib" "^2.3.1" + +"@motionone/generators@^10.13.1": + "integrity" "sha512-6kRHezoFfIjFN7pPpaxmkdZXD36tQNcyJe3nwVqwJ+ZfC0e3rFmszR8kp9DEVFs9QL/akWjuGPSLBI1tvz+Vjg==" + "resolved" "https://registry.npmjs.org/@motionone/generators/-/generators-10.14.0.tgz" + "version" "10.14.0" + dependencies: + "@motionone/types" "^10.14.0" + "@motionone/utils" "^10.14.0" + "tslib" "^2.3.1" + +"@motionone/types@^10.13.0", "@motionone/types@^10.14.0": + "integrity" "sha512-3bNWyYBHtVd27KncnJLhksMFQ5o2MSdk1cA/IZqsHtA9DnRM1SYgN01CTcJ8Iw8pCXF5Ocp34tyAjY7WRpOJJQ==" + "resolved" "https://registry.npmjs.org/@motionone/types/-/types-10.14.0.tgz" + "version" "10.14.0" + +"@motionone/utils@^10.13.1", "@motionone/utils@^10.14.0": + "integrity" "sha512-sLWBLPzRqkxmOTRzSaD3LFQXCPHvDzyHJ1a3VP9PRzBxyVd2pv51/gMOsdAcxQ9n+MIeGJnxzXBYplUHKj4jkw==" + "resolved" "https://registry.npmjs.org/@motionone/utils/-/utils-10.14.0.tgz" + "version" "10.14.0" + dependencies: + "@motionone/types" "^10.14.0" + "hey-listen" "^1.0.8" + "tslib" "^2.3.1" + +"@mui/base@5.0.0-alpha.103": + "integrity" "sha512-fJIyB2df3CHn7D26WHnutnY7vew6aytTlhmRJz6GX7ag19zU2GcOUhJAzY5qwWcrXKnlYgzimhEjaEnuiUWU4g==" + "resolved" "https://registry.npmjs.org/@mui/base/-/base-5.0.0-alpha.103.tgz" + "version" "5.0.0-alpha.103" + dependencies: + "@babel/runtime" "^7.19.0" + "@emotion/is-prop-valid" "^1.2.0" + "@mui/types" "^7.2.0" + "@mui/utils" "^5.10.9" + "@popperjs/core" "^2.11.6" + "clsx" "^1.2.1" + "prop-types" "^15.8.1" + "react-is" "^18.2.0" + +"@mui/core-downloads-tracker@^5.10.11": + "integrity" "sha512-u5ff+UCFDHcR8MoQ8tuJR4c35vt7T/ki3aMEE2O3XQoGs8KJSrBiisFpFKyldg9/W2NSyoZxN+kxEGIfRxh+9Q==" + "resolved" "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.10.11.tgz" + "version" "5.10.11" + +"@mui/material@^5.10.11": + "integrity" "sha512-KJ0wPCTbv6sFzwA3dgg0gowdfF+SRl7D510J9l6Nl/KFX0EawcewQudqKY4slYGFXniKa5PykqokpaWXsCCPqg==" + "resolved" "https://registry.npmjs.org/@mui/material/-/material-5.10.11.tgz" + "version" "5.10.11" + dependencies: + "@babel/runtime" "^7.19.0" + "@mui/base" "5.0.0-alpha.103" + "@mui/core-downloads-tracker" "^5.10.11" + "@mui/system" "^5.10.10" + "@mui/types" "^7.2.0" + "@mui/utils" "^5.10.9" + "@types/react-transition-group" "^4.4.5" + "clsx" "^1.2.1" + "csstype" "^3.1.1" + "prop-types" "^15.8.1" + "react-is" "^18.2.0" + "react-transition-group" "^4.4.5" + +"@mui/private-theming@^5.10.9": + "integrity" "sha512-BN7/CnsVPVyBaQpDTij4uV2xGYHHHhOgpdxeYLlIu+TqnsVM7wUeF+37kXvHovxM6xmL5qoaVUD98gDC0IZnHg==" + "resolved" "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.10.9.tgz" + "version" "5.10.9" + dependencies: + "@babel/runtime" "^7.19.0" + "@mui/utils" "^5.10.9" + "prop-types" "^15.8.1" + +"@mui/styled-engine@^5.10.8": + "integrity" "sha512-w+y8WI18EJV6zM/q41ug19cE70JTeO6sWFsQ7tgePQFpy6ToCVPh0YLrtqxUZXSoMStW5FMw0t9fHTFAqPbngw==" + "resolved" "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.10.8.tgz" + "version" "5.10.8" + dependencies: + "@babel/runtime" "^7.19.0" + "@emotion/cache" "^11.10.3" + "csstype" "^3.1.1" + "prop-types" "^15.8.1" + +"@mui/system@^5.10.10": + "integrity" "sha512-TXwtKN0adKpBrZmO+eilQWoPf2veh050HLYrN78Kps9OhlvO70v/2Kya0+mORFhu9yhpAwjHXO8JII/R4a5ZLA==" + "resolved" "https://registry.npmjs.org/@mui/system/-/system-5.10.10.tgz" + "version" "5.10.10" + dependencies: + "@babel/runtime" "^7.19.0" + "@mui/private-theming" "^5.10.9" + "@mui/styled-engine" "^5.10.8" + "@mui/types" "^7.2.0" + "@mui/utils" "^5.10.9" + "clsx" "^1.2.1" + "csstype" "^3.1.1" + "prop-types" "^15.8.1" + +"@mui/types@^7.2.0": + "integrity" "sha512-lGXtFKe5lp3UxTBGqKI1l7G8sE2xBik8qCfrLHD5olwP/YU0/ReWoWT7Lp1//ri32dK39oPMrJN8TgbkCSbsNA==" + "resolved" "https://registry.npmjs.org/@mui/types/-/types-7.2.0.tgz" + "version" "7.2.0" + +"@mui/utils@^5.10.9": + "integrity" "sha512-2tdHWrq3+WCy+G6TIIaFx3cg7PorXZ71P375ExuX61od1NOAJP1mK90VxQ8N4aqnj2vmO3AQDkV4oV2Ktvt4bA==" + "resolved" "https://registry.npmjs.org/@mui/utils/-/utils-5.10.9.tgz" + "version" "5.10.9" + dependencies: + "@babel/runtime" "^7.19.0" + "@types/prop-types" "^15.7.5" + "@types/react-is" "^16.7.1 || ^17.0.0" + "prop-types" "^15.8.1" + "react-is" "^18.2.0" + +"@nodelib/fs.scandir@2.1.5": + "integrity" "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==" + "resolved" "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz" + "version" "2.1.5" + dependencies: + "@nodelib/fs.stat" "2.0.5" + "run-parallel" "^1.1.9" + +"@nodelib/fs.stat@^2.0.2", "@nodelib/fs.stat@2.0.5": + "integrity" "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==" + "resolved" "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz" + "version" "2.0.5" + +"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": + "integrity" "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==" + "resolved" "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz" + "version" "1.2.8" + dependencies: + "@nodelib/fs.scandir" "2.1.5" + "fastq" "^1.6.0" + +"@npmcli/arborist@^6.2.3": + "version" "6.2.3" + dependencies: + "@isaacs/string-locale-compare" "^1.1.0" + "@npmcli/fs" "^3.1.0" + "@npmcli/installed-package-contents" "^2.0.0" + "@npmcli/map-workspaces" "^3.0.2" + "@npmcli/metavuln-calculator" "^5.0.0" + "@npmcli/name-from-folder" "^2.0.0" + "@npmcli/node-gyp" "^3.0.0" + "@npmcli/package-json" "^3.0.0" + "@npmcli/query" "^3.0.0" + "@npmcli/run-script" "^6.0.0" + "bin-links" "^4.0.1" + "cacache" "^17.0.4" + "common-ancestor-path" "^1.0.1" + "hosted-git-info" "^6.1.1" + "json-parse-even-better-errors" "^3.0.0" + "json-stringify-nice" "^1.1.4" + "minimatch" "^6.1.6" + "nopt" "^7.0.0" + "npm-install-checks" "^6.0.0" + "npm-package-arg" "^10.1.0" + "npm-pick-manifest" "^8.0.1" + "npm-registry-fetch" "^14.0.3" + "npmlog" "^7.0.1" + "pacote" "^15.0.8" + "parse-conflict-json" "^3.0.0" + "proc-log" "^3.0.0" + "promise-all-reject-late" "^1.0.0" + "promise-call-limit" "^1.0.1" + "read-package-json-fast" "^3.0.2" + "semver" "^7.3.7" + "ssri" "^10.0.1" + "treeverse" "^3.0.0" + "walk-up-path" "^1.0.0" + +"@npmcli/config@^6.1.3": + "version" "6.1.3" + dependencies: + "@npmcli/map-workspaces" "^3.0.2" + "ini" "^3.0.0" + "nopt" "^7.0.0" + "proc-log" "^3.0.0" + "read-package-json-fast" "^3.0.2" + "semver" "^7.3.5" + "walk-up-path" "^1.0.0" + +"@npmcli/disparity-colors@^3.0.0": + "version" "3.0.0" + dependencies: + "ansi-styles" "^4.3.0" + +"@npmcli/fs@^2.1.0": + "version" "2.1.2" + dependencies: + "@gar/promisify" "^1.1.3" + "semver" "^7.3.5" + +"@npmcli/fs@^3.1.0": + "version" "3.1.0" + dependencies: + "semver" "^7.3.5" + +"@npmcli/git@^4.0.0", "@npmcli/git@^4.0.1": + "version" "4.0.3" + dependencies: + "@npmcli/promise-spawn" "^6.0.0" + "lru-cache" "^7.4.4" + "mkdirp" "^1.0.4" + "npm-pick-manifest" "^8.0.0" + "proc-log" "^3.0.0" + "promise-inflight" "^1.0.1" + "promise-retry" "^2.0.1" + "semver" "^7.3.5" + "which" "^3.0.0" + +"@npmcli/installed-package-contents@^2.0.0", "@npmcli/installed-package-contents@^2.0.1": + "version" "2.0.1" + dependencies: + "npm-bundled" "^3.0.0" + "npm-normalize-package-bin" "^3.0.0" + +"@npmcli/map-workspaces@^3.0.2": + "version" "3.0.2" + dependencies: + "@npmcli/name-from-folder" "^2.0.0" + "glob" "^8.0.1" + "minimatch" "^6.1.6" + "read-package-json-fast" "^3.0.0" + +"@npmcli/metavuln-calculator@^5.0.0": + "version" "5.0.0" + dependencies: + "cacache" "^17.0.0" + "json-parse-even-better-errors" "^3.0.0" + "pacote" "^15.0.0" + "semver" "^7.3.5" + +"@npmcli/move-file@^2.0.0": + "version" "2.0.1" + dependencies: + "mkdirp" "^1.0.4" + "rimraf" "^3.0.2" + +"@npmcli/name-from-folder@^2.0.0": + "version" "2.0.0" + +"@npmcli/node-gyp@^3.0.0": + "version" "3.0.0" + +"@npmcli/package-json@^3.0.0": + "version" "3.0.0" + dependencies: + "json-parse-even-better-errors" "^3.0.0" + +"@npmcli/promise-spawn@^6.0.0", "@npmcli/promise-spawn@^6.0.1": + "version" "6.0.2" + dependencies: + "which" "^3.0.0" + +"@npmcli/query@^3.0.0": + "version" "3.0.0" + dependencies: + "postcss-selector-parser" "^6.0.10" + +"@npmcli/run-script@^6.0.0": + "version" "6.0.0" + dependencies: + "@npmcli/node-gyp" "^3.0.0" + "@npmcli/promise-spawn" "^6.0.0" + "node-gyp" "^9.0.0" + "read-package-json-fast" "^3.0.0" + "which" "^3.0.0" + +"@popperjs/core@^2.11.6": + "integrity" "sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==" + "resolved" "https://registry.npmjs.org/@popperjs/core/-/core-2.11.6.tgz" + "version" "2.11.6" + +"@remix-run/router@1.0.2": + "integrity" "sha512-GRSOFhJzjGN+d4sKHTMSvNeUPoZiDHWmRnXfzaxrqe7dE/Nzlc8BiMSJdLDESZlndM7jIUrZ/F4yWqVYlI0rwQ==" + "resolved" "https://registry.npmjs.org/@remix-run/router/-/router-1.0.2.tgz" + "version" "1.0.2" + +"@tootallnate/once@2": + "version" "2.0.0" + +"@types/crypto-js@^4.1.1": + "integrity" "sha512-BG7fQKZ689HIoc5h+6D2Dgq1fABRa0RbBWKBd9SP/MVRVXROflpm5fhwyATX5duFmbStzyzyycPB8qUYKDH3NA==" + "resolved" "https://registry.npmjs.org/@types/crypto-js/-/crypto-js-4.1.1.tgz" + "version" "4.1.1" + +"@types/eslint-scope@^3.7.3": + "integrity" "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==" + "resolved" "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz" + "version" "3.7.4" + dependencies: + "@types/eslint" "*" + "@types/estree" "*" + +"@types/eslint@*": + "integrity" "sha512-zUCKQI1bUCTi+0kQs5ZQzQ/XILWRLIlh15FXWNykJ+NG3TMKMVvwwC6GP3DR1Ylga15fB7iAExSzc4PNlR5i3w==" + "resolved" "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.8.tgz" + "version" "8.4.8" + dependencies: + "@types/estree" "*" + "@types/json-schema" "*" + +"@types/estree@*", "@types/estree@^0.0.51": + "integrity" "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==" + "resolved" "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz" + "version" "0.0.51" + +"@types/hoist-non-react-statics@^3.3.1": + "integrity" "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==" + "resolved" "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz" + "version" "3.3.1" + dependencies: + "@types/react" "*" + "hoist-non-react-statics" "^3.3.0" + +"@types/html-minifier-terser@^6.0.0": + "integrity" "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==" + "resolved" "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz" + "version" "6.1.0" + +"@types/json-schema@*", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": + "integrity" "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==" + "resolved" "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz" + "version" "7.0.11" + +"@types/jsrsasign@^10.5.4": + "integrity" "sha512-05S2f4lGaWgCwFHsa3OEirc4VJf/sJRfhofzxUbuFbmm6NbffPXZrnJqquQAtS3g4C8Z0L9NHgW0znmtDxNoTQ==" + "resolved" "https://registry.npmjs.org/@types/jsrsasign/-/jsrsasign-10.5.4.tgz" + "version" "10.5.4" + +"@types/node@*", "@types/node@^18.8.2": + "integrity" "sha512-3JRwhbjI+cHLAkUorhf8RnqUbFXajvzX4q6fMn5JwkgtuwfYtRQYI3u4V92vI6NJuTsbBQWWh3RZjFsuevyMGQ==" + "resolved" "https://registry.npmjs.org/@types/node/-/node-18.11.5.tgz" + "version" "18.11.5" + +"@types/parse-json@^4.0.0": + "integrity" "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==" + "resolved" "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz" + "version" "4.0.0" + +"@types/prop-types@*", "@types/prop-types@^15.7.5": + "integrity" "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" + "resolved" "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz" + "version" "15.7.5" + +"@types/react-dom@^18.0.6": + "integrity" "sha512-HaXc+BbqAZE1RdsK3tC8SbkFy6UL2xF76lT9rQs5JkPrJg3rWA3Ou/Lhw3YJQzEDkBpmJ79nBsfnd05WrBd2QQ==" + "resolved" "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.7.tgz" + "version" "18.0.7" + dependencies: + "@types/react" "*" + +"@types/react-is@^16.7.1 || ^17.0.0": + "integrity" "sha512-aBTIWg1emtu95bLTLx0cpkxwGW3ueZv71nE2YFBpL8k/z5czEW8yYpOo8Dp+UUAFAtKwNaOsh/ioSeQnWlZcfw==" + "resolved" "https://registry.npmjs.org/@types/react-is/-/react-is-17.0.3.tgz" + "version" "17.0.3" + dependencies: + "@types/react" "*" + +"@types/react-transition-group@^4.4.5": + "integrity" "sha512-juKD/eiSM3/xZYzjuzH6ZwpP+/lejltmiS3QEzV/vmb/Q8+HfDmxu+Baga8UEMGBqV88Nbg4l2hY/K2DkyaLLA==" + "resolved" "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.5.tgz" + "version" "4.4.5" + dependencies: + "@types/react" "*" + +"@types/react@*", "@types/react@^17.0.0 || ^18.0.0", "@types/react@^18.0.21", "@types/react@16 || 17 || 18": + "integrity" "sha512-R1wTULtCiJkudAN2DJGoYYySbGtOdzZyUWAACYinKdiQC8auxso4kLDUhQ7AJ2kh3F6A6z4v69U6tNY39hihVQ==" + "resolved" "https://registry.npmjs.org/@types/react/-/react-18.0.23.tgz" + "version" "18.0.23" + dependencies: + "@types/prop-types" "*" + "@types/scheduler" "*" + "csstype" "^3.0.2" + +"@types/scheduler@*": + "integrity" "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" + "resolved" "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz" + "version" "0.16.2" + +"@types/semver@^7.3.12": + "integrity" "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==" + "resolved" "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz" + "version" "7.3.13" + +"@typescript-eslint/eslint-plugin@^5.42.1": + "integrity" "sha512-wcAwhEWm1RgNd7dxD/o+nnLW8oH+6RK1OGnmbmkj/GGoDPV1WWMVP0FXYQBivKHdwM1pwii3bt//RC62EriIUQ==" + "resolved" "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.51.0.tgz" + "version" "5.51.0" + dependencies: + "@typescript-eslint/scope-manager" "5.51.0" + "@typescript-eslint/type-utils" "5.51.0" + "@typescript-eslint/utils" "5.51.0" + "debug" "^4.3.4" + "grapheme-splitter" "^1.0.4" + "ignore" "^5.2.0" + "natural-compare-lite" "^1.4.0" + "regexpp" "^3.2.0" + "semver" "^7.3.7" + "tsutils" "^3.21.0" + +"@typescript-eslint/parser@^5.0.0", "@typescript-eslint/parser@^5.42.1": + "integrity" "sha512-fEV0R9gGmfpDeRzJXn+fGQKcl0inIeYobmmUWijZh9zA7bxJ8clPhV9up2ZQzATxAiFAECqPQyMDB4o4B81AaA==" + "resolved" "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.51.0.tgz" + "version" "5.51.0" + dependencies: + "@typescript-eslint/scope-manager" "5.51.0" + "@typescript-eslint/types" "5.51.0" + "@typescript-eslint/typescript-estree" "5.51.0" + "debug" "^4.3.4" + +"@typescript-eslint/scope-manager@5.51.0": + "integrity" "sha512-gNpxRdlx5qw3yaHA0SFuTjW4rxeYhpHxt491PEcKF8Z6zpq0kMhe0Tolxt0qjlojS+/wArSDlj/LtE69xUJphQ==" + "resolved" "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.51.0.tgz" + "version" "5.51.0" + dependencies: + "@typescript-eslint/types" "5.51.0" + "@typescript-eslint/visitor-keys" "5.51.0" + +"@typescript-eslint/type-utils@5.51.0": + "integrity" "sha512-QHC5KKyfV8sNSyHqfNa0UbTbJ6caB8uhcx2hYcWVvJAZYJRBo5HyyZfzMdRx8nvS+GyMg56fugMzzWnojREuQQ==" + "resolved" "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.51.0.tgz" + "version" "5.51.0" + dependencies: + "@typescript-eslint/typescript-estree" "5.51.0" + "@typescript-eslint/utils" "5.51.0" + "debug" "^4.3.4" + "tsutils" "^3.21.0" + +"@typescript-eslint/types@5.51.0": + "integrity" "sha512-SqOn0ANn/v6hFn0kjvLwiDi4AzR++CBZz0NV5AnusT2/3y32jdc0G4woXPWHCumWtUXZKPAS27/9vziSsC9jnw==" + "resolved" "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.51.0.tgz" + "version" "5.51.0" + +"@typescript-eslint/typescript-estree@5.51.0": + "integrity" "sha512-TSkNupHvNRkoH9FMA3w7TazVFcBPveAAmb7Sz+kArY6sLT86PA5Vx80cKlYmd8m3Ha2SwofM1KwraF24lM9FvA==" + "resolved" "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.51.0.tgz" + "version" "5.51.0" + dependencies: + "@typescript-eslint/types" "5.51.0" + "@typescript-eslint/visitor-keys" "5.51.0" + "debug" "^4.3.4" + "globby" "^11.1.0" + "is-glob" "^4.0.3" + "semver" "^7.3.7" + "tsutils" "^3.21.0" + +"@typescript-eslint/utils@5.51.0": + "integrity" "sha512-76qs+5KWcaatmwtwsDJvBk4H76RJQBFe+Gext0EfJdC3Vd2kpY2Pf//OHHzHp84Ciw0/rYoGTDnIAr3uWhhJYw==" + "resolved" "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.51.0.tgz" + "version" "5.51.0" + dependencies: + "@types/json-schema" "^7.0.9" + "@types/semver" "^7.3.12" + "@typescript-eslint/scope-manager" "5.51.0" + "@typescript-eslint/types" "5.51.0" + "@typescript-eslint/typescript-estree" "5.51.0" + "eslint-scope" "^5.1.1" + "eslint-utils" "^3.0.0" + "semver" "^7.3.7" + +"@typescript-eslint/visitor-keys@5.51.0": + "integrity" "sha512-Oh2+eTdjHjOFjKA27sxESlA87YPSOJafGCR0md5oeMdh1ZcCfAGCIOL216uTBAkAIptvLIfKQhl7lHxMJet4GQ==" + "resolved" "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.51.0.tgz" + "version" "5.51.0" + dependencies: + "@typescript-eslint/types" "5.51.0" + "eslint-visitor-keys" "^3.3.0" + +"@webassemblyjs/ast@1.11.1": + "integrity" "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==" + "resolved" "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz" + "version" "1.11.1" + dependencies: + "@webassemblyjs/helper-numbers" "1.11.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.1" + +"@webassemblyjs/floating-point-hex-parser@1.11.1": + "integrity" "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==" + "resolved" "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz" + "version" "1.11.1" + +"@webassemblyjs/helper-api-error@1.11.1": + "integrity" "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==" + "resolved" "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz" + "version" "1.11.1" + +"@webassemblyjs/helper-buffer@1.11.1": + "integrity" "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==" + "resolved" "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz" + "version" "1.11.1" + +"@webassemblyjs/helper-numbers@1.11.1": + "integrity" "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==" + "resolved" "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz" + "version" "1.11.1" + dependencies: + "@webassemblyjs/floating-point-hex-parser" "1.11.1" + "@webassemblyjs/helper-api-error" "1.11.1" + "@xtuc/long" "4.2.2" + +"@webassemblyjs/helper-wasm-bytecode@1.11.1": + "integrity" "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==" + "resolved" "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz" + "version" "1.11.1" + +"@webassemblyjs/helper-wasm-section@1.11.1": + "integrity" "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==" + "resolved" "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz" + "version" "1.11.1" + 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" + +"@webassemblyjs/ieee754@1.11.1": + "integrity" "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==" + "resolved" "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz" + "version" "1.11.1" + dependencies: + "@xtuc/ieee754" "^1.2.0" + +"@webassemblyjs/leb128@1.11.1": + "integrity" "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==" + "resolved" "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz" + "version" "1.11.1" + dependencies: + "@xtuc/long" "4.2.2" + +"@webassemblyjs/utf8@1.11.1": + "integrity" "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==" + "resolved" "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz" + "version" "1.11.1" + +"@webassemblyjs/wasm-edit@1.11.1": + "integrity" "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==" + "resolved" "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz" + "version" "1.11.1" + 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" + +"@webassemblyjs/wasm-gen@1.11.1": + "integrity" "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==" + "resolved" "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz" + "version" "1.11.1" + 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" + +"@webassemblyjs/wasm-opt@1.11.1": + "integrity" "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==" + "resolved" "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz" + "version" "1.11.1" + dependencies: + "@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@1.11.1": + "integrity" "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==" + "resolved" "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz" + "version" "1.11.1" + 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" + +"@webassemblyjs/wast-printer@1.11.1": + "integrity" "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==" + "resolved" "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz" + "version" "1.11.1" + dependencies: + "@webassemblyjs/ast" "1.11.1" + "@xtuc/long" "4.2.2" + +"@webpack-cli/configtest@^1.2.0": + "integrity" "sha512-4FB8Tj6xyVkyqjj1OaTqCjXYULB9FMkqQ8yGrZjRDrYh0nOE+7Lhs45WioWQQMV+ceFlE368Ukhe6xdvJM9Egg==" + "resolved" "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.2.0.tgz" + "version" "1.2.0" + +"@webpack-cli/info@^1.5.0": + "integrity" "sha512-e8tSXZpw2hPl2uMJY6fsMswaok5FdlGNRTktvFk2sD8RjH0hE2+XistawJx1vmKteh4NmGmNUrp+Tb2w+udPcQ==" + "resolved" "https://registry.npmjs.org/@webpack-cli/info/-/info-1.5.0.tgz" + "version" "1.5.0" + dependencies: + "envinfo" "^7.7.3" + +"@webpack-cli/serve@^1.7.0": + "integrity" "sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q==" + "resolved" "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.7.0.tgz" + "version" "1.7.0" + +"@xtuc/ieee754@^1.2.0": + "integrity" "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==" + "resolved" "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz" + "version" "1.2.0" + +"@xtuc/long@4.2.2": + "integrity" "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" + "resolved" "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz" + "version" "4.2.2" + +"abbrev@^1.0.0": + "version" "1.1.1" + +"abbrev@^2.0.0": + "version" "2.0.0" + +"abbrev@1": + "integrity" "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + "resolved" "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz" + "version" "1.1.1" + +"abort-controller@^3.0.0": + "version" "3.0.0" + dependencies: + "event-target-shim" "^5.0.0" + +"abortcontroller-polyfill@^1.7.3": + "integrity" "sha512-JMJ5soJWP18htbbxJjG7bG6yuI6pRhgJ0scHHTfkUjf6wjP912xZWvM+A4sJK3gqd9E8fcPbDnOefbA9Th/FIQ==" + "resolved" "https://registry.npmjs.org/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.5.tgz" + "version" "1.7.5" + +"accepts@~1.3.5": + "integrity" "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==" + "resolved" "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz" + "version" "1.3.8" + dependencies: + "mime-types" "~2.1.34" + "negotiator" "0.6.3" + +"acorn-import-assertions@^1.7.6": + "integrity" "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==" + "resolved" "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz" + "version" "1.8.0" + +"acorn-jsx@^5.3.2": + "integrity" "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==" + "resolved" "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz" + "version" "5.3.2" + +"acorn@^6.0.0 || ^7.0.0 || ^8.0.0", "acorn@^8", "acorn@^8.5.0", "acorn@^8.7.1", "acorn@^8.8.0": + "integrity" "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==" + "resolved" "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz" + "version" "8.8.1" + +"agent-base@^6.0.2", "agent-base@6": + "version" "6.0.2" + dependencies: + "debug" "4" + +"agentkeepalive@^4.2.1": + "version" "4.2.1" + dependencies: + "debug" "^4.1.0" + "depd" "^1.1.2" + "humanize-ms" "^1.2.1" + +"aggregate-error@^3.0.0": + "version" "3.1.0" + dependencies: + "clean-stack" "^2.0.0" + "indent-string" "^4.0.0" + +"ajv-keywords@^3.5.2": + "integrity" "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==" + "resolved" "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz" + "version" "3.5.2" + +"ajv@^6.10.0", "ajv@^6.12.4", "ajv@^6.12.5", "ajv@^6.9.1": + "integrity" "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==" + "resolved" "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" + "version" "6.12.6" + dependencies: + "fast-deep-equal" "^3.1.1" + "fast-json-stable-stringify" "^2.0.0" + "json-schema-traverse" "^0.4.1" + "uri-js" "^4.2.2" + +"ansi-regex@^5.0.1": + "integrity" "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + "resolved" "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz" + "version" "5.0.1" + +"ansi-styles@^3.2.1": + "integrity" "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==" + "resolved" "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz" + "version" "3.2.1" + dependencies: + "color-convert" "^1.9.0" + +"ansi-styles@^4.1.0", "ansi-styles@^4.3.0": + "integrity" "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==" + "resolved" "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" + "version" "4.3.0" + dependencies: + "color-convert" "^2.0.1" + +"anymatch@~3.1.2": + "integrity" "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==" + "resolved" "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz" + "version" "3.1.2" + dependencies: + "normalize-path" "^3.0.0" + "picomatch" "^2.0.4" + +"aproba@^1.0.3 || ^2.0.0", "aproba@^2.0.0": + "version" "2.0.0" + +"archy@~1.0.0": + "version" "1.0.0" + +"are-we-there-yet@^3.0.0": + "version" "3.0.1" + dependencies: + "delegates" "^1.0.0" + "readable-stream" "^3.6.0" + +"are-we-there-yet@^4.0.0": + "version" "4.0.0" + dependencies: + "delegates" "^1.0.0" + "readable-stream" "^4.1.0" + +"argparse@^2.0.1": + "integrity" "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + "resolved" "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz" + "version" "2.0.1" + +"array-flatten@1.1.1": + "integrity" "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + "resolved" "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz" + "version" "1.1.1" + +"array-includes@^3.1.5", "array-includes@^3.1.6": + "integrity" "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==" + "resolved" "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz" + "version" "3.1.6" + dependencies: + "call-bind" "^1.0.2" + "define-properties" "^1.1.4" + "es-abstract" "^1.20.4" + "get-intrinsic" "^1.1.3" + "is-string" "^1.0.7" + +"array-union@^2.1.0": + "integrity" "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==" + "resolved" "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz" + "version" "2.1.0" + +"array.prototype.flatmap@^1.3.1": + "integrity" "sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==" + "resolved" "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz" + "version" "1.3.1" + dependencies: + "call-bind" "^1.0.2" + "define-properties" "^1.1.4" + "es-abstract" "^1.20.4" + "es-shim-unscopables" "^1.0.0" + +"array.prototype.tosorted@^1.1.1": + "integrity" "sha512-pZYPXPRl2PqWcsUs6LOMn+1f1532nEoPTYowBtqLwAW+W8vSVhkIGnmOX1t/UQjD6YGI0vcD2B1U7ZFGQH9jnQ==" + "resolved" "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.1.tgz" + "version" "1.1.1" + dependencies: + "call-bind" "^1.0.2" + "define-properties" "^1.1.4" + "es-abstract" "^1.20.4" + "es-shim-unscopables" "^1.0.0" + "get-intrinsic" "^1.1.3" + +"asynckit@^0.4.0": + "integrity" "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + "resolved" "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz" + "version" "0.4.0" + +"available-typed-arrays@^1.0.5": + "integrity" "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==" + "resolved" "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz" + "version" "1.0.5" + +"await-semaphore@^0.1.3": + "integrity" "sha512-d1W2aNSYcz/sxYO4pMGX9vq65qOTu0P800epMud+6cYYX0QcT7zyqcxec3VWzpgvdXo57UWmVbZpLMjX2m1I7Q==" + "resolved" "https://registry.npmjs.org/await-semaphore/-/await-semaphore-0.1.3.tgz" + "version" "0.1.3" + +"axios@^1.3.4": + "integrity" "sha512-toYm+Bsyl6VC5wSkfkbbNB6ROv7KY93PEBBL6xyDczaIHasAiv4wPqQ/c4RjoQzipxRD2W5g21cOqQulZ7rHwQ==" + "resolved" "https://registry.npmjs.org/axios/-/axios-1.3.4.tgz" + "version" "1.3.4" + dependencies: + "follow-redirects" "^1.15.0" + "form-data" "^4.0.0" + "proxy-from-env" "^1.1.0" + +"babel-loader@^8.2.5": + "integrity" "sha512-OSiFfH89LrEMiWd4pLNqGz4CwJDtbs2ZVc+iGu2HrkRfPxId9F2anQj38IxWpmRfsUY0aBZYi1EFcd3mhtRMLQ==" + "resolved" "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.5.tgz" + "version" "8.2.5" + dependencies: + "find-cache-dir" "^3.3.1" + "loader-utils" "^2.0.0" + "make-dir" "^3.1.0" + "schema-utils" "^2.6.5" + +"babel-plugin-macros@^3.1.0": + "integrity" "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==" + "resolved" "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz" + "version" "3.1.0" + dependencies: + "@babel/runtime" "^7.12.5" + "cosmiconfig" "^7.0.0" + "resolve" "^1.19.0" + +"babel-plugin-polyfill-corejs2@^0.3.3": + "integrity" "sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==" + "resolved" "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz" + "version" "0.3.3" + dependencies: + "@babel/compat-data" "^7.17.7" + "@babel/helper-define-polyfill-provider" "^0.3.3" + "semver" "^6.1.1" + +"babel-plugin-polyfill-corejs3@^0.6.0": + "integrity" "sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA==" + "resolved" "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.6.0.tgz" + "version" "0.6.0" + dependencies: + "@babel/helper-define-polyfill-provider" "^0.3.3" + "core-js-compat" "^3.25.1" + +"babel-plugin-polyfill-regenerator@^0.4.1": + "integrity" "sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==" + "resolved" "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz" + "version" "0.4.1" + dependencies: + "@babel/helper-define-polyfill-provider" "^0.3.3" + +"balanced-match@^1.0.0": + "integrity" "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + "resolved" "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" + "version" "1.0.2" + +"base64-js@^1.3.1": + "version" "1.5.1" + +"basic-auth@~2.0.0": + "integrity" "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==" + "resolved" "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz" + "version" "2.0.1" + dependencies: + "safe-buffer" "5.1.2" + +"big.js@^5.2.2": + "integrity" "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==" + "resolved" "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz" + "version" "5.2.2" + +"bin-links@^4.0.1": + "version" "4.0.1" + dependencies: + "cmd-shim" "^6.0.0" + "npm-normalize-package-bin" "^3.0.0" + "read-cmd-shim" "^4.0.0" + "write-file-atomic" "^5.0.0" + +"binary-extensions@^2.0.0": + "integrity" "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==" + "resolved" "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz" + "version" "2.2.0" + +"binary-extensions@^2.2.0": + "version" "2.2.0" + +"body-parser@1.18.3": + "integrity" "sha512-YQyoqQG3sO8iCmf8+hyVpgHHOv0/hCEFiS4zTGUwTA1HjAFX66wRcNQrVCeJq9pgESMRvUAOvSil5MJlmccuKQ==" + "resolved" "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz" + "version" "1.18.3" + dependencies: + "bytes" "3.0.0" + "content-type" "~1.0.4" + "debug" "2.6.9" + "depd" "~1.1.2" + "http-errors" "~1.6.3" + "iconv-lite" "0.4.23" + "on-finished" "~2.3.0" + "qs" "6.5.2" + "raw-body" "2.3.3" + "type-is" "~1.6.16" + +"boolbase@^1.0.0": + "integrity" "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" + "resolved" "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz" + "version" "1.0.0" + +"brace-expansion@^1.1.7": + "integrity" "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==" + "resolved" "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz" + "version" "1.1.11" + dependencies: + "balanced-match" "^1.0.0" + "concat-map" "0.0.1" + +"brace-expansion@^2.0.1": + "version" "2.0.1" + dependencies: + "balanced-match" "^1.0.0" + +"braces@^3.0.2", "braces@~3.0.2": + "integrity" "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==" + "resolved" "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz" + "version" "3.0.2" + dependencies: + "fill-range" "^7.0.1" + +"browser-tabs-lock@^1.2.15": + "integrity" "sha512-J8K9vdivK0Di+b8SBdE7EZxDr88TnATing7XoLw6+nFkXMQ6sVBh92K3NQvZlZU91AIkFRi0w3sztk5Z+vsswA==" + "resolved" "https://registry.npmjs.org/browser-tabs-lock/-/browser-tabs-lock-1.2.15.tgz" + "version" "1.2.15" + dependencies: + "lodash" ">=4.17.21" + +"browserslist@^4.14.5", "browserslist@^4.21.3", "browserslist@^4.21.4", "browserslist@>= 4.21.0": + "integrity" "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==" + "resolved" "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz" + "version" "4.21.4" + dependencies: + "caniuse-lite" "^1.0.30001400" + "electron-to-chromium" "^1.4.251" + "node-releases" "^2.0.6" + "update-browserslist-db" "^1.0.9" + +"buffer-equal-constant-time@1.0.1": + "integrity" "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" + "resolved" "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz" + "version" "1.0.1" + +"buffer-from@^1.0.0": + "integrity" "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + "resolved" "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz" + "version" "1.1.2" + +"buffer@^6.0.3": + "version" "6.0.3" + dependencies: + "base64-js" "^1.3.1" + "ieee754" "^1.2.1" + +"builtins@^5.0.0": + "version" "5.0.1" + dependencies: + "semver" "^7.0.0" + +"bytes@3.0.0": + "integrity" "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==" + "resolved" "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz" + "version" "3.0.0" + +"cacache@^16.1.0": + "version" "16.1.3" + dependencies: + "@npmcli/fs" "^2.1.0" + "@npmcli/move-file" "^2.0.0" + "chownr" "^2.0.0" + "fs-minipass" "^2.1.0" + "glob" "^8.0.1" + "infer-owner" "^1.0.4" + "lru-cache" "^7.7.1" + "minipass" "^3.1.6" + "minipass-collect" "^1.0.2" + "minipass-flush" "^1.0.5" + "minipass-pipeline" "^1.2.4" + "mkdirp" "^1.0.4" + "p-map" "^4.0.0" + "promise-inflight" "^1.0.1" + "rimraf" "^3.0.2" + "ssri" "^9.0.0" + "tar" "^6.1.11" + "unique-filename" "^2.0.0" + +"cacache@^17.0.0", "cacache@^17.0.4": + "version" "17.0.4" + dependencies: + "@npmcli/fs" "^3.1.0" + "fs-minipass" "^3.0.0" + "glob" "^8.0.1" + "lru-cache" "^7.7.1" + "minipass" "^4.0.0" + "minipass-collect" "^1.0.2" + "minipass-flush" "^1.0.5" + "minipass-pipeline" "^1.2.4" + "p-map" "^4.0.0" + "promise-inflight" "^1.0.1" + "ssri" "^10.0.0" + "tar" "^6.1.11" + "unique-filename" "^3.0.0" + +"call-bind@^1.0.0", "call-bind@^1.0.2": + "integrity" "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==" + "resolved" "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz" + "version" "1.0.2" + dependencies: + "function-bind" "^1.1.1" + "get-intrinsic" "^1.0.2" + +"callsites@^3.0.0": + "integrity" "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" + "resolved" "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz" + "version" "3.1.0" + +"camel-case@^4.1.2": + "integrity" "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==" + "resolved" "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz" + "version" "4.1.2" + dependencies: + "pascal-case" "^3.1.2" + "tslib" "^2.0.3" + +"can-use-dom@^0.1.0": + "integrity" "sha512-ceOhN1DL7Y4O6M0j9ICgmTYziV89WMd96SvSl0REd8PMgrY0B/WBOPoed5S1KUmJqXgUXh8gzSe6E3ae27upsQ==" + "resolved" "https://registry.npmjs.org/can-use-dom/-/can-use-dom-0.1.0.tgz" + "version" "0.1.0" + +"caniuse-lite@^1.0.30001400": + "integrity" "sha512-/pzFv0OmNG6W0ym80P3NtapU0QEiDS3VuYAZMGoLLqiC7f6FJFe1MjpQDREGApeenD9wloeytmVDj+JLXPC6qw==" + "resolved" "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001425.tgz" + "version" "1.0.30001425" + +"chalk@^2.0.0": + "integrity" "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==" + "resolved" "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" + "version" "2.4.2" + dependencies: + "ansi-styles" "^3.2.1" + "escape-string-regexp" "^1.0.5" + "supports-color" "^5.3.0" + +"chalk@^4.0.0", "chalk@^4.1.0", "chalk@^4.1.2": + "integrity" "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==" + "resolved" "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz" + "version" "4.1.2" + dependencies: + "ansi-styles" "^4.1.0" + "supports-color" "^7.1.0" + +"chalk@^4.1.0": + "integrity" "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==" + "resolved" "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz" + "version" "4.1.2" + dependencies: + "ansi-styles" "^4.1.0" + "supports-color" "^7.1.0" + +"chokidar@^3.5.0", "chokidar@^3.5.2": + "integrity" "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==" + "resolved" "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz" + "version" "3.5.3" + dependencies: + "anymatch" "~3.1.2" + "braces" "~3.0.2" + "glob-parent" "~5.1.2" + "is-binary-path" "~2.1.0" + "is-glob" "~4.0.1" + "normalize-path" "~3.0.0" + "readdirp" "~3.6.0" + optionalDependencies: + "fsevents" "~2.3.2" + +"chownr@^2.0.0": + "version" "2.0.0" + +"chrome-trace-event@^1.0.2": + "integrity" "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==" + "resolved" "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz" + "version" "1.0.3" + +"ci-info@^3.6.1", "ci-info@^3.7.1", "ci-info@^3.8.0": + "version" "3.8.0" + +"cidr-regex@^3.1.1": + "version" "3.1.1" + dependencies: + "ip-regex" "^4.1.0" + +"classnames@^2.2.6": + "integrity" "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==" + "resolved" "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz" + "version" "2.3.2" + +"clean-css@^5.2.2": + "integrity" "sha512-lCr8OHhiWCTw4v8POJovCoh4T7I9U11yVsPjMWWnnMmp9ZowCxyad1Pathle/9HjaDp+fdQKjO9fQydE6RHTZg==" + "resolved" "https://registry.npmjs.org/clean-css/-/clean-css-5.3.1.tgz" + "version" "5.3.1" + dependencies: + "source-map" "~0.6.0" + +"clean-stack@^2.0.0": + "version" "2.2.0" + +"cli-columns@^4.0.0": + "version" "4.0.0" + dependencies: + "string-width" "^4.2.3" + "strip-ansi" "^6.0.1" + +"cli-table3@^0.6.3": + "version" "0.6.3" + dependencies: + "string-width" "^4.2.0" + optionalDependencies: + "@colors/colors" "1.5.0" + +"clone-deep@^4.0.1": + "integrity" "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==" + "resolved" "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz" + "version" "4.0.1" + dependencies: + "is-plain-object" "^2.0.4" + "kind-of" "^6.0.2" + "shallow-clone" "^3.0.0" + +"clone@^1.0.2": + "version" "1.0.4" + +"clsx@^1.2.1": + "integrity" "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==" + "resolved" "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz" + "version" "1.2.1" + +"cmd-shim@^6.0.0": + "version" "6.0.1" + +"color-convert@^1.9.0": + "integrity" "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==" + "resolved" "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz" + "version" "1.9.3" + dependencies: + "color-name" "1.1.3" + +"color-convert@^2.0.1": + "integrity" "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==" + "resolved" "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz" + "version" "2.0.1" + dependencies: + "color-name" "~1.1.4" + +"color-name@~1.1.4": + "integrity" "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + "resolved" "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" + "version" "1.1.4" + +"color-name@1.1.3": + "integrity" "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + "resolved" "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" + "version" "1.1.3" + +"color-support@^1.1.3": + "version" "1.1.3" + +"colorette@^2.0.14": + "integrity" "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==" + "resolved" "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz" + "version" "2.0.19" + +"columnify@^1.6.0": + "version" "1.6.0" + dependencies: + "strip-ansi" "^6.0.1" + "wcwidth" "^1.0.0" + +"combined-stream@^1.0.8": + "integrity" "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==" + "resolved" "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz" + "version" "1.0.8" + dependencies: + "delayed-stream" "~1.0.0" + +"commander@^2.20.0": + "integrity" "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + "resolved" "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz" + "version" "2.20.3" + +"commander@^7.0.0": + "integrity" "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==" + "resolved" "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz" + "version" "7.2.0" + +"commander@^8.3.0": + "integrity" "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==" + "resolved" "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz" + "version" "8.3.0" + +"common-ancestor-path@^1.0.1": + "version" "1.0.1" + +"commondir@^1.0.1": + "integrity" "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==" + "resolved" "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz" + "version" "1.0.1" + +"concat-map@0.0.1": + "integrity" "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + "resolved" "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" + "version" "0.0.1" + +"connect-livereload@^0.6.1": + "integrity" "sha512-3R0kMOdL7CjJpU66fzAkCe6HNtd3AavCS4m+uW4KtJjrdGPT0SQEZieAYd+cm+lJoBznNQ4lqipYWkhBMgk00g==" + "resolved" "https://registry.npmjs.org/connect-livereload/-/connect-livereload-0.6.1.tgz" + "version" "0.6.1" + +"console-control-strings@^1.1.0": + "version" "1.1.0" + +"content-disposition@0.5.2": + "integrity" "sha512-kRGRZw3bLlFISDBgwTSA1TMBFN6J6GWDeubmDE3AF+3+yXL8hTWv8r5rkLbqYXY4RjPk/EzHnClI3zQf1cFmHA==" + "resolved" "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz" + "version" "0.5.2" + +"content-type@~1.0.4": + "integrity" "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + "resolved" "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz" + "version" "1.0.4" + +"convert-source-map@^1.5.0", "convert-source-map@^1.7.0": + "integrity" "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" + "resolved" "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz" + "version" "1.9.0" + +"cookie-parser@^1.4.6": + "integrity" "sha512-z3IzaNjdwUC2olLIB5/ITd0/setiaFMLYiZJle7xg5Fe9KWAceil7xszYfHHBtDFYLSgJduS2Ty0P1uJdPDJeA==" + "resolved" "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.6.tgz" + "version" "1.4.6" + dependencies: + "cookie" "0.4.1" + "cookie-signature" "1.0.6" + +"cookie-signature@1.0.6": + "integrity" "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + "resolved" "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz" + "version" "1.0.6" + +"cookie@0.3.1": + "integrity" "sha512-+IJOX0OqlHCszo2mBUq+SrEbCj6w7Kpffqx60zYbPTFaO4+yYgRjHwcZNpWvaTylDHaV7PPmBHzSecZiMhtPgw==" + "resolved" "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz" + "version" "0.3.1" + +"cookie@0.4.1": + "integrity" "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==" + "resolved" "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz" + "version" "0.4.1" + +"copy-to-clipboard@^3.3.1": + "integrity" "sha512-Vme1Z6RUDzrb6xAI7EZlVZ5uvOk2F//GaxKUxajDqm9LhOVM1inxNAD2vy+UZDYsd0uyA9s7b3/FVZPSxqrCfg==" + "resolved" "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.2.tgz" + "version" "3.3.2" + dependencies: + "toggle-selection" "^1.0.6" + +"core-js-compat@^3.25.1": + "integrity" "sha512-piOX9Go+Z4f9ZiBFLnZ5VrOpBl0h7IGCkiFUN11QTe6LjAvOT3ifL/5TdoizMh99hcGy5SoLyWbapIY/PIb/3A==" + "resolved" "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.26.0.tgz" + "version" "3.26.0" + dependencies: + "browserslist" "^4.21.4" + +"core-js@^3.0.1", "core-js@^3.25.1": + "integrity" "sha512-+DkDrhoR4Y0PxDz6rurahuB+I45OsEUv8E1maPTB6OuHRohMMcznBq9TMpdpDMm/hUPob/mJJS3PqgbHpMTQgw==" + "resolved" "https://registry.npmjs.org/core-js/-/core-js-3.26.0.tgz" + "version" "3.26.0" + +"cosmiconfig@^7.0.0": + "integrity" "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==" + "resolved" "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz" + "version" "7.0.1" + dependencies: + "@types/parse-json" "^4.0.0" + "import-fresh" "^3.2.1" + "parse-json" "^5.0.0" + "path-type" "^4.0.0" + "yaml" "^1.10.0" + +"cross-spawn@^7.0.2", "cross-spawn@^7.0.3": + "integrity" "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==" + "resolved" "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz" + "version" "7.0.3" + dependencies: + "path-key" "^3.1.0" + "shebang-command" "^2.0.0" + "which" "^2.0.1" + +"crypto-js@^4.1.1": + "integrity" "sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw==" + "resolved" "https://registry.npmjs.org/crypto-js/-/crypto-js-4.1.1.tgz" + "version" "4.1.1" + +"css-loader@^6.7.1": + "integrity" "sha512-yB5CNFa14MbPJcomwNh3wLThtkZgcNyI2bNMRt8iE5Z8Vwl7f8vQXFAzn2HDOJvtDq2NTZBUGMSUNNyrv3/+cw==" + "resolved" "https://registry.npmjs.org/css-loader/-/css-loader-6.7.1.tgz" + "version" "6.7.1" + dependencies: + "icss-utils" "^5.1.0" + "postcss" "^8.4.7" + "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.5" + +"css-select@^4.1.3": + "integrity" "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==" + "resolved" "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz" + "version" "4.3.0" + dependencies: + "boolbase" "^1.0.0" + "css-what" "^6.0.1" + "domhandler" "^4.3.1" + "domutils" "^2.8.0" + "nth-check" "^2.0.1" + +"css-what@^6.0.1": + "integrity" "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==" + "resolved" "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz" + "version" "6.1.0" + +"cssesc@^3.0.0": + "integrity" "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==" + "resolved" "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz" + "version" "3.0.0" + +"csstype@^3.0.10", "csstype@^3.0.2", "csstype@^3.1.1": + "integrity" "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==" + "resolved" "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz" + "version" "3.1.1" + +"data-uri-to-buffer@^4.0.0": + "integrity" "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==" + "resolved" "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz" + "version" "4.0.1" + +"debug@^3.2.7": + "integrity" "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==" + "resolved" "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz" + "version" "3.2.7" + dependencies: + "ms" "^2.1.1" + +"debug@^4.1.0", "debug@^4.3.3", "debug@4": + "integrity" "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==" + "resolved" "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" + "version" "4.3.4" + dependencies: + "ms" "2.1.2" + +"debug@^4.1.1": + "integrity" "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==" + "resolved" "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" + "version" "4.3.4" + dependencies: + "ms" "2.1.2" + +"debug@^4.3.2": + "integrity" "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==" + "resolved" "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" + "version" "4.3.4" + dependencies: + "ms" "2.1.2" + +"debug@^4.3.4": + "integrity" "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==" + "resolved" "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" + "version" "4.3.4" + dependencies: + "ms" "2.1.2" + +"debug@~2.6.9", "debug@2.6.9": + "integrity" "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==" + "resolved" "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz" + "version" "2.6.9" + dependencies: + "ms" "2.0.0" + +"deep-is@^0.1.3": + "integrity" "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==" + "resolved" "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz" + "version" "0.1.4" + +"defaults@^1.0.3": + "version" "1.0.4" + dependencies: + "clone" "^1.0.2" + +"define-properties@^1.1.3", "define-properties@^1.1.4": + "integrity" "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==" + "resolved" "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz" + "version" "1.2.0" + dependencies: + "has-property-descriptors" "^1.0.0" + "object-keys" "^1.1.1" + +"delayed-stream@~1.0.0": + "integrity" "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" + "resolved" "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz" + "version" "1.0.0" + +"delegates@^1.0.0": + "version" "1.0.0" + +"depd@^1.1.2": + "version" "1.1.2" + +"depd@~1.1.2": + "integrity" "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==" + "resolved" "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz" + "version" "1.1.2" + +"destroy@~1.0.4": + "integrity" "sha512-3NdhDuEXnfun/z7x9GOElY49LoqVHoGScmOKwmxhsS8N5Y+Z8KyPPDnaSzqWgYt/ji4mqwfTS34Htrk0zPIXVg==" + "resolved" "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz" + "version" "1.0.4" + +"diff@^5.1.0": + "version" "5.1.0" + +"dir-glob@^3.0.1": + "integrity" "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==" + "resolved" "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz" + "version" "3.0.1" + dependencies: + "path-type" "^4.0.0" + +"doctrine@^2.1.0": + "integrity" "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==" + "resolved" "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz" + "version" "2.1.0" + dependencies: + "esutils" "^2.0.2" + +"doctrine@^3.0.0": + "integrity" "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==" + "resolved" "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz" + "version" "3.0.0" + dependencies: + "esutils" "^2.0.2" + +"dom-converter@^0.2.0": + "integrity" "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==" + "resolved" "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz" + "version" "0.2.0" + dependencies: + "utila" "~0.4" + +"dom-helpers@^5.0.1": + "integrity" "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==" + "resolved" "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz" + "version" "5.2.1" + dependencies: + "@babel/runtime" "^7.8.7" + "csstype" "^3.0.2" + +"dom-serializer@^1.0.1": + "integrity" "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==" + "resolved" "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz" + "version" "1.4.1" + dependencies: + "domelementtype" "^2.0.1" + "domhandler" "^4.2.0" + "entities" "^2.0.0" + +"domelementtype@^2.0.1", "domelementtype@^2.2.0": + "integrity" "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==" + "resolved" "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz" + "version" "2.3.0" + +"domhandler@^4.0.0", "domhandler@^4.2.0", "domhandler@^4.3.1": + "integrity" "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==" + "resolved" "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz" + "version" "4.3.1" + dependencies: + "domelementtype" "^2.2.0" + +"domutils@^2.5.2", "domutils@^2.8.0": + "integrity" "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==" + "resolved" "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz" + "version" "2.8.0" + dependencies: + "dom-serializer" "^1.0.1" + "domelementtype" "^2.2.0" + "domhandler" "^4.2.0" + +"dot-case@^3.0.4": + "integrity" "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==" + "resolved" "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz" + "version" "3.0.4" + dependencies: + "no-case" "^3.0.4" + "tslib" "^2.0.3" + +"dotenv@^16.0.3": + "integrity" "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==" + "resolved" "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz" + "version" "16.0.3" + +"ecdsa-sig-formatter@1.0.11": + "integrity" "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==" + "resolved" "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz" + "version" "1.0.11" + dependencies: + "safe-buffer" "^5.0.1" + +"ee-first@1.1.1": + "integrity" "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + "resolved" "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz" + "version" "1.1.1" + +"electron-to-chromium@^1.4.251": + "integrity" "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==" + "resolved" "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz" + "version" "1.4.284" + +"emoji-regex@^8.0.0": + "version" "8.0.0" + +"emojis-list@^3.0.0": + "integrity" "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==" + "resolved" "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz" + "version" "3.0.0" + +"encodeurl@~1.0.2": + "integrity" "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" + "resolved" "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz" + "version" "1.0.2" + +"encoding@^0.1.13": + "version" "0.1.13" + dependencies: + "iconv-lite" "^0.6.2" + +"enhanced-resolve@^5.0.0", "enhanced-resolve@^5.10.0": + "integrity" "sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ==" + "resolved" "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz" + "version" "5.10.0" + dependencies: + "graceful-fs" "^4.2.4" + "tapable" "^2.2.0" + +"entities@^2.0.0": + "integrity" "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==" + "resolved" "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz" + "version" "2.2.0" + +"env-paths@^2.2.0": + "version" "2.2.1" + +"envinfo@^7.7.3": + "integrity" "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==" + "resolved" "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz" + "version" "7.8.1" + +"err-code@^2.0.2": + "version" "2.0.3" + +"error-ex@^1.3.1": + "integrity" "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==" + "resolved" "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz" + "version" "1.3.2" + dependencies: + "is-arrayish" "^0.2.1" + +"es-abstract@^1.19.0", "es-abstract@^1.20.4": + "integrity" "sha512-QudMsPOz86xYz/1dG1OuGBKOELjCh99IIWHLzy5znUB6j8xG2yMA7bfTV86VSqKF+Y/H08vQPR+9jyXpuC6hfg==" + "resolved" "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.1.tgz" + "version" "1.21.1" + dependencies: + "available-typed-arrays" "^1.0.5" + "call-bind" "^1.0.2" + "es-set-tostringtag" "^2.0.1" + "es-to-primitive" "^1.2.1" + "function-bind" "^1.1.1" + "function.prototype.name" "^1.1.5" + "get-intrinsic" "^1.1.3" + "get-symbol-description" "^1.0.0" + "globalthis" "^1.0.3" + "gopd" "^1.0.1" + "has" "^1.0.3" + "has-property-descriptors" "^1.0.0" + "has-proto" "^1.0.1" + "has-symbols" "^1.0.3" + "internal-slot" "^1.0.4" + "is-array-buffer" "^3.0.1" + "is-callable" "^1.2.7" + "is-negative-zero" "^2.0.2" + "is-regex" "^1.1.4" + "is-shared-array-buffer" "^1.0.2" + "is-string" "^1.0.7" + "is-typed-array" "^1.1.10" + "is-weakref" "^1.0.2" + "object-inspect" "^1.12.2" + "object-keys" "^1.1.1" + "object.assign" "^4.1.4" + "regexp.prototype.flags" "^1.4.3" + "safe-regex-test" "^1.0.0" + "string.prototype.trimend" "^1.0.6" + "string.prototype.trimstart" "^1.0.6" + "typed-array-length" "^1.0.4" + "unbox-primitive" "^1.0.2" + "which-typed-array" "^1.1.9" + +"es-cookie@~1.3.2": + "integrity" "sha512-UTlYYhXGLOy05P/vKVT2Ui7WtC7NiRzGtJyAKKn32g5Gvcjn7KAClLPWlipCtxIus934dFg9o9jXiBL0nP+t9Q==" + "resolved" "https://registry.npmjs.org/es-cookie/-/es-cookie-1.3.2.tgz" + "version" "1.3.2" + +"es-module-lexer@^0.9.0": + "integrity" "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==" + "resolved" "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz" + "version" "0.9.3" + +"es-set-tostringtag@^2.0.1": + "integrity" "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==" + "resolved" "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz" + "version" "2.0.1" + dependencies: + "get-intrinsic" "^1.1.3" + "has" "^1.0.3" + "has-tostringtag" "^1.0.0" + +"es-shim-unscopables@^1.0.0": + "integrity" "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==" + "resolved" "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz" + "version" "1.0.0" + dependencies: + "has" "^1.0.3" + +"es-to-primitive@^1.2.1": + "integrity" "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==" + "resolved" "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz" + "version" "1.2.1" + dependencies: + "is-callable" "^1.1.4" + "is-date-object" "^1.0.1" + "is-symbol" "^1.0.2" + +"escalade@^3.1.1": + "integrity" "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" + "resolved" "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz" + "version" "3.1.1" + +"escape-html@~1.0.3": + "integrity" "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + "resolved" "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz" + "version" "1.0.3" + +"escape-string-regexp@^1.0.5": + "integrity" "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" + "resolved" "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" + "version" "1.0.5" + +"escape-string-regexp@^4.0.0": + "integrity" "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" + "resolved" "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz" + "version" "4.0.0" + +"eslint-plugin-react@^7.31.10": + "integrity" "sha512-t2fBMa+XzonrrNkyVirzKlvn5RXzzPwRHtMvLAtVZrt8oxgnTQaYbU6SXTOO1mwQgp1y5+toMSKInnzGr0Knqg==" + "resolved" "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.32.2.tgz" + "version" "7.32.2" + dependencies: + "array-includes" "^3.1.6" + "array.prototype.flatmap" "^1.3.1" + "array.prototype.tosorted" "^1.1.1" + "doctrine" "^2.1.0" + "estraverse" "^5.3.0" + "jsx-ast-utils" "^2.4.1 || ^3.0.0" + "minimatch" "^3.1.2" + "object.entries" "^1.1.6" + "object.fromentries" "^2.0.6" + "object.hasown" "^1.1.2" + "object.values" "^1.1.6" + "prop-types" "^15.8.1" + "resolve" "^2.0.0-next.4" + "semver" "^6.3.0" + "string.prototype.matchall" "^4.0.8" + +"eslint-scope@^5.1.1", "eslint-scope@5.1.1": + "integrity" "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==" + "resolved" "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz" + "version" "5.1.1" + dependencies: + "esrecurse" "^4.3.0" + "estraverse" "^4.1.1" + +"eslint-scope@^7.1.1": + "integrity" "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==" + "resolved" "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz" + "version" "7.1.1" + dependencies: + "esrecurse" "^4.3.0" + "estraverse" "^5.2.0" + +"eslint-utils@^3.0.0": + "integrity" "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==" + "resolved" "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz" + "version" "3.0.0" + dependencies: + "eslint-visitor-keys" "^2.0.0" + +"eslint-visitor-keys@^2.0.0": + "integrity" "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==" + "resolved" "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz" + "version" "2.1.0" + +"eslint-visitor-keys@^3.3.0": + "integrity" "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==" + "resolved" "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz" + "version" "3.3.0" + +"eslint@*", "eslint@^3 || ^4 || ^5 || ^6 || ^7 || ^8", "eslint@^6.0.0 || ^7.0.0 || ^8.0.0", "eslint@^8.27.0", "eslint@>=5": + "integrity" "sha512-0y1bfG2ho7mty+SiILVf9PfuRA49ek4Nc60Wmmu62QlobNR+CeXa4xXIJgcuwSQgZiWaPH+5BDsctpIW0PR/wQ==" + "resolved" "https://registry.npmjs.org/eslint/-/eslint-8.27.0.tgz" + "version" "8.27.0" + dependencies: + "@eslint/eslintrc" "^1.3.3" + "@humanwhocodes/config-array" "^0.11.6" + "@humanwhocodes/module-importer" "^1.0.1" + "@nodelib/fs.walk" "^1.2.8" + "ajv" "^6.10.0" + "chalk" "^4.0.0" + "cross-spawn" "^7.0.2" + "debug" "^4.3.2" + "doctrine" "^3.0.0" + "escape-string-regexp" "^4.0.0" + "eslint-scope" "^7.1.1" + "eslint-utils" "^3.0.0" + "eslint-visitor-keys" "^3.3.0" + "espree" "^9.4.0" + "esquery" "^1.4.0" + "esutils" "^2.0.2" + "fast-deep-equal" "^3.1.3" + "file-entry-cache" "^6.0.1" + "find-up" "^5.0.0" + "glob-parent" "^6.0.2" + "globals" "^13.15.0" + "grapheme-splitter" "^1.0.4" + "ignore" "^5.2.0" + "import-fresh" "^3.0.0" + "imurmurhash" "^0.1.4" + "is-glob" "^4.0.0" + "is-path-inside" "^3.0.3" + "js-sdsl" "^4.1.4" + "js-yaml" "^4.1.0" + "json-stable-stringify-without-jsonify" "^1.0.1" + "levn" "^0.4.1" + "lodash.merge" "^4.6.2" + "minimatch" "^3.1.2" + "natural-compare" "^1.4.0" + "optionator" "^0.9.1" + "regexpp" "^3.2.0" + "strip-ansi" "^6.0.1" + "strip-json-comments" "^3.1.0" + "text-table" "^0.2.0" + +"espree@^9.4.0": + "integrity" "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==" + "resolved" "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz" + "version" "9.4.1" + dependencies: + "acorn" "^8.8.0" + "acorn-jsx" "^5.3.2" + "eslint-visitor-keys" "^3.3.0" + +"esquery@^1.4.0": + "integrity" "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==" + "resolved" "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz" + "version" "1.4.0" + dependencies: + "estraverse" "^5.1.0" + +"esrecurse@^4.3.0": + "integrity" "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==" + "resolved" "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz" + "version" "4.3.0" + dependencies: + "estraverse" "^5.2.0" + +"estraverse@^4.1.1": + "integrity" "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==" + "resolved" "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz" + "version" "4.3.0" + +"estraverse@^5.1.0": + "integrity" "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==" + "resolved" "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz" + "version" "5.3.0" + +"estraverse@^5.2.0": + "integrity" "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==" + "resolved" "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz" + "version" "5.3.0" + +"estraverse@^5.3.0": + "integrity" "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==" + "resolved" "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz" + "version" "5.3.0" + +"esutils@^2.0.2": + "integrity" "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" + "resolved" "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz" + "version" "2.0.3" + +"etag@~1.8.1": + "integrity" "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" + "resolved" "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz" + "version" "1.8.1" + +"event-target-shim@^5.0.0": + "version" "5.0.1" + +"events@^3.2.0": + "integrity" "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==" + "resolved" "https://registry.npmjs.org/events/-/events-3.3.0.tgz" + "version" "3.3.0" + +"events@^3.3.0": + "version" "3.3.0" + +"express@~4.16.1": + "integrity" "sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg==" + "resolved" "https://registry.npmjs.org/express/-/express-4.16.4.tgz" + "version" "4.16.4" + dependencies: + "accepts" "~1.3.5" + "array-flatten" "1.1.1" + "body-parser" "1.18.3" + "content-disposition" "0.5.2" + "content-type" "~1.0.4" + "cookie" "0.3.1" + "cookie-signature" "1.0.6" + "debug" "2.6.9" + "depd" "~1.1.2" + "encodeurl" "~1.0.2" + "escape-html" "~1.0.3" + "etag" "~1.8.1" + "finalhandler" "1.1.1" + "fresh" "0.5.2" + "merge-descriptors" "1.0.1" + "methods" "~1.1.2" + "on-finished" "~2.3.0" + "parseurl" "~1.3.2" + "path-to-regexp" "0.1.7" + "proxy-addr" "~2.0.4" + "qs" "6.5.2" + "range-parser" "~1.2.0" + "safe-buffer" "5.1.2" + "send" "0.16.2" + "serve-static" "1.13.2" + "setprototypeof" "1.1.0" + "statuses" "~1.4.0" + "type-is" "~1.6.16" + "utils-merge" "1.0.1" + "vary" "~1.1.2" + +"fast-deep-equal@^3.1.1", "fast-deep-equal@^3.1.3": + "integrity" "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + "resolved" "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz" + "version" "3.1.3" + +"fast-glob@^3.2.9": + "integrity" "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==" + "resolved" "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz" + "version" "3.2.12" + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + "glob-parent" "^5.1.2" + "merge2" "^1.3.0" + "micromatch" "^4.0.4" + +"fast-json-stable-stringify@^2.0.0": + "integrity" "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + "resolved" "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz" + "version" "2.1.0" + +"fast-levenshtein@^2.0.6": + "integrity" "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==" + "resolved" "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz" + "version" "2.0.6" + +"fast-text-encoding@^1.0.6": + "integrity" "sha512-VhXlQgj9ioXCqGstD37E/HBeqEGV/qOD/kmbVG8h5xKBYvM1L3lR1Zn4555cQ8GkYbJa8aJSipLPndE1k6zK2w==" + "resolved" "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.6.tgz" + "version" "1.0.6" + +"fastest-levenshtein@^1.0.12": + "integrity" "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==" + "resolved" "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz" + "version" "1.0.16" + +"fastest-levenshtein@^1.0.16": + "version" "1.0.16" + +"fastq@^1.6.0": + "integrity" "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==" + "resolved" "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz" + "version" "1.13.0" + dependencies: + "reusify" "^1.0.4" + +"fetch-blob@^3.1.2", "fetch-blob@^3.1.4": + "integrity" "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==" + "resolved" "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz" + "version" "3.2.0" + dependencies: + "node-domexception" "^1.0.0" + "web-streams-polyfill" "^3.0.3" + +"file-entry-cache@^6.0.1": + "integrity" "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==" + "resolved" "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz" + "version" "6.0.1" + dependencies: + "flat-cache" "^3.0.4" + +"file-loader@^6.2.0": + "integrity" "sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==" + "resolved" "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz" + "version" "6.2.0" + dependencies: + "loader-utils" "^2.0.0" + "schema-utils" "^3.0.0" + +"fill-range@^7.0.1": + "integrity" "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==" + "resolved" "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz" + "version" "7.0.1" + dependencies: + "to-regex-range" "^5.0.1" + +"finalhandler@1.1.1": + "integrity" "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==" + "resolved" "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz" + "version" "1.1.1" + dependencies: + "debug" "2.6.9" + "encodeurl" "~1.0.2" + "escape-html" "~1.0.3" + "on-finished" "~2.3.0" + "parseurl" "~1.3.2" + "statuses" "~1.4.0" + "unpipe" "~1.0.0" + +"find-cache-dir@^3.3.1": + "integrity" "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==" + "resolved" "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz" + "version" "3.3.2" + dependencies: + "commondir" "^1.0.1" + "make-dir" "^3.0.2" + "pkg-dir" "^4.1.0" + +"find-root@^1.1.0": + "integrity" "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==" + "resolved" "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz" + "version" "1.1.0" + +"find-up@^4.0.0": + "integrity" "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==" + "resolved" "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz" + "version" "4.1.0" + dependencies: + "locate-path" "^5.0.0" + "path-exists" "^4.0.0" + +"find-up@^5.0.0": + "integrity" "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==" + "resolved" "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz" + "version" "5.0.0" + dependencies: + "locate-path" "^6.0.0" + "path-exists" "^4.0.0" + +"flat-cache@^3.0.4": + "integrity" "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==" + "resolved" "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz" + "version" "3.0.4" + dependencies: + "flatted" "^3.1.0" + "rimraf" "^3.0.2" + +"flatted@^3.1.0": + "integrity" "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==" + "resolved" "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz" + "version" "3.2.7" + +"follow-redirects@^1.15.0": + "integrity" "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==" + "resolved" "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz" + "version" "1.15.2" + +"for-each@^0.3.3": + "integrity" "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==" + "resolved" "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz" + "version" "0.3.3" + dependencies: + "is-callable" "^1.1.3" + +"form-data@^4.0.0": + "integrity" "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==" + "resolved" "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz" + "version" "4.0.0" + dependencies: + "asynckit" "^0.4.0" + "combined-stream" "^1.0.8" + "mime-types" "^2.1.12" + +"formdata-polyfill@^4.0.10": + "integrity" "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==" + "resolved" "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz" + "version" "4.0.10" + dependencies: + "fetch-blob" "^3.1.2" + +"forwarded@0.2.0": + "integrity" "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" + "resolved" "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz" + "version" "0.2.0" + +"framer-motion@^7.6.1": + "integrity" "sha512-8US03IWJKrLoSb81l5OahNzB9Sv7Jo1RhIwUoTG/25BRUdO9lOqq/klsdZqNmNG0ua9IEJJQ8hkYpETJ4N6VSw==" + "resolved" "https://registry.npmjs.org/framer-motion/-/framer-motion-7.6.1.tgz" + "version" "7.6.1" + dependencies: + "@motionone/dom" "10.13.1" + "framesync" "6.1.2" + "hey-listen" "^1.0.8" + "popmotion" "11.0.5" + "style-value-types" "5.1.2" + "tslib" "2.4.0" + optionalDependencies: + "@emotion/is-prop-valid" "^0.8.2" + +"framesync@6.1.2": + "integrity" "sha512-jBTqhX6KaQVDyus8muwZbBeGGP0XgujBRbQ7gM7BRdS3CadCZIHiawyzYLnafYcvZIh5j8WE7cxZKFn7dXhu9g==" + "resolved" "https://registry.npmjs.org/framesync/-/framesync-6.1.2.tgz" + "version" "6.1.2" + dependencies: + "tslib" "2.4.0" + +"fresh@0.5.2": + "integrity" "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" + "resolved" "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz" + "version" "0.5.2" + +"fs-minipass@^2.0.0": + "version" "2.1.0" + dependencies: + "minipass" "^3.0.0" + +"fs-minipass@^2.1.0": + "version" "2.1.0" + dependencies: + "minipass" "^3.0.0" + +"fs-minipass@^3.0.0", "fs-minipass@^3.0.1": + "version" "3.0.1" + dependencies: + "minipass" "^4.0.0" + +"fs.realpath@^1.0.0": + "integrity" "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + "resolved" "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" + "version" "1.0.0" + +"fsevents@~2.3.2": + "integrity" "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==" + "resolved" "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz" + "version" "2.3.2" + +"function-bind@^1.1.1": + "integrity" "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + "resolved" "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz" + "version" "1.1.1" + +"function.prototype.name@^1.1.5": + "integrity" "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==" + "resolved" "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz" + "version" "1.1.5" + dependencies: + "call-bind" "^1.0.2" + "define-properties" "^1.1.3" + "es-abstract" "^1.19.0" + "functions-have-names" "^1.2.2" + +"functions-have-names@^1.2.2": + "integrity" "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==" + "resolved" "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz" + "version" "1.2.3" + +"gauge@^4.0.3": + "version" "4.0.4" + dependencies: + "aproba" "^1.0.3 || ^2.0.0" + "color-support" "^1.1.3" + "console-control-strings" "^1.1.0" + "has-unicode" "^2.0.1" + "signal-exit" "^3.0.7" + "string-width" "^4.2.3" + "strip-ansi" "^6.0.1" + "wide-align" "^1.1.5" + +"gauge@^5.0.0": + "version" "5.0.0" + dependencies: + "aproba" "^1.0.3 || ^2.0.0" + "color-support" "^1.1.3" + "console-control-strings" "^1.1.0" + "has-unicode" "^2.0.1" + "signal-exit" "^3.0.7" + "string-width" "^4.2.3" + "strip-ansi" "^6.0.1" + "wide-align" "^1.1.5" + +"gensync@^1.0.0-beta.2": + "integrity" "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==" + "resolved" "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz" + "version" "1.0.0-beta.2" + +"get-intrinsic@^1.0.2", "get-intrinsic@^1.1.1", "get-intrinsic@^1.1.3", "get-intrinsic@^1.2.0": + "integrity" "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==" + "resolved" "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz" + "version" "1.2.0" + dependencies: + "function-bind" "^1.1.1" + "has" "^1.0.3" + "has-symbols" "^1.0.3" + +"get-symbol-description@^1.0.0": + "integrity" "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==" + "resolved" "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz" + "version" "1.0.0" + dependencies: + "call-bind" "^1.0.2" + "get-intrinsic" "^1.1.1" + +"glob-parent@^5.1.2", "glob-parent@~5.1.2": + "integrity" "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==" + "resolved" "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz" + "version" "5.1.2" + dependencies: + "is-glob" "^4.0.1" + +"glob-parent@^6.0.2": + "integrity" "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==" + "resolved" "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz" + "version" "6.0.2" + dependencies: + "is-glob" "^4.0.3" + +"glob-to-regexp@^0.4.1": + "integrity" "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==" + "resolved" "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz" + "version" "0.4.1" + +"glob@^7.1.3": + "integrity" "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==" + "resolved" "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz" + "version" "7.2.3" + dependencies: + "fs.realpath" "^1.0.0" + "inflight" "^1.0.4" + "inherits" "2" + "minimatch" "^3.1.1" + "once" "^1.3.0" + "path-is-absolute" "^1.0.0" + +"glob@^7.1.4": + "version" "7.2.3" + dependencies: + "fs.realpath" "^1.0.0" + "inflight" "^1.0.4" + "inherits" "2" + "minimatch" "^3.1.1" + "once" "^1.3.0" + "path-is-absolute" "^1.0.0" + +"glob@^8.0.1", "glob@^8.1.0": + "version" "8.1.0" + dependencies: + "fs.realpath" "^1.0.0" + "inflight" "^1.0.4" + "inherits" "2" + "minimatch" "^5.0.1" + "once" "^1.3.0" + +"globals@^11.1.0": + "integrity" "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" + "resolved" "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz" + "version" "11.12.0" + +"globals@^13.15.0": + "integrity" "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==" + "resolved" "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz" + "version" "13.17.0" + dependencies: + "type-fest" "^0.20.2" + +"globalthis@^1.0.3": + "integrity" "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==" + "resolved" "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz" + "version" "1.0.3" + dependencies: + "define-properties" "^1.1.3" + +"globby@^11.1.0": + "integrity" "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==" + "resolved" "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz" + "version" "11.1.0" + dependencies: + "array-union" "^2.1.0" + "dir-glob" "^3.0.1" + "fast-glob" "^3.2.9" + "ignore" "^5.2.0" + "merge2" "^1.4.1" + "slash" "^3.0.0" + +"goober@^2.1.10": + "integrity" "sha512-5SS2lmxbhqH0u9ABEWq7WPU69a4i2pYcHeCxqaNq6Cw3mnrF0ghWNM4tEGid4dKy8XNIAUbuThuozDHHKJVh3A==" + "resolved" "https://registry.npmjs.org/goober/-/goober-2.1.11.tgz" + "version" "2.1.11" + +"gopd@^1.0.1": + "integrity" "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==" + "resolved" "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz" + "version" "1.0.1" + dependencies: + "get-intrinsic" "^1.1.3" + +"graceful-fs@^4.1.2", "graceful-fs@^4.2.4", "graceful-fs@^4.2.9": + "integrity" "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" + "resolved" "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz" + "version" "4.2.10" + +"graceful-fs@^4.2.10", "graceful-fs@^4.2.6": + "version" "4.2.10" + +"grapheme-splitter@^1.0.4": + "integrity" "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==" + "resolved" "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz" + "version" "1.0.4" + +"has-bigints@^1.0.1", "has-bigints@^1.0.2": + "integrity" "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==" + "resolved" "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz" + "version" "1.0.2" + +"has-flag@^3.0.0": + "integrity" "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" + "resolved" "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz" + "version" "3.0.0" + +"has-flag@^4.0.0": + "integrity" "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + "resolved" "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz" + "version" "4.0.0" + +"has-property-descriptors@^1.0.0": + "integrity" "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==" + "resolved" "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz" + "version" "1.0.0" + dependencies: + "get-intrinsic" "^1.1.1" + +"has-proto@^1.0.1": + "integrity" "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==" + "resolved" "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz" + "version" "1.0.1" + +"has-symbols@^1.0.2", "has-symbols@^1.0.3": + "integrity" "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" + "resolved" "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz" + "version" "1.0.3" + +"has-tostringtag@^1.0.0": + "integrity" "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==" + "resolved" "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz" + "version" "1.0.0" + dependencies: + "has-symbols" "^1.0.2" + +"has-unicode@^2.0.1": + "version" "2.0.1" + +"has@^1.0.3": + "integrity" "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==" + "resolved" "https://registry.npmjs.org/has/-/has-1.0.3.tgz" + "version" "1.0.3" + dependencies: + "function-bind" "^1.1.1" + +"he@^1.2.0": + "integrity" "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" + "resolved" "https://registry.npmjs.org/he/-/he-1.2.0.tgz" + "version" "1.2.0" + +"hey-listen@^1.0.8": + "integrity" "sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q==" + "resolved" "https://registry.npmjs.org/hey-listen/-/hey-listen-1.0.8.tgz" + "version" "1.0.8" + +"hoist-non-react-statics@^3.3.0", "hoist-non-react-statics@^3.3.1", "hoist-non-react-statics@^3.3.2": + "integrity" "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==" + "resolved" "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz" + "version" "3.3.2" + dependencies: + "react-is" "^16.7.0" + +"hosted-git-info@^6.0.0", "hosted-git-info@^6.1.1": + "version" "6.1.1" + dependencies: + "lru-cache" "^7.5.1" + +"html-minifier-terser@^6.0.2": + "integrity" "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==" + "resolved" "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz" + "version" "6.1.0" + 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" + +"html-webpack-plugin@^5.5.0": + "integrity" "sha512-sy88PC2cRTVxvETRgUHFrL4No3UxvcH8G1NepGhqaTT+GXN2kTamqasot0inS5hXeg1cMbFDt27zzo9p35lZVw==" + "resolved" "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.5.0.tgz" + "version" "5.5.0" + 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" + +"htmlparser2@^6.1.0": + "integrity" "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==" + "resolved" "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz" + "version" "6.1.0" + dependencies: + "domelementtype" "^2.0.1" + "domhandler" "^4.0.0" + "domutils" "^2.5.2" + "entities" "^2.0.0" + +"http-cache-semantics@^4.1.0", "http-cache-semantics@^4.1.1": + "version" "4.1.1" + +"http-errors@~1.6.2", "http-errors@~1.6.3", "http-errors@1.6.3": + "integrity" "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==" + "resolved" "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz" + "version" "1.6.3" + dependencies: + "depd" "~1.1.2" + "inherits" "2.0.3" + "setprototypeof" "1.1.0" + "statuses" ">= 1.4.0 < 2" + +"http-proxy-agent@^5.0.0": + "version" "5.0.0" + dependencies: + "@tootallnate/once" "2" + "agent-base" "6" + "debug" "4" + +"https-proxy-agent@^5.0.0": + "version" "5.0.1" + dependencies: + "agent-base" "6" + "debug" "4" + +"humanize-ms@^1.2.1": + "version" "1.2.1" + dependencies: + "ms" "^2.0.0" + +"iconv-lite@^0.6.2": + "version" "0.6.3" + dependencies: + "safer-buffer" ">= 2.1.2 < 3.0.0" + +"iconv-lite@0.4.23": + "integrity" "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==" + "resolved" "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz" + "version" "0.4.23" + dependencies: + "safer-buffer" ">= 2.1.2 < 3" + +"icss-utils@^5.0.0", "icss-utils@^5.1.0": + "integrity" "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==" + "resolved" "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz" + "version" "5.1.0" + +"ieee754@^1.2.1": + "version" "1.2.1" + +"ignore-by-default@^1.0.1": + "integrity" "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==" + "resolved" "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz" + "version" "1.0.1" + +"ignore-walk@^6.0.0": + "version" "6.0.1" + dependencies: + "minimatch" "^6.1.6" + +"ignore@^5.2.0": + "integrity" "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==" + "resolved" "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz" + "version" "5.2.0" + +"import-fresh@^3.0.0", "import-fresh@^3.2.1": + "integrity" "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==" + "resolved" "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz" + "version" "3.3.0" + dependencies: + "parent-module" "^1.0.0" + "resolve-from" "^4.0.0" + +"import-local@^3.0.2": + "integrity" "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==" + "resolved" "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz" + "version" "3.1.0" + dependencies: + "pkg-dir" "^4.2.0" + "resolve-cwd" "^3.0.0" + +"imurmurhash@^0.1.4": + "integrity" "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==" + "resolved" "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz" + "version" "0.1.4" + +"indent-string@^4.0.0": + "version" "4.0.0" + +"infer-owner@^1.0.4": + "version" "1.0.4" + +"inflight@^1.0.4": + "integrity" "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==" + "resolved" "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz" + "version" "1.0.6" + dependencies: + "once" "^1.3.0" + "wrappy" "1" + +"inherits@^2.0.3": + "version" "2.0.4" + +"inherits@2", "inherits@2.0.3": + "integrity" "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==" + "resolved" "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz" + "version" "2.0.3" + +"ini@^3.0.0", "ini@^3.0.1": + "version" "3.0.1" + +"init-package-json@^5.0.0": + "version" "5.0.0" + dependencies: + "npm-package-arg" "^10.0.0" + "promzard" "^1.0.0" + "read" "^2.0.0" + "read-package-json" "^6.0.0" + "semver" "^7.3.5" + "validate-npm-package-license" "^3.0.4" + "validate-npm-package-name" "^5.0.0" + +"install@^0.13.0": + "integrity" "sha512-zDml/jzr2PKU9I8J/xyZBQn8rPCAY//UOYNmR01XwNwyfhEWObo2SWfSl1+0tm1u6PhxLwDnfsT/6jB7OUxqFA==" + "resolved" "https://registry.npmjs.org/install/-/install-0.13.0.tgz" + "version" "0.13.0" + +"internal-slot@^1.0.3", "internal-slot@^1.0.4": + "integrity" "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==" + "resolved" "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz" + "version" "1.0.5" + dependencies: + "get-intrinsic" "^1.2.0" + "has" "^1.0.3" + "side-channel" "^1.0.4" + +"interpret@^2.2.0": + "integrity" "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==" + "resolved" "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz" + "version" "2.2.0" + +"intl-messageformat@10.2.1": + "integrity" "sha512-1lrJG2qKzcC1TVzYu1VuB1yiY68LU5rwpbHa2THCzA67Vutkz7+1lv5U20K3Lz5RAiH78zxNztMEtchokMWv8A==" + "resolved" "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-10.2.1.tgz" + "version" "10.2.1" + dependencies: + "@formatjs/ecma402-abstract" "1.13.0" + "@formatjs/fast-memoize" "1.2.6" + "@formatjs/icu-messageformat-parser" "2.1.10" + "tslib" "2.4.0" + +"ip-regex@^4.1.0": + "version" "4.3.0" + +"ip@^2.0.0": + "version" "2.0.0" + +"ipaddr.js@1.9.1": + "integrity" "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" + "resolved" "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz" + "version" "1.9.1" + +"is-array-buffer@^3.0.1": + "integrity" "sha512-ASfLknmY8Xa2XtB4wmbz13Wu202baeA18cJBCeCy0wXUHZF0IPyVEXqKEcd+t2fNSLLL1vC6k7lxZEojNbISXQ==" + "resolved" "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.1.tgz" + "version" "3.0.1" + dependencies: + "call-bind" "^1.0.2" + "get-intrinsic" "^1.1.3" + "is-typed-array" "^1.1.10" + +"is-arrayish@^0.2.1": + "integrity" "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" + "resolved" "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz" + "version" "0.2.1" + +"is-bigint@^1.0.1": + "integrity" "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==" + "resolved" "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz" + "version" "1.0.4" + dependencies: + "has-bigints" "^1.0.1" + +"is-binary-path@~2.1.0": + "integrity" "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==" + "resolved" "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz" + "version" "2.1.0" + dependencies: + "binary-extensions" "^2.0.0" + +"is-boolean-object@^1.1.0": + "integrity" "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==" + "resolved" "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz" + "version" "1.1.2" + dependencies: + "call-bind" "^1.0.2" + "has-tostringtag" "^1.0.0" + +"is-callable@^1.1.3", "is-callable@^1.1.4", "is-callable@^1.2.7": + "integrity" "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==" + "resolved" "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz" + "version" "1.2.7" + +"is-cidr@^4.0.2": + "version" "4.0.2" + dependencies: + "cidr-regex" "^3.1.1" + +"is-core-module@^2.8.1": + "version" "2.11.0" + dependencies: + "has" "^1.0.3" + +"is-core-module@^2.9.0": + "integrity" "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==" + "resolved" "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz" + "version" "2.11.0" + dependencies: + "has" "^1.0.3" + +"is-date-object@^1.0.1": + "integrity" "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==" + "resolved" "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz" + "version" "1.0.5" + dependencies: + "has-tostringtag" "^1.0.0" + +"is-extglob@^2.1.1": + "integrity" "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==" + "resolved" "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz" + "version" "2.1.1" + +"is-fullwidth-code-point@^3.0.0": + "version" "3.0.0" + +"is-glob@^4.0.0", "is-glob@^4.0.1", "is-glob@^4.0.3", "is-glob@~4.0.1": + "integrity" "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==" + "resolved" "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz" + "version" "4.0.3" + dependencies: + "is-extglob" "^2.1.1" + +"is-lambda@^1.0.1": + "version" "1.0.1" + +"is-negative-zero@^2.0.2": + "integrity" "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==" + "resolved" "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz" + "version" "2.0.2" + +"is-number-object@^1.0.4": + "integrity" "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==" + "resolved" "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz" + "version" "1.0.7" + dependencies: + "has-tostringtag" "^1.0.0" + +"is-number@^7.0.0": + "integrity" "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + "resolved" "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz" + "version" "7.0.0" + +"is-path-inside@^3.0.3": + "integrity" "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==" + "resolved" "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz" + "version" "3.0.3" + +"is-plain-object@^2.0.4": + "integrity" "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==" + "resolved" "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz" + "version" "2.0.4" + dependencies: + "isobject" "^3.0.1" + +"is-regex@^1.1.4": + "integrity" "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==" + "resolved" "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz" + "version" "1.1.4" + dependencies: + "call-bind" "^1.0.2" + "has-tostringtag" "^1.0.0" + +"is-shared-array-buffer@^1.0.2": + "integrity" "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==" + "resolved" "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz" + "version" "1.0.2" + dependencies: + "call-bind" "^1.0.2" + +"is-string@^1.0.5", "is-string@^1.0.7": + "integrity" "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==" + "resolved" "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz" + "version" "1.0.7" + dependencies: + "has-tostringtag" "^1.0.0" + +"is-symbol@^1.0.2", "is-symbol@^1.0.3": + "integrity" "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==" + "resolved" "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz" + "version" "1.0.4" + dependencies: + "has-symbols" "^1.0.2" + +"is-typed-array@^1.1.10", "is-typed-array@^1.1.9": + "integrity" "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==" + "resolved" "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz" + "version" "1.1.10" + 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-weakref@^1.0.2": + "integrity" "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==" + "resolved" "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz" + "version" "1.0.2" + dependencies: + "call-bind" "^1.0.2" + +"isexe@^2.0.0": + "integrity" "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + "resolved" "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz" + "version" "2.0.0" + +"isobject@^3.0.1": + "integrity" "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==" + "resolved" "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz" + "version" "3.0.1" + +"jest-worker@^27.4.5": + "integrity" "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==" + "resolved" "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz" + "version" "27.5.1" + dependencies: + "@types/node" "*" + "merge-stream" "^2.0.0" + "supports-color" "^8.0.0" + +"js-sdsl@^4.1.4": + "integrity" "sha512-08bOAKweV2NUC1wqTtf3qZlnpOX/R2DU9ikpjOHs0H+ibQv3zpncVQg6um4uYtRtrwIX8M4Nh3ytK4HGlYAq7Q==" + "resolved" "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.5.tgz" + "version" "4.1.5" + +"js-tokens@^3.0.0 || ^4.0.0", "js-tokens@^4.0.0": + "integrity" "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + "resolved" "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" + "version" "4.0.0" + +"js-yaml@^4.1.0": + "integrity" "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==" + "resolved" "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz" + "version" "4.1.0" + dependencies: + "argparse" "^2.0.1" + +"jsesc@^2.5.1": + "integrity" "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" + "resolved" "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz" + "version" "2.5.2" + +"jsesc@~0.5.0": + "integrity" "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==" + "resolved" "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz" + "version" "0.5.0" + +"json-parse-even-better-errors@^2.3.0", "json-parse-even-better-errors@^2.3.1": + "integrity" "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" + "resolved" "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz" + "version" "2.3.1" + +"json-parse-even-better-errors@^3.0.0": + "version" "3.0.0" + +"json-schema-traverse@^0.4.1": + "integrity" "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + "resolved" "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz" + "version" "0.4.1" + +"json-stable-stringify-without-jsonify@^1.0.1": + "integrity" "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==" + "resolved" "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz" + "version" "1.0.1" + +"json-stringify-nice@^1.1.4": + "version" "1.1.4" + +"json5@^2.1.2", "json5@^2.2.1": + "integrity" "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==" + "resolved" "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz" + "version" "2.2.1" + +"jsonparse@^1.3.1": + "version" "1.3.1" + +"jsonwebtoken@^9.0.0": + "integrity" "sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw==" + "resolved" "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz" + "version" "9.0.0" + dependencies: + "jws" "^3.2.2" + "lodash" "^4.17.21" + "ms" "^2.1.1" + "semver" "^7.3.8" + +"jsrsasign@^10.5.27": + "integrity" "sha512-1F4LmDeJZHYwoVvB44jEo2uZL3XuwYNzXCDOu53Ui6vqofGQ/gCYDmaxfVZtN0TGd92UKXr/BONcfrPonUIcQQ==" + "resolved" "https://registry.npmjs.org/jsrsasign/-/jsrsasign-10.5.27.tgz" + "version" "10.5.27" + +"jsx-ast-utils@^2.4.1 || ^3.0.0": + "integrity" "sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw==" + "resolved" "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz" + "version" "3.3.3" + dependencies: + "array-includes" "^3.1.5" + "object.assign" "^4.1.3" + +"just-diff-apply@^5.2.0": + "version" "5.5.0" + +"just-diff@^5.0.1": + "version" "5.2.0" + +"jwa@^1.4.1": + "integrity" "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==" + "resolved" "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz" + "version" "1.4.1" + dependencies: + "buffer-equal-constant-time" "1.0.1" + "ecdsa-sig-formatter" "1.0.11" + "safe-buffer" "^5.0.1" + +"jws@^3.2.2": + "integrity" "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==" + "resolved" "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz" + "version" "3.2.2" + dependencies: + "jwa" "^1.4.1" + "safe-buffer" "^5.0.1" + +"jwt-decode@^3.1.2": + "integrity" "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==" + "resolved" "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz" + "version" "3.1.2" + +"kind-of@^6.0.2": + "integrity" "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" + "resolved" "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz" + "version" "6.0.3" + +"levn@^0.4.1": + "integrity" "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==" + "resolved" "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz" + "version" "0.4.1" + dependencies: + "prelude-ls" "^1.2.1" + "type-check" "~0.4.0" + +"libnpmaccess@^7.0.2": + "version" "7.0.2" + dependencies: + "npm-package-arg" "^10.1.0" + "npm-registry-fetch" "^14.0.3" + +"libnpmdiff@^5.0.11": + "version" "5.0.11" + dependencies: + "@npmcli/arborist" "^6.2.3" + "@npmcli/disparity-colors" "^3.0.0" + "@npmcli/installed-package-contents" "^2.0.0" + "binary-extensions" "^2.2.0" + "diff" "^5.1.0" + "minimatch" "^6.1.6" + "npm-package-arg" "^10.1.0" + "pacote" "^15.0.8" + "tar" "^6.1.13" + +"libnpmexec@^5.0.11": + "version" "5.0.11" + dependencies: + "@npmcli/arborist" "^6.2.3" + "@npmcli/run-script" "^6.0.0" + "chalk" "^4.1.0" + "ci-info" "^3.7.1" + "npm-package-arg" "^10.1.0" + "npmlog" "^7.0.1" + "pacote" "^15.0.8" + "proc-log" "^3.0.0" + "read" "^2.0.0" + "read-package-json-fast" "^3.0.2" + "semver" "^7.3.7" + "walk-up-path" "^1.0.0" + +"libnpmfund@^4.0.11": + "version" "4.0.11" + dependencies: + "@npmcli/arborist" "^6.2.3" + +"libnpmhook@^9.0.3": + "version" "9.0.3" + dependencies: + "aproba" "^2.0.0" + "npm-registry-fetch" "^14.0.3" + +"libnpmorg@^5.0.3": + "version" "5.0.3" + dependencies: + "aproba" "^2.0.0" + "npm-registry-fetch" "^14.0.3" + +"libnpmpack@^5.0.11": + "version" "5.0.11" + dependencies: + "@npmcli/arborist" "^6.2.3" + "@npmcli/run-script" "^6.0.0" + "npm-package-arg" "^10.1.0" + "pacote" "^15.0.8" + +"libnpmpublish@^7.1.0": + "version" "7.1.0" + dependencies: + "ci-info" "^3.6.1" + "normalize-package-data" "^5.0.0" + "npm-package-arg" "^10.1.0" + "npm-registry-fetch" "^14.0.3" + "semver" "^7.3.7" + "sigstore" "^1.0.0" + "ssri" "^10.0.1" + +"libnpmsearch@^6.0.2": + "version" "6.0.2" + dependencies: + "npm-registry-fetch" "^14.0.3" + +"libnpmteam@^5.0.3": + "version" "5.0.3" + dependencies: + "aproba" "^2.0.0" + "npm-registry-fetch" "^14.0.3" + +"libnpmversion@^4.0.2": + "version" "4.0.2" + dependencies: + "@npmcli/git" "^4.0.1" + "@npmcli/run-script" "^6.0.0" + "json-parse-even-better-errors" "^3.0.0" + "proc-log" "^3.0.0" + "semver" "^7.3.7" + +"lines-and-columns@^1.1.6": + "integrity" "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" + "resolved" "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz" + "version" "1.2.4" + +"livereload-js@^3.3.1": + "integrity" "sha512-5MP0uUeVCec89ZbNOT/i97Mc+q3SxXmiUGhRFOTmhrGPn//uWVQdCvcLJDy64MSBR5MidFdOR7B9viumoavy6g==" + "resolved" "https://registry.npmjs.org/livereload-js/-/livereload-js-3.4.1.tgz" + "version" "3.4.1" + +"livereload@^0.9.3": + "integrity" "sha512-q7Z71n3i4X0R9xthAryBdNGVGAO2R5X+/xXpmKeuPMrteg+W2U8VusTKV3YiJbXZwKsOlFlHe+go6uSNjfxrZw==" + "resolved" "https://registry.npmjs.org/livereload/-/livereload-0.9.3.tgz" + "version" "0.9.3" + dependencies: + "chokidar" "^3.5.0" + "livereload-js" "^3.3.1" + "opts" ">= 1.2.0" + "ws" "^7.4.3" + +"loader-runner@^4.2.0": + "integrity" "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==" + "resolved" "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz" + "version" "4.3.0" + +"loader-utils@^2.0.0": + "integrity" "sha512-THWqIsn8QRnvLl0shHYVBN9syumU8pYWEHPTmkiVGd+7K5eFNVSY6AJhRvgGF70gg1Dz+l/k8WicvFCxdEs60A==" + "resolved" "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.3.tgz" + "version" "2.0.3" + dependencies: + "big.js" "^5.2.2" + "emojis-list" "^3.0.0" + "json5" "^2.1.2" + +"locate-path@^5.0.0": + "integrity" "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==" + "resolved" "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz" + "version" "5.0.0" + dependencies: + "p-locate" "^4.1.0" + +"locate-path@^6.0.0": + "integrity" "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==" + "resolved" "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz" + "version" "6.0.0" + dependencies: + "p-locate" "^5.0.0" + +"lodash.debounce@^4.0.8": + "integrity" "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" + "resolved" "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz" + "version" "4.0.8" + +"lodash.memoize@^4.1.2": + "integrity" "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==" + "resolved" "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz" + "version" "4.1.2" + +"lodash.merge@^4.6.2": + "integrity" "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" + "resolved" "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz" + "version" "4.6.2" + +"lodash.throttle@^4.1.1": + "integrity" "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==" + "resolved" "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz" + "version" "4.1.1" + +"lodash@^4.17.20", "lodash@^4.17.21", "lodash@>=4.17.21": + "integrity" "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + "resolved" "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" + "version" "4.17.21" + +"loose-envify@^1.1.0", "loose-envify@^1.4.0": + "integrity" "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==" + "resolved" "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz" + "version" "1.4.0" + dependencies: + "js-tokens" "^3.0.0 || ^4.0.0" + +"lower-case@^2.0.2": + "integrity" "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==" + "resolved" "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz" + "version" "2.0.2" + dependencies: + "tslib" "^2.0.3" + +"lru-cache@^6.0.0": + "integrity" "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==" + "resolved" "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz" + "version" "6.0.0" + dependencies: + "yallist" "^4.0.0" + +"lru-cache@^7.4.4", "lru-cache@^7.5.1", "lru-cache@^7.7.1": + "version" "7.16.2" + +"make-dir@^3.0.2", "make-dir@^3.1.0": + "integrity" "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==" + "resolved" "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz" + "version" "3.1.0" + dependencies: + "semver" "^6.0.0" + +"make-fetch-happen@^10.0.3": + "version" "10.2.1" + dependencies: + "agentkeepalive" "^4.2.1" + "cacache" "^16.1.0" + "http-cache-semantics" "^4.1.0" + "http-proxy-agent" "^5.0.0" + "https-proxy-agent" "^5.0.0" + "is-lambda" "^1.0.1" + "lru-cache" "^7.7.1" + "minipass" "^3.1.6" + "minipass-collect" "^1.0.2" + "minipass-fetch" "^2.0.3" + "minipass-flush" "^1.0.5" + "minipass-pipeline" "^1.2.4" + "negotiator" "^0.6.3" + "promise-retry" "^2.0.1" + "socks-proxy-agent" "^7.0.0" + "ssri" "^9.0.0" + +"make-fetch-happen@^11.0.0", "make-fetch-happen@^11.0.1", "make-fetch-happen@^11.0.3": + "version" "11.0.3" + dependencies: + "agentkeepalive" "^4.2.1" + "cacache" "^17.0.0" + "http-cache-semantics" "^4.1.1" + "http-proxy-agent" "^5.0.0" + "https-proxy-agent" "^5.0.0" + "is-lambda" "^1.0.1" + "lru-cache" "^7.7.1" + "minipass" "^4.0.0" + "minipass-fetch" "^3.0.0" + "minipass-flush" "^1.0.5" + "minipass-pipeline" "^1.2.4" + "negotiator" "^0.6.3" + "promise-retry" "^2.0.1" + "socks-proxy-agent" "^7.0.0" + "ssri" "^10.0.0" + +"media-typer@0.3.0": + "integrity" "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==" + "resolved" "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz" + "version" "0.3.0" + +"merge-descriptors@1.0.1": + "integrity" "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + "resolved" "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz" + "version" "1.0.1" + +"merge-stream@^2.0.0": + "integrity" "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" + "resolved" "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz" + "version" "2.0.0" + +"merge2@^1.3.0", "merge2@^1.4.1": + "integrity" "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==" + "resolved" "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz" + "version" "1.4.1" + +"methods@~1.1.2": + "integrity" "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==" + "resolved" "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz" + "version" "1.1.2" + +"micromatch@^4.0.0", "micromatch@^4.0.4": + "integrity" "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==" + "resolved" "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz" + "version" "4.0.5" + dependencies: + "braces" "^3.0.2" + "picomatch" "^2.3.1" + +"mime-db@1.52.0": + "integrity" "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + "resolved" "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz" + "version" "1.52.0" + +"mime-types@^2.1.12", "mime-types@^2.1.27", "mime-types@~2.1.24", "mime-types@~2.1.34": + "integrity" "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==" + "resolved" "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz" + "version" "2.1.35" + dependencies: + "mime-db" "1.52.0" + +"mime@1.4.1": + "integrity" "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==" + "resolved" "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz" + "version" "1.4.1" + +"minimatch@^3.0.5", "minimatch@^3.1.1", "minimatch@^3.1.2": + "integrity" "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==" + "resolved" "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" + "version" "3.1.2" + dependencies: + "brace-expansion" "^1.1.7" + +"minimatch@^5.0.1": + "version" "5.1.6" + dependencies: + "brace-expansion" "^2.0.1" + +"minimatch@^6.1.0", "minimatch@^6.1.6", "minimatch@^6.2.0": + "version" "6.2.0" + dependencies: + "brace-expansion" "^2.0.1" + +"minipass-collect@^1.0.2": + "version" "1.0.2" + dependencies: + "minipass" "^3.0.0" + +"minipass-fetch@^2.0.3": + "version" "2.1.2" + dependencies: + "minipass" "^3.1.6" + "minipass-sized" "^1.0.3" + "minizlib" "^2.1.2" + optionalDependencies: + "encoding" "^0.1.13" + +"minipass-fetch@^3.0.0": + "version" "3.0.1" + dependencies: + "minipass" "^4.0.0" + "minipass-sized" "^1.0.3" + "minizlib" "^2.1.2" + optionalDependencies: + "encoding" "^0.1.13" + +"minipass-flush@^1.0.5": + "version" "1.0.5" + dependencies: + "minipass" "^3.0.0" + +"minipass-json-stream@^1.0.1": + "version" "1.0.1" + dependencies: + "jsonparse" "^1.3.1" + "minipass" "^3.0.0" + +"minipass-pipeline@^1.2.4": + "version" "1.2.4" + dependencies: + "minipass" "^3.0.0" + +"minipass-sized@^1.0.3": + "version" "1.0.3" + dependencies: + "minipass" "^3.0.0" + +"minipass@^3.0.0", "minipass@^3.1.1", "minipass@^3.1.6": + "version" "3.3.6" + dependencies: + "yallist" "^4.0.0" + +"minipass@^4.0.0", "minipass@^4.0.3": + "version" "4.0.3" + +"minizlib@^2.1.1", "minizlib@^2.1.2": + "version" "2.1.2" + dependencies: + "minipass" "^3.0.0" + "yallist" "^4.0.0" + +"mkdirp@^1.0.3", "mkdirp@^1.0.4": + "version" "1.0.4" + +"moment@^2.29.4": + "integrity" "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==" + "resolved" "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz" + "version" "2.29.4" + +"morgan@~1.9.1": + "integrity" "sha512-HQStPIV4y3afTiCYVxirakhlCfGkI161c76kKFca7Fk1JusM//Qeo1ej2XaMniiNeaZklMVrh3vTtIzpzwbpmA==" + "resolved" "https://registry.npmjs.org/morgan/-/morgan-1.9.1.tgz" + "version" "1.9.1" + dependencies: + "basic-auth" "~2.0.0" + "debug" "2.6.9" + "depd" "~1.1.2" + "on-finished" "~2.3.0" + "on-headers" "~1.0.1" + +"ms@^2.0.0", "ms@^2.1.2": + "version" "2.1.3" + +"ms@^2.1.1": + "integrity" "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + "resolved" "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" + "version" "2.1.3" + +"ms@2.0.0": + "integrity" "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + "resolved" "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz" + "version" "2.0.0" + +"ms@2.1.2": + "integrity" "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "resolved" "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" + "version" "2.1.2" + +"mute-stream@~1.0.0": + "version" "1.0.0" + +"nanoid@^3.3.4": + "integrity" "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==" + "resolved" "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz" + "version" "3.3.4" + +"natural-compare-lite@^1.4.0": + "integrity" "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==" + "resolved" "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz" + "version" "1.4.0" + +"natural-compare@^1.4.0": + "integrity" "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==" + "resolved" "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz" + "version" "1.4.0" + +"negotiator@^0.6.3": + "version" "0.6.3" + +"negotiator@0.6.3": + "integrity" "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" + "resolved" "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz" + "version" "0.6.3" + +"neo-async@^2.6.2": + "integrity" "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" + "resolved" "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz" + "version" "2.6.2" + +"no-case@^3.0.4": + "integrity" "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==" + "resolved" "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz" + "version" "3.0.4" + dependencies: + "lower-case" "^2.0.2" + "tslib" "^2.0.3" + +"node-domexception@^1.0.0": + "integrity" "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==" + "resolved" "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz" + "version" "1.0.0" + +"node-fetch@^3.3.0": + "integrity" "sha512-BKwRP/O0UvoMKp7GNdwPlObhYGB5DQqwhEDQlNKuoqwVYSxkSZCSbHjnFFmUEtwSKRPU4kNK8PbDYYitwaE3QA==" + "resolved" "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.0.tgz" + "version" "3.3.0" + dependencies: + "data-uri-to-buffer" "^4.0.0" + "fetch-blob" "^3.1.4" + "formdata-polyfill" "^4.0.10" + +"node-gyp@^9.0.0", "node-gyp@^9.3.1": + "version" "9.3.1" + dependencies: + "env-paths" "^2.2.0" + "glob" "^7.1.4" + "graceful-fs" "^4.2.6" + "make-fetch-happen" "^10.0.3" + "nopt" "^6.0.0" + "npmlog" "^6.0.0" + "rimraf" "^3.0.2" + "semver" "^7.3.5" + "tar" "^6.1.2" + "which" "^2.0.2" + +"node-releases@^2.0.6": + "integrity" "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==" + "resolved" "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz" + "version" "2.0.6" + +"nodemon@^2.0.20": + "integrity" "sha512-Km2mWHKKY5GzRg6i1j5OxOHQtuvVsgskLfigG25yTtbyfRGn/GNvIbRyOf1PSCKJ2aT/58TiuUsuOU5UToVViw==" + "resolved" "https://registry.npmjs.org/nodemon/-/nodemon-2.0.20.tgz" + "version" "2.0.20" + dependencies: + "chokidar" "^3.5.2" + "debug" "^3.2.7" + "ignore-by-default" "^1.0.1" + "minimatch" "^3.1.2" + "pstree.remy" "^1.1.8" + "semver" "^5.7.1" + "simple-update-notifier" "^1.0.7" + "supports-color" "^5.5.0" + "touch" "^3.1.0" + "undefsafe" "^2.0.5" + +"nopt@^6.0.0": + "version" "6.0.0" + dependencies: + "abbrev" "^1.0.0" + +"nopt@^7.0.0": + "version" "7.0.0" + dependencies: + "abbrev" "^2.0.0" + +"nopt@~1.0.10": + "integrity" "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==" + "resolved" "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz" + "version" "1.0.10" + dependencies: + "abbrev" "1" + +"normalize-package-data@^5.0.0": + "version" "5.0.0" + dependencies: + "hosted-git-info" "^6.0.0" + "is-core-module" "^2.8.1" + "semver" "^7.3.5" + "validate-npm-package-license" "^3.0.4" + +"normalize-path@^3.0.0", "normalize-path@~3.0.0": + "integrity" "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" + "resolved" "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz" + "version" "3.0.0" + +"npm-audit-report@^4.0.0": + "version" "4.0.0" + dependencies: + "chalk" "^4.0.0" + +"npm-bundled@^3.0.0": + "version" "3.0.0" + dependencies: + "npm-normalize-package-bin" "^3.0.0" + +"npm-install-checks@^6.0.0": + "version" "6.0.0" + dependencies: + "semver" "^7.1.1" + +"npm-normalize-package-bin@^3.0.0": + "version" "3.0.0" + +"npm-package-arg@^10.0.0", "npm-package-arg@^10.1.0": + "version" "10.1.0" + dependencies: + "hosted-git-info" "^6.0.0" + "proc-log" "^3.0.0" + "semver" "^7.3.5" + "validate-npm-package-name" "^5.0.0" + +"npm-packlist@^7.0.0": + "version" "7.0.4" + dependencies: + "ignore-walk" "^6.0.0" + +"npm-pick-manifest@^8.0.0", "npm-pick-manifest@^8.0.1": + "version" "8.0.1" + dependencies: + "npm-install-checks" "^6.0.0" + "npm-normalize-package-bin" "^3.0.0" + "npm-package-arg" "^10.0.0" + "semver" "^7.3.5" + +"npm-profile@^7.0.1": + "version" "7.0.1" + dependencies: + "npm-registry-fetch" "^14.0.0" + "proc-log" "^3.0.0" + +"npm-registry-fetch@^14.0.0", "npm-registry-fetch@^14.0.3": + "version" "14.0.3" + dependencies: + "make-fetch-happen" "^11.0.0" + "minipass" "^4.0.0" + "minipass-fetch" "^3.0.0" + "minipass-json-stream" "^1.0.1" + "minizlib" "^2.1.2" + "npm-package-arg" "^10.0.0" + "proc-log" "^3.0.0" + +"npm-user-validate@^2.0.0": + "version" "2.0.0" + +"npm@^9.5.1": + "integrity" "sha512-MzULm9eEWPuPyHmRBxjcKm47KKYYT1gteVOXPlNJbfdaXNtp+sO4y2X3v5g375KudEAGJVDVCoFuk7bFnuuvNg==" + "resolved" "https://registry.npmjs.org/npm/-/npm-9.5.1.tgz" + "version" "9.5.1" + dependencies: + "@isaacs/string-locale-compare" "^1.1.0" + "@npmcli/arborist" "^6.2.3" + "@npmcli/config" "^6.1.3" + "@npmcli/map-workspaces" "^3.0.2" + "@npmcli/package-json" "^3.0.0" + "@npmcli/run-script" "^6.0.0" + "abbrev" "^2.0.0" + "archy" "~1.0.0" + "cacache" "^17.0.4" + "chalk" "^4.1.2" + "ci-info" "^3.8.0" + "cli-columns" "^4.0.0" + "cli-table3" "^0.6.3" + "columnify" "^1.6.0" + "fastest-levenshtein" "^1.0.16" + "fs-minipass" "^3.0.1" + "glob" "^8.1.0" + "graceful-fs" "^4.2.10" + "hosted-git-info" "^6.1.1" + "ini" "^3.0.1" + "init-package-json" "^5.0.0" + "is-cidr" "^4.0.2" + "json-parse-even-better-errors" "^3.0.0" + "libnpmaccess" "^7.0.2" + "libnpmdiff" "^5.0.11" + "libnpmexec" "^5.0.11" + "libnpmfund" "^4.0.11" + "libnpmhook" "^9.0.3" + "libnpmorg" "^5.0.3" + "libnpmpack" "^5.0.11" + "libnpmpublish" "^7.1.0" + "libnpmsearch" "^6.0.2" + "libnpmteam" "^5.0.3" + "libnpmversion" "^4.0.2" + "make-fetch-happen" "^11.0.3" + "minimatch" "^6.2.0" + "minipass" "^4.0.3" + "minipass-pipeline" "^1.2.4" + "ms" "^2.1.2" + "node-gyp" "^9.3.1" + "nopt" "^7.0.0" + "npm-audit-report" "^4.0.0" + "npm-install-checks" "^6.0.0" + "npm-package-arg" "^10.1.0" + "npm-pick-manifest" "^8.0.1" + "npm-profile" "^7.0.1" + "npm-registry-fetch" "^14.0.3" + "npm-user-validate" "^2.0.0" + "npmlog" "^7.0.1" + "p-map" "^4.0.0" + "pacote" "^15.1.1" + "parse-conflict-json" "^3.0.0" + "proc-log" "^3.0.0" + "qrcode-terminal" "^0.12.0" + "read" "^2.0.0" + "read-package-json" "^6.0.0" + "read-package-json-fast" "^3.0.2" + "semver" "^7.3.8" + "ssri" "^10.0.1" + "tar" "^6.1.13" + "text-table" "~0.2.0" + "tiny-relative-date" "^1.3.0" + "treeverse" "^3.0.0" + "validate-npm-package-name" "^5.0.0" + "which" "^3.0.0" + "write-file-atomic" "^5.0.0" + +"npmlog@^6.0.0": + "version" "6.0.2" + dependencies: + "are-we-there-yet" "^3.0.0" + "console-control-strings" "^1.1.0" + "gauge" "^4.0.3" + "set-blocking" "^2.0.0" + +"npmlog@^7.0.1": + "version" "7.0.1" + dependencies: + "are-we-there-yet" "^4.0.0" + "console-control-strings" "^1.1.0" + "gauge" "^5.0.0" + "set-blocking" "^2.0.0" + +"nth-check@^2.0.1": + "integrity" "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==" + "resolved" "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz" + "version" "2.1.1" + dependencies: + "boolbase" "^1.0.0" + +"object-assign@^4.1.1": + "integrity" "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" + "resolved" "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz" + "version" "4.1.1" + +"object-inspect@^1.12.2", "object-inspect@^1.9.0": + "integrity" "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==" + "resolved" "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz" + "version" "1.12.3" + +"object-keys@^1.1.1": + "integrity" "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + "resolved" "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz" + "version" "1.1.1" + +"object.assign@^4.1.3", "object.assign@^4.1.4": + "integrity" "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==" + "resolved" "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz" + "version" "4.1.4" + dependencies: + "call-bind" "^1.0.2" + "define-properties" "^1.1.4" + "has-symbols" "^1.0.3" + "object-keys" "^1.1.1" + +"object.entries@^1.1.6": + "integrity" "sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w==" + "resolved" "https://registry.npmjs.org/object.entries/-/object.entries-1.1.6.tgz" + "version" "1.1.6" + dependencies: + "call-bind" "^1.0.2" + "define-properties" "^1.1.4" + "es-abstract" "^1.20.4" + +"object.fromentries@^2.0.6": + "integrity" "sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg==" + "resolved" "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.6.tgz" + "version" "2.0.6" + dependencies: + "call-bind" "^1.0.2" + "define-properties" "^1.1.4" + "es-abstract" "^1.20.4" + +"object.hasown@^1.1.2": + "integrity" "sha512-B5UIT3J1W+WuWIU55h0mjlwaqxiE5vYENJXIXZ4VFe05pNYrkKuK0U/6aFcb0pKywYJh7IhfoqUfKVmrJJHZHw==" + "resolved" "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.2.tgz" + "version" "1.1.2" + dependencies: + "define-properties" "^1.1.4" + "es-abstract" "^1.20.4" + +"object.values@^1.1.6": + "integrity" "sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==" + "resolved" "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz" + "version" "1.1.6" + dependencies: + "call-bind" "^1.0.2" + "define-properties" "^1.1.4" + "es-abstract" "^1.20.4" + +"on-finished@~2.3.0": + "integrity" "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==" + "resolved" "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz" + "version" "2.3.0" + dependencies: + "ee-first" "1.1.1" + +"on-headers@~1.0.1": + "integrity" "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==" + "resolved" "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz" + "version" "1.0.2" + +"once@^1.3.0": + "integrity" "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==" + "resolved" "https://registry.npmjs.org/once/-/once-1.4.0.tgz" + "version" "1.4.0" + dependencies: + "wrappy" "1" + +"optionator@^0.9.1": + "integrity" "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==" + "resolved" "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz" + "version" "0.9.1" + dependencies: + "deep-is" "^0.1.3" + "fast-levenshtein" "^2.0.6" + "levn" "^0.4.1" + "prelude-ls" "^1.2.1" + "type-check" "^0.4.0" + "word-wrap" "^1.2.3" + +"opts@>= 1.2.0": + "integrity" "sha512-k41FwbcLnlgnFh69f4qdUfvDQ+5vaSDnVPFI/y5XuhKRq97EnVVneO9F1ESVCdiVu4fCS2L8usX3mU331hB7pg==" + "resolved" "https://registry.npmjs.org/opts/-/opts-2.0.2.tgz" + "version" "2.0.2" + +"p-limit@^2.2.0": + "integrity" "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==" + "resolved" "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz" + "version" "2.3.0" + dependencies: + "p-try" "^2.0.0" + +"p-limit@^3.0.2": + "integrity" "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==" + "resolved" "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz" + "version" "3.1.0" + dependencies: + "yocto-queue" "^0.1.0" + +"p-locate@^4.1.0": + "integrity" "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==" + "resolved" "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz" + "version" "4.1.0" + dependencies: + "p-limit" "^2.2.0" + +"p-locate@^5.0.0": + "integrity" "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==" + "resolved" "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz" + "version" "5.0.0" + dependencies: + "p-limit" "^3.0.2" + +"p-map@^4.0.0": + "version" "4.0.0" + dependencies: + "aggregate-error" "^3.0.0" + +"p-try@^2.0.0": + "integrity" "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" + "resolved" "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz" + "version" "2.2.0" + +"pacote@^15.0.0", "pacote@^15.0.8", "pacote@^15.1.1": + "version" "15.1.1" + dependencies: + "@npmcli/git" "^4.0.0" + "@npmcli/installed-package-contents" "^2.0.1" + "@npmcli/promise-spawn" "^6.0.1" + "@npmcli/run-script" "^6.0.0" + "cacache" "^17.0.0" + "fs-minipass" "^3.0.0" + "minipass" "^4.0.0" + "npm-package-arg" "^10.0.0" + "npm-packlist" "^7.0.0" + "npm-pick-manifest" "^8.0.0" + "npm-registry-fetch" "^14.0.0" + "proc-log" "^3.0.0" + "promise-retry" "^2.0.1" + "read-package-json" "^6.0.0" + "read-package-json-fast" "^3.0.0" + "sigstore" "^1.0.0" + "ssri" "^10.0.0" + "tar" "^6.1.11" + +"param-case@^3.0.4": + "integrity" "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==" + "resolved" "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz" + "version" "3.0.4" + dependencies: + "dot-case" "^3.0.4" + "tslib" "^2.0.3" + +"parent-module@^1.0.0": + "integrity" "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==" + "resolved" "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz" + "version" "1.0.1" + dependencies: + "callsites" "^3.0.0" + +"parse-conflict-json@^3.0.0": + "version" "3.0.0" + dependencies: + "json-parse-even-better-errors" "^3.0.0" + "just-diff" "^5.0.1" + "just-diff-apply" "^5.2.0" + +"parse-json@^5.0.0": + "integrity" "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==" + "resolved" "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz" + "version" "5.2.0" + dependencies: + "@babel/code-frame" "^7.0.0" + "error-ex" "^1.3.1" + "json-parse-even-better-errors" "^2.3.0" + "lines-and-columns" "^1.1.6" + +"parseurl@~1.3.2": + "integrity" "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + "resolved" "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz" + "version" "1.3.3" + +"pascal-case@^3.1.2": + "integrity" "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==" + "resolved" "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz" + "version" "3.1.2" + dependencies: + "no-case" "^3.0.4" + "tslib" "^2.0.3" + +"path-exists@^4.0.0": + "integrity" "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" + "resolved" "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz" + "version" "4.0.0" + +"path-is-absolute@^1.0.0": + "integrity" "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" + "resolved" "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz" + "version" "1.0.1" + +"path-key@^3.1.0": + "integrity" "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" + "resolved" "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz" + "version" "3.1.1" + +"path-parse@^1.0.7": + "integrity" "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + "resolved" "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz" + "version" "1.0.7" + +"path-to-regexp@0.1.7": + "integrity" "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + "resolved" "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz" + "version" "0.1.7" + +"path-type@^4.0.0": + "integrity" "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==" + "resolved" "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz" + "version" "4.0.0" + +"picocolors@^1.0.0": + "integrity" "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + "resolved" "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz" + "version" "1.0.0" + +"picomatch@^2.0.4", "picomatch@^2.2.1", "picomatch@^2.3.1": + "integrity" "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" + "resolved" "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz" + "version" "2.3.1" + +"pkg-dir@^4.1.0", "pkg-dir@^4.2.0": + "integrity" "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==" + "resolved" "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz" + "version" "4.2.0" + dependencies: + "find-up" "^4.0.0" + +"popmotion@11.0.5": + "integrity" "sha512-la8gPM1WYeFznb/JqF4GiTkRRPZsfaj2+kCxqQgr2MJylMmIKUwBfWW8Wa5fml/8gmtlD5yI01MP1QCZPWmppA==" + "resolved" "https://registry.npmjs.org/popmotion/-/popmotion-11.0.5.tgz" + "version" "11.0.5" + dependencies: + "framesync" "6.1.2" + "hey-listen" "^1.0.8" + "style-value-types" "5.1.2" + "tslib" "2.4.0" + +"postcss-modules-extract-imports@^3.0.0": + "integrity" "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==" + "resolved" "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz" + "version" "3.0.0" + +"postcss-modules-local-by-default@^4.0.0": + "integrity" "sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ==" + "resolved" "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz" + "version" "4.0.0" + dependencies: + "icss-utils" "^5.0.0" + "postcss-selector-parser" "^6.0.2" + "postcss-value-parser" "^4.1.0" + +"postcss-modules-scope@^3.0.0": + "integrity" "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==" + "resolved" "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz" + "version" "3.0.0" + dependencies: + "postcss-selector-parser" "^6.0.4" + +"postcss-modules-values@^4.0.0": + "integrity" "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==" + "resolved" "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz" + "version" "4.0.0" + dependencies: + "icss-utils" "^5.0.0" + +"postcss-selector-parser@^6.0.10": + "version" "6.0.11" + dependencies: + "cssesc" "^3.0.0" + "util-deprecate" "^1.0.2" + +"postcss-selector-parser@^6.0.2", "postcss-selector-parser@^6.0.4": + "integrity" "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==" + "resolved" "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz" + "version" "6.0.10" + dependencies: + "cssesc" "^3.0.0" + "util-deprecate" "^1.0.2" + +"postcss-value-parser@^4.1.0", "postcss-value-parser@^4.2.0": + "integrity" "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" + "resolved" "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz" + "version" "4.2.0" + +"postcss@^8.1.0", "postcss@^8.4.7": + "integrity" "sha512-Wi8mWhncLJm11GATDaQKobXSNEYGUHeQLiQqDFG1qQ5UTDPTEvKw0Xt5NsTpktGTwLps3ByrWsBrG0rB8YQ9oA==" + "resolved" "https://registry.npmjs.org/postcss/-/postcss-8.4.18.tgz" + "version" "8.4.18" + dependencies: + "nanoid" "^3.3.4" + "picocolors" "^1.0.0" + "source-map-js" "^1.0.2" + +"prelude-ls@^1.2.1": + "integrity" "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==" + "resolved" "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz" + "version" "1.2.1" + +"pretty-error@^4.0.0": + "integrity" "sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==" + "resolved" "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz" + "version" "4.0.0" + dependencies: + "lodash" "^4.17.20" + "renderkid" "^3.0.0" + +"proc-log@^3.0.0": + "version" "3.0.0" + +"process@^0.11.10": + "version" "0.11.10" + +"promise-all-reject-late@^1.0.0": + "version" "1.0.1" + +"promise-call-limit@^1.0.1": + "version" "1.0.1" + +"promise-inflight@^1.0.1": + "version" "1.0.1" + +"promise-polyfill@^8.2.3": + "integrity" "sha512-Og0+jCRQetV84U8wVjMNccfGCnMQ9mGs9Hv78QFe+pSDD3gWTpz0y+1QCuxy5d/vBFuZ3iwP2eycAkvqIMPmWg==" + "resolved" "https://registry.npmjs.org/promise-polyfill/-/promise-polyfill-8.2.3.tgz" + "version" "8.2.3" + +"promise-retry@^2.0.1": + "version" "2.0.1" + dependencies: + "err-code" "^2.0.2" + "retry" "^0.12.0" + +"promzard@^1.0.0": + "version" "1.0.0" + dependencies: + "read" "^2.0.0" + +"prop-types@^15.6.1", "prop-types@^15.6.2", "prop-types@^15.8.1": + "integrity" "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==" + "resolved" "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz" + "version" "15.8.1" + dependencies: + "loose-envify" "^1.4.0" + "object-assign" "^4.1.1" + "react-is" "^16.13.1" + +"proxy-addr@~2.0.4": + "integrity" "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==" + "resolved" "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz" + "version" "2.0.7" + dependencies: + "forwarded" "0.2.0" + "ipaddr.js" "1.9.1" + +"proxy-from-env@^1.1.0": + "integrity" "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + "resolved" "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz" + "version" "1.1.0" + +"pstree.remy@^1.1.8": + "integrity" "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==" + "resolved" "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz" + "version" "1.1.8" + +"punycode@^2.1.0": + "integrity" "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + "resolved" "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz" + "version" "2.1.1" + +"punycode@1.3.2": + "integrity" "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==" + "resolved" "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz" + "version" "1.3.2" + +"qrcode-terminal@^0.12.0": + "version" "0.12.0" + +"qs@6.5.2": + "integrity" "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" + "resolved" "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz" + "version" "6.5.2" + +"querystring@0.2.0": + "integrity" "sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==" + "resolved" "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz" + "version" "0.2.0" + +"queue-microtask@^1.2.2": + "integrity" "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==" + "resolved" "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz" + "version" "1.2.3" + +"randombytes@^2.1.0": + "integrity" "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==" + "resolved" "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz" + "version" "2.1.0" + dependencies: + "safe-buffer" "^5.1.0" + +"range-parser@~1.2.0": + "integrity" "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + "resolved" "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz" + "version" "1.2.1" + +"raw-body@2.3.3": + "integrity" "sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==" + "resolved" "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz" + "version" "2.3.3" + dependencies: + "bytes" "3.0.0" + "http-errors" "1.6.3" + "iconv-lite" "0.4.23" + "unpipe" "1.0.0" + +"rc-util@^5.9.4": + "integrity" "sha512-8XHRbeJOWlTR2Hk1K2xLaPOf7lZu+3taskAGuqOPccA676vB3ygrz3ZgdrA3wml40CzR9RlIEHDWwI7FZT3wBQ==" + "resolved" "https://registry.npmjs.org/rc-util/-/rc-util-5.27.2.tgz" + "version" "5.27.2" + dependencies: + "@babel/runtime" "^7.18.3" + "react-is" "^16.12.0" + +"react-copy-to-clipboard@^5.1.0": + "integrity" "sha512-k61RsNgAayIJNoy9yDsYzDe/yAZAzEbEgcz3DZMhF686LEyukcE1hzurxe85JandPUG+yTfGVFzuEw3xt8WP/A==" + "resolved" "https://registry.npmjs.org/react-copy-to-clipboard/-/react-copy-to-clipboard-5.1.0.tgz" + "version" "5.1.0" + dependencies: + "copy-to-clipboard" "^3.3.1" + "prop-types" "^15.8.1" + +"react-device-detect@^2.2.2": + "integrity" "sha512-zSN1gIAztUekp5qUT/ybHwQ9fmOqVT1psxpSlTn1pe0CO+fnJHKRLOWWac5nKxOxvOpD/w84hk1I+EydrJp7SA==" + "resolved" "https://registry.npmjs.org/react-device-detect/-/react-device-detect-2.2.2.tgz" + "version" "2.2.2" + dependencies: + "ua-parser-js" "^1.0.2" + +"react-dom@^0.14.9 || ^15.3.0 || ^16.0.0-rc || ^16.0 || ^17.0 || ^18.0.0", "react-dom@^16.11.0 || ^17 || ^18", "react-dom@^17.0.0 || ^18.0.0", "react-dom@^18.0.0", "react-dom@^18.2.0", "react-dom@>= 0.14.0", "react-dom@>=16", "react-dom@>=16.0.0", "react-dom@>=16.6.0", "react-dom@>=16.8", "react-dom@>=16.9.0": + "integrity" "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==" + "resolved" "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz" + "version" "18.2.0" + dependencies: + "loose-envify" "^1.1.0" + "scheduler" "^0.23.0" + +"react-hot-toast@^2.4.0": + "integrity" "sha512-qnnVbXropKuwUpriVVosgo8QrB+IaPJCpL8oBI6Ov84uvHZ5QQcTp2qg6ku2wNfgJl6rlQXJIQU5q+5lmPOutA==" + "resolved" "https://registry.npmjs.org/react-hot-toast/-/react-hot-toast-2.4.0.tgz" + "version" "2.4.0" + dependencies: + "goober" "^2.1.10" + +"react-intl@^6.2.1": + "integrity" "sha512-hYxcSamgoA3Mvc55nwhTF1v15T0NUSkaV/EScMNVZXg0kRyaMAoNHkCi9/9H+TnXWNiWrcWH9bjlMlJwrG2V7g==" + "resolved" "https://registry.npmjs.org/react-intl/-/react-intl-6.2.1.tgz" + "version" "6.2.1" + dependencies: + "@formatjs/ecma402-abstract" "1.13.0" + "@formatjs/icu-messageformat-parser" "2.1.10" + "@formatjs/intl" "2.5.1" + "@formatjs/intl-displaynames" "6.1.4" + "@formatjs/intl-listformat" "7.1.3" + "@types/hoist-non-react-statics" "^3.3.1" + "@types/react" "16 || 17 || 18" + "hoist-non-react-statics" "^3.3.2" + "intl-messageformat" "10.2.1" + "tslib" "2.4.0" + +"react-is@^16.12.0": + "integrity" "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + "resolved" "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz" + "version" "16.13.1" + +"react-is@^16.13.1": + "integrity" "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + "resolved" "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz" + "version" "16.13.1" + +"react-is@^16.7.0": + "integrity" "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + "resolved" "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz" + "version" "16.13.1" + +"react-is@^18.2.0": + "integrity" "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" + "resolved" "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz" + "version" "18.2.0" + +"react-router-dom@^6.4.1": + "integrity" "sha512-yM1kjoTkpfjgczPrcyWrp+OuQMyB1WleICiiGfstnQYo/S8hPEEnVjr/RdmlH6yKK4Tnj1UGXFSa7uwAtmDoLQ==" + "resolved" "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.4.2.tgz" + "version" "6.4.2" + dependencies: + "@remix-run/router" "1.0.2" + "react-router" "6.4.2" + +"react-router@6.4.2": + "integrity" "sha512-Rb0BAX9KHhVzT1OKhMvCDMw776aTYM0DtkxqUBP8dNBom3mPXlfNs76JNGK8wKJ1IZEY1+WGj+cvZxHVk/GiKw==" + "resolved" "https://registry.npmjs.org/react-router/-/react-router-6.4.2.tgz" + "version" "6.4.2" + dependencies: + "@remix-run/router" "1.0.2" + +"react-table@^7.8.0": + "integrity" "sha512-hNaz4ygkZO4bESeFfnfOft73iBUj8K5oKi1EcSHPAibEydfsX2MyU6Z8KCr3mv3C9Kqqh71U+DhZkFvibbnPbA==" + "resolved" "https://registry.npmjs.org/react-table/-/react-table-7.8.0.tgz" + "version" "7.8.0" + +"react-transition-group@^4.4.5": + "integrity" "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==" + "resolved" "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz" + "version" "4.4.5" + dependencies: + "@babel/runtime" "^7.5.5" + "dom-helpers" "^5.0.1" + "loose-envify" "^1.4.0" + "prop-types" "^15.6.2" + +"react@^0.14.9 || ^15.3.0 || ^16.0.0-rc || ^16.0 || ^17.0 || ^18.0.0", "react@^15.3.0 || 16 || 17 || 18", "react@^16.11.0 || ^17 || ^18", "react@^16.6.0 || 17 || 18", "react@^16.8.0 || ^17.0.2 || ^18.0.0", "react@^16.8.3 || ^17.0.0-0 || ^18.0.0", "react@^17.0.0 || ^18.0.0", "react@^18.0.0", "react@^18.2.0", "react@>= 0.14.0", "react@>=16", "react@>=16.0.0", "react@>=16.3", "react@>=16.6.0", "react@>=16.8", "react@>=16.8.0", "react@>=16.9.0": + "integrity" "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==" + "resolved" "https://registry.npmjs.org/react/-/react-18.2.0.tgz" + "version" "18.2.0" + dependencies: + "loose-envify" "^1.1.0" + +"read-cmd-shim@^4.0.0": + "version" "4.0.0" + +"read-package-json-fast@^3.0.0", "read-package-json-fast@^3.0.2": + "version" "3.0.2" + dependencies: + "json-parse-even-better-errors" "^3.0.0" + "npm-normalize-package-bin" "^3.0.0" + +"read-package-json@^6.0.0": + "version" "6.0.0" + dependencies: + "glob" "^8.0.1" + "json-parse-even-better-errors" "^3.0.0" + "normalize-package-data" "^5.0.0" + "npm-normalize-package-bin" "^3.0.0" + +"read@^2.0.0": + "version" "2.0.0" + dependencies: + "mute-stream" "~1.0.0" + +"readable-stream@^3.6.0": + "version" "3.6.0" + dependencies: + "inherits" "^2.0.3" + "string_decoder" "^1.1.1" + "util-deprecate" "^1.0.1" + +"readable-stream@^4.1.0": + "version" "4.3.0" + dependencies: + "abort-controller" "^3.0.0" + "buffer" "^6.0.3" + "events" "^3.3.0" + "process" "^0.11.10" + +"readdirp@~3.6.0": + "integrity" "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==" + "resolved" "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz" + "version" "3.6.0" + dependencies: + "picomatch" "^2.2.1" + +"rechoir@^0.7.0": + "integrity" "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==" + "resolved" "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz" + "version" "0.7.1" + dependencies: + "resolve" "^1.9.0" + +"regenerate-unicode-properties@^10.1.0": + "integrity" "sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==" + "resolved" "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz" + "version" "10.1.0" + dependencies: + "regenerate" "^1.4.2" + +"regenerate@^1.4.2": + "integrity" "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" + "resolved" "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz" + "version" "1.4.2" + +"regenerator-runtime@^0.13.4": + "integrity" "sha512-KepLsg4dU12hryUO7bp/axHAKvwGOCV0sGloQtpagJ12ai+ojVDqkeGSiRX1zlq+kjIMZ1t7gpze+26QqtdGqw==" + "resolved" "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.10.tgz" + "version" "0.13.10" + +"regenerator-transform@^0.15.0": + "integrity" "sha512-LsrGtPmbYg19bcPHwdtmXwbW+TqNvtY4riE3P83foeHRroMbH6/2ddFBfab3t7kbzc7v7p4wbkIecHImqt0QNg==" + "resolved" "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.0.tgz" + "version" "0.15.0" + dependencies: + "@babel/runtime" "^7.8.4" + +"regexp.prototype.flags@^1.4.3": + "integrity" "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==" + "resolved" "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz" + "version" "1.4.3" + dependencies: + "call-bind" "^1.0.2" + "define-properties" "^1.1.3" + "functions-have-names" "^1.2.2" + +"regexpp@^3.2.0": + "integrity" "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==" + "resolved" "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz" + "version" "3.2.0" + +"regexpu-core@^5.1.0": + "integrity" "sha512-HrnlNtpvqP1Xkb28tMhBUO2EbyUHdQlsnlAhzWcwHy8WJR53UWr7/MAvqrsQKMbV4qdpv03oTMG8iIhfsPFktQ==" + "resolved" "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.2.1.tgz" + "version" "5.2.1" + 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.0.0" + +"regjsgen@^0.7.1": + "integrity" "sha512-RAt+8H2ZEzHeYWxZ3H2z6tF18zyyOnlcdaafLrm21Bguj7uZy6ULibiAFdXEtKQY4Sy7wDTwDiOazasMLc4KPA==" + "resolved" "https://registry.npmjs.org/regjsgen/-/regjsgen-0.7.1.tgz" + "version" "0.7.1" + +"regjsparser@^0.9.1": + "integrity" "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==" + "resolved" "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz" + "version" "0.9.1" + dependencies: + "jsesc" "~0.5.0" + +"relateurl@^0.2.7": + "integrity" "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==" + "resolved" "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz" + "version" "0.2.7" + +"renderkid@^3.0.0": + "integrity" "sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==" + "resolved" "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz" + "version" "3.0.0" + dependencies: + "css-select" "^4.1.3" + "dom-converter" "^0.2.0" + "htmlparser2" "^6.1.0" + "lodash" "^4.17.21" + "strip-ansi" "^6.0.1" + +"resolve-cwd@^3.0.0": + "integrity" "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==" + "resolved" "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz" + "version" "3.0.0" + dependencies: + "resolve-from" "^5.0.0" + +"resolve-from@^4.0.0": + "integrity" "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" + "resolved" "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz" + "version" "4.0.0" + +"resolve-from@^5.0.0": + "integrity" "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==" + "resolved" "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz" + "version" "5.0.0" + +"resolve@^1.14.2", "resolve@^1.19.0", "resolve@^1.9.0": + "integrity" "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==" + "resolved" "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz" + "version" "1.22.1" + dependencies: + "is-core-module" "^2.9.0" + "path-parse" "^1.0.7" + "supports-preserve-symlinks-flag" "^1.0.0" + +"resolve@^2.0.0-next.4": + "integrity" "sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==" + "resolved" "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz" + "version" "2.0.0-next.4" + dependencies: + "is-core-module" "^2.9.0" + "path-parse" "^1.0.7" + "supports-preserve-symlinks-flag" "^1.0.0" + +"retry@^0.12.0": + "version" "0.12.0" + +"reusify@^1.0.4": + "integrity" "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==" + "resolved" "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz" + "version" "1.0.4" + +"rimraf@^3.0.2": + "integrity" "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==" + "resolved" "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz" + "version" "3.0.2" + dependencies: + "glob" "^7.1.3" + +"run-parallel@^1.1.9": + "integrity" "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==" + "resolved" "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz" + "version" "1.2.0" + dependencies: + "queue-microtask" "^1.2.2" + +"safe-buffer@^5.0.1", "safe-buffer@^5.1.0", "safe-buffer@5.1.2": + "integrity" "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + "resolved" "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" + "version" "5.1.2" + +"safe-buffer@~5.1.0": + "version" "5.1.2" + +"safe-regex-test@^1.0.0": + "integrity" "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==" + "resolved" "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz" + "version" "1.0.0" + dependencies: + "call-bind" "^1.0.2" + "get-intrinsic" "^1.1.3" + "is-regex" "^1.1.4" + +"safer-buffer@>= 2.1.2 < 3.0.0": + "version" "2.1.2" + +"safer-buffer@>= 2.1.2 < 3": + "integrity" "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + "resolved" "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz" + "version" "2.1.2" + +"scheduler@^0.23.0": + "integrity" "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==" + "resolved" "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz" + "version" "0.23.0" + dependencies: + "loose-envify" "^1.1.0" + +"schema-utils@^2.6.5": + "integrity" "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==" + "resolved" "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz" + "version" "2.7.1" + dependencies: + "@types/json-schema" "^7.0.5" + "ajv" "^6.12.4" + "ajv-keywords" "^3.5.2" + +"schema-utils@^3.0.0": + "integrity" "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==" + "resolved" "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz" + "version" "3.1.1" + dependencies: + "@types/json-schema" "^7.0.8" + "ajv" "^6.12.5" + "ajv-keywords" "^3.5.2" + +"schema-utils@^3.1.0": + "integrity" "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==" + "resolved" "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz" + "version" "3.1.1" + dependencies: + "@types/json-schema" "^7.0.8" + "ajv" "^6.12.5" + "ajv-keywords" "^3.5.2" + +"schema-utils@^3.1.1": + "integrity" "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==" + "resolved" "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz" + "version" "3.1.1" + dependencies: + "@types/json-schema" "^7.0.8" + "ajv" "^6.12.5" + "ajv-keywords" "^3.5.2" + +"semver@^5.7.1": + "integrity" "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + "resolved" "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz" + "version" "5.7.1" + +"semver@^6.0.0", "semver@^6.1.1", "semver@^6.1.2", "semver@^6.3.0": + "integrity" "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + "resolved" "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz" + "version" "6.3.0" + +"semver@^7.0.0", "semver@^7.1.1", "semver@^7.3.5", "semver@^7.3.7", "semver@^7.3.8": + "integrity" "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==" + "resolved" "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz" + "version" "7.3.8" + dependencies: + "lru-cache" "^6.0.0" + +"semver@^7.3.4": + "integrity" "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==" + "resolved" "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz" + "version" "7.3.8" + dependencies: + "lru-cache" "^6.0.0" + +"semver@~7.0.0": + "integrity" "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==" + "resolved" "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz" + "version" "7.0.0" + +"send@0.16.2": + "integrity" "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==" + "resolved" "https://registry.npmjs.org/send/-/send-0.16.2.tgz" + "version" "0.16.2" + dependencies: + "debug" "2.6.9" + "depd" "~1.1.2" + "destroy" "~1.0.4" + "encodeurl" "~1.0.2" + "escape-html" "~1.0.3" + "etag" "~1.8.1" + "fresh" "0.5.2" + "http-errors" "~1.6.2" + "mime" "1.4.1" + "ms" "2.0.0" + "on-finished" "~2.3.0" + "range-parser" "~1.2.0" + "statuses" "~1.4.0" + +"serialize-javascript@^6.0.0": + "integrity" "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==" + "resolved" "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz" + "version" "6.0.0" + dependencies: + "randombytes" "^2.1.0" + +"serve-static@1.13.2": + "integrity" "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==" + "resolved" "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz" + "version" "1.13.2" + dependencies: + "encodeurl" "~1.0.2" + "escape-html" "~1.0.3" + "parseurl" "~1.3.2" + "send" "0.16.2" + +"set-blocking@^2.0.0": + "version" "2.0.0" + +"setprototypeof@1.1.0": + "integrity" "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" + "resolved" "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz" + "version" "1.1.0" + +"shallow-clone@^3.0.0": + "integrity" "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==" + "resolved" "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz" + "version" "3.0.1" + dependencies: + "kind-of" "^6.0.2" + +"shebang-command@^2.0.0": + "integrity" "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==" + "resolved" "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz" + "version" "2.0.0" + dependencies: + "shebang-regex" "^3.0.0" + +"shebang-regex@^3.0.0": + "integrity" "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" + "resolved" "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz" + "version" "3.0.0" + +"side-channel@^1.0.4": + "integrity" "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==" + "resolved" "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz" + "version" "1.0.4" + dependencies: + "call-bind" "^1.0.0" + "get-intrinsic" "^1.0.2" + "object-inspect" "^1.9.0" + +"signal-exit@^3.0.7": + "version" "3.0.7" + +"sigstore@^1.0.0": + "version" "1.0.0" + dependencies: + "make-fetch-happen" "^11.0.1" + "tuf-js" "^1.0.0" + +"simple-update-notifier@^1.0.7": + "integrity" "sha512-BBKgR84BJQJm6WjWFMHgLVuo61FBDSj1z/xSFUIozqO6wO7ii0JxCqlIud7Enr/+LhlbNI0whErq96P2qHNWew==" + "resolved" "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.0.7.tgz" + "version" "1.0.7" + dependencies: + "semver" "~7.0.0" + +"simplebar-react@^2.4.3": + "integrity" "sha512-Ep8gqAUZAS5IC2lT5RE4t1ZFUIVACqbrSRQvFV9a6NbVUzXzOMnc4P82Hl8Ak77AnPQvmgUwZS7aUKLyBoMAcg==" + "resolved" "https://registry.npmjs.org/simplebar-react/-/simplebar-react-2.4.3.tgz" + "version" "2.4.3" + dependencies: + "prop-types" "^15.6.1" + "simplebar" "^5.3.9" + +"simplebar@^5.3.9": + "integrity" "sha512-1vIIpjDvY9sVH14e0LGeiCiTFU3ILqAghzO6OI9axeG+mvU/vMSrvXeAXkBolqFFz3XYaY8n5ahH9MeP3sp2Ag==" + "resolved" "https://registry.npmjs.org/simplebar/-/simplebar-5.3.9.tgz" + "version" "5.3.9" + dependencies: + "@juggle/resize-observer" "^3.3.1" + "can-use-dom" "^0.1.0" + "core-js" "^3.0.1" + "lodash.debounce" "^4.0.8" + "lodash.memoize" "^4.1.2" + "lodash.throttle" "^4.1.1" + +"slash@^3.0.0": + "integrity" "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==" + "resolved" "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz" + "version" "3.0.0" + +"smart-buffer@^4.2.0": + "version" "4.2.0" + +"socks-proxy-agent@^7.0.0": + "version" "7.0.0" + dependencies: + "agent-base" "^6.0.2" + "debug" "^4.3.3" + "socks" "^2.6.2" + +"socks@^2.6.2": + "version" "2.7.1" + dependencies: + "ip" "^2.0.0" + "smart-buffer" "^4.2.0" + +"source-map-js@^1.0.2": + "integrity" "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==" + "resolved" "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz" + "version" "1.0.2" + +"source-map-support@~0.5.20": + "integrity" "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==" + "resolved" "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz" + "version" "0.5.21" + dependencies: + "buffer-from" "^1.0.0" + "source-map" "^0.6.0" + +"source-map@^0.5.7": + "integrity" "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==" + "resolved" "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz" + "version" "0.5.7" + +"source-map@^0.6.0": + "integrity" "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + "resolved" "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz" + "version" "0.6.1" + +"source-map@~0.6.0": + "integrity" "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + "resolved" "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz" + "version" "0.6.1" + +"spdx-correct@^3.0.0": + "version" "3.1.1" + dependencies: + "spdx-expression-parse" "^3.0.0" + "spdx-license-ids" "^3.0.0" + +"spdx-exceptions@^2.1.0": + "version" "2.3.0" + +"spdx-expression-parse@^3.0.0": + "version" "3.0.1" + dependencies: + "spdx-exceptions" "^2.1.0" + "spdx-license-ids" "^3.0.0" + +"spdx-license-ids@^3.0.0": + "version" "3.0.12" + +"ssri@^10.0.0", "ssri@^10.0.1": + "version" "10.0.1" + dependencies: + "minipass" "^4.0.0" + +"ssri@^9.0.0": + "version" "9.0.1" + dependencies: + "minipass" "^3.1.1" + +"statuses@>= 1.4.0 < 2", "statuses@~1.4.0": + "integrity" "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" + "resolved" "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz" + "version" "1.4.0" + +"string_decoder@^1.1.1": + "version" "1.1.1" + dependencies: + "safe-buffer" "~5.1.0" + +"string-width@^1.0.2 || 2 || 3 || 4", "string-width@^4.2.0", "string-width@^4.2.3": + "version" "4.2.3" + dependencies: + "emoji-regex" "^8.0.0" + "is-fullwidth-code-point" "^3.0.0" + "strip-ansi" "^6.0.1" + +"string.prototype.matchall@^4.0.8": + "integrity" "sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg==" + "resolved" "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.8.tgz" + "version" "4.0.8" + dependencies: + "call-bind" "^1.0.2" + "define-properties" "^1.1.4" + "es-abstract" "^1.20.4" + "get-intrinsic" "^1.1.3" + "has-symbols" "^1.0.3" + "internal-slot" "^1.0.3" + "regexp.prototype.flags" "^1.4.3" + "side-channel" "^1.0.4" + +"string.prototype.trimend@^1.0.6": + "integrity" "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==" + "resolved" "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz" + "version" "1.0.6" + dependencies: + "call-bind" "^1.0.2" + "define-properties" "^1.1.4" + "es-abstract" "^1.20.4" + +"string.prototype.trimstart@^1.0.6": + "integrity" "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==" + "resolved" "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz" + "version" "1.0.6" + dependencies: + "call-bind" "^1.0.2" + "define-properties" "^1.1.4" + "es-abstract" "^1.20.4" + +"strip-ansi@^6.0.1": + "integrity" "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==" + "resolved" "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" + "version" "6.0.1" + dependencies: + "ansi-regex" "^5.0.1" + +"strip-json-comments@^3.1.0", "strip-json-comments@^3.1.1": + "integrity" "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==" + "resolved" "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz" + "version" "3.1.1" + +"style-loader@^3.3.1": + "integrity" "sha512-GPcQ+LDJbrcxHORTRes6Jy2sfvK2kS6hpSfI/fXhPt+spVzxF6LJ1dHLN9zIGmVaaP044YKaIatFaufENRiDoQ==" + "resolved" "https://registry.npmjs.org/style-loader/-/style-loader-3.3.1.tgz" + "version" "3.3.1" + +"style-value-types@5.1.2": + "integrity" "sha512-Vs9fNreYF9j6W2VvuDTP7kepALi7sk0xtk2Tu8Yxi9UoajJdEVpNpCov0HsLTqXvNGKX+Uv09pkozVITi1jf3Q==" + "resolved" "https://registry.npmjs.org/style-value-types/-/style-value-types-5.1.2.tgz" + "version" "5.1.2" + dependencies: + "hey-listen" "^1.0.8" + "tslib" "2.4.0" + +"stylis@4.0.13": + "integrity" "sha512-xGPXiFVl4YED9Jh7Euv2V220mriG9u4B2TA6Ybjc1catrstKD2PpIdU3U0RKpkVBC2EhmL/F0sPCr9vrFTNRag==" + "resolved" "https://registry.npmjs.org/stylis/-/stylis-4.0.13.tgz" + "version" "4.0.13" + +"supports-color@^5.3.0", "supports-color@^5.5.0": + "integrity" "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==" + "resolved" "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz" + "version" "5.5.0" + dependencies: + "has-flag" "^3.0.0" + +"supports-color@^7.1.0": + "integrity" "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==" + "resolved" "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz" + "version" "7.2.0" + dependencies: + "has-flag" "^4.0.0" + +"supports-color@^8.0.0": + "integrity" "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==" + "resolved" "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz" + "version" "8.1.1" + dependencies: + "has-flag" "^4.0.0" + +"supports-preserve-symlinks-flag@^1.0.0": + "integrity" "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" + "resolved" "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz" + "version" "1.0.0" + +"tapable@^2.0.0", "tapable@^2.1.1", "tapable@^2.2.0": + "integrity" "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==" + "resolved" "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz" + "version" "2.2.1" + +"tar@^6.1.11", "tar@^6.1.13", "tar@^6.1.2": + "version" "6.1.13" + 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" + +"terser-webpack-plugin@^5.1.3": + "integrity" "sha512-kfLFk+PoLUQIbLmB1+PZDMRSZS99Mp+/MHqDNmMA6tOItzRt+Npe3E+fsMs5mfcM0wCtrrdU387UnV+vnSffXQ==" + "resolved" "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.6.tgz" + "version" "5.3.6" + 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" + +"terser@^5.10.0", "terser@^5.14.1": + "integrity" "sha512-K1faMUvpm/FBxjBXud0LWVAGxmvoPbZbfTCYbSgaaYQaIXI3/TdI7a7ZGA73Zrou6Q8Zmz3oeUTsp/dj+ag2Xw==" + "resolved" "https://registry.npmjs.org/terser/-/terser-5.15.1.tgz" + "version" "5.15.1" + dependencies: + "@jridgewell/source-map" "^0.3.2" + "acorn" "^8.5.0" + "commander" "^2.20.0" + "source-map-support" "~0.5.20" + +"text-table@^0.2.0": + "integrity" "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==" + "resolved" "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz" + "version" "0.2.0" + +"text-table@~0.2.0": + "version" "0.2.0" + +"tiny-relative-date@^1.3.0": + "version" "1.3.0" + +"to-fast-properties@^2.0.0": + "integrity" "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==" + "resolved" "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz" + "version" "2.0.0" + +"to-regex-range@^5.0.1": + "integrity" "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==" + "resolved" "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz" + "version" "5.0.1" + dependencies: + "is-number" "^7.0.0" + +"toggle-selection@^1.0.6": + "integrity" "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==" + "resolved" "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz" + "version" "1.0.6" + +"touch@^3.1.0": + "integrity" "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==" + "resolved" "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz" + "version" "3.1.0" + dependencies: + "nopt" "~1.0.10" + +"treeverse@^3.0.0": + "version" "3.0.0" + +"ts-loader@^9.4.1": + "integrity" "sha512-384TYAqGs70rn9F0VBnh6BPTfhga7yFNdC5gXbQpDrBj9/KsT4iRkGqKXhziofHOlE2j6YEaiTYVGKKvPhGWvw==" + "resolved" "https://registry.npmjs.org/ts-loader/-/ts-loader-9.4.1.tgz" + "version" "9.4.1" + dependencies: + "chalk" "^4.1.0" + "enhanced-resolve" "^5.0.0" + "micromatch" "^4.0.0" + "semver" "^7.3.4" + +"tslib@^1.8.1": + "integrity" "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + "resolved" "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz" + "version" "1.14.1" + +"tslib@^2.0.3", "tslib@^2.3.1", "tslib@2.4.0": + "integrity" "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + "resolved" "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz" + "version" "2.4.0" + +"tss-react@^4.4.1": + "integrity" "sha512-typ6yVmBGz1GIHmWaN+bmwHaAfxZLImfiNTiGIfJCFgas3rEpdYSty2/JENXAFvzKFl53CHc/6Z/FM2EkE2ZTQ==" + "resolved" "https://registry.npmjs.org/tss-react/-/tss-react-4.4.2.tgz" + "version" "4.4.2" + dependencies: + "@emotion/cache" "*" + "@emotion/serialize" "*" + "@emotion/utils" "*" + +"tsutils@^3.21.0": + "integrity" "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==" + "resolved" "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz" + "version" "3.21.0" + dependencies: + "tslib" "^1.8.1" + +"tuf-js@^1.0.0": + "version" "1.0.0" + dependencies: + "make-fetch-happen" "^11.0.1" + "minimatch" "^6.1.0" + +"type-check@^0.4.0", "type-check@~0.4.0": + "integrity" "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==" + "resolved" "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz" + "version" "0.4.0" + dependencies: + "prelude-ls" "^1.2.1" + +"type-fest@^0.20.2": + "integrity" "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==" + "resolved" "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz" + "version" "0.20.2" + +"type-is@~1.6.16": + "integrity" "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==" + "resolved" "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz" + "version" "1.6.18" + dependencies: + "media-typer" "0.3.0" + "mime-types" "~2.1.24" + +"typed-array-length@^1.0.4": + "integrity" "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==" + "resolved" "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz" + "version" "1.0.4" + dependencies: + "call-bind" "^1.0.2" + "for-each" "^0.3.3" + "is-typed-array" "^1.1.9" + +"typescript@*", "typescript@^4.7", "typescript@^4.8.4", "typescript@>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta": + "integrity" "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==" + "resolved" "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz" + "version" "4.8.4" + +"ua-parser-js@^1.0.2": + "integrity" "sha512-dXVsz3M4j+5tTiovFVyVqssXBu5HM47//YSOeZ9fQkdDKkfzv2v3PP1jmH6FUyPW+yCSn7aBVK1fGGKNhowdDA==" + "resolved" "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.32.tgz" + "version" "1.0.32" + +"unbox-primitive@^1.0.2": + "integrity" "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==" + "resolved" "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz" + "version" "1.0.2" + dependencies: + "call-bind" "^1.0.2" + "has-bigints" "^1.0.2" + "has-symbols" "^1.0.3" + "which-boxed-primitive" "^1.0.2" + +"undefsafe@^2.0.5": + "integrity" "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==" + "resolved" "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz" + "version" "2.0.5" + +"unfetch@^4.2.0": + "integrity" "sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA==" + "resolved" "https://registry.npmjs.org/unfetch/-/unfetch-4.2.0.tgz" + "version" "4.2.0" + +"unicode-canonical-property-names-ecmascript@^2.0.0": + "integrity" "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==" + "resolved" "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz" + "version" "2.0.0" + +"unicode-match-property-ecmascript@^2.0.0": + "integrity" "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==" + "resolved" "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz" + "version" "2.0.0" + dependencies: + "unicode-canonical-property-names-ecmascript" "^2.0.0" + "unicode-property-aliases-ecmascript" "^2.0.0" + +"unicode-match-property-value-ecmascript@^2.0.0": + "integrity" "sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw==" + "resolved" "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz" + "version" "2.0.0" + +"unicode-property-aliases-ecmascript@^2.0.0": + "integrity" "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==" + "resolved" "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz" + "version" "2.1.0" + +"unique-filename@^2.0.0": + "version" "2.0.1" + dependencies: + "unique-slug" "^3.0.0" + +"unique-filename@^3.0.0": + "version" "3.0.0" + dependencies: + "unique-slug" "^4.0.0" + +"unique-slug@^3.0.0": + "version" "3.0.0" + dependencies: + "imurmurhash" "^0.1.4" + +"unique-slug@^4.0.0": + "version" "4.0.0" + dependencies: + "imurmurhash" "^0.1.4" + +"unpipe@~1.0.0", "unpipe@1.0.0": + "integrity" "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==" + "resolved" "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz" + "version" "1.0.0" + +"update-browserslist-db@^1.0.9": + "integrity" "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==" + "resolved" "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz" + "version" "1.0.10" + dependencies: + "escalade" "^3.1.1" + "picocolors" "^1.0.0" + +"uri-js@^4.2.2": + "integrity" "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==" + "resolved" "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz" + "version" "4.4.1" + dependencies: + "punycode" "^2.1.0" + +"url@^0.11.0": + "integrity" "sha512-kbailJa29QrtXnxgq+DdCEGlbTeYM2eJUxsz6vjZavrCYPMIFHMKQmSKYAIuUK2i7hgPm28a8piX5NTUtM/LKQ==" + "resolved" "https://registry.npmjs.org/url/-/url-0.11.0.tgz" + "version" "0.11.0" + dependencies: + "punycode" "1.3.2" + "querystring" "0.2.0" + +"util-deprecate@^1.0.1", "util-deprecate@^1.0.2": + "integrity" "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + "resolved" "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" + "version" "1.0.2" + +"utila@~0.4": + "integrity" "sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==" + "resolved" "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz" + "version" "0.4.0" + +"utils-merge@1.0.1": + "integrity" "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==" + "resolved" "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz" + "version" "1.0.1" + +"validate-npm-package-license@^3.0.4": + "version" "3.0.4" + dependencies: + "spdx-correct" "^3.0.0" + "spdx-expression-parse" "^3.0.0" + +"validate-npm-package-name@^5.0.0": + "version" "5.0.0" + dependencies: + "builtins" "^5.0.0" + +"vary@~1.1.2": + "integrity" "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" + "resolved" "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz" + "version" "1.1.2" + +"walk-up-path@^1.0.0": + "version" "1.0.0" + +"watchpack@^2.4.0": + "integrity" "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==" + "resolved" "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz" + "version" "2.4.0" + dependencies: + "glob-to-regexp" "^0.4.1" + "graceful-fs" "^4.1.2" + +"wcwidth@^1.0.0": + "version" "1.0.1" + dependencies: + "defaults" "^1.0.3" + +"web-streams-polyfill@^3.0.3": + "integrity" "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==" + "resolved" "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz" + "version" "3.2.1" + +"webpack-cli@^4.10.0", "webpack-cli@4.x.x": + "integrity" "sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w==" + "resolved" "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.10.0.tgz" + "version" "4.10.0" + dependencies: + "@discoveryjs/json-ext" "^0.5.0" + "@webpack-cli/configtest" "^1.2.0" + "@webpack-cli/info" "^1.5.0" + "@webpack-cli/serve" "^1.7.0" + "colorette" "^2.0.14" + "commander" "^7.0.0" + "cross-spawn" "^7.0.3" + "fastest-levenshtein" "^1.0.12" + "import-local" "^3.0.2" + "interpret" "^2.2.0" + "rechoir" "^0.7.0" + "webpack-merge" "^5.7.3" + +"webpack-merge@^5.7.3": + "integrity" "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==" + "resolved" "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz" + "version" "5.8.0" + dependencies: + "clone-deep" "^4.0.1" + "wildcard" "^2.0.0" + +"webpack-sources@^3.2.3": + "integrity" "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==" + "resolved" "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz" + "version" "3.2.3" + +"webpack@^4.0.0 || ^5.0.0", "webpack@^5.0.0", "webpack@^5.1.0", "webpack@^5.20.0", "webpack@^5.74.0", "webpack@>=2", "webpack@4.x.x || 5.x.x": + "integrity" "sha512-A2InDwnhhGN4LYctJj6M1JEaGL7Luj6LOmyBHjcI8529cm5p6VXiTIW2sn6ffvEAKmveLzvu4jrihwXtPojlAA==" + "resolved" "https://registry.npmjs.org/webpack/-/webpack-5.74.0.tgz" + "version" "5.74.0" + 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" + +"which-boxed-primitive@^1.0.2": + "integrity" "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==" + "resolved" "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz" + "version" "1.0.2" + dependencies: + "is-bigint" "^1.0.1" + "is-boolean-object" "^1.1.0" + "is-number-object" "^1.0.4" + "is-string" "^1.0.5" + "is-symbol" "^1.0.3" + +"which-typed-array@^1.1.9": + "integrity" "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==" + "resolved" "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz" + "version" "1.1.9" + dependencies: + "available-typed-arrays" "^1.0.5" + "call-bind" "^1.0.2" + "for-each" "^0.3.3" + "gopd" "^1.0.1" + "has-tostringtag" "^1.0.0" + "is-typed-array" "^1.1.10" + +"which@^2.0.1": + "integrity" "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==" + "resolved" "https://registry.npmjs.org/which/-/which-2.0.2.tgz" + "version" "2.0.2" + dependencies: + "isexe" "^2.0.0" + +"which@^2.0.2": + "version" "2.0.2" + dependencies: + "isexe" "^2.0.0" + +"which@^3.0.0": + "version" "3.0.0" + dependencies: + "isexe" "^2.0.0" + +"wide-align@^1.1.5": + "version" "1.1.5" + dependencies: + "string-width" "^1.0.2 || 2 || 3 || 4" + +"wildcard@^2.0.0": + "integrity" "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==" + "resolved" "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz" + "version" "2.0.0" + +"word-wrap@^1.2.3": + "integrity" "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==" + "resolved" "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz" + "version" "1.2.3" + +"wrappy@1": + "integrity" "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + "resolved" "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" + "version" "1.0.2" + +"write-file-atomic@^5.0.0": + "version" "5.0.0" + dependencies: + "imurmurhash" "^0.1.4" + "signal-exit" "^3.0.7" + +"ws@^7.4.3": + "integrity" "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==" + "resolved" "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz" + "version" "7.5.9" + +"yallist@^4.0.0": + "integrity" "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "resolved" "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz" + "version" "4.0.0" + +"yaml@^1.10.0": + "integrity" "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==" + "resolved" "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz" + "version" "1.10.2" + +"yocto-queue@^0.1.0": + "integrity" "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==" + "resolved" "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz" + "version" "0.1.0" diff --git a/backoffice/backoffice-domain-service/.gitignore b/backoffice/backoffice-domain-service/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/backoffice/backoffice-domain-service/.gitignore @@ -0,0 +1 @@ +target diff --git a/backoffice/backoffice-domain-service/README.md b/backoffice/backoffice-domain-service/README.md new file mode 100644 index 000000000..253790a73 --- /dev/null +++ b/backoffice/backoffice-domain-service/README.md @@ -0,0 +1 @@ +## Backoffice Domain Service \ No newline at end of file diff --git a/backoffice/backoffice-domain-service/ballerina/.devcontainer.json b/backoffice/backoffice-domain-service/ballerina/.devcontainer.json new file mode 100644 index 000000000..015cdb62d --- /dev/null +++ b/backoffice/backoffice-domain-service/ballerina/.devcontainer.json @@ -0,0 +1,4 @@ +{ + "image": "ballerina/ballerina-devcontainer:2201.2.0", + "extensions": ["WSO2.ballerina"], +} diff --git a/backoffice/backoffice-domain-service/ballerina/Artifact.bal b/backoffice/backoffice-domain-service/ballerina/Artifact.bal new file mode 100644 index 000000000..9c67be41d --- /dev/null +++ b/backoffice/backoffice-domain-service/ballerina/Artifact.bal @@ -0,0 +1,28 @@ +// +// Copyright (c) 2022, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + + +// Defines a record to create artifact. +type Artifact record {| + string? id; + string apiName; + string context; + string 'version; + string? status; + string? providerName; +|}; diff --git a/backoffice/backoffice-domain-service/ballerina/Ballerina.toml b/backoffice/backoffice-domain-service/ballerina/Ballerina.toml new file mode 100644 index 000000000..fd61d3d2b --- /dev/null +++ b/backoffice/backoffice-domain-service/ballerina/Ballerina.toml @@ -0,0 +1,25 @@ +[package] +org = "wso2" +name = "backoffice_service" +version = "0.0.1-SNAPSHOT" +distribution = "2201.8.0" + +[[dependency]] +org = "wso2" +name = "apk_common_lib" +version = "0.0.1-SNAPSHOT" +repository = "local" + +[[dependency]] +org = "wso2" +name = "notification_grpc_client" +version = "0.0.1-SNAPSHOT" +repository = "local" + +[build-options] +observabilityIncluded = true + +[[platform.java11.dependency]] +groupId = "org.postgresql" +artifactId = "postgresql" +version = "42.5.0" diff --git a/backoffice/backoffice-domain-service/ballerina/Ballerina.toml.template b/backoffice/backoffice-domain-service/ballerina/Ballerina.toml.template new file mode 100644 index 000000000..e9dd73114 --- /dev/null +++ b/backoffice/backoffice-domain-service/ballerina/Ballerina.toml.template @@ -0,0 +1,25 @@ +[package] +org = "wso2" +name = "backoffice_service" +version = "PROJECT_VERSION" +distribution = "2201.8.0" + +[[dependency]] +org = "wso2" +name = "apk_common_lib" +version = "0.0.1-SNAPSHOT" +repository = "local" + +[[dependency]] +org = "wso2" +name = "notification_grpc_client" +version = "0.0.1-SNAPSHOT" +repository = "local" + +[build-options] +observabilityIncluded = true + +[[platform.java11.dependency]] +groupId = "org.postgresql" +artifactId = "postgresql" +version = "42.5.0" diff --git a/backoffice/backoffice-domain-service/ballerina/BusinessPlan.bal b/backoffice/backoffice-domain-service/ballerina/BusinessPlan.bal new file mode 100644 index 000000000..9d5e00096 --- /dev/null +++ b/backoffice/backoffice-domain-service/ballerina/BusinessPlan.bal @@ -0,0 +1,21 @@ +public type BusinessPlanDAO record { + *Policy; + *GraphQLQuery; + string defaulLimitType; + # Unit of the time. Allowed values are "sec", "min", "hour", "day" + string timeUnit; + # Time limit that the throttling limit applies. + int unitTime; + int quota; + # Unit of data allowed to be transfered. Allowed values are "KB", "MB" and "GB" + string dataUnit?; + # Burst control request count + int rateLimitCount?; + # Burst control time unit + string rateLimitTimeUnit?; + # Number of subscriptions allowed + int subscriberCount?; + # Custom attributes added to the Subscription Throttling Policy + CustomAttribute[] customAttributes?; + BusinessPlanPermission permissions?; +}; \ No newline at end of file diff --git a/backoffice/backoffice-domain-service/ballerina/Config.toml b/backoffice/backoffice-domain-service/ballerina/Config.toml new file mode 100644 index 000000000..f11078a88 --- /dev/null +++ b/backoffice/backoffice-domain-service/ballerina/Config.toml @@ -0,0 +1,24 @@ +[wso2.backoffice_service] +BACKOFFICE_PORT = 9443 + +# Sample configurations +[wso2.backoffice_service.datasourceConfiguration] +description = "APK DB" +url = "jdbc:postgresql://localhost:5432/APKDB" +username = "admin" +password = "admin" +validationTimeout = 30000 +testQuery = "SELECT 1" +driver = "org.postgresql.Driver" +host = "localhost" +port = 5432 +databaseName = "APKDB" + +[wso2.backoffice_service.k8sConfig] +host = "localhost:9090" +serviceAccountPath = "tests/resources/serviceAccount" + +[wso2.backoffice_service.managementServerConfig] +serviceName = "apk-test-wso2-apk-management-server" +namespace = "apk" +certPath = "/home/wso2apk/backoffice/security/truststore/management-server.pem" \ No newline at end of file diff --git a/backoffice/backoffice-domain-service/ballerina/Dependencies.toml b/backoffice/backoffice-domain-service/ballerina/Dependencies.toml new file mode 100644 index 000000000..418ee5d3d --- /dev/null +++ b/backoffice/backoffice-domain-service/ballerina/Dependencies.toml @@ -0,0 +1,495 @@ +# AUTO-GENERATED FILE. DO NOT MODIFY. + +# This file is auto-generated by Ballerina for managing dependency versions. +# It should not be modified by hand. + +[ballerina] +dependencies-toml-version = "2" +distribution-version = "2201.8.0" + +[[package]] +org = "ballerina" +name = "auth" +version = "2.10.0" +dependencies = [ + {org = "ballerina", name = "crypto"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.array"}, + {org = "ballerina", name = "lang.string"}, + {org = "ballerina", name = "log"} +] + +[[package]] +org = "ballerina" +name = "cache" +version = "3.7.0" +dependencies = [ + {org = "ballerina", name = "constraint"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "task"}, + {org = "ballerina", name = "time"} +] + +[[package]] +org = "ballerina" +name = "constraint" +version = "1.4.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] +modules = [ + {org = "ballerina", packageName = "constraint", moduleName = "constraint"} +] + +[[package]] +org = "ballerina" +name = "crypto" +version = "2.5.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "time"} +] + +[[package]] +org = "ballerina" +name = "file" +version = "1.9.0" +dependencies = [ + {org = "ballerina", name = "io"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "os"}, + {org = "ballerina", name = "time"} +] + +[[package]] +org = "ballerina" +name = "grpc" +version = "1.10.1" +dependencies = [ + {org = "ballerina", name = "auth"}, + {org = "ballerina", name = "crypto"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "jwt"}, + {org = "ballerina", name = "lang.runtime"}, + {org = "ballerina", name = "log"}, + {org = "ballerina", name = "oauth2"}, + {org = "ballerina", name = "protobuf"}, + {org = "ballerina", name = "time"} +] + +[[package]] +org = "ballerina" +name = "http" +version = "2.10.1" +dependencies = [ + {org = "ballerina", name = "auth"}, + {org = "ballerina", name = "cache"}, + {org = "ballerina", name = "constraint"}, + {org = "ballerina", name = "crypto"}, + {org = "ballerina", name = "file"}, + {org = "ballerina", name = "io"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "jwt"}, + {org = "ballerina", name = "lang.array"}, + {org = "ballerina", name = "lang.decimal"}, + {org = "ballerina", name = "lang.int"}, + {org = "ballerina", name = "lang.regexp"}, + {org = "ballerina", name = "lang.runtime"}, + {org = "ballerina", name = "lang.string"}, + {org = "ballerina", name = "lang.value"}, + {org = "ballerina", name = "log"}, + {org = "ballerina", name = "mime"}, + {org = "ballerina", name = "oauth2"}, + {org = "ballerina", name = "observe"}, + {org = "ballerina", name = "time"}, + {org = "ballerina", name = "url"} +] +modules = [ + {org = "ballerina", packageName = "http", moduleName = "http"}, + {org = "ballerina", packageName = "http", moduleName = "http.httpscerr"} +] + +[[package]] +org = "ballerina" +name = "io" +version = "1.6.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.value"} +] +modules = [ + {org = "ballerina", packageName = "io", moduleName = "io"} +] + +[[package]] +org = "ballerina" +name = "jballerina.java" +version = "0.0.0" + +[[package]] +org = "ballerina" +name = "jballerina.java.arrays" +version = "1.4.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] + +[[package]] +org = "ballerina" +name = "jwt" +version = "2.10.0" +dependencies = [ + {org = "ballerina", name = "cache"}, + {org = "ballerina", name = "crypto"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.int"}, + {org = "ballerina", name = "lang.string"}, + {org = "ballerina", name = "log"}, + {org = "ballerina", name = "time"} +] + +[[package]] +org = "ballerina" +name = "lang.__internal" +version = "0.0.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.object"} +] + +[[package]] +org = "ballerina" +name = "lang.array" +version = "0.0.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.__internal"} +] + +[[package]] +org = "ballerina" +name = "lang.decimal" +version = "0.0.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] + +[[package]] +org = "ballerina" +name = "lang.error" +version = "0.0.0" +scope = "testOnly" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] + +[[package]] +org = "ballerina" +name = "lang.int" +version = "0.0.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.__internal"}, + {org = "ballerina", name = "lang.object"} +] + +[[package]] +org = "ballerina" +name = "lang.object" +version = "0.0.0" + +[[package]] +org = "ballerina" +name = "lang.regexp" +version = "0.0.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] + +[[package]] +org = "ballerina" +name = "lang.runtime" +version = "0.0.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] + +[[package]] +org = "ballerina" +name = "lang.string" +version = "0.0.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.regexp"} +] + +[[package]] +org = "ballerina" +name = "lang.transaction" +version = "0.0.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] + +[[package]] +org = "ballerina" +name = "lang.value" +version = "0.0.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] + +[[package]] +org = "ballerina" +name = "log" +version = "2.9.0" +dependencies = [ + {org = "ballerina", name = "io"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.value"}, + {org = "ballerina", name = "observe"} +] +modules = [ + {org = "ballerina", packageName = "log", moduleName = "log"} +] + +[[package]] +org = "ballerina" +name = "mime" +version = "2.9.0" +dependencies = [ + {org = "ballerina", name = "io"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.int"} +] +modules = [ + {org = "ballerina", packageName = "mime", moduleName = "mime"} +] + +[[package]] +org = "ballerina" +name = "oauth2" +version = "2.10.0" +dependencies = [ + {org = "ballerina", name = "cache"}, + {org = "ballerina", name = "crypto"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "log"}, + {org = "ballerina", name = "time"}, + {org = "ballerina", name = "url"} +] + +[[package]] +org = "ballerina" +name = "observe" +version = "1.2.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] + +[[package]] +org = "ballerina" +name = "os" +version = "1.8.0" +dependencies = [ + {org = "ballerina", name = "io"}, + {org = "ballerina", name = "jballerina.java"} +] + +[[package]] +org = "ballerina" +name = "protobuf" +version = "1.6.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "time"} +] + +[[package]] +org = "ballerina" +name = "regex" +version = "1.4.3" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.string"} +] + +[[package]] +org = "ballerina" +name = "sql" +version = "1.11.0" +dependencies = [ + {org = "ballerina", name = "io"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.object"}, + {org = "ballerina", name = "time"} +] +modules = [ + {org = "ballerina", packageName = "sql", moduleName = "sql"} +] + +[[package]] +org = "ballerina" +name = "task" +version = "2.5.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "time"} +] + +[[package]] +org = "ballerina" +name = "test" +version = "0.0.0" +scope = "testOnly" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.error"} +] +modules = [ + {org = "ballerina", packageName = "test", moduleName = "test"} +] + +[[package]] +org = "ballerina" +name = "time" +version = "2.4.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] +modules = [ + {org = "ballerina", packageName = "time", moduleName = "time"} +] + +[[package]] +org = "ballerina" +name = "url" +version = "2.4.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] + +[[package]] +org = "ballerina" +name = "uuid" +version = "1.7.0" +dependencies = [ + {org = "ballerina", name = "crypto"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.int"}, + {org = "ballerina", name = "time"} +] +modules = [ + {org = "ballerina", packageName = "uuid", moduleName = "uuid"} +] + +[[package]] +org = "ballerinai" +name = "observe" +version = "0.0.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "observe"} +] +modules = [ + {org = "ballerinai", packageName = "observe", moduleName = "observe"} +] + +[[package]] +org = "ballerinai" +name = "transaction" +version = "0.0.0" +dependencies = [ + {org = "ballerina", name = "cache"}, + {org = "ballerina", name = "http"}, + {org = "ballerina", name = "io"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.runtime"}, + {org = "ballerina", name = "lang.transaction"}, + {org = "ballerina", name = "lang.value"}, + {org = "ballerina", name = "log"}, + {org = "ballerina", name = "task"}, + {org = "ballerina", name = "time"}, + {org = "ballerina", name = "uuid"} +] +modules = [ + {org = "ballerinai", packageName = "transaction", moduleName = "transaction"} +] + +[[package]] +org = "ballerinax" +name = "postgresql" +version = "1.11.0" +dependencies = [ + {org = "ballerina", name = "crypto"}, + {org = "ballerina", name = "io"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "sql"}, + {org = "ballerina", name = "time"} +] +modules = [ + {org = "ballerinax", packageName = "postgresql", moduleName = "postgresql"} +] + +[[package]] +org = "wso2" +name = "apk_common_lib" +version = "0.0.1-SNAPSHOT" +dependencies = [ + {org = "ballerina", name = "http"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "jballerina.java.arrays"}, + {org = "ballerina", name = "jwt"}, + {org = "ballerina", name = "lang.value"}, + {org = "ballerina", name = "log"}, + {org = "ballerina", name = "os"}, + {org = "ballerina", name = "regex"}, + {org = "ballerina", name = "sql"}, + {org = "ballerina", name = "uuid"}, + {org = "ballerinax", name = "postgresql"} +] +modules = [ + {org = "wso2", packageName = "apk_common_lib", moduleName = "apk_common_lib"}, + {org = "wso2", packageName = "apk_common_lib", moduleName = "apk_common_lib.java.io"}, + {org = "wso2", packageName = "apk_common_lib", moduleName = "apk_common_lib.java.lang"} +] + +[[package]] +org = "wso2" +name = "backoffice_service" +version = "0.0.1-SNAPSHOT" +dependencies = [ + {org = "ballerina", name = "constraint"}, + {org = "ballerina", name = "http"}, + {org = "ballerina", name = "io"}, + {org = "ballerina", name = "log"}, + {org = "ballerina", name = "mime"}, + {org = "ballerina", name = "sql"}, + {org = "ballerina", name = "test"}, + {org = "ballerina", name = "time"}, + {org = "ballerina", name = "uuid"}, + {org = "ballerinai", name = "observe"}, + {org = "ballerinai", name = "transaction"}, + {org = "ballerinax", name = "postgresql"}, + {org = "wso2", name = "apk_common_lib"}, + {org = "wso2", name = "notification_grpc_client"} +] +modules = [ + {org = "wso2", packageName = "backoffice_service", moduleName = "backoffice_service"}, + {org = "wso2", packageName = "backoffice_service", moduleName = "backoffice_service.backoffice"} +] + +[[package]] +org = "wso2" +name = "notification_grpc_client" +version = "0.0.1-SNAPSHOT" +dependencies = [ + {org = "ballerina", name = "grpc"}, + {org = "ballerina", name = "io"}, + {org = "ballerina", name = "log"}, + {org = "ballerina", name = "protobuf"} +] +modules = [ + {org = "wso2", packageName = "notification_grpc_client", moduleName = "notification_grpc_client"} +] + diff --git a/backoffice/backoffice-domain-service/ballerina/Dependencies.toml.template b/backoffice/backoffice-domain-service/ballerina/Dependencies.toml.template new file mode 100644 index 000000000..5c08b6a37 --- /dev/null +++ b/backoffice/backoffice-domain-service/ballerina/Dependencies.toml.template @@ -0,0 +1,495 @@ +# AUTO-GENERATED FILE. DO NOT MODIFY. + +# This file is auto-generated by Ballerina for managing dependency versions. +# It should not be modified by hand. + +[ballerina] +dependencies-toml-version = "2" +distribution-version = "2201.8.0" + +[[package]] +org = "ballerina" +name = "auth" +version = "2.10.0" +dependencies = [ + {org = "ballerina", name = "crypto"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.array"}, + {org = "ballerina", name = "lang.string"}, + {org = "ballerina", name = "log"} +] + +[[package]] +org = "ballerina" +name = "cache" +version = "3.7.0" +dependencies = [ + {org = "ballerina", name = "constraint"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "task"}, + {org = "ballerina", name = "time"} +] + +[[package]] +org = "ballerina" +name = "constraint" +version = "1.4.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] +modules = [ + {org = "ballerina", packageName = "constraint", moduleName = "constraint"} +] + +[[package]] +org = "ballerina" +name = "crypto" +version = "2.5.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "time"} +] + +[[package]] +org = "ballerina" +name = "file" +version = "1.9.0" +dependencies = [ + {org = "ballerina", name = "io"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "os"}, + {org = "ballerina", name = "time"} +] + +[[package]] +org = "ballerina" +name = "grpc" +version = "1.10.1" +dependencies = [ + {org = "ballerina", name = "auth"}, + {org = "ballerina", name = "crypto"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "jwt"}, + {org = "ballerina", name = "lang.runtime"}, + {org = "ballerina", name = "log"}, + {org = "ballerina", name = "oauth2"}, + {org = "ballerina", name = "protobuf"}, + {org = "ballerina", name = "time"} +] + +[[package]] +org = "ballerina" +name = "http" +version = "2.10.1" +dependencies = [ + {org = "ballerina", name = "auth"}, + {org = "ballerina", name = "cache"}, + {org = "ballerina", name = "constraint"}, + {org = "ballerina", name = "crypto"}, + {org = "ballerina", name = "file"}, + {org = "ballerina", name = "io"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "jwt"}, + {org = "ballerina", name = "lang.array"}, + {org = "ballerina", name = "lang.decimal"}, + {org = "ballerina", name = "lang.int"}, + {org = "ballerina", name = "lang.regexp"}, + {org = "ballerina", name = "lang.runtime"}, + {org = "ballerina", name = "lang.string"}, + {org = "ballerina", name = "lang.value"}, + {org = "ballerina", name = "log"}, + {org = "ballerina", name = "mime"}, + {org = "ballerina", name = "oauth2"}, + {org = "ballerina", name = "observe"}, + {org = "ballerina", name = "time"}, + {org = "ballerina", name = "url"} +] +modules = [ + {org = "ballerina", packageName = "http", moduleName = "http"}, + {org = "ballerina", packageName = "http", moduleName = "http.httpscerr"} +] + +[[package]] +org = "ballerina" +name = "io" +version = "1.6.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.value"} +] +modules = [ + {org = "ballerina", packageName = "io", moduleName = "io"} +] + +[[package]] +org = "ballerina" +name = "jballerina.java" +version = "0.0.0" + +[[package]] +org = "ballerina" +name = "jballerina.java.arrays" +version = "1.4.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] + +[[package]] +org = "ballerina" +name = "jwt" +version = "2.10.0" +dependencies = [ + {org = "ballerina", name = "cache"}, + {org = "ballerina", name = "crypto"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.int"}, + {org = "ballerina", name = "lang.string"}, + {org = "ballerina", name = "log"}, + {org = "ballerina", name = "time"} +] + +[[package]] +org = "ballerina" +name = "lang.__internal" +version = "0.0.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.object"} +] + +[[package]] +org = "ballerina" +name = "lang.array" +version = "0.0.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.__internal"} +] + +[[package]] +org = "ballerina" +name = "lang.decimal" +version = "0.0.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] + +[[package]] +org = "ballerina" +name = "lang.error" +version = "0.0.0" +scope = "testOnly" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] + +[[package]] +org = "ballerina" +name = "lang.int" +version = "0.0.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.__internal"}, + {org = "ballerina", name = "lang.object"} +] + +[[package]] +org = "ballerina" +name = "lang.object" +version = "0.0.0" + +[[package]] +org = "ballerina" +name = "lang.regexp" +version = "0.0.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] + +[[package]] +org = "ballerina" +name = "lang.runtime" +version = "0.0.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] + +[[package]] +org = "ballerina" +name = "lang.string" +version = "0.0.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.regexp"} +] + +[[package]] +org = "ballerina" +name = "lang.transaction" +version = "0.0.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] + +[[package]] +org = "ballerina" +name = "lang.value" +version = "0.0.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] + +[[package]] +org = "ballerina" +name = "log" +version = "2.9.0" +dependencies = [ + {org = "ballerina", name = "io"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.value"}, + {org = "ballerina", name = "observe"} +] +modules = [ + {org = "ballerina", packageName = "log", moduleName = "log"} +] + +[[package]] +org = "ballerina" +name = "mime" +version = "2.9.0" +dependencies = [ + {org = "ballerina", name = "io"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.int"} +] +modules = [ + {org = "ballerina", packageName = "mime", moduleName = "mime"} +] + +[[package]] +org = "ballerina" +name = "oauth2" +version = "2.10.0" +dependencies = [ + {org = "ballerina", name = "cache"}, + {org = "ballerina", name = "crypto"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "log"}, + {org = "ballerina", name = "time"}, + {org = "ballerina", name = "url"} +] + +[[package]] +org = "ballerina" +name = "observe" +version = "1.2.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] + +[[package]] +org = "ballerina" +name = "os" +version = "1.8.0" +dependencies = [ + {org = "ballerina", name = "io"}, + {org = "ballerina", name = "jballerina.java"} +] + +[[package]] +org = "ballerina" +name = "protobuf" +version = "1.6.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "time"} +] + +[[package]] +org = "ballerina" +name = "regex" +version = "1.4.3" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.string"} +] + +[[package]] +org = "ballerina" +name = "sql" +version = "1.11.0" +dependencies = [ + {org = "ballerina", name = "io"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.object"}, + {org = "ballerina", name = "time"} +] +modules = [ + {org = "ballerina", packageName = "sql", moduleName = "sql"} +] + +[[package]] +org = "ballerina" +name = "task" +version = "2.5.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "time"} +] + +[[package]] +org = "ballerina" +name = "test" +version = "0.0.0" +scope = "testOnly" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.error"} +] +modules = [ + {org = "ballerina", packageName = "test", moduleName = "test"} +] + +[[package]] +org = "ballerina" +name = "time" +version = "2.4.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] +modules = [ + {org = "ballerina", packageName = "time", moduleName = "time"} +] + +[[package]] +org = "ballerina" +name = "url" +version = "2.4.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] + +[[package]] +org = "ballerina" +name = "uuid" +version = "1.7.0" +dependencies = [ + {org = "ballerina", name = "crypto"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.int"}, + {org = "ballerina", name = "time"} +] +modules = [ + {org = "ballerina", packageName = "uuid", moduleName = "uuid"} +] + +[[package]] +org = "ballerinai" +name = "observe" +version = "0.0.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "observe"} +] +modules = [ + {org = "ballerinai", packageName = "observe", moduleName = "observe"} +] + +[[package]] +org = "ballerinai" +name = "transaction" +version = "0.0.0" +dependencies = [ + {org = "ballerina", name = "cache"}, + {org = "ballerina", name = "http"}, + {org = "ballerina", name = "io"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.runtime"}, + {org = "ballerina", name = "lang.transaction"}, + {org = "ballerina", name = "lang.value"}, + {org = "ballerina", name = "log"}, + {org = "ballerina", name = "task"}, + {org = "ballerina", name = "time"}, + {org = "ballerina", name = "uuid"} +] +modules = [ + {org = "ballerinai", packageName = "transaction", moduleName = "transaction"} +] + +[[package]] +org = "ballerinax" +name = "postgresql" +version = "1.11.0" +dependencies = [ + {org = "ballerina", name = "crypto"}, + {org = "ballerina", name = "io"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "sql"}, + {org = "ballerina", name = "time"} +] +modules = [ + {org = "ballerinax", packageName = "postgresql", moduleName = "postgresql"} +] + +[[package]] +org = "wso2" +name = "apk_common_lib" +version = "0.0.1-SNAPSHOT" +dependencies = [ + {org = "ballerina", name = "http"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "jballerina.java.arrays"}, + {org = "ballerina", name = "jwt"}, + {org = "ballerina", name = "lang.value"}, + {org = "ballerina", name = "log"}, + {org = "ballerina", name = "os"}, + {org = "ballerina", name = "regex"}, + {org = "ballerina", name = "sql"}, + {org = "ballerina", name = "uuid"}, + {org = "ballerinax", name = "postgresql"} +] +modules = [ + {org = "wso2", packageName = "apk_common_lib", moduleName = "apk_common_lib"}, + {org = "wso2", packageName = "apk_common_lib", moduleName = "apk_common_lib.java.io"}, + {org = "wso2", packageName = "apk_common_lib", moduleName = "apk_common_lib.java.lang"} +] + +[[package]] +org = "wso2" +name = "backoffice_service" +version = "PROJECT_VERSION" +dependencies = [ + {org = "ballerina", name = "constraint"}, + {org = "ballerina", name = "http"}, + {org = "ballerina", name = "io"}, + {org = "ballerina", name = "log"}, + {org = "ballerina", name = "mime"}, + {org = "ballerina", name = "sql"}, + {org = "ballerina", name = "test"}, + {org = "ballerina", name = "time"}, + {org = "ballerina", name = "uuid"}, + {org = "ballerinai", name = "observe"}, + {org = "ballerinai", name = "transaction"}, + {org = "ballerinax", name = "postgresql"}, + {org = "wso2", name = "apk_common_lib"}, + {org = "wso2", name = "notification_grpc_client"} +] +modules = [ + {org = "wso2", packageName = "backoffice_service", moduleName = "backoffice_service"}, + {org = "wso2", packageName = "backoffice_service", moduleName = "backoffice_service.backoffice"} +] + +[[package]] +org = "wso2" +name = "notification_grpc_client" +version = "0.0.1-SNAPSHOT" +dependencies = [ + {org = "ballerina", name = "grpc"}, + {org = "ballerina", name = "io"}, + {org = "ballerina", name = "log"}, + {org = "ballerina", name = "protobuf"} +] +modules = [ + {org = "wso2", packageName = "notification_grpc_client", moduleName = "notification_grpc_client"} +] + diff --git a/backoffice/backoffice-domain-service/ballerina/Errors.bal b/backoffice/backoffice-domain-service/ballerina/Errors.bal new file mode 100644 index 000000000..6946cc3fe --- /dev/null +++ b/backoffice/backoffice-domain-service/ballerina/Errors.bal @@ -0,0 +1,301 @@ +// +// Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// +// Before adding another function for a new error code +// make sure there is no already existing error code for that. +// If there is an error code for that, reuse it. + +import wso2/apk_common_lib as commons; + +public isolated function e909601(error e) returns commons:APKError { + return error commons:APKError( "Error while retrieving connection", e, + code = 909601, + message = "Error while retrieving connection", + statusCode = 500, + description = "Error while retrieving connection" + ); +} + +public isolated function e909602() returns commons:APKError { + return error commons:APKError( "API Definition Not Found for provided API ID", + code = 909602, + message = "API Definition Not Found for provided API ID", + statusCode = 404, + description = "API Definition Not Found for provided API ID" + ); +} + +public isolated function e909603() returns commons:APKError { + return error commons:APKError( "API not found in the database", + code = 909603, + message = "API not found in the database", + statusCode = 404, + description = "API not found in the database" + ); +} + +public isolated function e909604() returns commons:APKError { + return error commons:APKError( "Error while retrieving API", + code = 909604, + message = "Error while retrieving API", + statusCode = 500, + description = "Error while retrieving API" + ); +} + +public isolated function e909605() returns commons:APKError { + return error commons:APKError( "Internal Error while deleting API By Id", + code = 909605, + message = "Internal Error while deleting API By Id", + statusCode = 500, + description = "Internal Error while deleting API By Id" + ); +} + +public isolated function e909606(string apiId) returns commons:APKError { + return error commons:APKError( "API with " + apiId + " not found", + code = 909606, + message = "API with " + apiId + " not found", + statusCode = 404, + description = "API with " + apiId + " not found" + ); +} + +public isolated function e909607(error e) returns commons:APKError { + return error commons:APKError( "Internal Error occured while retrieving APIs", e, + code = 909607, + message = "Internal Error occured while retrieving APIs", + statusCode = 500, + description = "Internal Error occured while retrieving APIs" + ); +} + +public isolated function e909608(error e) returns commons:APKError { + return error commons:APKError( "Error while updating LC state into Database", e, + code = 909608, + message = "Error while updating LC state into Database", + statusCode = 500, + description = "Error while updating LC state into Database" + ); +} + +public isolated function e909609() returns commons:APKError { + return error commons:APKError( "Invalid Lifecycle targetState", + code = 909609, + message = "Invalid Lifecycle targetState", + statusCode = 400, + description = "Invalid Lifecycle targetState" + ); +} + +public isolated function e909610(error e) returns commons:APKError { + return error commons:APKError( "Error while geting LC state from Database", e, + code = 909610, + message = "Error while geting LC state from Database", + statusCode = 400, + description = "Error while geting LC state from Database" + ); +} + +public isolated function e909611(error e) returns commons:APKError { + return error commons:APKError( "Error while inserting data into Database", e, + code = 909611, + message = "Error while inserting data into Database", + statusCode = 500, + description = "Error while inserting data into Database" + ); +} + +public isolated function e909612(error e) returns commons:APKError { + return error commons:APKError( "Internal Error occured while retrieving LC event History", e, + code = 909612, + message = "Internal Error occured while retrieving LC event History", + statusCode = 500, + description = "Internal Error occured while retrieving LC event History" + ); +} + +public isolated function e909613(error e) returns commons:APKError { + return error commons:APKError( "Internal Error while geting subscription infomation", e, + code = 909613, + message = "Internal Error while geting subscription infomation", + statusCode = 500, + description = "Internal Error while geting subscription infomation" + ); +} + +public isolated function e909614(error e, string apiId) returns commons:APKError { + return error commons:APKError( "Internal Error while geting API for provided apiId " + apiId, e, + code = 909614, + message = "Internal Error while geting API for provided apiId " + apiId, + statusCode = 500, + description = "Internal Error while geting API for provided apiId " + apiId + ); +} + +public isolated function e909615(error e) returns commons:APKError { + return error commons:APKError( "Error while changing status of the subscription in the Database", e, + code = 909615, + message = "Error while changing status of the subscription in the Database", + statusCode = 500, + description = "Error while changing status of the subscription in the Database" + ); +} + +public isolated function e909616(error e) returns commons:APKError { + return error commons:APKError( "Error while retrieving API", e, + code = 909616, + message = "Error while retrieving API", + statusCode = 500, + description = "Error while retrieving API" + ); +} + +public isolated function e909617(error e) returns commons:APKError { + return error commons:APKError( "Internal Error while retrieving API Definition", e, + code = 909617, + message = "Internal Error while retrieving API Definition", + statusCode = 500, + description = "Internal Error while retrieving API Definition" + ); +} + +public isolated function e909618(error e) returns commons:APKError { + return error commons:APKError( "Error while updating API data into Database", e, + code = 909618, + message = "Error while updating API data into Database", + statusCode = 500, + description = "Error while updating API data into Database" + ); +} + +public isolated function e909619(error e) returns commons:APKError { + return error commons:APKError( "Internal Error occured while retrieving API Categories", e, + code = 909619, + message = "Internal Error occured while retrieving API Categories", + statusCode = 500, + description = "Internal Error occured while retrieving API Categories" + ); +} + +public isolated function e909620(error e) returns commons:APKError { + return error commons:APKError( "Internal Error occured while retrieving Business Plans", e, + code = 909620, + message = "Internal Error occured while retrieving Business Plans", + statusCode = 500, + description = "Internal Error occured while retrieving Business Plans" + ); +} + +public isolated function e909621() returns commons:APKError { + return error commons:APKError( "Invalid Content Search Text Provided. Missing :", + code = 909621, + message = "Invalid Content Search Text Provided. Missing :", + statusCode = 400, + description = "Invalid Content Search Text Provided. Missing :" + ); +} + +public isolated function e909622() returns commons:APKError { + return error commons:APKError( "Invalid Content Search Text Provided. Missing content keyword", + code = 909622, + message = "Invalid Content Search Text Provided. Missing content keyword", + statusCode = 400, + description = "Invalid Content Search Text Provided. Missing content keyword" + ); +} + +public isolated function e909623() returns commons:APKError { + return error commons:APKError( "Invalid blockState provided", + code = 909623, + message = "Invalid blockState provided", + statusCode = 400, + description = "Invalid blockState provided" + ); +} + +public isolated function e909624(error e) returns commons:APKError { + return error commons:APKError( "Error while adding resource data into Database", e, + code = 909624, + message = "Error while adding resource data into Database", + statusCode = 500, + description = "Error while adding resource data into Database" + ); +} + +public isolated function e909625(error e) returns commons:APKError { + return error commons:APKError( "Error while updating resource data into Database", e, + code = 909625, + message = "Error while updating resource data into Database", + statusCode = 500, + description = "Error while updating resource data into Database" + ); +} + +public isolated function e909626(error e) returns commons:APKError { + return error commons:APKError( "Error while getting a resource from Database", e, + code = 909626, + message = "Error while getting a resource from Database", + statusCode = 400, + description = "Error while getting a resource from Database" + ); +} + +public isolated function e909627(error e) returns commons:APKError { + return error commons:APKError( "Error while adding resource category data into Database", e, + code = 909627, + message = "Error while adding resource category data into Database", + statusCode = 500, + description = "Error while adding resource category data into Database" + ); +} + +public isolated function e909628(error e) returns commons:APKError { + return error commons:APKError( "Error while getting resource category data into Database", e, + code = 909628, + message = "Error while getting resource category data into Database", + statusCode = 500, + description = "Error while getting resource category data into Database" + ); +} + +public isolated function e909629(error e) returns commons:APKError { + return error commons:APKError( "Error while getting the document from Database", e, + code = 909626, + message = "Error while getting the document from Database", + statusCode = 400, + description = "Error while getting the document from Database" + ); +} + +public isolated function e909630(error e) returns commons:APKError { + return error commons:APKError( "Internal Error occured while retrieving Documents", e, + code = 909607, + message = "Internal Error occured while retrieving Documents", + statusCode = 500, + description = "Internal Error occured while retrieving Documents" + ); +} + +public isolated function e909631(error e, string contentType) returns commons:APKError { + return error commons:APKError("Error in parsing " + contentType + " XML data", e, + code = 909607, + message = "Error in parsing " + contentType + " XML data", + statusCode = 500, + description = "Error in parsing " + contentType + " XML data" + ); +} \ No newline at end of file diff --git a/backoffice/backoffice-domain-service/ballerina/Errors.md b/backoffice/backoffice-domain-service/ballerina/Errors.md new file mode 100644 index 000000000..3e328347f --- /dev/null +++ b/backoffice/backoffice-domain-service/ballerina/Errors.md @@ -0,0 +1,29 @@ +# Errors in BackOffice Domain Service + +These are the backoffice domain service errors and their respective error codes. + +| Error Code | Status Code | Error Message | +|---|---|---| +| 909601 | 500 | Error while retrieving connection | +| 909602 | 404 | API Definition Not Found for provided API ID | +| 909603 | 404 | API not found in the database | +| 909604 | 500 | Error while retrieving API | +| 909605 | 500 | Internal Error while deleting API By Id | +| 909606 | 404 | API with **apiId** not found | +| 909607 | 500 | Internal Error occured while retrieving APIs | +| 909608 | 500 | Error while updating LC state into Database | +| 909609 | 400 | Invalid Lifecycle targetState | +| 909610 | 400 | Error while geting LC state from Database | +| 909611 | 500 | Error while inserting data into Database | +| 909612 | 500 | Internal Error occured while retrieving LC event History | +| 909613 | 500 | Internal Error while geting subscription infomation | +| 909614 | 500 | Internal Error while geting API for provided apiId **apiId** | +| 909615 | 500 | Error while changing status of the subscription in the Database | +| 909616 | 500 | Error while retrieving API | +| 909617 | 500 | Internal Error while retrieving API Definition | +| 909618 | 500 | Error while updating API data into Database | +| 909619 | 500 | Internal Error occured while retrieving API Categories | +| 909620 | 500 | Internal Error occured while retrieving Business Plans | +| 909621 | 400 | Invalid Content Search Text Provided. Missing : | +| 909622 | 400 | Invalid Content Search Text Provided. Missing content keyword | +| 909623 | 400 | Invalid blockState provided | diff --git a/backoffice/backoffice-domain-service/ballerina/K8sClient.bal b/backoffice/backoffice-domain-service/ballerina/K8sClient.bal new file mode 100644 index 000000000..7a9c6b9a7 --- /dev/null +++ b/backoffice/backoffice-domain-service/ballerina/K8sClient.bal @@ -0,0 +1,83 @@ +// +// Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + +import ballerina/io; +import ballerina/http; +import ballerina/log; +import wso2/apk_common_lib as commons; + +const string K8S_API_ENDPOINT = "/api/v1"; +final string token = check io:fileReadString(k8sConfig.serviceAccountPath + "/token"); +final string caCertPath = k8sConfig.serviceAccountPath + "/ca.crt"; +string namespaceFile = k8sConfig.serviceAccountPath + "/namespace"; +final string currentNameSpace = check io:fileReadString(namespaceFile); +final http:Client k8sApiServerEp = check initializeK8sClient(); + +# This initialize the k8s Client. +# + return - k8s http client +public function initializeK8sClient() returns http:Client|error { + http:Client k8sApiClient = check new ("https://" + k8sConfig.host, + auth = { + token: token + }, + secureSocket = { + cert: caCertPath + + } + ); + return k8sApiClient; +} + +# This returns Pod value according to given name and namespace. +# +# + name - Name of Pod +# + namespace - Namespace of Pod +# + return - Return Pod value for a given name and namespace +isolated function getPodFromNameAndNamespace(string name, string namespace) returns string[]| commons:APKError { + string endpoint = "/api/v1/namespaces/" + namespace + "/endpoints/" + name; + http:Response|error response = k8sApiServerEp->get(endpoint, targetType = http:Response); + if response is http:Response { + json|http:ClientError podValue = response.getJsonPayload(); + if podValue is json{ + do { + log:printDebug(podValue.toString()); + json[] subsets = check podValue.subsets; + json[] addresses = check subsets[0].addresses; + string[] hosts =[]; + foreach json item in addresses { + string ip = check item.ip; + hosts.push(ip); + } + log:printDebug(hosts.toString()); + return hosts; + } on fail var e { + string message ="Error while retrieving host. Error while retrieving pod information for pod: " + name; + log:printError(message + e.toBalString()); + return error(message,e, message = message, description = message, code = 909000, statusCode = 500); + } + } else { + string message ="Response isn't a json. Error while retrieving pod information for pod: " + name; + log:printError(message); + return error(message, message = message, description = message, code = 909000, statusCode = 500); + } + } else { + string message ="Error while retrieving pod information for pod" + name; + log:printError(message); + return error(message, message = message, description = message, code = 909000, statusCode = 500); + } +} diff --git a/backoffice/backoffice-domain-service/ballerina/Resource.bal b/backoffice/backoffice-domain-service/ballerina/Resource.bal new file mode 100644 index 000000000..d0b0c6e7a --- /dev/null +++ b/backoffice/backoffice-domain-service/ballerina/Resource.bal @@ -0,0 +1,46 @@ +// +// Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + +type Resource record {| + string resourceUUID; + string apiUuid; + int resourceCategoryId; + string dataType; + string resourceContent; + byte[] resourceBinaryValue?; + json resourceJsonValue?; +|}; + +type Thumbnail record {| + string imageType; + byte[] imageContent; +|}; + +type DocumentMetaData record {| + string documentId?; + string resourceId?; + string name; + string documentType; + string summary?; + string sourceType; + string sourceUrl?; + string fileName?; + string inlineContent?; + string otherTypeName?; + string visibility; +|}; diff --git a/backoffice/backoffice-domain-service/ballerina/Subscription.bal b/backoffice/backoffice-domain-service/ballerina/Subscription.bal new file mode 100644 index 000000000..847fd29ac --- /dev/null +++ b/backoffice/backoffice-domain-service/ballerina/Subscription.bal @@ -0,0 +1,25 @@ +// +// Copyright (c) 2022, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + +public type Subscriptions record { + string subscriptionId; + string applicationId; + string name; + string usagePlan; + string subscriptionStatus; +}; diff --git a/backoffice/backoffice-domain-service/ballerina/Utils.bal b/backoffice/backoffice-domain-service/ballerina/Utils.bal new file mode 100644 index 000000000..ee4175d83 --- /dev/null +++ b/backoffice/backoffice-domain-service/ballerina/Utils.bal @@ -0,0 +1,37 @@ +// +// Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// +import ballerina/log; + +isolated function isFileSizeGreaterThan1MB(byte[] data) returns boolean { + int fileSizeInBytes = data.length(); + int fileSizeInMB = fileSizeInBytes / (1024 * 1024); + if fileSizeInMB > 1 { + log:printDebug("File is greater than 1MB"); + return true; + } + return false; +} + +isolated function isThumbnailHasValidFileExtention(string contentType) returns boolean { + if (contentType == RESOURCE_DATA_TYPE_JPG_IMAGE || contentType == RESOURCE_DATA_TYPE_PNG_IMAGE || + contentType == RESOURCE_DATA_TYPE_GIF_IMAGE || contentType == RESOURCE_DATA_TYPE_SVG_IMAGE) { + return true; + } else { + return false; + } +} diff --git a/backoffice/backoffice-domain-service/ballerina/backoffice-api_service.bal b/backoffice/backoffice-domain-service/ballerina/backoffice-api_service.bal new file mode 100644 index 000000000..7263d746d --- /dev/null +++ b/backoffice/backoffice-domain-service/ballerina/backoffice-api_service.bal @@ -0,0 +1,186 @@ +// +// Copyright (c) 2022, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + +import ballerina/http; +import ballerina/log; + +import wso2/apk_common_lib as commons; + +configurable int BACKOFFICE_PORT = 9443; + +listener http:Listener ep0 = new (BACKOFFICE_PORT, secureSocket = { + 'key: { + certFile: keyStores.tls.certFilePath, + keyFile: keyStores.tls.keyFilePath + } +}); + +@http:ServiceConfig { + cors: { + allowOrigins: ["*"], + allowCredentials: true, + allowHeaders: ["*"], + exposeHeaders: ["*"], + maxAge: 84900 + } +} + +service http:InterceptableService /api/backoffice on ep0 { + + public function createInterceptors() returns http:Interceptor|http:Interceptor[] { + http:Interceptor[] interceptors = [jwtValidationInterceptor, requestErrorInterceptor, responseErrorInterceptor]; + return interceptors; + } + isolated resource function get apis(http:RequestContext requestContext, string? query, @http:Header string? 'if\-none\-match, int 'limit = 25, int offset = 0, string sortBy = "createdTime", string sortOrder = "desc", @http:Header string? accept = "application/json") returns APIList|http:NotModified|commons:APKError { + commons:UserContext authenticatedUserContext = check commons:getAuthenticatedUserContext(requestContext); + commons:Organization organization = authenticatedUserContext.organization; + return getAPIList('limit, offset, query, organization.uuid); + } + + isolated resource function get apis/[string apiId](http:RequestContext requestContext, @http:Header string? 'if\-none\-match) returns API|http:NotModified|commons:APKError { + return getAPI(apiId); + } + resource function put apis/[string apiId](http:RequestContext requestContext, @http:Header string? 'if\-none\-match, @http:Payload ModifiableAPI payload) returns API|commons:APKError { + return updateAPI(apiId, payload); + } + + isolated resource function get apis/[string apiId]/definition(http:RequestContext requestContext, @http:Header string? 'if\-none\-match) returns APIDefinition|http:NotModified|commons:APKError { + APIDefinition|commons:APKError apiDefinition = getAPIDefinition(apiId); + if apiDefinition is APIDefinition { + log:printDebug(apiDefinition.toString()); + } + return apiDefinition; + } + // resource function get apis/[string apiId]/'resource\-paths(@http:Header string? 'if\-none\-match, int 'limit = 25, int offset = 0) returns ResourcePathList|http:NotModified|NotFoundError|NotAcceptableError { + // } + isolated resource function get apis/[string apiId]/thumbnail(@http:Header string? 'if\-none\-match, @http:Header string? accept = "application/json") returns http:Response|http:NotModified|NotFoundError|NotAcceptableError|commons:APKError { + return getThumbnail(apiId); + } + isolated resource function put apis/[string apiId]/thumbnail(@http:Header string? 'if\-match, http:Request message) returns FileInfo|BadRequestError|NotFoundError|PreconditionFailedError|commons:APKError|error { + return updateThumbnail(apiId, message); + } + resource function get apis/[string apiId]/documents(@http:Header string? 'if\-none\-match, int 'limit = 25, int offset = 0, @http:Header string? accept = "application/json") returns DocumentList|http:NotModified|NotFoundError|NotAcceptableError|commons:APKError { + return getDocumentList(apiId, 'limit, offset); + } + isolated resource function post apis/[string apiId]/documents(@http:Payload Document payload) returns CreatedDocument|BadRequestError|UnsupportedMediaTypeError|commons:APKError|error { + Document documentBody = check payload.cloneWithType(Document); + + Document|commons:APKError createdDocument = createDocument(apiId, documentBody); + if createdDocument is Document { + CreatedDocument createdDoc = { + body: createdDocument + }; + return createdDoc; + } else { + return createdDocument; + } + } + resource function get apis/[string apiId]/documents/[string documentId](@http:Header string? 'if\-none\-match, @http:Header string? accept = "application/json") returns Document|http:NotModified|NotFoundError|NotAcceptableError|commons:APKError { + return getDocumentMetaData(apiId, documentId); + } + resource function put apis/[string apiId]/documents/[string documentId](@http:Header string? 'if\-match, @http:Payload Document payload) returns Document|BadRequestError|NotFoundError|PreconditionFailedError|commons:APKError|error { + Document documentBody = check payload.cloneWithType(Document); + return UpdateDocumentMetaData(apiId, documentId, documentBody); + } + resource function delete apis/[string apiId]/documents/[string documentId](@http:Header string? 'if\-match) returns http:Ok|NotFoundError|PreconditionFailedError|commons:APKError { + http:Ok|NotFoundError|commons:APKError deletedDocument = deleteDocument(apiId, documentId); + return deletedDocument; + } + resource function get apis/[string apiId]/documents/[string documentId]/content(@http:Header string? 'if\-none\-match, @http:Header string? accept = "application/json") returns http:Response|http:SeeOther|http:NotModified|NotFoundError|NotAcceptableError|commons:APKError { + return getDocumentContent(apiId, documentId); + } + resource function post apis/[string apiId]/documents/[string documentId]/content(@http:Header string? 'if\-match, http:Request message) returns Document|BadRequestError|NotFoundError|PreconditionFailedError|commons:APKError|error { + return addDocumentContent(apiId, documentId, message); + } + // resource function get apis/[string apiId]/comments(int 'limit = 25, int offset = 0, boolean includeCommenterInfo = false) returns CommentList|NotFoundError|InternalServerErrorError { + // } + // resource function post apis/[string apiId]/comments(string? replyTo, @http:Payload 'postRequestBody payload) returns CreatedComment|BadRequestError|UnauthorizedError|NotFoundError|UnsupportedMediaTypeError|InternalServerErrorError { + // } + // resource function get apis/[string apiId]/comments/[string commentId](@http:Header string? 'if\-none\-match, boolean includeCommenterInfo = false, int replyLimit = 25, int replyOffset = 0) returns Comment|UnauthorizedError|NotFoundError|NotAcceptableError|InternalServerErrorError { + // } + // resource function delete apis/[string apiId]/comments/[string commentId](@http:Header string? 'if\-match) returns http:Ok|UnauthorizedError|ForbiddenError|NotFoundError|http:MethodNotAllowed|InternalServerErrorError { + // } + // resource function patch apis/[string apiId]/comments/[string commentId](@http:Payload 'patchRequestBody payload) returns Comment|BadRequestError|UnauthorizedError|ForbiddenError|NotFoundError|UnsupportedMediaTypeError|InternalServerErrorError { + // } + // resource function get apis/[string apiId]/comments/[string commentId]/replies(@http:Header string? 'if\-none\-match, int 'limit = 25, int offset = 0, boolean includeCommenterInfo = false) returns CommentList|UnauthorizedError|NotFoundError|NotAcceptableError|InternalServerErrorError { + // } + isolated resource function get subscriptions(http:RequestContext requestContext, string? apiId, @http:Header string? 'if\-none\-match, string? query, int 'limit = 25, int offset = 0) returns SubscriptionList|http:NotModified|commons:APKError { + return getSubscriptions(apiId); + } + // resource function get subscriptions/[string subscriptionId]/'subscriber\-info() returns SubscriberInfo|NotFoundError { + // } + isolated resource function post subscriptions/'block\-subscription(http:RequestContext requestContext, string subscriptionId, string blockState, @http:Header string? 'if\-match) returns http:Ok|commons:APKError { + string|commons:APKError response = blockSubscription(subscriptionId, blockState); + if response is commons:APKError { + return response; + } else { + return http:OK; + } + } + isolated resource function post subscriptions/'unblock\-subscription(http:RequestContext requestContext, string subscriptionId, @http:Header string? 'if\-match) returns http:Ok|commons:APKError { + string|error response = unblockSubscription(subscriptionId); + if response is commons:APKError { + return response; + } else { + return http:OK; + } + } + // resource function get 'usage\-plans(@http:Header string? 'if\-none\-match, int 'limit = 25, int offset = 0) returns UsagePlanList|http:NotModified|NotAcceptableError { + // } + // resource function get search(string? query, @http:Header string? 'if\-none\-match, int 'limit = 25, int offset = 0) returns SearchResultList|http:NotModified|NotAcceptableError { + // } + // resource function get settings() returns Settings|NotFoundError { + // } + + isolated resource function get 'api\-categories(http:RequestContext requestContext) returns APICategoryList|commons:APKError { + commons:UserContext authenticatedUserContext = check commons:getAuthenticatedUserContext(requestContext); + commons:Organization organization = authenticatedUserContext.organization; + return getAllCategoryList(organization.uuid); + } + + isolated resource function post apis/'change\-lifecycle(http:RequestContext requestContext, string targetState, string apiId, @http:Header string? 'if\-match) returns LifecycleState|commons:APKError|error { + commons:UserContext authenticatedUserContext = check commons:getAuthenticatedUserContext(requestContext); + commons:Organization organization = authenticatedUserContext.organization; + LifecycleState|error changeState = changeLifeCyleState(targetState, apiId, organization.uuid); + if changeState is LifecycleState { + return changeState; + } else { + return error("Error while updating LC state of API" + changeState.message()); + } + } + isolated resource function get apis/[string apiId]/'lifecycle\-history(http:RequestContext requestContext, @http:Header string? 'if\-none\-match) returns LifecycleHistory|commons:APKError { + return getLcEventHistory(apiId); + } + isolated resource function get apis/[string apiId]/'lifecycle\-state(http:RequestContext requestContext, @http:Header string? 'if\-none\-match) returns LifecycleState|commons:APKError|error { + LifecycleState|error currentState = getLifeCyleState(apiId); + if currentState is LifecycleState { + return currentState; + } else { + return error("Error while getting LC state of API" + currentState.message()); + } + } + resource function get 'business\-plans(http:RequestContext requestContext, @http:Header string? accept = "application/json") returns BusinessPlanList|commons:APKError { + commons:UserContext authenticatedUserContext = check commons:getAuthenticatedUserContext(requestContext); + commons:Organization organization = authenticatedUserContext.organization; + BusinessPlanList|commons:APKError subPolicyList = getBusinessPlans(organization.uuid); + if subPolicyList is BusinessPlanList { + log:printDebug(subPolicyList.toString()); + } + return subPolicyList; + } +} diff --git a/backoffice/backoffice-domain-service/ballerina/backoffice-internal-api_service.bal b/backoffice/backoffice-domain-service/ballerina/backoffice-internal-api_service.bal new file mode 100644 index 000000000..95e1ce1ba --- /dev/null +++ b/backoffice/backoffice-domain-service/ballerina/backoffice-internal-api_service.bal @@ -0,0 +1,69 @@ +import ballerina/http; +import wso2/apk_common_lib as commons; + +configurable int BACKOFFICE_PORT_INT = 9444; +listener http:Listener ep1 = new (BACKOFFICE_PORT_INT, secureSocket = { + 'key: { + certFile: keyStores.tls.certFilePath, + keyFile: keyStores.tls.keyFilePath + } +}); + +service http:InterceptableService /api/backoffice/internal on ep1 { + + public function createInterceptors() returns http:Interceptor|http:Interceptor[] { + http:Interceptor[] interceptors = [requestErrorInterceptor, responseErrorInterceptor]; + return interceptors; + } + isolated resource function post apis(@http:Payload json payload) returns CreatedAPI|error { + APIBody apiBody = check payload.cloneWithType(APIBody); + + API|error? createdApi = createAPI(apiBody); + if createdApi is API { + CreatedAPI crAPI = {body: check createdApi.cloneWithType(API)}; + return crAPI; + } + return error("Error while adding API", createdApi); + } + + isolated resource function get apis/[string apiId](@http:Header string? 'if\-none\-match) returns API|commons:APKError|error { + API | commons:APKError | error ? response = getAPI_internal(apiId); + if (response is API | commons:APKError) { + return response; + } + return error("Error while retireving API"); + } + + isolated resource function put apis/[string apiId](@http:Header string? 'if\-match, @http:Payload json payload) returns API|commons:APKError|error { + APIBody apiUpdateBody = check payload.cloneWithType(APIBody); + + API|commons:APKError |error? updatedAPI = updateAPI_internal(apiId, apiUpdateBody); + if updatedAPI is API { + API upAPI = check updatedAPI.cloneWithType(API); + return upAPI; + } else if (updatedAPI is commons:APKError) { + return updatedAPI; + } + return error("Error while updating API"); + } + + isolated resource function delete apis/[string apiId](@http:Header string? 'if\-match) returns http:Ok|commons:APKError { + string|commons:APKError|error? response = deleteAPI(apiId); + if response is commons:APKError { + return response; + } + else if response is error { + return e909605(); + } else { + return http:OK; + } + } + isolated resource function put apis/[string apiId]/definition(@http:Header string? 'if\-match, @http:Payload APIDefinition1 payload) returns string|error { + APIDefinition1|error? updateDef = updateDefinition(payload, apiId); + if updateDef is APIDefinition1 { + APIDefinition1 crAPI = check updateDef.cloneWithType(APIDefinition1); + return crAPI.Definition.toString(); + } + return error("Error while updating API definition"); + } +} diff --git a/backoffice/backoffice-domain-service/ballerina/backoffice_dao.bal b/backoffice/backoffice-domain-service/ballerina/backoffice_dao.bal new file mode 100644 index 000000000..1959f11ed --- /dev/null +++ b/backoffice/backoffice-domain-service/ballerina/backoffice_dao.bal @@ -0,0 +1,689 @@ +// +// Copyright (c) 2022, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + +import ballerina/sql; +import ballerina/time; +import ballerinax/postgresql; +import ballerina/io; +import wso2/apk_common_lib as commons; +import ballerina/log; + +isolated function db_getAPIsDAO(string organization) returns API[]|commons:APKError { + postgresql:Client|error db_Client = getConnection(); + if db_Client is error { + return e909601(db_Client); + } else { + do { + sql:ParameterizedQuery GET_API = `SELECT UUID AS ID, + API_NAME as NAME, API_VERSION as VERSION,CONTEXT, ORGANIZATION, STATUS as STATE, string_to_array(SDK::text,',')::text[] AS SDK,string_to_array(API_TIER::text,',') AS POLICIES, ARTIFACT as ARTIFACT + FROM API where ORGANIZATION = ${organization}`; + stream apisStream = db_Client->query(GET_API); + API[] apis = check from API api in apisStream + select api; + check apisStream.close(); + return apis; + } on fail var e { + return e909607(e); + } + } +} + +isolated function db_changeLCState(string targetState, string apiId) returns string|commons:APKError { + postgresql:Client|error db_Client = getConnection(); + if db_Client is error { + return e909601(db_Client); + } else { + string newState = actionToLCState(targetState); + if newState.equalsIgnoreCaseAscii("any") { + return e909609(); + } + sql:ParameterizedQuery UPDATE_API_LifeCycle_Prefix = `UPDATE api SET status = `; + sql:ParameterizedQuery values = `${newState} + WHERE uuid = ${apiId}`; + sql:ParameterizedQuery sqlQuery = sql:queryConcat(UPDATE_API_LifeCycle_Prefix, values); + + sql:ExecutionResult|sql:Error result = db_Client->execute(sqlQuery); + + if result is sql:ExecutionResult { + return targetState; + } else { + return e909608(result); + } + } +} + +isolated function db_getCurrentLCStatus(string apiId) returns string|commons:APKError { + postgresql:Client|error db_Client = getConnection(); + if db_Client is error { + return e909601(db_Client); + } else { + sql:ParameterizedQuery GET_API_LifeCycle_Prefix = `SELECT status from api where uuid = `; + sql:ParameterizedQuery values = `${apiId}`; + sql:ParameterizedQuery sqlQuery = sql:queryConcat(GET_API_LifeCycle_Prefix, values); + + string|sql:Error result = db_Client->queryRow(sqlQuery); + + if result is string { + return result; + } else { + return e909610(result); + } + } +} + +# Update LC event to the database +# +# + apiId - API id Parameter +# + organization - organization +# + prev_state - prev_state +# + new_state - new_state +# + return - API | error +isolated function db_AddLCEvent(string? apiId, string? prev_state, string? new_state, string organization) returns string|commons:APKError { + postgresql:Client|error db_client = getConnection(); + time:Utc utc = time:utcNow(); + if db_client is error { + return e909601(db_client); + } else { + sql:ParameterizedQuery values = `${apiId}, + ${prev_state}, + ${new_state}, + 'apkuser', + ${organization}, + ${utc} + )`; + sql:ParameterizedQuery ADD_LC_EVENT_Prefix = `INSERT INTO api_lc_event (api_uuid,previous_state,new_state,user_uuid,organization,event_date) VALUES (`; + sql:ParameterizedQuery sqlQuery = sql:queryConcat(ADD_LC_EVENT_Prefix, values); + + sql:ExecutionResult|sql:Error result = db_client->execute(sqlQuery); + + if result is sql:ExecutionResult { + return result.toString(); + } else { + return e909611(result); + } + } +} + +isolated function db_getLCEventHistory(string apiId) returns LifecycleHistoryItem[]|commons:APKError { + postgresql:Client|error dbClient = getConnection(); + if dbClient is error { + return e909601(dbClient); + } else { + do { + sql:ParameterizedQuery query = `SELECT previous_state, new_state, user_uuid, event_date FROM api_lc_event WHERE api_uuid =${apiId}`; + stream lcStream = dbClient->query(query); + LifecycleHistoryItem[] lcItems = check from LifecycleHistoryItem lcitem in lcStream + select lcitem; + check lcStream.close(); + return lcItems; + } on fail var e { + return e909612(e); + } + } +} + +isolated function db_getSubscriptionsForAPI(string apiId) returns Subscription[]|commons:APKError { + postgresql:Client|error dbClient = getConnection(); + if dbClient is error { + return e909601(dbClient); + } else { + + sql:ParameterizedQuery query = `SELECT uuid as api_id FROM api WHERE uuid =${apiId}`; + string|sql:Error result = dbClient->queryRow(query); + if result is string { + do { + sql:ParameterizedQuery query1 = `SELECT + SUBS.UUID AS subscriptionId, + APP.UUID AS applicationId, + APP.name AS name, + SUBS.TIER_ID AS usagePlan, + SUBS.sub_status AS subscriptionStatus + FROM SUBSCRIPTION SUBS, API API, APPLICATION APP + WHERE APP.UUID=SUBS.APPLICATION_UUID AND API.UUID = SUBS.API_UUID AND API.UUID = ${apiId}`; + stream result1 = dbClient->query(query1); + Subscription[] subsList = []; + check from Subscriptions subitem in result1 + do { + Subscription sub = {applicationInfo: {}, subscriptionId: "", subscriptionStatus: "", usagePlan: ""}; + sub.subscriptionId = subitem.subscriptionId; + sub.subscriptionStatus = subitem.subscriptionStatus; + sub.applicationInfo.applicationId = subitem.applicationId; + sub.usagePlan = subitem.usagePlan; + sub.applicationInfo.name = subitem.name; + subsList.push(sub); + }; + return subsList; + } on fail var e { + return e909613(e); + } + } else { + return e909614(result, apiId); + } + } +} + +isolated function getSubscriptionByIdDAO(string subId) returns SubscriptionInternal|commons:APKError { + postgresql:Client|error dbClient = getConnection(); + if dbClient is error { + return e909601(dbClient); + } else { + sql:ParameterizedQuery query = `SELECT + SUBS.UUID AS SUBSCRIPTION_ID, + API.API_NAME AS API_NAME, + API.API_VERSION AS API_VERSION, + API.API_TYPE AS API_TYPE, + API.ORGANIZATION AS ORGANIZATION, + APP.UUID AS APPLICATIONID, + SUBS.TIER_ID AS THROTTLINGPOLICY, + SUBS.TIER_ID_PENDING AS TIER_ID_PENDING, + SUBS.SUB_STATUS AS STATUS, + SUBS.SUBS_CREATE_STATE AS SUBS_CREATE_STATE, + SUBS.UUID AS UUID, + SUBS.CREATED_TIME AS CREATED_TIME, + SUBS.UPDATED_TIME AS UPDATED_TIME, + API.UUID AS APIID + FROM SUBSCRIPTION SUBS, API API, APPLICATION APP + WHERE APP.UUID=SUBS.APPLICATION_UUID AND API.UUID = SUBS.API_UUID AND SUBS.UUID =${subId}`; + SubscriptionInternal|sql:Error result = dbClient->queryRow(query); + if result is sql:NoRowsError { + log:printDebug(result.toString()); + string message = "Subscription Not Found for provided ID"; + return error(message, result, message = message, description = message, code = 909000, statusCode = 404); + } else if result is SubscriptionInternal { + log:printDebug(result.toString()); + return result; + } else { + log:printDebug(result.toString()); + string message = "Error while retrieving Subscription"; + return error(message, result, message = message, description = message, code = 909000, statusCode = 500); + } + } +} + +isolated function db_blockSubscription(string subscriptionId, string blockState) returns string|commons:APKError { + postgresql:Client|error db_client = getConnection(); + if db_client is error { + return e909601(db_client); + } else { + sql:ParameterizedQuery SUBSCRIPTION_BLOCK_Prefix = `UPDATE subscription set sub_status = `; + sql:ParameterizedQuery values = `${blockState} where uuid = ${subscriptionId}`; + sql:ParameterizedQuery sqlQuery = sql:queryConcat(SUBSCRIPTION_BLOCK_Prefix, values); + sql:ExecutionResult|sql:Error result = db_client->execute(sqlQuery); + + if result is sql:ExecutionResult { + return "blocked"; + } else { + return e909615(result); + } + } +} + +isolated function db_unblockSubscription(string subscriptionId) returns string|commons:APKError { + postgresql:Client|error db_client = getConnection(); + if db_client is error { + return e909601(db_client); + } else { + sql:ParameterizedQuery SUBSCRIPTION_UNBLOCK_Prefix = `UPDATE subscription set sub_status = 'UNBLOCKED'`; + sql:ParameterizedQuery values = ` where uuid = ${subscriptionId}`; + sql:ParameterizedQuery sqlQuery = sql:queryConcat(SUBSCRIPTION_UNBLOCK_Prefix, values); + sql:ExecutionResult|sql:Error result = db_client->execute(sqlQuery); + + if result is sql:ExecutionResult { + return "Unblocked"; + } else { + return e909615(result); + } + } +} + +isolated function db_getAPI(string apiId) returns API|commons:APKError { + postgresql:Client|error db_Client = getConnection(); + if db_Client is error { + return e909601(db_Client); + } else { + sql:ParameterizedQuery GET_API_Prefix = `SELECT UUID AS ID, + API_NAME as NAME, API_VERSION as VERSION,CONTEXT, ORGANIZATION,STATUS,string_to_array(SDK::text,',')::text[] AS SDK,string_to_array(API_TIER::text,',') AS POLICIES, ARTIFACT as ARTIFACT + FROM API where UUID = `; + sql:ParameterizedQuery values = `${apiId}`; + sql:ParameterizedQuery sqlQuery = sql:queryConcat(GET_API_Prefix, values); + + API|sql:Error result = db_Client->queryRow(sqlQuery); + + if result is API { + return result; + } else { + return e909616(result); + } + } +} + +isolated function db_getAPIDefinition(string apiId) returns APIDefinition|commons:APKError { + postgresql:Client|error dbClient = getConnection(); + if dbClient is error { + return e909601(dbClient); + } else { + sql:ParameterizedQuery query = `SELECT encode(API_DEFINITION, 'escape')::text AS schemaDefinition, MEDIA_TYPE as type + FROM API_ARTIFACT WHERE API_UUID =${apiId}`; + APIDefinition|sql:Error result = dbClient->queryRow(query); + if result is sql:NoRowsError { + return e909602(); + } else if result is APIDefinition { + return result; + } else { + return e909617(result); + } + } +} + +isolated function db_updateAPI(string apiId, ModifiableAPI payload) returns API|commons:APKError { + postgresql:Client|error dbClient = getConnection(); + if dbClient is error { + return e909601(dbClient); + } else { + postgresql:JsonBinaryValue sdk = new (payload.sdk.toJson()); + postgresql:JsonBinaryValue categories = new (payload.categories.toJson()); + postgresql:JsonBinaryValue businessPlans = new (payload.policies.toJson()); + sql:ParameterizedQuery UPDATE_API_Suffix = `UPDATE api SET`; + sql:ParameterizedQuery values = ` status= ${payload.state}, sdk = ${sdk}, + categories = ${categories}, api_tier=${businessPlans} WHERE uuid = ${apiId}`; + sql:ParameterizedQuery sqlQuery = sql:queryConcat(UPDATE_API_Suffix, values); + + sql:ExecutionResult|sql:Error result = dbClient->execute(sqlQuery); + + if result is sql:ExecutionResult { + return db_getAPI(apiId); + } else { + return e909618(result); + } + } +} + +isolated function getAPICategoriesDAO(string org) returns APICategory[]|commons:APKError { + postgresql:Client|error dbClient = getConnection(); + if dbClient is error { + return e909601(dbClient); + } else { + do { + sql:ParameterizedQuery query = `SELECT UUID as ID, NAME, DESCRIPTION + FROM API_CATEGORIES WHERE ORGANIZATION =${org} ORDER BY NAME`; + stream apiCategoryStream = dbClient->query(query); + APICategory[] apiCategoryList = check from APICategory apiCategory in apiCategoryStream + select apiCategory; + check apiCategoryStream.close(); + return apiCategoryList; + } on fail var e { + return e909619(e); + } + } +} + +isolated function getAPIsByQueryDAO(string payload, string org) returns API[]|commons:APKError { + postgresql:Client|error dbClient = getConnection(); + if dbClient is error { + return e909601(dbClient); + } else { + do { + sql:ParameterizedQuery query = `SELECT DISTINCT UUID AS ID, + API_NAME as NAME, API_VERSION as VERSION,CONTEXT, ORGANIZATION,STATUS, + ARTIFACT as ARTIFACT FROM API JOIN JSONB_EACH_TEXT(ARTIFACT) e ON true + WHERE e.value LIKE ${payload} AND ORGANIZATION = ${org}`; + stream apisStream = dbClient->query(query); + API[] apis = check from API api in apisStream + select api; + check apisStream.close(); + return apis; + } on fail var e { + io:print(e); + return e909607(e); + } + } +} + +public isolated function getBusinessPlansDAO(string org) returns BusinessPlan[]|commons:APKError { + postgresql:Client|error dbClient = getConnection(); + if dbClient is error { + return e909601(dbClient); + } else { + do { + sql:ParameterizedQuery query = `SELECT NAME as PLANNAME, DISPLAY_NAME as DISPLAYNAME, DESCRIPTION, + UUID as PLANID, IS_DEPLOYED as ISDEPLOYED, + QUOTA_TYPE as DefaulLimitType, QUOTA , TIME_UNIT as TIMEUNIT, UNIT_TIME as + UNITTIME, RATE_LIMIT_COUNT as RATELIMITCOUNT, RATE_LIMIT_TIME_UNIT as RATELIMITTIMEUNIT FROM BUSINESS_PLAN WHERE ORGANIZATION =${org}`; + stream businessPlanStream = dbClient->query(query); + BusinessPlanDAO[] businessPlansDAO = check from BusinessPlanDAO businessPlan in businessPlanStream + select businessPlan; + check businessPlanStream.close(); + BusinessPlan[] businessPlans = []; + if businessPlansDAO is BusinessPlanDAO[] { + foreach BusinessPlanDAO result in businessPlansDAO { + if result.defaulLimitType == "requestCount" { + BusinessPlan bp = { + planName: result.planName, + displayName: result.displayName, + description: result.description, + planId: result.planId, + isDeployed: result.isDeployed, + rateLimitCount: result.rateLimitCount, + rateLimitTimeUnit: result.rateLimitTimeUnit, + defaultLimit: { + 'type: result.defaulLimitType, + requestCount: + {requestCount: result.quota, timeUnit: result.timeUnit, unitTime: result.unitTime} + } + }; + businessPlans.push(bp); + } else if result.defaulLimitType == "bandwidth" { + BusinessPlan bp = { + planName: result.planName, + displayName: result.displayName, + description: result.description, + planId: result.planId, + isDeployed: result.isDeployed, + rateLimitCount: result.rateLimitCount, + rateLimitTimeUnit: result.rateLimitTimeUnit, + defaultLimit: { + 'type: result.defaulLimitType, + bandwidth: + {dataAmount: result.quota, dataUnit: result.dataUnit, timeUnit: result.timeUnit, unitTime: result.unitTime} + } + }; + businessPlans.push(bp); + } else { + BusinessPlan bp = { + planName: result.planName, + displayName: result.displayName, + description: result.description, + planId: result.planId, + isDeployed: result.isDeployed, + rateLimitCount: result.rateLimitCount, + rateLimitTimeUnit: result.rateLimitTimeUnit, + defaultLimit: { + 'type: result.defaulLimitType, + eventCount: + {eventCount: result.quota, timeUnit: result.timeUnit, unitTime: result.unitTime} + } + }; + businessPlans.push(bp); + } + } + } + return businessPlans; + } on fail var e { + return e909620(e); + } + } +} + +isolated function db_getResourceByResourceCategory(string apiId, int resourceCategoryId) returns Resource|NotFoundError|commons:APKError { + postgresql:Client|error db_Client = getConnection(); + if db_Client is error { + return e909601(db_Client); + } else { + sql:ParameterizedQuery sqlQuery = `SELECT UUID AS resourceUUID, API_UUID AS apiUuid, RESOURCE_CATEGORY_ID AS resourceCategoryId, DATA_TYPE AS dataType, + RESOURCE_CONTENT AS resourceContent, RESOURCE_BINARY_VALUE AS resourceBinaryValue + FROM API_RESOURCES where API_UUID = ${apiId} AND RESOURCE_CATEGORY_ID = ${resourceCategoryId}`; + Resource|sql:Error result = db_Client->queryRow(sqlQuery); + + if result is sql:NoRowsError { + log:printDebug(result.toString()); + NotFoundError nfe = {body: {code: 90915, message: "Thumbnail Not Found for provided API ID"}}; + return nfe; + } else if result is Resource { + return result; + } else { + return e909626(result); + } + } +} + +isolated function db_getResourceByResourceId(string resourceId) returns Resource|commons:APKError { + postgresql:Client|error db_Client = getConnection(); + if db_Client is error { + return e909601(db_Client); + } else { + sql:ParameterizedQuery GET_RESOURCE_Prefix = `SELECT UUID AS resourceUUID, API_UUID AS apiUuid, RESOURCE_CATEGORY_ID AS resourceCategoryId, DATA_TYPE AS dataType, + RESOURCE_CONTENT AS resourceContent, RESOURCE_BINARY_VALUE AS resourceBinaryValue + FROM API_RESOURCES where UUID = `; + sql:ParameterizedQuery values = `${resourceId}`; + sql:ParameterizedQuery sqlQuery = sql:queryConcat(GET_RESOURCE_Prefix, values); + Resource|sql:Error result = db_Client->queryRow(sqlQuery); + if result is Resource { + return result; + } else { + return e909626(result); + } + } +} + +isolated function db_addResource(Resource resourceItem) returns Resource|commons:APKError { + postgresql:Client|error dbClient = getConnection(); + if dbClient is error { + return e909601(dbClient); + } else { + time:Utc utc = time:utcNow(); + sql:ParameterizedQuery values = `${resourceItem.resourceUUID}, + ${resourceItem.apiUuid}, + ${resourceItem.resourceCategoryId}, + ${resourceItem.dataType}, + to_tsvector(${resourceItem.resourceContent}), + bytea(${resourceItem.resourceBinaryValue}), + 'apkuser', + ${utc}, + 'apkuser', + ${utc} + )`; + sql:ParameterizedQuery ADD_THUMBNAIL_Prefix = `INSERT INTO API_RESOURCES (UUID, API_UUID, RESOURCE_CATEGORY_ID, DATA_TYPE, RESOURCE_CONTENT, RESOURCE_BINARY_VALUE, CREATED_BY, CREATED_TIME, UPDATED_BY, LAST_UPDATED_TIME) VALUES (`; + sql:ParameterizedQuery sqlQuery = sql:queryConcat(ADD_THUMBNAIL_Prefix, values); + sql:ExecutionResult|sql:Error result = dbClient->execute(sqlQuery); + if result is sql:ExecutionResult { + log:printDebug("Resource added successfully"); + return resourceItem; + } else { + return e909624(result); + } + } +} + +isolated function db_updateResource(Resource resourceItem) returns Resource|commons:APKError { + log:printInfo(resourceItem.toBalString()); + postgresql:Client|error dbClient = getConnection(); + if dbClient is error { + return e909601(dbClient); + } else { + time:Utc utc = time:utcNow(); + string user = "apkuser"; + sql:ParameterizedQuery UPDATE_RESOURCE_Suffix = `UPDATE API_RESOURCES SET`; + sql:ParameterizedQuery values = ` API_UUID= ${resourceItem.apiUuid}, RESOURCE_CATEGORY_ID = ${resourceItem.resourceCategoryId}, DATA_TYPE = ${resourceItem.dataType}, + RESOURCE_CONTENT = to_tsvector(${resourceItem.resourceContent}), + RESOURCE_BINARY_VALUE = bytea(${resourceItem.resourceBinaryValue}), UPDATED_BY =${user}, LAST_UPDATED_TIME =${utc} WHERE UUID = ${resourceItem.resourceUUID}`; + sql:ParameterizedQuery sqlQuery = sql:queryConcat(UPDATE_RESOURCE_Suffix, values); + sql:ExecutionResult|sql:Error result = dbClient->execute(sqlQuery); + if result is sql:ExecutionResult { + return resourceItem; + } else { + return e909625(result); + } + } +} + +isolated function db_getResourceCategoryIdByCategoryType(string resourceType) returns int|commons:APKError { + postgresql:Client|error db_Client = getConnection(); + if db_Client is error { + return e909601(db_Client); + } else { + sql:ParameterizedQuery GET_RESOURCE_CATEGORY_Prefix = `SELECT RESOURCE_CATEGORY_ID FROM RESOURCE_CATEGORIES where RESOURCE_CATEGORY = `; + sql:ParameterizedQuery values = `${resourceType}`; + sql:ParameterizedQuery sqlQuery = sql:queryConcat(GET_RESOURCE_CATEGORY_Prefix, values); + int|sql:Error result = db_Client->queryRow(sqlQuery); + if result is int { + return result; + } else { + return e909626(result); + } + } +} + +isolated function db_addDocumentMetaData(DocumentMetaData documentMetaData, string apiId) returns DocumentMetaData|commons:APKError { + postgresql:Client|error dbClient = getConnection(); + if dbClient is error { + return e909601(dbClient); + } else { + time:Utc utc = time:utcNow(); + sql:ParameterizedQuery values = `${documentMetaData.documentId}, + ${documentMetaData.resourceId}, + ${apiId}, + ${documentMetaData.name}, + ${documentMetaData.summary}, + ${documentMetaData.documentType}, + ${documentMetaData.otherTypeName}, + ${documentMetaData.sourceUrl}, + ${documentMetaData.fileName}, + ${documentMetaData.sourceType}, + ${documentMetaData.visibility}, + 'apkuser', + ${utc}, + 'apkuser', + ${utc} + )`; + sql:ParameterizedQuery ADD_DOCUMENT_Prefix = `INSERT INTO API_DOC_META_DATA (UUID, RESOURCE_UUID, API_UUID, NAME, SUMMARY, TYPE, OTHER_TYPE_NAME, SOURCE_URL, FILE_NAME, SOURCE_TYPE, + VISIBILITY, CREATED_BY, CREATED_TIME, UPDATED_BY, LAST_UPDATED_TIME) VALUES (`; + sql:ParameterizedQuery sqlQuery = sql:queryConcat(ADD_DOCUMENT_Prefix, values); + sql:ExecutionResult|sql:Error result = dbClient->execute(sqlQuery); + if result is sql:ExecutionResult { + log:printDebug("Resource added successfully"); + return documentMetaData; + } else { + return e909624(result); + } + } +} + +isolated function db_updateDocumentMetaData(DocumentMetaData documentMetaData, string apiId) returns DocumentMetaData|commons:APKError { + postgresql:Client|error dbClient = getConnection(); + if dbClient is error { + return e909601(dbClient); + } else { + time:Utc utc = time:utcNow(); + string user = "apkuser"; + sql:ParameterizedQuery UPDATE_RESOURCE_Suffix = `UPDATE API_DOC_META_DATA SET`; + sql:ParameterizedQuery values = ` NAME= ${documentMetaData.name}, SUMMARY = ${documentMetaData.summary}, TYPE = ${documentMetaData.documentType}, + OTHER_TYPE_NAME = ${documentMetaData.otherTypeName}, SOURCE_URL = ${documentMetaData.sourceUrl}, FILE_NAME = ${documentMetaData.fileName}, SOURCE_TYPE = ${documentMetaData.sourceType}, + VISIBILITY = ${documentMetaData.visibility}, UPDATED_BY =${user}, LAST_UPDATED_TIME =${utc} WHERE UUID = ${documentMetaData.documentId} AND API_UUID = ${apiId}`; + sql:ParameterizedQuery sqlQuery = sql:queryConcat(UPDATE_RESOURCE_Suffix, values); + sql:ExecutionResult|sql:Error result = dbClient->execute(sqlQuery); + if result is sql:ExecutionResult { + return documentMetaData; + } else { + return e909625(result); + } + } +} + +isolated function db_getResourceIdByDocumentId(string documentId) returns string|commons:APKError { + postgresql:Client|error db_Client = getConnection(); + if db_Client is error { + return e909601(db_Client); + } else { + sql:ParameterizedQuery GET_RESOURCE_ID_Prefix = `SELECT RESOURCE_UUID FROM API_DOC_META_DATA where UUID = `; + sql:ParameterizedQuery values = `${documentId}`; + sql:ParameterizedQuery sqlQuery = sql:queryConcat(GET_RESOURCE_ID_Prefix, values); + string|sql:Error result = db_Client->queryRow(sqlQuery); + if result is string { + return result; + } else { + return e909626(result); + } + } +} + +isolated function db_deleteDocumentMetaData(string documentId, string apiId) returns string|commons:APKError { + postgresql:Client|error db_Client = getConnection(); + if db_Client is error { + return e909601(db_Client); + } else { + sql:ParameterizedQuery sqlQuery = `DELETE FROM API_DOC_META_DATA WHERE UUID = ${documentId} AND API_UUID = ${apiId}`; + sql:ExecutionResult|sql:Error result = db_Client->execute(sqlQuery); + if result is sql:ExecutionResult { + return "deleted"; + } else { + return e909626(result); + } + } +} + +isolated function db_getDocumentByDocumentId(string documentId, string apiId) returns DocumentMetaData|NotFoundError|commons:APKError { + postgresql:Client|error db_Client = getConnection(); + if db_Client is error { + return e909601(db_Client); + } else { + sql:ParameterizedQuery GET_DOCUMENT_Prefix = `SELECT UUID AS documentId, RESOURCE_UUID AS resourceId, NAME AS name, SUMMARY AS summary, + TYPE AS documentType, OTHER_TYPE_NAME AS otherTypeName, SOURCE_URL AS sourceUrl, FILE_NAME AS fileName, + SOURCE_TYPE AS sourceType, VISIBILITY AS visibility FROM API_DOC_META_DATA where UUID = `; + sql:ParameterizedQuery values = `${documentId}`; + sql:ParameterizedQuery sqlQuery = sql:queryConcat(GET_DOCUMENT_Prefix, values); + DocumentMetaData|sql:Error result = db_Client->queryRow(sqlQuery); + if result is sql:NoRowsError { + log:printDebug(result.toString()); + NotFoundError nfe = {body: {code: 90915, message: "Document Not Found for provided Document ID"}}; + return nfe; + } else if result is DocumentMetaData { + return result; + } else { + return e909629(result); + } + } +} + +isolated function db_deleteResource(string resourceId) returns string|commons:APKError { + postgresql:Client|error db_Client = getConnection(); + if db_Client is error { + return e909601(db_Client); + } else { + sql:ParameterizedQuery DELETE_DOCUMENT_Prefix = `DELETE FROM API_RESOURCES WHERE UUID = `; + sql:ParameterizedQuery values = `${resourceId}`; + sql:ParameterizedQuery sqlQuery = sql:queryConcat(DELETE_DOCUMENT_Prefix, values); + sql:ExecutionResult|sql:Error result = db_Client->execute(sqlQuery); + if result is sql:ExecutionResult { + return "deleted"; + } else { + return e909626(result); + } + } +} + +isolated function db_getDocuments(string apiId) returns Document[]|commons:APKError { + postgresql:Client|error db_Client = getConnection(); + if db_Client is error { + return e909601(db_Client); + } else { + do { + sql:ParameterizedQuery GET_DOCUMENTS_Prefix = `SELECT UUID AS documentId, NAME AS name, SUMMARY AS summary, + TYPE AS documentType, OTHER_TYPE_NAME AS otherTypeName, SOURCE_URL AS sourceUrl, FILE_NAME AS fileName, + SOURCE_TYPE AS sourceType, VISIBILITY AS visibility FROM API_DOC_META_DATA where API_UUID = `; + sql:ParameterizedQuery values = `${apiId}`; + sql:ParameterizedQuery sqlQuery = sql:queryConcat(GET_DOCUMENTS_Prefix, values); + stream documentStream = db_Client->query(sqlQuery); + Document[] documents = check from Document document in documentStream + select document; + check documentStream.close(); + return documents; + } on fail var e { + return e909630(e); + } + } +} diff --git a/backoffice/backoffice-domain-service/ballerina/backoffice_impl.bal b/backoffice/backoffice-domain-service/ballerina/backoffice_impl.bal new file mode 100644 index 000000000..698eebd44 --- /dev/null +++ b/backoffice/backoffice-domain-service/ballerina/backoffice_impl.bal @@ -0,0 +1,718 @@ +// +// Copyright (c) 2022, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + +import wso2/apk_common_lib as commons; +import ballerina/log; +import ballerina/time; +import ballerina/uuid; +import wso2/notification_grpc_client as notification; +import ballerina/http; +import ballerina/mime; + +# This function used to get API from database +# +# + return - Return Value string?|APIList|error +isolated function getAPIList(int 'limit, int offset, string? query, string organization) returns APIList|commons:APKError { + if query !is string { + API[]|commons:APKError apis = db_getAPIsDAO(organization); + if apis is API[] { + API[] limitSet = []; + if apis.length() > offset { + foreach int i in offset ... (apis.length() - 1) { + if limitSet.length() < 'limit { + limitSet.push(apis[i]); + } + } + } + APIList apisList = {count: limitSet.length(), list: limitSet, pagination: {total: apis.length(), 'limit: 'limit, offset: offset}}; + return apisList; + } else { + return apis; + } + } else { + boolean hasPrefix = query.startsWith("content"); + if hasPrefix { + int? index = query.indexOf(":"); + if index is int { + string modifiedQuery = "%" + query.substring(index + 1) + "%"; + API[]|commons:APKError apis = getAPIsByQueryDAO(modifiedQuery, organization); + if apis is API[] { + API[] limitSet = []; + if apis.length() > offset { + foreach int i in offset ... (apis.length() - 1) { + if limitSet.length() < 'limit { + limitSet.push(apis[i]); + } + } + } + APIList apisList = {count: limitSet.length(), list: limitSet, pagination: {total: apis.length(), 'limit: 'limit, offset: offset}}; + return apisList; + } else { + return apis; + } + } else { + return e909621(); + } + } else { + return e909622(); + } + } +} + +# This function used to change the lifecycle of API +# +# + targetState - lifecycle action +# + apiId - API Id +# + organization - organization +# + return - Return Value LifecycleState|error +isolated function changeLifeCyleState(string targetState, string apiId, string organization) returns LifecycleState|error { + string prevLCState = check db_getCurrentLCStatus(apiId); + transaction { + string|error lcState = db_changeLCState(targetState, apiId); + if lcState is string { + string newvLCState = check db_getCurrentLCStatus(apiId); + string|error lcEvent = db_AddLCEvent(apiId, prevLCState, newvLCState, organization); + if lcEvent is string { + check commit; + json lcPayload = check getTransitionsFromState(targetState); + LifecycleState lcCr = check lcPayload.cloneWithType(LifecycleState); + return lcCr; + } else { + rollback; + return error("error while adding LC event" + lcEvent.message()); + } + } else { + rollback; + return error("error while updating LC state" + lcState.message()); + } + } +} + +# This function used to get current state of the API. +# +# + apiId - API Id parameter +# + organization - organization +# + return - Return Value LifecycleState|error +isolated function getLifeCyleState(string apiId) returns LifecycleState|error { + string|error currentLCState = db_getCurrentLCStatus(apiId); + if currentLCState is string { + json lcPayload = check getTransitionsFromState(currentLCState); + LifecycleState|error lcGet = lcPayload.cloneWithType(LifecycleState); + if lcGet is error { + return e909601(lcGet); + } + return lcGet; + } else { + return currentLCState; + } +} + +# This function used to map user action to LC state +# +# + v - any parameter object +# + return - Return LC state +isolated function actionToLCState(any v) returns string { + if (v.toString().equalsIgnoreCaseAscii("published")) { + return "PUBLISHED"; + } else if (v.toString().equalsIgnoreCaseAscii("created")) { + return "CREATED"; + } else if (v.toString().equalsIgnoreCaseAscii("blocked")) { + return "BLOCKED"; + } else if (v.toString().equalsIgnoreCaseAscii("deprecated")) { + return "DEPRECATED"; + } else if (v.toString().equalsIgnoreCaseAscii("prototyped")) { + return "PROTOTYPED"; + } else if (v.toString().equalsIgnoreCaseAscii("retired")) { + return "RETIRED"; + } else { + return "any"; + } +} + +# This function used to get the availble event transitions from state +# +# + state - state parameter +# + return - Return Value jsons +isolated function getTransitionsFromState(string state) returns json|error { + StatesList c = check lifeCycleStateTransitions.cloneWithType(StatesList); + foreach States x in c.States { + if (state.equalsIgnoreCaseAscii(x.State)) { + return x.toJson(); + } + } + +} + +# This function used to connect API create service to database +# +# + apiId - API Id parameter +# + return - Return Value LifecycleHistory +isolated function getLcEventHistory(string apiId) returns LifecycleHistory|commons:APKError { + LifecycleHistoryItem[]|commons:APKError lcHistory = db_getLCEventHistory(apiId); + if lcHistory is LifecycleHistoryItem[] { + int count = lcHistory.length(); + LifecycleHistory eventList = {count: count, list: lcHistory}; + return eventList; + } else { + return lcHistory; + } +} + +isolated function getSubscriptions(string? apiId) returns SubscriptionList|commons:APKError { + Subscription[]|commons:APKError subcriptions; + subcriptions = check db_getSubscriptionsForAPI(apiId.toString()); + if subcriptions is Subscription[] { + int count = subcriptions.length(); + SubscriptionList subsList = {count: count, list: subcriptions}; + return subsList; + } else { + return subcriptions; + } +} + +isolated function blockSubscription(string subscriptionId, string blockState) returns string|commons:APKError { + if ("blocked".equalsIgnoreCaseAscii(blockState) || "prod_only_blocked".equalsIgnoreCaseAscii(blockState)) { + commons:APKError|string blockSub = db_blockSubscription(subscriptionId, blockState); + if blockSub is commons:APKError { + return blockSub; + } else { + SubscriptionInternal|commons:APKError updatedSub = getSubscriptionByIdDAO(subscriptionId); + if updatedSub is SubscriptionInternal { + string[]|commons:APKError hostList = retrieveManagementServerHostsList(); + if hostList is string[] { + string eventId = uuid:createType1AsString(); + time:Utc currTime = time:utcNow(); + string date = time:utcToString(currTime); + SubscriptionGRPC updateSubscriptionRequest = { + eventId: eventId, + applicationRef: updatedSub.applicationId, + apiRef: updatedSub.apiId, + policyId: updatedSub.throttlingPolicy, + subStatus: updatedSub.status, + subscriber: "user", + uuid: subscriptionId, + timeStamp: date, + organization: "org" + }; + string backofficePubCert = keyStores.tls.certFilePath; + string backofficeKeyCert = keyStores.tls.keyFilePath; + string pubCertPath = managementServerConfig.certPath; + foreach string host in hostList { + NotificationResponse|error subscriptionNotification = notification:updateSubscription(updateSubscriptionRequest, + "https://" + host + ":8766", pubCertPath, backofficePubCert, backofficeKeyCert); + if subscriptionNotification is error { + string message = "Error while sending subscription update grpc event"; + log:printError(subscriptionNotification.toString()); + commons:APKError e = error(message, subscriptionNotification, message = message, description = message, code = 909000, statusCode = 500); + return e; + } + } + } else { + return hostList; + } + } else { + return updatedSub; + } + return blockSub; + } + } else { + return e909623(); + } +} + +isolated function unblockSubscription(string subscriptionId) returns string|commons:APKError { + commons:APKError|string unblockSub = db_unblockSubscription(subscriptionId); + if unblockSub is commons:APKError { + return unblockSub; + } else { + SubscriptionInternal|commons:APKError updatedSub = getSubscriptionByIdDAO(subscriptionId); + if updatedSub is SubscriptionInternal { + string[]|commons:APKError hostList = retrieveManagementServerHostsList(); + if hostList is string[] { + string eventId = uuid:createType1AsString(); + time:Utc currTime = time:utcNow(); + string date = time:utcToString(currTime); + SubscriptionGRPC updateSubscriptionRequest = { + eventId: eventId, + applicationRef: updatedSub.applicationId, + apiRef: updatedSub.apiId, + policyId: updatedSub.throttlingPolicy, + subStatus: updatedSub.status, + subscriber: "user", + uuid: subscriptionId, + timeStamp: date, + organization: "org" + }; + string backofficePubCert = keyStores.tls.certFilePath; + string backofficeKeyCert = keyStores.tls.keyFilePath; + string pubCertPath = managementServerConfig.certPath; + foreach string host in hostList { + NotificationResponse|error subscriptionNotification = notification:updateSubscription(updateSubscriptionRequest, + "https://" + host + ":8766", pubCertPath, backofficePubCert, backofficeKeyCert); + if subscriptionNotification is error { + string message = "Error while sending subscription update grpc event"; + log:printError(subscriptionNotification.toString()); + commons:APKError e = error(message, subscriptionNotification, message = message, description = message, code = 909000, statusCode = 500); + return e; + } + } + } else { + return hostList; + } + } else { + return updatedSub; + } + return unblockSub; + } +} + +isolated function getAPI(string apiId) returns API|commons:APKError { + API|commons:APKError getAPI = check db_getAPI(apiId); + return getAPI; +} + +isolated function getAPIDefinition(string apiId) returns APIDefinition|commons:APKError { + APIDefinition|commons:APKError apiDefinition = db_getAPIDefinition(apiId); + return apiDefinition; +} + +isolated function updateAPI(string apiId, ModifiableAPI payload) returns API|commons:APKError { + API|commons:APKError api = db_updateAPI(apiId, payload); + return api; +} + +isolated function getAllCategoryList(string organization) returns APICategoryList|commons:APKError { + APICategory[]|commons:APKError categories = getAPICategoriesDAO(organization); + if categories is APICategory[] { + int count = categories.length(); + APICategoryList apiCategoriesList = {count: count, list: categories}; + return apiCategoriesList; + } else { + return categories; + } +} + +isolated function getBusinessPlans(string organization) returns BusinessPlanList|commons:APKError { + BusinessPlan[]|commons:APKError businessPlans = getBusinessPlansDAO(organization); + if businessPlans is BusinessPlan[] { + int count = businessPlans.length(); + BusinessPlanList BusinessPlansList = {count: count, list: businessPlans}; + return BusinessPlansList; + } else { + return businessPlans; + } +} + +isolated function retrieveManagementServerHostsList() returns string[]|commons:APKError { + string managementServerServiceName = managementServerConfig.serviceName; + string managementServerNamespace = managementServerConfig.namespace; + log:printDebug("Service:" + managementServerServiceName); + log:printDebug("Namespace:" + managementServerNamespace); + string[]|commons:APKError hostList = getPodFromNameAndNamespace(managementServerServiceName, managementServerNamespace); + return hostList; +} + +isolated function updateThumbnail(string apiId, http:Request message) returns FileInfo|NotFoundError|PreconditionFailedError|commons:APKError|error { + API|commons:APKError getApi = check db_getAPI(apiId); + if getApi is commons:APKError|NotFoundError { + return getApi; + } else if getApi is API { + string|() fileName = (); + byte[]|() fileContent = (); + string imageType = ""; + mime:Entity[]|http:ClientError payLoadParts = message.getBodyParts(); + if payLoadParts is mime:Entity[] { + foreach mime:Entity payLoadPart in payLoadParts { + mime:ContentDisposition contentDisposition = payLoadPart.getContentDisposition(); + string fieldName = contentDisposition.name; + if fieldName == "file" { + fileName = contentDisposition.fileName; + fileContent = check payLoadPart.getByteArray(); + imageType = payLoadPart.getContentType(); + } + } + } + if fileName is () || fileContent is () { + string msg = "Thumbnail is not provided"; + commons:APKError e = error(msg, (), message = msg, description = msg, code = 909000, statusCode = 500); + return e; + } else { + if !isThumbnailHasValidFileExtention(imageType) { + PreconditionFailedError pfe = { + body: { + code: 90915, + message: "Thumbnail file extension is not allowed. Supported extensions are .jpg, .png, .jpeg .svg and .gif" + } + }; + return pfe; + } + if isFileSizeGreaterThan1MB(fileContent) { + PreconditionFailedError pfe = {body: {code: 90915, message: "Thumbnail size should be less than 1MB"}}; + return pfe; + } + int|commons:APKError thumbnailCategoryId = db_getResourceCategoryIdByCategoryType(RESOURCE_TYPE_THUMBNAIL); + if thumbnailCategoryId is int { + Resource thumbnailResource = { + resourceUUID: "", + apiUuid: apiId, + resourceCategoryId: thumbnailCategoryId, + dataType: imageType, + resourceContent: fileName, + resourceBinaryValue: fileContent + }; + Resource|NotFoundError|commons:APKError thumbnail = db_getResourceByResourceCategory(apiId, thumbnailCategoryId); + if thumbnail is Resource { + thumbnailResource.resourceUUID = thumbnail.resourceUUID; + Resource|commons:APKError updatedThumbnail = db_updateResource(thumbnailResource); + if updatedThumbnail is Resource { + return {fileName: updatedThumbnail.resourceContent, mediaType: updatedThumbnail.dataType}; + } else { + return updatedThumbnail; + } + } else if thumbnail is NotFoundError { + string resourceUUID = uuid:createType1AsString(); + thumbnailResource.resourceUUID = resourceUUID; + Resource|commons:APKError addedThumbnail = db_addResource(thumbnailResource); + if addedThumbnail is Resource { + return {fileName: addedThumbnail.resourceContent, mediaType: addedThumbnail.dataType}; + } else { + return addedThumbnail; + } + } else { + return thumbnail; + } + } else { + return thumbnailCategoryId; + } + } + } +} + +isolated function getThumbnail(string apiId) returns http:Response|NotFoundError|commons:APKError { + API|commons:APKError getApi = check db_getAPI(apiId); + if getApi is API { + int|commons:APKError thumbnailCategoryId = db_getResourceCategoryIdByCategoryType(RESOURCE_TYPE_THUMBNAIL); + if thumbnailCategoryId is int { + Resource|NotFoundError|commons:APKError thumbnail = db_getResourceByResourceCategory(apiId, thumbnailCategoryId); + if thumbnail is Resource { + http:Response outResponse = new; + outResponse.setBinaryPayload(thumbnail.resourceBinaryValue, thumbnail.dataType); + return outResponse; + } else { + return thumbnail; + } + } + return thumbnailCategoryId; + } else { + return getApi; + } +} + +isolated function createDocument(string apiId, Document documentPayload) returns Document|commons:APKError { + API|commons:APKError getApi = check db_getAPI(apiId); + if getApi is API { + int|commons:APKError documentCategoryId = db_getResourceCategoryIdByCategoryType(RESOURCE_TYPE_DOCUMENT); + if documentCategoryId is int { + Resource documentResource = { + resourceUUID: "", + apiUuid: apiId, + resourceCategoryId: documentCategoryId, + dataType: "", + resourceContent: "", + resourceBinaryValue: [] + }; + string resourceUUID = uuid:createType1AsString(); + documentResource.resourceUUID = resourceUUID; + Resource|commons:APKError addedDocResource = db_addResource(documentResource); + if addedDocResource is Resource { + // Add document metaData + string documentUUID = uuid:createType1AsString(); + DocumentMetaData documentMetaData = { + documentId: documentUUID, + resourceId: addedDocResource.resourceUUID, + name: documentPayload.name, + summary: documentPayload.summary, + sourceType: documentPayload.sourceType, + sourceUrl: documentPayload.sourceUrl, + fileName: documentPayload.fileName, + documentType: documentPayload.documentType, + otherTypeName: documentPayload.otherTypeName, + visibility: documentPayload.visibility, + inlineContent: documentPayload.inlineContent + }; + DocumentMetaData|commons:APKError addedDocMetaData = db_addDocumentMetaData(documentMetaData, apiId); + if addedDocMetaData is DocumentMetaData { + Document document = { + documentId: addedDocMetaData.documentId, + name: addedDocMetaData.name, + summary: addedDocMetaData.summary, + sourceType: addedDocMetaData.sourceType, + sourceUrl: addedDocMetaData.sourceUrl, + fileName: addedDocMetaData.fileName, + documentType: addedDocMetaData.documentType, + otherTypeName: addedDocMetaData.otherTypeName, + visibility: addedDocMetaData.visibility, + inlineContent: addedDocMetaData.inlineContent + }; + return document; + } else { + return addedDocMetaData; + } + } else { + return addedDocResource; + } + } else { + return documentCategoryId; + } + } else { + return getApi; + } +} + +isolated function UpdateDocumentMetaData(string apiId, string documentId, Document documentPayload) returns Document|NotFoundError|commons:APKError|error { + API|commons:APKError getApi = check db_getAPI(apiId); + if getApi is API { + DocumentMetaData|NotFoundError|commons:APKError getDocumentMetaData = db_getDocumentByDocumentId(documentId, apiId); + if getDocumentMetaData is DocumentMetaData { + DocumentMetaData documentMetaData = { + documentId: documentId, + name: documentPayload.name, + summary: documentPayload.summary, + sourceType: documentPayload.sourceType, + sourceUrl: documentPayload.sourceUrl, + fileName: documentPayload.fileName, + documentType: documentPayload.documentType, + otherTypeName: documentPayload.otherTypeName, + visibility: documentPayload.visibility, + inlineContent: documentPayload.inlineContent + }; + DocumentMetaData|commons:APKError updatedDocMetaData = db_updateDocumentMetaData(documentMetaData, apiId); + if updatedDocMetaData is DocumentMetaData { + // Convert documentMetadata object to Document object + Document document = { + documentId: updatedDocMetaData.documentId, + name: updatedDocMetaData.name, + summary: updatedDocMetaData.summary, + sourceType: updatedDocMetaData.sourceType, + sourceUrl: updatedDocMetaData.sourceUrl, + fileName: updatedDocMetaData.fileName, + documentType: updatedDocMetaData.documentType, + otherTypeName: updatedDocMetaData.otherTypeName, + visibility: updatedDocMetaData.visibility, + inlineContent: updatedDocMetaData.inlineContent + }; + return document; + } else { + return updatedDocMetaData; + } + } else { + return getDocumentMetaData; + } + } else { + return getApi; + } +} + +isolated function addDocumentContent(string apiId, string documentId, http:Request message) returns Document|NotFoundError|commons:APKError|error { + API|commons:APKError getApi = check db_getAPI(apiId); + if getApi is API { + DocumentMetaData|NotFoundError|commons:APKError getDocumentMetaData = db_getDocumentByDocumentId(documentId, apiId); + if getDocumentMetaData is DocumentMetaData { + // Convert documentMetadata object to Document object + Document document = { + documentId: getDocumentMetaData.documentId, + name: getDocumentMetaData.name, + summary: getDocumentMetaData.summary, + sourceType: getDocumentMetaData.sourceType, + sourceUrl: getDocumentMetaData.sourceUrl, + fileName: getDocumentMetaData.fileName, + documentType: getDocumentMetaData.documentType, + otherTypeName: getDocumentMetaData.otherTypeName, + visibility: getDocumentMetaData.visibility, + inlineContent: getDocumentMetaData.inlineContent + }; + byte[]|() fileContent = (); + string baseType = mime:TEXT_PLAIN; + string inlineContent = ""; + mime:Entity[]|http:ClientError payLoadParts = message.getBodyParts(); + if payLoadParts is mime:Entity[] { + foreach mime:Entity payLoadPart in payLoadParts { + mime:ContentDisposition contentDisposition = payLoadPart.getContentDisposition(); + baseType = payLoadPart.getContentType(); + if mime:APPLICATION_XML == baseType || mime:TEXT_XML == baseType { + var payload = payLoadPart.getXml(); + if payload is xml { + inlineContent = payload.toString(); + fileContent = check payLoadPart.getByteArray(); + } else { + log:printError("Error in parsing XML data", 'error = payload); + return e909631(payload, "XML"); + } + } else if mime:APPLICATION_JSON == baseType { + var payload = payLoadPart.getJson(); + if payload is json { + inlineContent = payload.toJsonString(); + fileContent = check payLoadPart.getByteArray(); + } else { + log:printError("Error in parsing JSON data", 'error = payload); + return e909631(payload, "JSON"); + } + } else if mime:TEXT_PLAIN == baseType { + var payload = payLoadPart.getText(); + if payload is string { + inlineContent = payload; + fileContent = payload.toBytes(); + } else { + log:printError("Error in parsing text data", 'error = payload); + return e909631(payload, "text"); + } + } else if mime:APPLICATION_PDF == baseType { + fileContent = check payLoadPart.getByteArray(); + inlineContent = contentDisposition.fileName; + } else { + baseType = mime:TEXT_PLAIN; + inlineContent = check payLoadPart.getText(); + fileContent = inlineContent.toBytes(); + } + } + } + int|commons:APKError documentCategoryId = db_getResourceCategoryIdByCategoryType(RESOURCE_TYPE_DOCUMENT); + if documentCategoryId is int { + string|commons:APKError resourceId = db_getResourceIdByDocumentId(documentId); + if resourceId is string { + Resource documentResource = { + resourceUUID: resourceId, + apiUuid: apiId, + resourceCategoryId: documentCategoryId, + dataType: baseType, + resourceContent: inlineContent, + resourceBinaryValue: fileContent + }; + Resource|commons:APKError updatedDcoumentResource = db_updateResource(documentResource); + if updatedDcoumentResource is Resource { + return document; + } else { + return updatedDcoumentResource; + } + } else { + return resourceId; + } + } else { + return documentCategoryId; + } + } else { + return getDocumentMetaData; + } + } else { + return getApi; + } +} + +isolated function getDocumentMetaData(string apiId, string documentId) returns Document|NotFoundError|commons:APKError { + API|commons:APKError getApi = check db_getAPI(apiId); + if getApi is API { + DocumentMetaData|NotFoundError|commons:APKError getDocumentMetaData = db_getDocumentByDocumentId(documentId, apiId); + if getDocumentMetaData is DocumentMetaData { + // Convert documentMetadata object to Document object + Document document = { + documentId: getDocumentMetaData.documentId, + name: getDocumentMetaData.name, + summary: getDocumentMetaData.summary, + sourceType: getDocumentMetaData.sourceType, + sourceUrl: getDocumentMetaData.sourceUrl, + fileName: getDocumentMetaData.fileName, + documentType: getDocumentMetaData.documentType, + otherTypeName: getDocumentMetaData.otherTypeName, + visibility: getDocumentMetaData.visibility, + inlineContent: getDocumentMetaData.inlineContent + }; + return document; + } else { + return getDocumentMetaData; + } + } else { + return getApi; + } +} + +isolated function getDocumentContent(string apiId, string documentId) returns http:Response|NotFoundError|commons:APKError { + API|commons:APKError getApi = check db_getAPI(apiId); + if getApi is API { + DocumentMetaData|NotFoundError|commons:APKError getDocumentMetaData = db_getDocumentByDocumentId(documentId, apiId); + if getDocumentMetaData is DocumentMetaData { + Resource|commons:APKError getDocumentResource = db_getResourceByResourceId(getDocumentMetaData.resourceId); + if getDocumentResource is Resource { + http:Response outResponse = new; + outResponse.setBinaryPayload(getDocumentResource.resourceBinaryValue, getDocumentResource.dataType); + return outResponse; + } else { + return getDocumentResource; + } + } else { + return getDocumentMetaData; + } + } else { + return getApi; + } +} + +isolated function getDocumentList(string apiId, int 'limit, int offset) returns DocumentList|commons:APKError { + API|commons:APKError getApi = check db_getAPI(apiId); + if getApi is API { + Document[]|commons:APKError documents = db_getDocuments(apiId); + if documents is Document[] { + Document[] limitSet = []; + if documents.length() > offset { + foreach int i in offset ... (documents.length() - 1) { + if limitSet.length() < 'limit { + limitSet.push(documents[i]); + } + } + } + DocumentList documentList = {count: limitSet.length(), list: limitSet, pagination: {total: documents.length(), 'limit: 'limit, offset: offset}}; + return documentList; + } else { + return documents; + } + } else { + return getApi; + } +} + +isolated function deleteDocument(string apiId, string documentId) returns http:Ok|NotFoundError|commons:APKError { + API|commons:APKError getApi = check db_getAPI(apiId); + if getApi is API { + DocumentMetaData|NotFoundError|commons:APKError getDocumentMetaData = db_getDocumentByDocumentId(documentId, apiId); + if getDocumentMetaData is DocumentMetaData { + string|commons:APKError deletedDocMetaData = db_deleteDocumentMetaData(documentId, apiId); + string|commons:APKError deletedDocResource = db_deleteResource(getDocumentMetaData.resourceId); + if deletedDocMetaData is commons:APKError { + return deletedDocMetaData; + } + if deletedDocResource is commons:APKError { + return deletedDocResource; + } + http:Ok okResponse = {body: "Document deleted successfully"}; + return okResponse; + } else { + return getDocumentMetaData; + } + } else { + return getApi; + } +} diff --git a/backoffice/backoffice-domain-service/ballerina/backoffice_internal_dao.bal b/backoffice/backoffice-domain-service/ballerina/backoffice_internal_dao.bal new file mode 100644 index 000000000..e747bf429 --- /dev/null +++ b/backoffice/backoffice-domain-service/ballerina/backoffice_internal_dao.bal @@ -0,0 +1,262 @@ +// +// Copyright (c) 2022, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + +import ballerina/sql; +import ballerinax/postgresql; +import ballerina/time; + +import wso2/apk_common_lib as commons; + +# Add API details to the database +# +# + apiBody - API Parameter +# + organization - organization +# + return - API | error +isolated function db_createAPI(APIBody apiBody, string organization) returns API | error { + postgresql:Client | error db_client = getConnection(); + if db_client is error { + return error("Issue while conecting to databse"); + } else { + postgresql:JsonBinaryValue artifact = new (createArtifact(apiBody.apiProperties.id, apiBody.apiProperties)); + sql:ParameterizedQuery ADD_API_Suffix = `INSERT INTO api(uuid, api_name, api_version,context,status,organization,artifact) VALUES (`; + sql:ParameterizedQuery values = `${apiBody.apiProperties.id}, + ${apiBody.apiProperties.name}, + ${apiBody.apiProperties.'version}, + ${apiBody.apiProperties.context}, + 'CREATED', + ${organization}, + ${artifact})`; + sql:ParameterizedQuery sqlQuery = sql:queryConcat(ADD_API_Suffix, values); + + sql:ExecutionResult | sql:Error result = db_client->execute(sqlQuery); + + if result is sql:ExecutionResult { + return apiBody.apiProperties; + } else { + return error("Error while inserting data into Database", result); + } + } +} + +# Add API definition to the database +# +# + apiBody - API Parameter +# + organization - organization +# + return - API | error +isolated function db_AddDefinition(APIBody apiBody, string organization) returns API | error { + postgresql:Client | error db_client = getConnection(); + if db_client is error { + return error("Issue while conecting to databse"); + } else { + sql:ParameterizedQuery ADD_API_DEFINITION_Suffix = `INSERT INTO api_artifact(organization, api_uuid, api_definition,media_type) VALUES (`; + sql:ParameterizedQuery values = `${organization}, + ${apiBody.apiProperties.id}, + ${apiBody.Definition.toString().toBytes()}, + ${apiBody.apiProperties.'type} + )`; + sql:ParameterizedQuery sqlQuery = sql:queryConcat(ADD_API_DEFINITION_Suffix, values); + + sql:ExecutionResult | sql:Error result = db_client->execute(sqlQuery); + + if result is sql:ExecutionResult { + return apiBody.apiProperties; + } else { + return error("Error while inserting data into Database"); + } + } +} + +# Get API details from the database +# +# + apiId - API Id parameter +# + organization - organization +# + return - API | error +isolated function db_getAPI_internal(string apiId) returns API | commons:APKError| error { + postgresql:Client | error db_Client = getConnection(); + if db_Client is error { + return error("Issue while conecting to databse"); + } else { + sql:ParameterizedQuery GET_API_Prefix = `SELECT UUID AS ID, + API_NAME as NAME, API_VERSION as VERSION,CONTEXT, ORGANIZATION,STATUS + FROM API where UUID = `; + sql:ParameterizedQuery values = `${apiId}`; + sql:ParameterizedQuery sqlQuery = sql:queryConcat(GET_API_Prefix, values); + + API | sql:Error result = db_Client->queryRow(sqlQuery); + + if result is sql:NoRowsError { + return e909603(); + } else if result is API { + return result; + } else { + return e909604(); + } + } +} + +# Update API details to the database +# +# + api - API Parameter +# + apiId - API Id parameter +# + organization - organization +# + return - API | error +isolated function db_updateAPI_internal(string apiId, APIBody api) returns API | error { + postgresql:Client | error db_client = getConnection(); + if db_client is error { + return error("Issue while conecting to databse"); + } else { + sql:ParameterizedQuery UPDATE_API_Suffix = `UPDATE api SET`; + sql:ParameterizedQuery values = ` api_name = ${api.apiProperties.name} + WHERE uuid = ${apiId}`; + sql:ParameterizedQuery sqlQuery = sql:queryConcat(UPDATE_API_Suffix, values); + + sql:ExecutionResult | sql:Error result = db_client->execute(sqlQuery); + + if result is sql:ExecutionResult { + return api.apiProperties; + } else { + return error("Error while updating data into Database"); + } + } +} + +# Update API details to the database +# +# + api - API Parameter +# + apiId - API Id parameter +# + return - API | error +isolated function db_updateDefinition(string apiId, APIBody api) returns API | error { + postgresql:Client | error db_client = getConnection(); + if db_client is error { + return error("Issue while conecting to databse"); + } else { + sql:ParameterizedQuery UPDATE_API_DEFINITION_Suffix = `UPDATE api_artifact SET`; + sql:ParameterizedQuery values = ` api_definition = ${api.Definition.toString().toBytes()} + WHERE api_uuid = ${apiId}`; + sql:ParameterizedQuery sqlQuery = sql:queryConcat(UPDATE_API_DEFINITION_Suffix, values); + + sql:ExecutionResult | sql:Error result = db_client->execute(sqlQuery); + + if result is sql:ExecutionResult { + return api.apiProperties; + } else { + return error("Error while updating definition into Database"); + } + } +} + +# Delete API details from the database +# +# + apiId - API Id parameter +# + return - string | error +isolated function db_deleteAPI(string apiId) returns string | error? { + postgresql:Client | error db_client = getConnection(); + if db_client is error { + return error("Issue while conecting to databse"); + } else { + sql:ParameterizedQuery DELETE_API_Suffix = `DELETE FROM api WHERE uuid = `; + sql:ParameterizedQuery values = `${apiId}`; + sql:ParameterizedQuery sqlQuery = sql:queryConcat(DELETE_API_Suffix, values); + sql:ExecutionResult | sql:Error result = db_client->execute(sqlQuery); + + if result is sql:ExecutionResult { + return "deleted"; + } else { + return error("Error while deleting api data record in the Database"); + } + } +} + +# Delete API details from the database +# +# + apiId - API Id parameter +# + return - string | error +isolated function db_deleteDefinition(string apiId) returns string | error? { + postgresql:Client | error db_client = getConnection(); + if db_client is error { + return error("Issue while conecting to databse"); + } else { + sql:ParameterizedQuery DELETE_API_DEFINITION_Suffix = `DELETE FROM api_artifact WHERE api_uuid = `; + sql:ParameterizedQuery values = `${apiId}`; + sql:ParameterizedQuery sqlQuery = sql:queryConcat(DELETE_API_DEFINITION_Suffix, values); + sql:ExecutionResult | sql:Error result = db_client->execute(sqlQuery); + + if result is sql:ExecutionResult { + return "deleted"; + } else { + return error("Error while deleting definition record in the Database"); + } + } +} + + +# Update API details to the database +# +# + api - API Parameter +# + apiId - API Id parameter +# + return - API | error +isolated function db_updateDefinitionbyId(string apiId, APIDefinition1 api) returns APIDefinition1 | error { + postgresql:Client | error db_client = getConnection(); + if db_client is error { + return error("Issue while conecting to databse"); + } else { + sql:ParameterizedQuery UPDATE_API_DEFINITION_Suffix = `UPDATE api_artifact SET`; + sql:ParameterizedQuery values = ` api_definition = ${api.Definition.toString().toBytes()} + WHERE api_uuid = ${apiId}`; + sql:ParameterizedQuery sqlQuery = sql:queryConcat(UPDATE_API_DEFINITION_Suffix, values); + + sql:ExecutionResult | sql:Error result = db_client->execute(sqlQuery); + + if result is sql:ExecutionResult { + return api; + } else { + return error("Error while updating definition into Database"); + } + } +} + +# Add LC event to the database +# +# + apiId - API id Parameter +# + organization - organization +# + return - API | error +isolated function db_AddLCEvent_internal(string? apiId, string organization) returns string | error { + postgresql:Client | error db_client = getConnection(); + time:Utc utc = time:utcNow(); + if db_client is error { + return error("Issue while conecting to databse"); + } else { + sql:ParameterizedQuery values = `${apiId}, + null, + 'CREATED', + 'apkuser', + ${organization}, + ${utc} + )`; + sql:ParameterizedQuery ADD_LC_EVENT_Prefix = `INSERT INTO api_lc_event (api_uuid,previous_state,new_state,user_uuid,organization,event_date) VALUES (`; + sql:ParameterizedQuery sqlQuery = sql:queryConcat(ADD_LC_EVENT_Prefix, values); + + sql:ExecutionResult | sql:Error result = db_client->execute(sqlQuery); + + if result is sql:ExecutionResult { + return result.toString(); + } else { + return error("Error while inserting data into Database"); + } + } +} \ No newline at end of file diff --git a/backoffice/backoffice-domain-service/ballerina/backoffice_internal_impl.bal b/backoffice/backoffice-domain-service/ballerina/backoffice_internal_impl.bal new file mode 100644 index 000000000..1d4eec333 --- /dev/null +++ b/backoffice/backoffice-domain-service/ballerina/backoffice_internal_impl.bal @@ -0,0 +1,138 @@ +// +// Copyright (c) 2022, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + +import wso2/apk_common_lib as commons; + +# This function used to connect API create service to database +# +# + body - API parameter +# + organization - organization +# + return - Return Value API | error +isolated function createAPI(APIBody body) returns API|error { + transaction { + API|error apiCr = db_createAPI(body, body.apiProperties.organization); + if apiCr is API { + API|error defCr = db_AddDefinition(body, body.apiProperties.organization); + if defCr is API { + string|error lcEveCr = db_AddLCEvent_internal(body.apiProperties.id, body.apiProperties.organization); + if lcEveCr is string { + check commit; + } else { + rollback; + return error("Error while adding API LC event"); + } + } else { + rollback; + return error("Error while adding API definition"); + } + } else { + rollback; + return error("Error while adding API data", apiCr); + } + return apiCr; + } +} + +# This function used to connect API get service from database +# +# + apiId - API Id parameter +# + organization - organization +# + return - Return Value API | error +isolated function getAPI_internal(string apiId) returns API|commons:APKError|error { + API|commons:APKError|error response = db_getAPI_internal(apiId); + if response is error && response !is commons:APKError { + return error("Error while retrieving API data"); + } + return response; +} + +# This function used to connect API update service to database +# +# + body - API parameter +# + apiId - API Id parameter +# + organization - organization +# + return - Return Value API | error +isolated function updateAPI_internal(string apiId, APIBody body) returns API|commons:APKError|error { + API|commons:APKError api = check getAPI_internal(apiId); + if api is API { + API|error apiUp = db_updateAPI_internal(apiId, body); + if apiUp is error { + return error("Error while updating API data"); + } + API|error defUp = db_updateDefinition(apiId, body); + if defUp is error { + return error("Error while updating API definition"); + } + return apiUp; + } else { + return api; + } +} + +# This function used to connect API update service to database +# +# + apiId - API Id parameter +# + organization - organization +# + return - Return Value string | error +isolated function deleteAPI(string apiId) returns string|commons:APKError|error? { + API|commons:APKError api = check getAPI_internal(apiId); + if api is API { + error?|string apiDel = db_deleteAPI(apiId); + if apiDel is error { + return error("Error while deleting API data"); + } + error?|string defDel = db_deleteDefinition(apiId); + if defDel is error { + return error("Error while deleting API definition data"); + } + return apiDel; + } else { + return e909606(apiId); + } +} + +# This function used to connect API update service to database +# +# + apiId - API Id parameter +# + apiBody - ApiidDefinitionBody +# + return - Return Value string | error +isolated function updateDefinition(APIDefinition1 apiBody, string apiId) returns APIDefinition1|error? { + APIDefinition1|error apiUp = db_updateDefinitionbyId(apiId, apiBody); + if apiUp is error { + return error("Error while updating API definition data"); + } + return apiUp; +} + +# This function used to create artifact from API +# +# + apiID - API Id parameter +# + api - api object +# + return - Return Value json +isolated function createArtifact(string? apiID, API api) returns json { + Artifact artifact = { + id: apiID, + apiName: api.name, + context: api.context, + 'version: api.'version, + status: api.lifeCycleStatus, + providerName: api.provider + }; + json artifactJson = artifact; + return artifactJson; +} diff --git a/backoffice/backoffice-domain-service/ballerina/build.gradle b/backoffice/backoffice-domain-service/ballerina/build.gradle new file mode 100644 index 000000000..37af8f502 --- /dev/null +++ b/backoffice/backoffice-domain-service/ballerina/build.gradle @@ -0,0 +1,41 @@ +// +// Copyright (c) 2022, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + +apply from: "$rootDir/../../common-gradle-scripts/ballerina.gradle" +apply from: "$rootDir/../../common-gradle-scripts/docker.gradle" + +tasks.register('build') { + group 'build' + description 'Build ballerina component' + dependsOn 'test' + mustRunAfter('test') + dependsOn 'bal_build' +} + +tasks.register('test') { + group 'test' + description 'Test ballerina component' + dependsOn('start_postgres_image') + dependsOn('bal_test') + finalizedBy('stop_postgres_image') + mustRunAfter('start_postgres_image') +} + +task clean{ + dependsOn 'bal_clean' +} diff --git a/backoffice/backoffice-domain-service/ballerina/config.bal b/backoffice/backoffice-domain-service/ballerina/config.bal new file mode 100644 index 000000000..7a468570d --- /dev/null +++ b/backoffice/backoffice-domain-service/ballerina/config.bal @@ -0,0 +1,35 @@ +// +// Copyright (c) 2022, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// +import wso2/apk_common_lib as commons; + + +public type KeyStores record{| + commons:KeyStore tls; +|}; + +public type K8sConfiguration record {| + string host = "kubernetes.default"; + string serviceAccountPath = "/var/run/secrets/kubernetes.io/serviceaccount"; + decimal readTimeout = 5; +|}; + +public type ManagementServerConfiguration record {| + string serviceName = "apk-test-wso2-apk-management-server"; + string namespace = "apk"; + string certPath = "/home/wso2apk/devportal/security/truststore/management-server.pem"; +|}; \ No newline at end of file diff --git a/backoffice/backoffice-domain-service/ballerina/constants.bal b/backoffice/backoffice-domain-service/ballerina/constants.bal new file mode 100644 index 000000000..737d5bb88 --- /dev/null +++ b/backoffice/backoffice-domain-service/ballerina/constants.bal @@ -0,0 +1,27 @@ +// +// Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + +import ballerina/mime; + +const string RESOURCE_TYPE_THUMBNAIL = "Thumbnail"; +const string RESOURCE_TYPE_DOCUMENT = "Document"; +const string RESOURCE_DATA_TYPE_JPG_IMAGE = mime:IMAGE_JPEG; +const string RESOURCE_DATA_TYPE_PNG_IMAGE = mime:IMAGE_PNG; +const string RESOURCE_DATA_TYPE_GIF_IMAGE = mime:IMAGE_GIF; +const string RESOURCE_DATA_TYPE_SVG_IMAGE = "image/svg+xml"; + diff --git a/backoffice/backoffice-domain-service/ballerina/health_service.bal b/backoffice/backoffice-domain-service/ballerina/health_service.bal new file mode 100644 index 000000000..7201f32a4 --- /dev/null +++ b/backoffice/backoffice-domain-service/ballerina/health_service.bal @@ -0,0 +1,26 @@ +// +// Copyright (c) 2022, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + +import ballerina/http; + +service / on ep0 { + resource function get health() returns http:Ok { + json status = {"health": "Ok"}; + return {body: status}; + } +} \ No newline at end of file diff --git a/backoffice/backoffice-domain-service/ballerina/init.bal b/backoffice/backoffice-domain-service/ballerina/init.bal new file mode 100644 index 000000000..f3d64b9f2 --- /dev/null +++ b/backoffice/backoffice-domain-service/ballerina/init.bal @@ -0,0 +1,56 @@ +// +// Copyright (c) 2022, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + +import ballerina/log; +import ballerinax/postgresql; +import ballerina/sql; +import wso2/apk_common_lib as commons; + +configurable commons:DatasourceConfiguration datasourceConfiguration = ?; +configurable K8sConfiguration k8sConfig = ?; +configurable ManagementServerConfiguration & readonly managementServerConfig = ?; +final postgresql:Client|sql:Error dbClient; + +configurable commons:IDPConfiguration idpConfiguration = { + publicKey: {certFilePath: "/home/wso2apk/backoffice/security/mg.pem"} +}; +configurable KeyStores & readonly keyStores = { + tls: {certFilePath: "/home/wso2apk/admin/security/backoffice.pem", keyFilePath: "/home/wso2apk/admin/security/backoffice.key"} +}; + +commons:DBBasedOrgResolver organizationResolver = new (datasourceConfiguration); +commons:JWTValidationInterceptor jwtValidationInterceptor = new (idpConfiguration, organizationResolver, ["/health"]); +commons:RequestErrorInterceptor requestErrorInterceptor = new; +commons:ResponseErrorInterceptor responseErrorInterceptor = new; + +function init() { + log:printInfo("Starting APK Backoffice Domain Service..."); + + dbClient = + new (host = datasourceConfiguration.host, + username = datasourceConfiguration.username, + password = datasourceConfiguration.password, + database = datasourceConfiguration.databaseName, + port = datasourceConfiguration.port, + connectionPool = {maxOpenConnections: datasourceConfiguration.maxPoolSize} + ); +} + +public isolated function getConnection() returns postgresql:Client|error { + return dbClient; +} diff --git a/backoffice/backoffice-domain-service/ballerina/lifeCycle.bal b/backoffice/backoffice-domain-service/ballerina/lifeCycle.bal new file mode 100644 index 000000000..456a672c7 --- /dev/null +++ b/backoffice/backoffice-domain-service/ballerina/lifeCycle.bal @@ -0,0 +1,132 @@ +// +// Copyright (c) 2022, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + + +# Description +# +# + States - The states of the life cycle +public type StatesList record { + States[] States; +}; + +# Description +# +# + State - The state of the life cycle +# + Transitions - The transitions of the life cycle +public type States record { + string State; + Transitions[] Transitions?; +}; + +# Description +# +# + event - The event of the life cycle +# + targetState - The target state of the life cycle +public type Transitions record { + string event?; + string targetState?; +}; + + + + +final readonly & json lifeCycleStateTransitions = { + "States": [ + { + "State": "Created", + "Transitions": [ + { + "event": "Published", + "targetState": "Published" + }, + { + "event": "Prototyped", + "targetState": "Prototyped" + } + ] + }, + { + "State": "Prototyped", + "Transitions": [ + { + "event": "Published", + "targetState": "Published" + }, + { + "event": "Created", + "targetState": "Created" + }, + { + "event": "Prototyped", + "targetState": "Prototyped" + } + ] + }, + { + "State": "Published", + "Transitions": [ + { + "event": "Blocked", + "targetState": "Blocked" + }, + { + "event": "Prototyped", + "targetState": "Prototyped" + }, + { + "event": "Created", + "targetState": "Created" + }, + { + "event": "Deprecated", + "targetState": "Deprecated" + }, + { + "Event": "Published", + "targetState": "Published" + } + ] + }, + { + "State": "Blocked", + "Transitions": [ + { + "event": "Deprecated", + "targetState": "Deprecated" + }, + { + "event": "Published", + "targetState": "Published" + } + ] + }, + { + "State": "Deprecated", + "Transitions": [ + { + "event": "Retire", + "targetState": "Retired" + } + ] + }, + { + "State": "Retired" + } + ] +}; + diff --git a/backoffice/backoffice-domain-service/ballerina/modules/backoffice/resources/.keep b/backoffice/backoffice-domain-service/ballerina/modules/backoffice/resources/.keep new file mode 100644 index 000000000..e69de29bb diff --git a/backoffice/backoffice-domain-service/ballerina/modules/backoffice/resources/backoffice-api.yaml b/backoffice/backoffice-domain-service/ballerina/modules/backoffice/resources/backoffice-api.yaml new file mode 100644 index 000000000..c50642d1c --- /dev/null +++ b/backoffice/backoffice-domain-service/ballerina/modules/backoffice/resources/backoffice-api.yaml @@ -0,0 +1,3684 @@ +# Copyright (c) 2022, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. +# +# 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. +################################################################################ +openapi: 3.0.1 +info: + title: WSO2 API Platform for Kubernetes (APK) - BackOffice REST API + description: This document specifies a **RESTful API** for WSO2 **APK** - **BackOffice**. + contact: + name: WSO2 + url: https://wso2.com/api-manager/ + email: architecture@wso2.com + license: + name: Apache 2.0 + url: http://www.apache.org/licenses/LICENSE-2.0.html + version: v1 +servers: + - url: https://apis.wso2.com/api/backoffice/ + +paths: + ###################################################### + # The "API Collection" resource APIs + ###################################################### + /apis: + get: + tags: + - APIs + summary: | + Retrieve/Search APIs + description: | + This operation provides you a list of available APIs qualifying under a given search condition. + + Each retrieved API is represented with a minimal amount of attributes. If you want to get complete details of an API, you need to use **Get details of an API** operation. + parameters: + - $ref: '#/components/parameters/limit' + - $ref: '#/components/parameters/offset' + - $ref: '#/components/parameters/sortBy' + - $ref: '#/components/parameters/sortOrder' + - name: query + in: query + description: | + **Search condition**. + + You can search in attributes by using an **`:`** modifier. + + **Example** + + - `provider:wso2` will match an API if the provider of the API contains `wso2`. + - `provider:"wso2` will match an API if the provider of the API is exactly `wso2`. + - `status:PUBLISHED` will match an API if the API is in `PUBLISHED` state. + + In addition, you can use combined modifiers. + + **Example** + `name:pizzashack version:v1` will match an API if the name of the API is pizzashack and version is v1. + + Supported attribute modifiers are [**version, context, name, status, + description, provider, api-category, tags, doc, contexttemplate, + lcstate, content, type, label, enablestore, thirdparty**] + + If no advanced attribute modifier has been specified, the API names containing + the search term will be returned as a result. + + Please note that you need to use encoded URL (URL encoding) if you are using a client which does not support URL encoding (such as curl) + schema: + type: string + - $ref: '#/components/parameters/If-None-Match' + - $ref: '#/components/parameters/Accept' + responses: + 200: + description: | + OK. + List of qualifying APIs is returned. + headers: + ETag: + description: | + Entity Tag of the response resource. Used by caches, or in conditional requests (Will be supported in the future). + schema: + type: string + Content-Type: + description: The content type of the body. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/APIList' + 304: + description: | + Not Modified. + Empty body because the client has already the latest version of the requested resource (Will be supported in the future). + content: {} + 406: + $ref: '#/components/responses/NotAcceptable' + security: + - OAuth2Security: + - apk:api_view + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://api.am.wso2.com:9095/api/backoffice/v1/apis"' + operationId: getAllAPIs + + ###################################################### + # The "Individual API" resource APIs + ###################################################### + /apis/{apiId}: + get: + tags: + - APIs + summary: Get Details of an API + description: | + Using this operation, you can retrieve complete details of a single API. You need to provide the Id of the API to retrieve it. + parameters: + - $ref: '#/components/parameters/apiId' + - $ref: '#/components/parameters/If-None-Match' + responses: + 200: + description: | + OK. + Requested API is returned + headers: + ETag: + description: | + Entity Tag of the response resource. Used by caches, or in conditional requests (Will be supported in the future). + schema: + type: string + Last-Modified: + description: | + Date and time the resource has been modified the last time. + Used by caches, or in conditional requests (Will be supported in the future). + schema: + type: string + Content-Type: + description: | + The content type of the body. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/API' + 304: + description: | + Not Modified. + Empty body because the client has already the latest version of the requested resource (Will be supported in the future). + content: {} + 404: + $ref: '#/components/responses/NotFound' + 406: + $ref: '#/components/responses/NotAcceptable' + security: + - OAuth2Security: + - apk:api_view + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://api.am.wso2.com:9095/api/backoffice/v1/apis/01234567-0123-0123-0123-012345678901"' + operationId: getAPI + put: + tags: + - APIs + summary: Update an API + description: | + This operation can be used to update an existing API. + But the properties `name`, `provider` and `version` cannot be changed. + parameters: + - $ref: '#/components/parameters/apiId' + - $ref: '#/components/parameters/If-None-Match' + requestBody: + description: API object that needs to be updated + content: + application/json: + schema: + $ref: '#/components/schemas/ModifiableAPI' + required: true + responses: + 200: + description: | + OK. + Successful response with updated API object + headers: + ETag: + description: | + Entity Tag of the response resource. Used by caches, or in conditional requests (Will be supported in the future). + schema: + type: string + Last-Modified: + description: | + Date and time the resource has been modified the last time. + Used by caches, or in conditional requests (Will be supported in the future). + schema: + type: string + Location: + description: | + The URL of the newly created resource. + schema: + type: string + Content-Type: + description: | + The content type of the body. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/API' + 400: + $ref: '#/components/responses/BadRequest' + 403: + $ref: '#/components/responses/Forbidden' + 404: + $ref: '#/components/responses/NotFound' + 412: + $ref: '#/components/responses/PreconditionFailed' + security: + - OAuth2Security: + - apk:api_publish + - apk:api_manage + x-code-samples: + - lang: Curl + source: 'curl -k -X PUT -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + -H "Content-Type: application/json" -d @data.json "https://api.am.wso2.com:9095/api/backoffice/v1/apis/01234567-0123-0123-0123-012345678901"' + operationId: updateAPI + + /apis/{apiId}/definition: + get: + tags: + - APIs + summary: Get the API Definition + description: | + This operation can be used to retrieve the definition of an API. + parameters: + - $ref: '#/components/parameters/apiId' + - $ref: '#/components/parameters/If-None-Match' + responses: + 200: + description: | + OK. + Requested definition document of the API is returned + headers: + ETag: + description: | + Entity Tag of the response resource. Used by caches, or in conditional requests (Will be supported in the future). + schema: + type: string + Last-Modified: + description: | + Date and time the resource has been modified the last time. + Used by caches, or in conditional requests (Will be supported in the future). + schema: + type: string + Content-Type: + description: | + The content type of the body. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/APIDefinition' + 304: + description: | + Not Modified. + Empty body because the client has already the latest version of the requested resource (Will be supported in the future). + content: {} + 404: + $ref: '#/components/responses/NotFound' + 406: + $ref: '#/components/responses/NotAcceptable' + security: + - OAuth2Security: + - apk:api_view + - apk:api_definition_view + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://api.am.wso2.com:9095/api/backoffice/v1/apis/01234567-0123-0123-0123-012345678901/definition"' + operationId: getAPIDefinition + + /apis/{apiId}/resource-paths: + get: + tags: + - APIs + summary: Get Resource Paths of an API + description: | + This operation can be used to retrieve resource paths defined for a specific API. + parameters: + - $ref: '#/components/parameters/apiId' + - $ref: '#/components/parameters/limit' + - $ref: '#/components/parameters/offset' + - $ref: '#/components/parameters/If-None-Match' + responses: + 200: + description: | + OK. + ResourcePaths returned. + headers: + ETag: + description: | + Entity Tag of the response resource. + Used by caches, or in conditional requests (Will be supported in the future). + schema: + type: string + Last-Modified: + description: | + Date and time the resource has been modified the last time. + Used by caches, or in conditional requests (Will be supported in the future). + schema: + type: string + Content-Type: + description: | + The content type of the body. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/ResourcePathList' + 304: + description: | + Not Modified. + Empty body because the client has already the latest version of the requested resource (Will be supported in the future). + content: {} + 404: + $ref: '#/components/responses/NotFound' + 406: + $ref: '#/components/responses/NotAcceptable' + security: + - OAuth2Security: + - apk:api_view + - apk:api_manage + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://api.am.wso2.com:9095/api/backoffice/v1/apis/01234567-0123-0123-0123-012345678901/resource-paths"' + operationId: getAPIResourcePaths + + /apis/{apiId}/thumbnail: + get: + tags: + - APIs + summary: Get Thumbnail Image + description: | + This operation can be used to download a thumbnail image of an API. + parameters: + - $ref: '#/components/parameters/apiId' + - $ref: '#/components/parameters/Accept' + - $ref: '#/components/parameters/If-None-Match' + responses: + 200: + description: | + OK. + Thumbnail image returned + headers: + ETag: + description: | + Entity Tag of the response resource. + Used by caches, or in conditional requests (Will be supported in the future). + schema: + type: string + Last-Modified: + description: | + Date and time the resource has been modified the last time. + Used by caches, or in conditional requests (Will be supported in the future). + schema: + type: string + Content-Type: + description: | + The content type of the body. + schema: + type: string + content: {} + 304: + description: | + Not Modified. + Empty body because the client has already the latest version of the requested resource (Will be supported in the future). + content: {} + 404: + $ref: '#/components/responses/NotFound' + 406: + $ref: '#/components/responses/NotAcceptable' + security: + - OAuth2Security: + - apk:api_view + - apk:api_publish + - apk:api_manage + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://api.am.wso2.com:9095/api/backoffice/v1/apis/01234567-0123-0123-0123-012345678901/thumbnail" + > image.jpeg' + operationId: getAPIThumbnail + + put: + tags: + - APIs + summary: Upload a Thumbnail Image + description: | + This operation can be used to upload a thumbnail image of an API. The thumbnail to be uploaded should be given as a form data parameter `file`. + parameters: + - $ref: '#/components/parameters/apiId' + - $ref: '#/components/parameters/If-Match' + requestBody: + content: + multipart/form-data: + schema: + required: + - file + properties: + file: + type: string + description: Image to upload + format: binary + required: true + responses: + 200: + description: | + OK. + Image updated + headers: + ETag: + description: | + Entity Tag of the response resource. + Used by caches, or in conditional requests (Will be supported in the future). + schema: + type: string + Last-Modified: + description: | + Date and time the resource has been modified the last time. + Used by caches, or in conditional requests (Will be supported in the future). + schema: + type: string + Location: + description: | + The URL of the uploaded thumbnail image of the API. + schema: + type: string + Content-Type: + description: | + The content type of the body. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/FileInfo' + 400: + $ref: '#/components/responses/BadRequest' + 404: + $ref: '#/components/responses/NotFound' + 412: + $ref: '#/components/responses/PreconditionFailed' + security: + - OAuth2Security: + - apk:api_publish + - apk:api_manage + x-code-samples: + - lang: Curl + source: 'curl -k -X PUT -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + -H "Content-Type: multipart/form-data" -F file=@image.jpeg "https://api.am.wso2.com:9095/api/backoffice/v1/apis/01234567-0123-0123-0123-012345678901/thumbnail"' + operationId: updateAPIThumbnail + + /apis/{apiId}/documents: + get: + tags: + - API Documents + summary: Get a List of Documents of an API + description: | + This operation can be used to retrieve a list of documents belonging to an API by providing the ID of the API. + parameters: + - $ref: '#/components/parameters/apiId' + - $ref: '#/components/parameters/limit' + - $ref: '#/components/parameters/offset' + - $ref: '#/components/parameters/Accept' + - $ref: '#/components/parameters/If-None-Match' + responses: + 200: + description: | + OK. + Document list is returned. + headers: + ETag: + description: | + Entity Tag of the response resource. Used by caches, or in conditional requests (Will be supported in the future). + schema: + type: string + Content-Type: + description: | + The content type of the body. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/DocumentList' + 304: + description: | + Not Modified. + Empty body because the client has already the latest version of the requested resource (Will be supported in the future). + content: {} + 404: + $ref: '#/components/responses/NotFound' + 406: + $ref: '#/components/responses/NotAcceptable' + security: + - OAuth2Security: + - apk:api_view + - apk:document_manage + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://api.am.wso2.com:9095/api/backoffice/v1/apis/01234567-0123-0123-0123-012345678901/documents"' + operationId: getAPIDocuments + + post: + tags: + - API Documents + summary: Add a New Document to an API + description: | + This operation can be used to add a new documentation to an API. This operation only adds the metadata of a document. To add the actual content we need to use **Upload the content of an API document ** API once we obtain a document Id by this operation. + parameters: + - $ref: '#/components/parameters/apiId' + requestBody: + description: Document object that needs to be added + content: + application/json: + schema: + $ref: '#/components/schemas/Document' + required: true + responses: + 201: + description: | + Created. + Successful response with the newly created Document object as entity in the body. + Location header contains URL of newly added document. + headers: + ETag: + description: | + Entity Tag of the response resource. + Used by caches, or in conditional requests (Will be supported in the future). + schema: + type: string + Location: + description: | + Location to the newly created Document. + schema: + type: string + Content-Type: + description: | + The content type of the body. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/Document' + 400: + $ref: '#/components/responses/BadRequest' + 415: + $ref: '#/components/responses/UnsupportedMediaType' + security: + - OAuth2Security: + - apk:api_view + - apk:document_manage + x-code-samples: + - lang: Curl + source: 'curl -k -X POST -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + -H "Content-Type: application/json" -d @data.json "https://api.am.wso2.com:9095/api/backoffice/v1/apis/01234567-0123-0123-0123-012345678901/documents"' + operationId: addAPIDocument + + /apis/{apiId}/documents/{documentId}: + get: + tags: + - API Documents + summary: Get a Document of an API + description: | + This operation can be used to retrieve a particular document's metadata associated with an API. + parameters: + - $ref: '#/components/parameters/apiId' + - $ref: '#/components/parameters/documentId' + - $ref: '#/components/parameters/Accept' + - $ref: '#/components/parameters/If-None-Match' + responses: + 200: + description: | + OK. + Document returned. + headers: + ETag: + description: | + Entity Tag of the response resource. + Used by caches, or in conditional requests (Will be supported in the future). + schema: + type: string + Last-Modified: + description: | + Date and time the resource has been modified the last time. + Used by caches, or in conditional requests (Will be supported in the future). + schema: + type: string + Content-Type: + description: | + The content type of the body. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/Document' + 304: + description: | + Not Modified. + Empty body because the client has already the latest version of the requested resource (Will be supported in the future). + content: {} + 404: + $ref: '#/components/responses/NotFound' + 406: + $ref: '#/components/responses/NotAcceptable' + security: + - OAuth2Security: + - apk:api_view + - apk:document_manage + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://api.am.wso2.com:9095/api/backoffice/v1/apis/01234567-0123-0123-0123-012345678901/documents/83312daf-0d8a-427b-8f72-12755b7901d3"' + operationId: getAPIDocument + + put: + tags: + - API Documents + summary: Update a Document of an API + description: | + This operation can be used to update metadata of an API's document. + parameters: + - $ref: '#/components/parameters/apiId' + - $ref: '#/components/parameters/documentId' + - $ref: '#/components/parameters/If-Match' + requestBody: + description: Document object that needs to be added + content: + application/json: + schema: + $ref: '#/components/schemas/Document' + required: true + responses: + 200: + description: | + OK. + Document updated + headers: + ETag: + description: | + Entity Tag of the response resource. + Used by caches, or in conditional requests (Will be supported in the future). + schema: + type: string + Last-Modified: + description: | + Date and time the resource has been modified the last time. + Used by caches, or in conditional requests (Will be supported in the future). + schema: + type: string + Location: + description: | + The URL of the updated document. + schema: + type: string + Content-Type: + description: | + The content type of the body. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/Document' + 400: + $ref: '#/components/responses/BadRequest' + 404: + $ref: '#/components/responses/NotFound' + 412: + $ref: '#/components/responses/PreconditionFailed' + security: + - OAuth2Security: + - apk:api_view + - apk:document_manage + x-code-samples: + - lang: Curl + source: 'curl -k -X PUT -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + -H "Content-Type: application/json" -d @data.json "https://api.am.wso2.com:9095/api/backoffice/v1/apis/01234567-0123-0123-0123-012345678901/documents/83312daf-0d8a-427b-8f72-12755b7901d3"' + operationId: updateAPIDocument + + delete: + tags: + - API Documents + summary: Delete a Document of an API + description: | + This operation can be used to delete a document associated with an API. + parameters: + - $ref: '#/components/parameters/apiId' + - $ref: '#/components/parameters/documentId' + - $ref: '#/components/parameters/If-Match' + responses: + 200: + description: | + OK. + Resource successfully deleted. + content: {} + 404: + $ref: '#/components/responses/NotFound' + 412: + $ref: '#/components/responses/PreconditionFailed' + security: + - OAuth2Security: + - apk:api_view + - apk:document_manage + x-code-samples: + - lang: Curl + source: 'curl -k -X DELETE -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://api.am.wso2.com:9095/api/backoffice/v1/apis/01234567-0123-0123-0123-012345678901/documents/83312daf-0d8a-427b-8f72-12755b7901d3"' + operationId: deleteAPIDocument + + /apis/{apiId}/documents/{documentId}/content: + get: + tags: + - API Documents + summary: Get the Content of an API Document + description: | + This operation can be used to retrieve the content of an API's document. + + The document can be of 3 types. In each cases responses are different. + + 1. **Inline type**: + The content of the document will be retrieved in `text/plain` content type + + _Sample cURL_ : `curl -k -H "Authorization:Bearer 579f0af4-37be-35c7-81a4-f1f1e9ee7c51" -F inlineContent=@"docs.txt" -X POST "https://api.am.wso2.com:9095/api/backoffice/v1/apis/01234567-0123-0123-0123-012345678901/documents/43c2bcce-60e7-405f-bc36-e39c0c5e189e/content` + 2. **FILE type**: + The file will be downloaded with the related content type (eg. `application/pdf`) + 3. **URL type**: + The client will receive the URL of the document as the Location header with the response with - `303 See Other` + parameters: + - $ref: '#/components/parameters/apiId' + - $ref: '#/components/parameters/documentId' + - $ref: '#/components/parameters/Accept' + - $ref: '#/components/parameters/If-None-Match' + responses: + 200: + description: | + OK. + File or inline content returned. + headers: + ETag: + description: | + Entity Tag of the response resource. + Used by caches, or in conditional requests (Will be supported in the future). + schema: + type: string + Last-Modified: + description: | + Date and time the resource has been modified the last time. + Used by caches, or in conditional requests (Will be supported in the future). + schema: + type: string + Content-Type: + description: | + The content type of the body. + schema: + type: string + content: {} + 303: + description: | + See Other. + Source can be retrieved from the URL specified at the Location header. + headers: + Location: + description: | + The Source URL of the document. + schema: + type: string + content: {} + 304: + description: | + Not Modified. + Empty body because the client has already the latest version of the requested resource (Will be supported in the future). + content: {} + 404: + $ref: '#/components/responses/NotFound' + 406: + $ref: '#/components/responses/NotAcceptable' + security: + - OAuth2Security: + - apk:api_view + - apk:document_manage + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://api.am.wso2.com:9095/api/backoffice/v1/apis/01234567-0123-0123-0123-012345678901/documents/83312daf-0d8a-427b-8f72-12755b7901d3/content"' + operationId: getAPIDocumentContent + + post: + tags: + - API Documents + summary: Upload the Content of an API Document + description: | + This operation can be used to upload a file or add inline content to an API document. + + **IMPORTANT:** + * Either **file** or **inlineContent** form data parameters should be specified at one time. + * Document's source type should be **FILE** in order to upload a file to the document using **file** parameter. + * Document's source type should be **INLINE** in order to add inline content to the document using **inlineContent** parameter. + parameters: + - $ref: '#/components/parameters/apiId' + - $ref: '#/components/parameters/documentId' + - $ref: '#/components/parameters/If-Match' + requestBody: + content: + multipart/form-data: + schema: + properties: + file: + type: string + description: Document to upload + format: binary + inlineContent: + type: string + description: Inline content of the document + responses: + 200: + description: | + OK. + Document updated + headers: + ETag: + description: | + Entity Tag of the response resource. + Used by caches, or in conditional requests (Will be supported in the future). + schema: + type: string + Last-Modified: + description: | + Date and time the resource has been modified the last time. + Used by caches, or in conditional requests (Will be supported in the future). + schema: + type: string + Location: + description: | + The URL of the updated content of the document. + schema: + type: string + Content-Type: + description: | + The content type of the body. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/Document' + 400: + $ref: '#/components/responses/BadRequest' + 404: + $ref: '#/components/responses/NotFound' + 412: + $ref: '#/components/responses/PreconditionFailed' + security: + - OAuth2Security: + - apk:api_view + - apk:document_manage + x-code-samples: + - lang: Curl + source: 'curl -k -X POST -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + -H "Content-Type: multipart/form-data" -F file=@sample.pdf "https://api.am.wso2.com:9095/api/backoffice/v1/apis/01234567-0123-0123-0123-012345678901/documents/83312daf-0d8a-427b-8f72-12755b7901d3/content"' + operationId: addAPIDocumentContent + + /apis/{apiId}/comments: + get: + tags: + - Comments + summary: Retrieve API Comments + description: | + Get a list of Comments that are already added to APIs + operationId: getAllCommentsOfAPI + parameters: + - $ref: '#/components/parameters/apiId' + - $ref: '#/components/parameters/limit' + - $ref: '#/components/parameters/offset' + - $ref: '#/components/parameters/includeCommenterInfo' + responses: + 200: + description: | + OK. + Comments list is returned. + content: + application/json: + schema: + $ref: '#/components/schemas/CommentList' + 404: + $ref: '#/components/responses/NotFound' + 500: + $ref: '#/components/responses/InternalServerError' + security: + - OAuth2Security: + - apk:api_view + - apk:comment_view + - apk:comment_manage + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://localhost:9443/api/apk/backoffice/v1/apis/01234567-0123-0123-0123-012345678901/comments"' + + post: + tags: + - Comments + summary: Add an API Comment + operationId: addCommentToAPI + parameters: + - $ref: '#/components/parameters/apiId' + - $ref: '#/components/parameters/parentCommentID' + requestBody: + description: | + Comment object that should to be added + content: + application/json: + schema: + title: Post request body + type: object + properties: + content: + type: string + maxLength: 512 + description: | + Content of the comment + example: This is a comment + category: + type: string + description: | + Category of the comment + example: general + required: + - content + required: true + responses: + 201: + description: | + Created. + Successful response with the newly created object as entity in the body. + Location header contains URL of newly created entity. + headers: + ETag: + description: | + Entity Tag of the response resource. Used by caches, or in conditional request. + schema: + type: string + Location: + description: | + Location to the newly created Comment. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/Comment' + 400: + $ref: '#/components/responses/BadRequest' + 401: + $ref: '#/components/responses/Unauthorized' + 404: + $ref: '#/components/responses/NotFound' + 415: + $ref: '#/components/responses/UnsupportedMediaType' + 500: + $ref: '#/components/responses/InternalServerError' + security: + - OAuth2Security: + - apk:comment_write + - apk:comment_manage + x-code-samples: + - lang: Curl + source: 'curl -k -X POST -H "Authorization:Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + -H "Content-Type: application/json" -d @data.json "https://localhost:9443/api/apk/backoffice/v1/apis/e93fb282-b456-48fc-8981-003fb89086ae/comments"' + + /apis/{apiId}/comments/{commentId}: + get: + tags: + - Comments + summary: Get Details of an API Comment + description: | + Get the individual comment given by a username for a certain API. + operationId: getCommentOfAPI + parameters: + - $ref: '#/components/parameters/commentId' + - $ref: '#/components/parameters/apiId' + - $ref: '#/components/parameters/If-None-Match' + - $ref: '#/components/parameters/includeCommenterInfo' + - $ref: '#/components/parameters/replyLimit' + - $ref: '#/components/parameters/replyOffset' + responses: + 200: + description: | + OK. + Comment returned. + headers: + ETag: + description: | + Entity Tag of the response resource. + Used by caches, or in conditional requests. + schema: + type: string + Last-Modified: + description: | + Date and time the resource has been modified the last time. + Used by caches, or in conditional requests. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/Comment' + 401: + $ref: '#/components/responses/Unauthorized' + 404: + $ref: '#/components/responses/NotFound' + 406: + $ref: '#/components/responses/NotAcceptable' + 500: + $ref: '#/components/responses/InternalServerError' + security: + - OAuth2Security: + - apk:api_view + - apk:comment_view + - apk:comment_manage + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization:Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://localhost:9443/api/apk/backoffice/v1/apis/01234567-0123-0123-0123-012345678901/comments/d4cf1704-5d09-491c-bc48-4d19ce6ea9b4"' + + patch: + tags: + - Comments + summary: Edit a comment + description: | + Edit the individual comment + operationId: editCommentOfAPI + parameters: + - $ref: '#/components/parameters/commentId' + - $ref: '#/components/parameters/apiId' + requestBody: + description: | + Comment object that should to be updated + content: + application/json: + schema: + title: Patch request body + type: object + properties: + content: + type: string + maxLength: 512 + description: | + Content of the comment + example: This is a comment + category: + type: string + description: | + Category of the comment + example: general + required: true + responses: + 200: + description: | + OK. + Comment updated. + headers: + ETag: + description: | + Entity Tag of the response resource. Used by caches, or in conditional request. + schema: + type: string + Location: + description: | + Location to the newly created Comment. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/Comment' + 400: + $ref: '#/components/responses/BadRequest' + 401: + $ref: '#/components/responses/Unauthorized' + 403: + $ref: '#/components/responses/Forbidden' + 404: + $ref: '#/components/responses/NotFound' + 415: + $ref: '#/components/responses/UnsupportedMediaType' + 500: + $ref: '#/components/responses/InternalServerError' + security: + - OAuth2Security: + - apk:comment_write + - apk:comment_manage + x-code-samples: + - lang: Curl + source: 'curl -k -X PATCH -H "Authorization:Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + -H "Content-Type: application/json" -d @data.json "https://localhost:9443/api/apk/backoffice/v1/apis/01234567-0123-0123-0123-012345678901/comments/d4cf1704-5d09-491c-bc48-4d19ce6ea9b4"' + + delete: + tags: + - Comments + summary: Delete an API Comment + description: | + Remove a Comment + operationId: deleteComment + parameters: + - $ref: '#/components/parameters/commentId' + - $ref: '#/components/parameters/apiId' + - $ref: '#/components/parameters/If-Match' + responses: + 200: + description: | + OK. + Resource successfully deleted. + content: {} + 401: + $ref: '#/components/responses/Unauthorized' + 403: + $ref: '#/components/responses/Forbidden' + 404: + $ref: '#/components/responses/NotFound' + 405: + description: | + MethodNotAllowed. + Request method is known by the server but is not supported by the target resource. + content: {} + 500: + $ref: '#/components/responses/InternalServerError' + security: + - OAuth2Security: + - apk:comment_write + - apk:comment_manage + - apk:admin # special scope added to moderate other comments as well + x-code-samples: + - lang: Curl + source: curl -k -X DELETE -H "Authorization:Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://localhost:9443/api/apk/backoffice/v1/apis/01234567-0123-0123-0123-012345678901/comments/d4cf1704-5d09-491c-bc48-4d19ce6ea9b4" + + /apis/{apiId}/comments/{commentId}/replies: + get: + tags: + - Comments + summary: Get replies of a comment + description: | + Get replies of a comment + operationId: getRepliesOfComment + parameters: + - $ref: '#/components/parameters/commentId' + - $ref: '#/components/parameters/apiId' + - $ref: '#/components/parameters/limit' + - $ref: '#/components/parameters/offset' + - $ref: '#/components/parameters/If-None-Match' + - $ref: '#/components/parameters/includeCommenterInfo' + responses: + 200: + description: | + OK. + Comment returned. + headers: + ETag: + description: | + Entity Tag of the response resource. + Used by caches, or in conditional requests. + schema: + type: string + Last-Modified: + description: | + Date and time the resource has been modified the last time. + Used by caches, or in conditional requests. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/CommentList' + 401: + $ref: '#/components/responses/Unauthorized' + 404: + $ref: '#/components/responses/NotFound' + 406: + $ref: '#/components/responses/NotAcceptable' + 500: + $ref: '#/components/responses/InternalServerError' + security: + - OAuth2Security: + - apk:api_view + - apk:comment_view + - apk:comment_manage + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization:Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://localhost:9443/api/apk/backoffice/v1/apis/01234567-0123-0123-0123-012345678901/comments/d4cf1704-5d09-491c-bc48-4d19ce6ea9b4/replies"' + + + ###################################################### + # The "Subscription Collection" resource APIs + ###################################################### + /subscriptions: + get: + tags: + - Subscriptions + summary: Get all Subscriptions + description: | + This operation can be used to retrieve a list of subscriptions of the user associated with the provided access token. This operation is capable of + + 1. Retrieving all subscriptions for the user's APIs. + `GET https://api.am.wso2.com:9095/api/backoffice/v1/subscriptions` + + 2. Retrieving subscriptions for a specific API. + `GET https://api.am.wso2.com:9095/api/backoffice/v1/subscriptions?apiId=01234567-0123-0123-0123-012345678901` + parameters: + - $ref: '#/components/parameters/apiId-Q-Opt' + - $ref: '#/components/parameters/limit' + - $ref: '#/components/parameters/offset' + - $ref: '#/components/parameters/If-None-Match' + - name: query + in: query + description: | + Keywords to filter subscriptions + schema: + type: string + responses: + 200: + description: | + OK. + Subscription list returned. + headers: + ETag: + description: | + Entity Tag of the response resource. + Used by caches, or in conditional requests (Will be supported in the future). + schema: + type: string + Content-Type: + description: | + The content type of the body. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/SubscriptionList' + 304: + description: | + Not Modified. + Empty body because the client has already the latest version of the requested resource (Will be supported in the future). + content: {} + 406: + $ref: '#/components/responses/NotAcceptable' + security: + - OAuth2Security: + - apk:api_view + - apk:subscription_view + - apk:subscription_manage + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://api.am.wso2.com:9095/api/backoffice/v1/subscriptions?apiId=01234567-0123-0123-0123-012345678901"' + operationId: getSubscriptions + + /subscriptions/{subscriptionId}/subscriber-info: + get: + tags: + - Subscriber + summary: Get Details of a Subscriber + description: | + This operation can be used to get details of a user who subscribed to the API. + parameters: + - $ref: '#/components/parameters/subscriptionId' + responses: + 200: + description: | + OK. + Details of the subscriber are returned. + content: + application/json: + schema: + $ref: '#/components/schemas/SubscriberInfo' + 404: + $ref: '#/components/responses/NotFound' + security: + - OAuth2Security: + - apk:api_view + - apk:subscription_view + - apk:subscription_manage + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://api.am.wso2.com:9095/api/backoffice/v1/subscriptions/64eca60b-2e55-4c38-8603-e9e6bad7d809/subscriber-info"' + operationId: getSubscriberInfoBySubscriptionId + + /subscriptions/block-subscription: + post: + tags: + - Subscriptions + summary: Block a Subscription + description: | + This operation can be used to block a subscription. Along with the request, `blockState` must be specified as a query parameter. + + 1. `BLOCKED` : Subscription is completely blocked for both Production and Sandbox environments. + 2. `PROD_ONLY_BLOCKED` : Subscription is blocked for Production environment only. + parameters: + - $ref: '#/components/parameters/subscriptionId-Q' + - name: blockState + in: query + description: | + Subscription block state. + required: true + schema: + type: string + enum: + - BLOCKED + - PROD_ONLY_BLOCKED + - $ref: '#/components/parameters/If-Match' + responses: + 200: + description: | + OK. + Subscription was blocked successfully. + headers: + ETag: + description: | + Entity Tag of the blocked subscription. + Used by caches, or in conditional requests (Will be supported in the future). + schema: + type: string + Last-Modified: + description: | + Date and time the subscription has been blocked. + Used by caches, or in conditional requests (Will be supported in the future). + schema: + type: string + content: {} + 400: + $ref: '#/components/responses/BadRequest' + 404: + $ref: '#/components/responses/NotFound' + 412: + $ref: '#/components/responses/PreconditionFailed' + security: + - OAuth2Security: + - apk:subscription_block + - apk:subscription_manage + x-code-samples: + - lang: Curl + source: 'curl -k -X POST -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://api.am.wso2.com:9095/api/backoffice/v1/subscriptions/block-subscription?subscriptionId=64eca60b-2e55-4c38-8603-e9e6bad7d809&blockState=PROD_ONLY_BLOCKED"' + operationId: blockSubscription + + /subscriptions/unblock-subscription: + post: + tags: + - Subscriptions + summary: Unblock a Subscription + description: | + This operation can be used to unblock a subscription specifying the subscription Id. The subscription will be fully unblocked after performing this operation. + parameters: + - $ref: '#/components/parameters/subscriptionId-Q' + - $ref: '#/components/parameters/If-Match' + responses: + 200: + description: | + OK. + Subscription was unblocked successfully. + headers: + ETag: + description: | + Entity Tag of the unblocked subscription. + Used by caches, or in conditional requests (Will be supported in the future). + schema: + type: string + Last-Modified: + description: | + Date and time the subscription has been unblocked. + Used by caches, or in conditional requests (Will be supported in the future). + schema: + type: string + content: {} + 400: + $ref: '#/components/responses/BadRequest' + 404: + $ref: '#/components/responses/NotFound' + 412: + $ref: '#/components/responses/PreconditionFailed' + security: + - OAuth2Security: + - apk:subscription_block + - apk:subscription_manage + x-code-samples: + - lang: Curl + source: 'curl -k -X POST -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://api.am.wso2.com:9095/api/backoffice/v1/subscriptions/unblock-subscription?subscriptionId=64eca60b-2e55-4c38-8603-e9e6bad7d809"' + operationId: unBlockSubscription + + + ###################################################### + # The "Thorttling Tier Collection" resource APIs + ###################################################### + /usage-plans: + get: + tags: + - Usage Plan + summary: Get All Usage Plans + description: | + This operation can be used to list the available usage plans. + operationId: getAllUsagePlans + parameters: + - $ref: '#/components/parameters/limit' + - $ref: '#/components/parameters/offset' + - $ref: '#/components/parameters/If-None-Match' + responses: + 200: + description: | + OK. + List of policies returned. + headers: + ETag: + description: | + Entity Tag of the response resource. + Used by caches, or in conditional requests (Will be supported in the future). + schema: + type: string + Content-Type: + description: The content type of the body. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/UsagePlanList' + 304: + description: | + Not Modified. + Empty body because the client has already the latest version of the requested resource (Will be supported in the future). + content: {} + 406: + $ref: '#/components/responses/NotAcceptable' + security: + - OAuth2Security: + - apk:api_view + - apk:tier_view + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://api.am.wso2.com:9095/api/backoffice/v1/usage-plans"' + + ###################################################### + # The "Content Search Results" resource APIs + ###################################################### + /search: + get: + tags: + - Unified Search + summary: | + Retrieve/Search APIs and API Documents by Content + description: | + This operation provides you a list of available APIs and API Documents qualifying the given keyword match. + parameters: + - $ref: '#/components/parameters/limit' + - $ref: '#/components/parameters/offset' + - name: query + in: query + description: | + **Search**. + + You can search by proving a keyword. + schema: + type: string + - $ref: '#/components/parameters/If-None-Match' + responses: + 200: + description: | + OK. + List of qualifying APIs and API documents is returned. + headers: + ETag: + description: | + Entity Tag of the response resource. Used by caches, or in conditional requests (Will be supported in the future). + schema: + type: string + Content-Type: + description: The content type of the body. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/SearchResultList' + 304: + description: | + Not Modified. + Empty body because the client has already the latest version of the requested resource (Will be supported in the future). + content: {} + 406: + $ref: '#/components/responses/NotAcceptable' + security: + - OAuth2Security: + - apk:api_view + - apk:api_manage + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://api.am.wso2.com:9095/api/backoffice/v1/search?query=pizza"' + operationId: search + + ###################################################### + # The BackOffice settings resource APIs + ###################################################### + /settings: + get: + tags: + - Settings + summary: Retrieve BackOffice Settings + description: | + Retrieve BackOffice settings + responses: + 200: + description: | + OK. + Settings returned + content: + application/json: + schema: + $ref: '#/components/schemas/Settings' + 404: + $ref: '#/components/responses/NotFound' + security: + - OAuth2Security: + - apk:api_view + - apk:backoffice_settings + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://api.am.wso2.com:9095/api/backoffice/v1/settings"' + operationId: getSettings + + ###################################################### + # The "API Category Collection" resource API + ###################################################### + /api-categories: + get: + tags: + - API Category (Collection) + summary: Get all API categories + description: | + Get all API categories + responses: + 200: + description: | + OK. + Categories returned + content: + application/json: + schema: + $ref: '#/components/schemas/APICategoryList' + security: + - OAuth2Security: + - apk:api_view + - apk:api_manage + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://api.am.wso2.com:9095/api/backoffice/v1/api-categories"' + operationId: getAllAPICategories + + /apis/change-lifecycle: + post: + tags: + - API Lifecycle + summary: Change API LC Status + description: | + This operation is used to change the lifecycle of an API. + Eg: Publish an API which is in `CREATED` state. In order to change the lifecycle, we need to provide the + lifecycle `action` as a query parameter. + + For example, to Publish an API, `action` should be `Publish`. + + parameters: + - name: targetState + in: query + description: | + The action to demote or promote the state of the API. + + Supported actions are [ **Publish**, **Demote to Created**] + required: true + schema: + type: string + enum: + - Publish + - Demote to Created + - $ref: '#/components/parameters/apiId-Q' + - $ref: '#/components/parameters/If-Match' + responses: + 200: + description: | + OK. + Lifecycle changed successfully. + content: + application/json: + schema: + $ref: '#/components/schemas/LifecycleState' + 400: + $ref: '#/components/responses/BadRequest' + 401: + $ref: '#/components/responses/Unauthorized' + 404: + $ref: '#/components/responses/NotFound' + 409: + $ref: '#/components/responses/Conflict' + 500: + $ref: '#/components/responses/InternalServerError' + security: + - OAuth2Security: + - apk:api_publish + - apk:api_manage + x-code-samples: + - lang: Curl + source: 'curl -k -X POST -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://api.am.wso2.com:9095/api/backoffice/v1/apis/change-lifecycle?apiId=01234567-0123-0123-0123-012345678901&action=Publish"' + operationId: changeAPILifecycle + + /apis/{apiId}/lifecycle-history: + get: + tags: + - API Lifecycle + summary: Get Lifecycle State Change History of the APIs. + description: | + This operation can be used to retrieve Lifecycle state change history of the APIs. + parameters: + - $ref: '#/components/parameters/apiId' + - $ref: '#/components/parameters/If-None-Match' + responses: + 200: + description: | + OK. + Lifecycle state change history returned successfully. + content: + application/json: + schema: + $ref: '#/components/schemas/LifecycleHistory' + 401: + $ref: '#/components/responses/Unauthorized' + 404: + $ref: '#/components/responses/NotFound' + 500: + $ref: '#/components/responses/InternalServerError' + security: + - OAuth2Security: + - apk:api_publish + - apk:api_manage + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://api.am.wso2.com:9095/api/backoffice/v1/apis/01234567-0123-0123-0123-012345678901/lifecycle-history"' + operationId: getAPILifecycleHistory + + /apis/{apiId}/lifecycle-state: + get: + tags: + - API Lifecycle + summary: Get Lifecycle State Data of the API + description: | + This operation can be used to retrieve Lifecycle state data of the API. + parameters: + - $ref: '#/components/parameters/apiId' + - $ref: '#/components/parameters/If-None-Match' + responses: + 200: + description: | + OK. + Lifecycle state data returned successfully. + content: + application/json: + schema: + $ref: '#/components/schemas/LifecycleState' + 401: + $ref: '#/components/responses/Unauthorized' + 404: + $ref: '#/components/responses/NotFound' + 500: + $ref: '#/components/responses/InternalServerError' + security: + - OAuth2Security: + - apk:api_publish + - apk:api_create + - apk:api_manage + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://api.am.wso2.com:9095/api/backoffice/v1/apis/01234567-0123-0123-0123-012345678901/lifecycle-state"' + operationId: getAPILifecycleState +###################################################### +# The "Business Plans Collection" resource API +###################################################### + /business-plans: + get: + tags: + - Business Plan (Collection) + summary: Get all Business Plans + description: | + This operation can be used to retrieve all Business Plans + parameters: + - $ref: '#/components/parameters/Accept' + responses: + 200: + description: | + OK. + Plans returned + headers: + Content-Type: + description: | + The content type of the body. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/BusinessPlanList' + 406: + $ref: '#/components/responses/NotAcceptable' + security: + - OAuth2Security: + - apk:admin + - apk:tier_view + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://api.am.wso2.com:9095/api/backoffice/v1/business-plans"' + operationId: getAllBusinessPlans +components: + schemas: + APIDefinition: + title: API Schema + required: + - type + type: object + properties: + type: + type: string + enum: + - swagger + - graphql + - wsdl + - async + schemaDefinition: + type: string + Comment: + title: Comment + required: + - content + type: object + properties: + id: + type: string + readOnly: true + example: 943d3002-000c-42d3-a1b9-d6559f8a4d49 + content: + maxLength: 512 + type: string + example: This is a comment + createdTime: + type: string + readOnly: true + example : 2021-02-11-09:57:25 + createdBy: + type: string + readOnly: true + example: admin + updatedTime: + type: string + readOnly: true + example : 2021-02-12-19:57:25 + category: + type: string + readOnly: true + default: general + example : general + parentCommentId: + type: string + readOnly: true + example: 6f38aea2-f41e-4ac9-b3f2-a9493d00ba97 + entryPoint: + type: string + readOnly: true + enum: [devPortal, publisher] + commenterInfo: + $ref: '#/components/schemas/CommenterInfo' + replies: + $ref: '#/components/schemas/CommentList' + CommentList: + title: Comments List + type: object + properties: + count: + type: integer + readOnly: true + description: | + Number of Comments returned. + example: 1 + list: + type: array + readOnly: true + items: + $ref: '#/components/schemas/Comment' + pagination: + $ref: '#/components/schemas/Pagination' + CommenterInfo: + type: object + properties: + firstName: + type: string + example: John + lastName: + type: string + example: David + fullName: + type: string + example: John David + APIList: + title: API List + type: object + properties: + count: + type: integer + description: | + Number of APIs returned. + example: 1 + list: + type: array + items: + $ref: '#/components/schemas/APIInfo' + pagination: + $ref: '#/components/schemas/Pagination' + + APIInfo: + title: API Info object with basic API details. + type: object + properties: + id: + type: string + example: 01234567-0123-0123-0123-012345678901 + name: + type: string + example: CalculatorAPI + description: + type: string + example: A calculator API that supports basic operations + context: + type: string + example: CalculatorAPI + version: + type: string + example: 1.0.0 + type: + type: string + example: HTTP + createdTime: + type: string + example : 2021-02-11 09:57:25 + updatedTime: + type: string + example : 2021-02-11 09:57:25 + hasThumbnail: + type: boolean + example: true + state: + type: string + description: | + State of the API. Only published APIs are visible on the Developer Portal + enum: + - CREATED + - PUBLISHED + + API: + title: API object + required: + - context + - name + - version + type: object + properties: + id: + type: string + description: | + UUID of the API + readOnly: true + example: 01234567-0123-0123-0123-012345678901 + name: + maxLength: 60 + minLength: 1 + pattern: '(^[^~!@#;:%^*()+={}|\\<>"'',&$\[\]\/]*$)' + type: string + example: PizzaShackAPI + description: + maxLength: 32766 + type: string + example: This is a simple API for Pizza Shack online pizza delivery store. + context: + maxLength: 232 + minLength: 1 + type: string + example: pizza + version: + maxLength: 30 + minLength: 1 + type: string + pattern: '^[^~!@#;:%^*()+={}|\\<>"'',&/$\[\]\s+\/]+$' + example: 1.0.0 + type: + type: string + description: The api creation type to be used. Accepted values are HTTP, + WS, SOAPTOREST, GRAPHQL, WEBSUB, SSE, WEBHOOK, ASYNC + example: HTTP + default: HTTP + enum: + - HTTP + - WS + - SOAPTOREST + - SOAP + - GRAPHQL + - WEBSUB + - SSE + - WEBHOOK + - ASYNC + transport: + type: array + description: | + Supported transports for the API (http and/or https). + example: + - http + - https + items: + type: string + hasThumbnail: + type: boolean + example: false + state: + type: string + description: | + State of the API. Only published APIs are visible on the Developer Portal + default: CREATED + enum: + - CREATED + - PUBLISHED + tags: + type: array + example: + - pizza + - food + items: + type: string + categories: + type: array + description: | + API categories + example: [] + items: + type: string + sdk: + type: array + description: | + Supported SDK + example: [] + items: + type: string + policies: + type: array + example: + - Unlimited + items: + type: string + additionalProperties: + type: object + additionalProperties: + type: object + properties: + name: + type: string + value: + type: string + display: + type: boolean + default: false + createdTime: + type: string + lastUpdatedTime: + type: string + operations: + type: array + example: + - target: /order/{orderId} + verb: POST + usagePlan: Unlimited + - target: /menu + verb: GET + usagePlan: Unlimited + items: + $ref: '#/components/schemas/APIOperations' + apiUsagePolicy: + type: string + description: The API level usage policy selected for the particular Runtime + API + example: Unlimited + monetization: + $ref: '#/components/schemas/APIMonetizationInfo' + businessInformation: + $ref: '#/components/schemas/APIBusinessInformation' + revision: + $ref: '#/components/schemas/APIRevision' + deployments: + type: array + readOnly: true + example: + - name: US + deployedTime: 2022-10-28T06:13:35.024Z + - name: Europe + deployedTime: 2022-10-28T06:13:35.024Z + items: + $ref: '#/components/schemas/APIDeployment' + + BusinessPlanList: + title: Business Plan List + type: object + properties: + count: + type: integer + description: | + Number of Business Plans returned. + example: 1 + list: + type: array + items: + $ref: '#/components/schemas/BusinessPlan' + BusinessPlan: + title: Business Plan + allOf: + - required: + - defaultLimit + type: object + properties: + defaultLimit: + $ref: '#/components/schemas/ThrottleLimit' + rateLimitCount: + type: integer + description: Burst control request count + example: 10 + rateLimitTimeUnit: + type: string + description: Burst control time unit + example: min + subscriberCount: + type: integer + description: Number of subscriptions allowed + example: 10 + customAttributes: + type: array + description: | + Custom attributes added to the Subscription Throttling Policy + example: [] + items: + $ref: '#/components/schemas/CustomAttribute' + permissions: + $ref: '#/components/schemas/BusinessPlanPermission' + BusinessPlanPermission: + title: Business Plan Permission + required: + - permissionType + - roles + type: object + properties: + permissionType: + type: string + example: deny + enum: + - ALLOW + - DENY + roles: + type: array + example: + - Internal/everyone + items: + type: string + ThrottleLimit: + title: Throttle Limit + required: + - type + type: object + properties: + type: + type: string + description: | + Type of the throttling limit. Allowed values are "REQUESTCOUNTLIMIT" and "BANDWIDTHLIMIT". + Please see schemas of "RequestCountLimit" and "BandwidthLimit" throttling limit types in + Definitions section. + example: REQUESTCOUNTLIMIT + enum: + - REQUESTCOUNTLIMIT + - BANDWIDTHLIMIT + - EVENTCOUNTLIMIT + requestCount: + $ref: '#/components/schemas/RequestCountLimit' + bandwidth: + $ref: '#/components/schemas/BandwidthLimit' + eventCount: + $ref: '#/components/schemas/EventCountLimit' + #----------------------------------------------------- + # The API Revision resource + #----------------------------------------------------- + APIRevision: + title: Object with basic API Revision details + properties: + displayName: + type: string + readOnly: true + example: REVISION 1 + id: + type: string + readOnly: true + example: c26b2b9b-4632-4ca4-b6f3-521c8863990c + description: + maxLength: 255 + minLength: 0 + type: string + example: removed a post resource + createdTime: + readOnly: true + type: string + format: date-time + #----------------------------------------------------- + # The API Revision Deployment resource + #----------------------------------------------------- + APIDeployment: + title: Basic API deployment details + properties: + name: + maxLength: 255 + minLength: 1 + type: string + example: Europe + deployedTime: + readOnly: true + type: string + format: date-time + ModifiableAPI: + title: Modifiable API object + required: + - name + type: object + properties: + id: + type: string + description: | + UUID of the API + readOnly: true + example: 01234567-0123-0123-0123-012345678901 + name: + maxLength: 50 + minLength: 1 + type: string + description: Name of the API + example: PizzaShackAPI + context: + maxLength: 60 + minLength: 1 + type: string + example: pizzaproduct + description: + type: string + description: A brief description about the API + example: This is a simple API for Pizza Shack online pizza delivery store + hasThumbnail: + type: boolean + example: false + state: + type: string + description: | + State of the API. Only published APIs are visible on the Developer Portal + default: CREATED + enum: + - CREATED + - PUBLISHED + tags: + type: array + example: + - pizza + - food + items: + type: string + additionalProperties: + type: object + additionalProperties: + type: object + properties: + name: + type: string + value: + type: string + display: + type: boolean + default: false + monetization: + $ref: '#/components/schemas/APIMonetizationInfo' + businessInformation: + $ref: '#/components/schemas/APIBusinessInformation' + categories: + type: array + description: | + API categories + example: [] + items: + type: string + sdk: + type: array + description: | + Supported SDK + example: [] + items: + type: string + policies: + type: array + example: + - Unlimited + items: + type: string + ResourcePath: + title: ResourcePath + required: + - id + type: object + properties: + id: + type: integer + example: 1 + resourcePath: + type: string + example: /menu + httpVerb: + type: string + example: GET + ResourcePathList: + title: ResourcePath List + type: object + properties: + count: + type: integer + description: | + Number of API Resource Paths returned. + example: 1 + list: + type: array + items: + $ref: '#/components/schemas/ResourcePath' + pagination: + $ref: '#/components/schemas/Pagination' + APIBusinessInformation: + type: object + properties: + businessOwner: + maxLength: 120 + type: string + example: businessowner + businessOwnerEmail: + type: string + example: businessowner@wso2.com + technicalOwner: + maxLength: 120 + type: string + example: technicalowner + technicalOwnerEmail: + type: string + example: technicalowner@wso2.com + SubscriberInfo: + title: SubscriberInfo + type: object + properties: + name: + type: string + example: admin + ApplicationInfo: + title: Application info object with basic application details + type: object + properties: + applicationId: + type: string + example: 01234567-0123-0123-0123-012345678901 + name: + type: string + example: CalculatorApp + subscriber: + type: string + example: admin + description: + type: string + example: Sample calculator application + subscriptionCount: + type: integer + DocumentList: + title: Document List + type: object + properties: + count: + type: integer + description: | + Number of Documents returned. + example: 1 + list: + type: array + items: + $ref: '#/components/schemas/Document' + pagination: + $ref: '#/components/schemas/Pagination' + Document: + title: Document + required: + - name + - sourceType + - type + - visibility + type: object + properties: + documentId: + type: string + readOnly: true + example: 01234567-0123-0123-0123-012345678901 + name: + maxLength: 60 + minLength: 1 + type: string + example: PizzaShackDoc + documentType: + type: string + example: HOWTO + enum: + - HOWTO + - SAMPLES + - PUBLIC_FORUM + - SUPPORT_FORUM + - API_MESSAGE_FORMAT + - SWAGGER_DOC + - OTHER + summary: + maxLength: 32766 + minLength: 1 + type: string + example: Summary of PizzaShackAPI Documentation + sourceType: + type: string + example: INLINE + enum: + - INLINE + - MARKDOWN + - URL + - FILE + sourceUrl: + type: string + readOnly: true + example: "" + fileName: + type: string + readOnly: true + example: "" + inlineContent: + type: string + example: This is doc content. This can have many lines. + otherTypeName: + type: string + readOnly: true + example: "" + visibility: + type: string + example: API_LEVEL + enum: + - OWNER_ONLY + - PRIVATE + - API_LEVEL + createdTime: + type: string + readOnly: true + createdBy: + type: string + example: admin + lastUpdatedTime: + type: string + readOnly: true + lastUpdatedBy: + type: string + readOnly: true + example: admin + UsagePlanList: + title: Usage Plan list + type: object + properties: + count: + type: integer + description: | + Number of Usage Plans returned. + example: 1 + list: + type: array + description: | + Array of Usage Policies + items: + $ref: '#/components/schemas/UsagePlan' + pagination: + $ref: '#/components/schemas/Pagination' + SubscriptionList: + title: Subscription List + type: object + properties: + count: + type: integer + description: | + Number of Subscriptions returned. + example: 1 + list: + type: array + items: + $ref: '#/components/schemas/Subscription' + pagination: + $ref: '#/components/schemas/Pagination' + Subscription: + title: Subscription + required: + - applicationInfo + - subscriptionId + - subscriptionStatus + - usagePlan + type: object + properties: + subscriptionId: + type: string + example: 01234567-0123-0123-0123-012345678901 + applicationInfo: + $ref: '#/components/schemas/ApplicationInfo' + usagePlan: + type: string + example: Unlimited + subscriptionStatus: + type: string + example: BLOCKED + enum: + - BLOCKED + - PROD_ONLY_BLOCKED + - UNBLOCKED + - ON_HOLD + - REJECTED + - TIER_UPDATE_PENDING + - DELETE_PENDING + UsageLimitBase: + title: Throttle Limit Base + required: + - timeUnit + - unitTime + type: object + properties: + timeUnit: + type: string + description: Unit of the time. Allowed values are "sec", "min", "hour", + "day" + example: min + unitTime: + type: integer + description: Time limit that the usage limit applies. + example: 10 + UsageLimit: + title: Usage Limit + required: + - type + type: object + properties: + type: + type: string + description: | + Type of the usage limit. Allowed values are "REQUESTCOUNTLIMIT" and "BANDWIDTHLIMIT". + Please see schemas of "RequestCountLimit" and "BandwidthLimit" usage limit types in + Definitions section. + example: REQUESTCOUNTLIMIT + enum: + - REQUESTCOUNTLIMIT + - BANDWIDTHLIMIT + - EVENTCOUNTLIMIT + requestCount: + $ref: '#/components/schemas/RequestCountLimit' + bandwidth: + $ref: '#/components/schemas/BandwidthLimit' + eventCount: + $ref: '#/components/schemas/EventCountLimit' + + BandwidthLimit: + title: Bandwidth Limit object + allOf: + - $ref: '#/components/schemas/UsageLimitBase' + - required: + - dataAmount + - dataUnit + type: object + properties: + dataAmount: + type: integer + description: Amount of data allowed to be transferred + format: int64 + example: 1000 + dataUnit: + type: string + description: Unit of data allowed to be transferred. Allowed values are + "KB", "MB" and "GB" + example: KB + RequestCountLimit: + title: Request Count Limit object + allOf: + - $ref: '#/components/schemas/UsageLimitBase' + - required: + - requestCount + type: object + properties: + requestCount: + type: integer + description: Maximum number of requests allowed + format: int64 + example: 30 + EventCountLimit: + title: Event Count Limit object + allOf: + - $ref: '#/components/schemas/UsageLimitBase' + - required: + - eventCount + type: object + properties: + eventCount: + type: integer + description: Maximum number of events allowed + format: int64 + example: 3000 + UsagePlan: + title: Usage Plan + allOf: + - required: + - defaultLimit + type: object + properties: + policyId: + type: integer + description: Id of policy + example: 1 + uuid: + type: string + description: policy uuid + example: 0c6439fd-9b16-3c2e-be6e-1086e0b9aa93 + policyName: + maxLength: 60 + minLength: 1 + type: string + description: Name of policy + example: 30PerMin + displayName: + type: string + description: Display name of the policy + example: 30PerMin + maxLength: 512 + description: + maxLength: 1024 + type: string + description: Description of the policy + example: Allows 30 request per minute + organization: + type: string + description: Usage policy organization + example: wso2 + defaultLimit: + $ref: '#/components/schemas/UsageLimit' + rateLimitCount: + type: integer + description: Burst control request count + example: 10 + rateLimitTimeUnit: + type: string + description: Burst control time unit + example: min + subscriberCount: + type: integer + description: Number of subscriptions allowed + example: 10 + customAttributes: + type: array + description: | + Custom attributes added to the Usage plan + example: [ ] + items: + $ref: '#/components/schemas/CustomAttribute' + stopOnQuotaReach: + type: boolean + description: | + This indicates the action to be taken when a user goes beyond the allocated quota. If checked, the user's requests will be dropped. If unchecked, the requests will be allowed to pass through. + default: false + billingPlan: + type: string + description: | + define whether this is Paid or a Free plan. Allowed values are FREE or COMMERCIAL. + example: FREE + permissions: + $ref: '#/components/schemas/SubscriptionThrottlePolicyPermission' + CustomAttribute: + title: Name-Value pair + required: + - name + - value + type: object + properties: + name: + type: string + description: Name of the custom attribute + example: customAttr1 + value: + type: string + description: Value of the custom attribute + example: value1 + SubscriptionThrottlePolicyPermission: + title: SubscriptionThrottlePolicyPermission + required: + - permissionType + - roles + type: object + properties: + permissionType: + type: string + example: deny + enum: + - ALLOW + - DENY + roles: + type: array + example: + - Internal/everyone + items: + type: string + APIMonetizationUsage: + title: API monetization usage object + type: object + properties: + properties: + type: object + additionalProperties: + type: string + description: Map of custom properties related to monetization usage + APIRevenue: + title: API revenue data object + type: object + properties: + properties: + type: object + additionalProperties: + type: string + description: Map of custom properties related to API revenue + Error: + title: Error object returned with 4XX HTTP Status + required: + - code + - message + type: object + properties: + code: + type: integer + format: int64 + message: + type: string + description: Error message. + description: + type: string + description: | + A detail description about the error message. + moreInfo: + type: string + description: | + Preferably an url with more details about the error. + error: + type: array + description: | + If there are more than one error list them out. + For example, list out validation errors by each field. + items: + $ref: '#/components/schemas/ErrorListItem' + ErrorListItem: + title: Description of individual errors that may have occurred during a request. + required: + - code + - message + type: object + properties: + code: + type: string + message: + type: string + description: | + Description about individual errors occurred + description: + type: string + description: | + A detail description about the error message. + Environment: + title: Environment + required: + - id + - name + - serverUrl + - showInApiConsole + - type + type: object + properties: + id: + type: string + name: + type: string + example: default + displayName: + type: string + example: Default + type: + type: string + example: hybrid + serverUrl: + type: string + example: https://localhost:9443/services/ + provider: + type: string + example: wso2 + showInApiConsole: + type: boolean + example: true + endpointURIs: + type: array + items: + $ref: '#/components/schemas/GatewayEnvironmentProtocolURI' + additionalProperties: + type: array + items: + $ref: '#/components/schemas/AdditionalProperty' + AdditionalProperty: + title: Additional Gateway Properties + type: object + properties: + key: + type: string + example: Organization + value: + type: string + example: wso2 + FileInfo: + title: File Information including meta data + type: object + properties: + fileName: + type: string + description: name of the file + example: thumbnail.png + mediaType: + type: string + description: media-type of the file + example: image/jpeg + Scope: + title: Scope + required: + - name + type: object + properties: + id: + type: string + description: | + UUID of the Scope. Valid only for shared scopes. + readOnly: true + example: 01234567-0123-0123-0123-012345678901 + name: + maxLength: 255 + minLength: 1 + type: string + description: | + name of Scope + example: apk:api_view + displayName: + maxLength: 255 + type: string + description: | + display name of Scope + example: api_view + description: + maxLength: 512 + type: string + description: | + description of Scope + example: This Scope can used to view Apis + bindings: + type: array + description: | + role bindings list of the Scope + example: + - admin + - Internal/creator + - Internal/publisher + items: + type: string + usageCount: + type: integer + description: | + usage count of Scope + readOnly: true + example: 3 + APIScope: + title: APIScope + required: + - scope + type: object + properties: + scope: + $ref: '#/components/schemas/Scope' + APIOperations: + title: Operation + type: object + properties: + id: + type: string + example: postapiresource + target: + type: string + example: /order/{orderId} + verb: + type: string + example: POST + usagePlan: + type: string + example: Unlimited + ExternalStore: + title: External Store + type: object + properties: + id: + type: string + description: | + The external store identifier, which is a unique value. + example: Store123# + displayName: + type: string + description: | + The name of the external API Store that is displayed in the Publisher UI. + example: UKStore + type: + type: string + description: | + The type of the Store. This can be a WSO2-specific API Store or an external one. + example: wso2 + endpoint: + type: string + description: | + The endpoint URL of the external store + example: http://localhost:9764/store + APIExternalStore: + title: API External Store + type: object + properties: + id: + type: string + description: | + The external store identifier, which is a unique value. + example: Store123# + lastUpdatedTime: + type: string + description: | + The recent timestamp which a given API is updated in the external store. + example: 2019-09-09T13:57:16.229 + APIExternalStoreList: + title: API External Store List + type: object + properties: + count: + type: integer + description: | + Number of external stores returned. + example: 1 + list: + type: array + items: + $ref: '#/components/schemas/APIExternalStore' + ExternalStoreList: + title: External Store List + type: object + properties: + count: + type: integer + description: | + Number of external stores returned. + example: 1 + list: + type: array + items: + $ref: '#/components/schemas/ExternalStore' + LifecycleState: + title: Lifecycle State + type: object + properties: + state: + type: string + example: Created + availableTransitions: + type: array + items: + type: object + properties: + event: + type: string + example: Publish + targetState: + type: string + example: Published + LifecycleHistory: + title: Lifecycle history item list + type: object + properties: + count: + type: integer + example: 1 + list: + type: array + items: + $ref: '#/components/schemas/LifecycleHistoryItem' + LifecycleHistoryItem: + title: Lifecycle history item + type: object + properties: + previousState: + type: string + example: Created + postState: + type: string + example: Published + user: + type: string + example: admin + updatedTime: + type: string + format: dateTime + example: 2019-02-31T23:59:60Z + WorkflowResponse: + title: workflow Response + required: + - workflowStatus + type: object + properties: + workflowStatus: + type: string + description: | + This attribute declares whether this workflow task is approved or rejected. + example: APPROVED + enum: + - CREATED + - APPROVED + - REJECTED + - REGISTERED + jsonPayload: + type: string + description: | + Attributes that returned after the workflow execution + example: null + lifecycleState: + $ref: '#/components/schemas/LifecycleState' + ThreatProtectionPolicy: + title: Threat Protection Policy Schema + required: + - name + - policy + - type + type: object + properties: + uuid: + type: string + description: Policy ID + name: + type: string + description: Name of the policy + type: + type: string + description: Type of the policy + policy: + type: string + description: policy as a json string + SearchResult: + title: Search Result + required: + - name + type: object + properties: + id: + type: string + example: 01234567-0123-0123-0123-012345678901 + name: + type: string + example: TestAPI + type: + type: string + example: API + enum: + - DOC + - API + transportType: + type: string + description: Accepted values are HTTP, WS, SOAPTOREST, GRAPHQL + discriminator: + propertyName: name + SearchResultList: + title: Unified Search Result List + type: object + properties: + count: + type: integer + description: | + Number of results returned. + example: 1 + list: + type: array + items: + type: object + pagination: + $ref: '#/components/schemas/Pagination' + APIMonetizationInfo: + title: API monetization object + required: + - enabled + type: object + properties: + enabled: + type: boolean + description: Flag to indicate the monetization status + example: true + properties: + type: object + additionalProperties: + type: string + description: Map of custom properties related to monetization + Settings: + title: SettingsDTO + type: object + properties: + devportalUrl: + type: string + description: The Developer Portal URL + example: https://localhost:9443/devportal + environment: + type: array + items: + $ref: '#/components/schemas/Environment' + monetizationAttributes: + type: array + example: [] + items: + $ref: '#/components/schemas/MonetizationAttribute' + docVisibilityEnabled: + type: boolean + description: | + Is Document Visibility configuration enabled + example: false + authorizationHeader: + type: string + description: Authorization Header + example: authorization + Pagination: + title: Pagination + type: object + properties: + offset: + type: integer + example: 0 + limit: + type: integer + example: 1 + total: + type: integer + example: 10 + next: + type: string + description: | + Link to the next subset of resources qualified. + Empty if no more resources are to be returned. + previous: + type: string + description: | + Link to the previous subset of resources qualified. + Empty if current subset is the first subset returned. + MonetizationAttribute: + title: Monetization attribute object + type: object + properties: + required: + type: boolean + description: | + Is attribute required + example: true + name: + type: string + description: | + Name of the attribute + displayName: + type: string + description: | + Display name of the attribute + description: + type: string + description: | + Description of the attribute + hidden: + type: boolean + description: | + Is attribute hidden + default: + type: string + description: | + Default value of the attribute + APICategory: + title: API Category + required: + - name + type: object + properties: + id: + type: string + example: 01234567-0123-0123-0123-012345678901 + name: + type: string + example: Finance + description: + type: string + example: Finance related APIs + APICategoryList: + title: API Category List + type: object + properties: + count: + type: integer + description: | + Number of API categories returned. + example: 1 + list: + type: array + items: + $ref: '#/components/schemas/APICategory' + GatewayEnvironmentProtocolURI: + title: Gateway Environment protocols and URIs + required: + - protocol + - endpointURI + type: object + properties: + protocol: + type: string + example: default + endpointURI: + type: string + example: default + responses: + BadRequest: + description: Bad Request. Invalid request or validation error. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + example: + code: 400 + message: Bad Request + description: Invalid request or validation error + moreInfo: "" + error: [] + Conflict: + description: Conflict. Specified resource already exists. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + example: + code: 409 + message: Conflict + description: Specified resource already exists + moreInfo: "" + error: [] + Forbidden: + description: Forbidden. The request must be conditional but no condition has + been specified. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + example: + code: 403 + message: Forbidden + description: The request must be conditional but no condition has been + specified + moreInfo: "" + error: [] + InternalServerError: + description: Internal Server Error. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + example: + code: 500 + message: Internal Server Error + description: The server encountered an internal error. Please contact + administrator. + moreInfo: "" + error: [] + NotAcceptable: + description: Not Acceptable. The requested media type is not supported. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + example: + code: 406 + message: Not Acceptable + description: The requested media type is not supported + moreInfo: "" + error: [] + NotFound: + description: Not Found. The specified resource does not exist. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + example: + code: 404 + message: Not Found + description: The specified resource does not exist + moreInfo: "" + error: [] + PreconditionFailed: + description: Precondition Failed. The request has not been performed because + one of the preconditions is not met. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + example: + code: 412 + message: Precondition Failed + description: The request has not been performed because one of the preconditions + is not met + moreInfo: "" + error: [] + Unauthorized: + description: Unauthorized. The user is not authorized. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + example: + code: 401 + message: Unauthorized + description: The user is not authorized + moreInfo: "" + error: [] + UnsupportedMediaType: + description: Unsupported Media Type. The entity of the request was not in a + supported format. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + example: + code: 415 + message: Unsupported media type + description: The entity of the request was not in a supported format + moreInfo: "" + error: [] + parameters: + replyLimit: + name: replyLimit + in: query + description: | + Maximum size of replies array to return. + schema: + type: integer + default: 25 + replyOffset: + name: replyOffset + in: query + description: | + Starting point within the complete list of replies. + schema: + type: integer + default: 0 + commentId: + name: commentId + in: path + description: | + Comment Id + required: true + schema: + type: string + parentCommentID: + name: replyTo + in: query + description: | + ID of the parent comment. + schema: + type: string + includeCommenterInfo: + name: includeCommenterInfo + in: query + description: | + Whether we need to display commenter details. + schema: + type: boolean + default : false + apiId: + name: apiId + in: path + description: | + **API ID** consisting of the **UUID** of the API. + required: true + schema: + type: string + endpointId: + name: endpointId + in: path + description: | + **Endpoint ID** consisting of the **UUID** of the Endpoint**. + required: true + schema: + type: string + apiId-Q: + name: apiId + in: query + description: | + **API ID** consisting of the **UUID** of the API. + The combination of the provider of the API, name of the API and the version is also accepted as a valid API I. + Should be formatted as **provider-name-version**. + required: true + schema: + type: string + apiId-Q-Opt: + name: apiId + in: query + description: | + **API ID** consisting of the **UUID** of the API. + The combination of the provider of the API, name of the API and the version is also accepted as a valid API I. + Should be formatted as **provider-name-version**. + schema: + type: string + labelType-Q: + name: labelType + in: query + description: | + **API ID** consisting of the **UUID** of the API. + The combination of the provider of the API, name of the API and the version is also accepted as a valid API I. + Should be formatted as **provider-name-version**. + schema: + type: string + name: + name: name + in: path + description: | + Name of the API + required: true + schema: + type: string + version: + name: version + in: path + description: | + Version of the API + required: true + schema: + type: string + apiName-Q: + name: name + in: query + description: | + Name of the API + schema: + type: string + apiVersion-Q: + name: version + in: query + description: | + Version of the API + schema: + type: string + apiProvider-Q: + name: providerName + in: query + description: | + Provider name of the API + schema: + type: string + documentId: + name: documentId + in: path + description: | + Document Identifier + required: true + schema: + type: string + applicationId: + name: applicationId + in: path + description: | + **Application Identifier** consisting of the UUID of the Application. + required: true + schema: + type: string + subscriptionId: + name: subscriptionId + in: path + description: | + Subscription Id + required: true + schema: + type: string + resourcePolicyId: + name: resourcePolicyId + in: path + description: | + registry resource Id + required: true + schema: + type: string + subscriptionId-Q: + name: subscriptionId + in: query + description: | + Subscription Id + required: true + schema: + type: string + operationPolicyId: + name: operationPolicyId + in: path + description: | + Operation policy Id + required: true + schema: + type: string + + # API Revision Identifier + # Specified as part of the path expression + revisionId: + name: revisionId + in: path + description: | + Revision ID of an API + required: true + schema: + type: string + + # API Revision Identifier + # Specified as part of the query string + revisionId-Q: + name: revisionId + in: query + description: | + Revision ID of an API + schema: + type: string + revisionNum-Q: + name: revisionNumber + in: query + description: | + Revision Number of an API + schema: + type: string + deploymentId: + name: deploymentId + in: path + description: | + Base64 URL encoded value of the name of an environment + required: true + schema: + type: string + policyName: + name: policyName + in: path + description: | + Tier name + required: true + schema: + type: string + policyName-Q: + name: policyName + in: query + description: | + Name of the policy + required: true + schema: + type: string + policyLevel: + name: policyLevel + in: path + description: | + List API or Application or Resource type policies. + required: true + schema: + type: string + enum: + - api + - subcription + policyLevel-Q: + name: policyLevel + in: query + description: | + List API or Application or Resource type policies. + required: true + schema: + type: string + enum: + - api + - subcription + limit: + name: limit + in: query + description: | + Maximum size of resource array to return. + schema: + type: integer + default: 25 + policyLimit: + name: limit + in: query + description: | + Maximum size of policy array to return. + schema: + type: integer + Accept: + name: Accept + in: header + description: | + Media types acceptable for the response. Default is application/json. + schema: + type: string + default: application/json + offset: + name: offset + in: query + description: | + Starting point within the complete list of items qualified. + schema: + type: integer + default: 0 + sortBy: + name: sortBy + in: query + description: | + Criteria for sorting. + schema: + type: string + default: createdTime + enum: + - apiName + - version + - createdTime + - status + sortOrder: + name: sortOrder + in: query + description: | + Order of sorting(ascending/descending). + schema: + type: string + default: desc + enum: + - asc + - desc + If-None-Match: + name: If-None-Match + in: header + description: | + Validator for conditional requests; based on the ETag of the formerly retrieved + variant of the resource. + schema: + type: string + If-Match: + name: If-Match + in: header + description: | + Validator for conditional requests; based on ETag. + schema: + type: string + scopeName: + name: scopeId + in: path + description: | + Base64 URL encoded value of the scope name + required: true + schema: + type: string + scopeId: + name: scopeId + in: path + description: | + Scope Id consisting the UUID of the shared scope + required: true + schema: + type: string + threatProtectionPolicyId: + name: policyId + in: path + description: | + The UUID of a Policy + required: true + schema: + type: string + roleId: + name: roleId + in: path + description: | + The Base 64 URL encoded role name with domain. If the given role is in secondary user-store, role ID should be + derived as Base64URLEncode({user-store-name}/{role-name}). If the given role is in PRIMARY user-store, role ID + can be derived as Base64URLEncode(role-name) + required: true + schema: + type: string + alertType: + name: alertType + in: path + description: The alert type. + required: true + schema: + type: string + configurationId: + name: configurationId + in: path + description: The alert configuration id. + required: true + schema: + type: string + tierQuotaType: + name: tierQuotaType + description: Filter the subscription base on tier quota type + in: query + schema: + type: string + envId: + name: envId + in: path + description: | + **Env ID** consisting of the **UUID** of the gateway environment. + required: true + schema: + type: string + requestBodies: + threatProtectionPolicy: + description: | + Threat protection policy request parameter + content: + application/json: + schema: + $ref: '#/components/schemas/ThreatProtectionPolicy' + required: true + securitySchemes: + OAuth2Security: + type: oauth2 + flows: + password: + tokenUrl: https://localhost:9443/oauth2/token + scopes: + type: array + items: test diff --git a/backoffice/backoffice-domain-service/ballerina/modules/backoffice/resources/backoffice-internal-api.yaml b/backoffice/backoffice-domain-service/ballerina/modules/backoffice/resources/backoffice-internal-api.yaml new file mode 100644 index 000000000..c97303b87 --- /dev/null +++ b/backoffice/backoffice-domain-service/ballerina/modules/backoffice/resources/backoffice-internal-api.yaml @@ -0,0 +1,1074 @@ +# Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. +# +# 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. +################################################################################ +openapi: 3.0.1 +info: + title: WSO2 API Manager - Backoffice Internal REST API + description: | + This document specifies a **RESTful Internal API** for WSO2 **APK** - **BackOffice**. + contact: + name: WSO2 + url: https://wso2.com/api-manager/ + email: architecture@wso2.com + license: + name: Apache 2.0 + url: http://www.apache.org/licenses/LICENSE-2.0.html + version: v1 +servers: + - url: https://apis.wso2.com/api/backoffice +paths: + ###################################################### + # The "API Collection" resource APIs + ###################################################### + /apis: + post: + tags: + - APIs + summary: Create a New API + description: | + This operation can be used to create a new API specifying the details of the API in the payload. The new API will be in `CREATED` state. + + There is a special capability for a user who has `APIM Admin` permission such that he can create APIs on behalf of other users. For that he can to specify `"provider" : "some_other_user"` in the payload so that the API's creator will be shown as `some_other_user` in the UI. + operationId: createAPI + requestBody: + content: + multipart/form-data: + schema: + $ref: '#/components/schemas/APIBody' + required: true + responses: + 201: + description: | + Created. + Successful response with the newly created object as entity in the body. + Location header contains URL of newly created entity. + headers: + ETag: + description: | + Entity Tag of the response resource. Used by caches, or in conditional requests (Will be supported in future). + schema: + type: string + Location: + description: | + The URL of the newly created resource. + schema: + type: string + Content-Type: + description: | + The content type of the body. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/API' + 400: + $ref: '#/components/responses/BadRequest' + 415: + $ref: '#/components/responses/UnsupportedMediaType' + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + -F file=@openapi.json -F additionalProperties=@data.json "https://127.0.0.1:9443/api/publisher/v3/apis/import-openapi"' + + ###################################################### + # The "Individual API" resource APIs + ###################################################### + /apis/{apiId}: + get: + tags: + - APIs + summary: Get Details of an API + description: | + Using this operation, you can retrieve complete details of a single API. You need to provide the Id of the API to retrive it. + parameters: + - $ref: '#/components/parameters/apiId' + - $ref: '#/components/parameters/If-None-Match' + responses: + 200: + description: | + OK. + Requested API is returned + headers: + ETag: + description: | + Entity Tag of the response resource. Used by caches, or in conditional requests (Will be supported in future). + schema: + type: string + Last-Modified: + description: | + Date and time the resource has been modifed the last time. + Used by caches, or in conditional requests (Will be supported in future). + schema: + type: string + Content-Type: + description: | + The content type of the body. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/API' + 304: + description: | + Not Modified. + Empty body because the client has already the latest version of the requested resource (Will be supported in future). + content: {} + 404: + $ref: '#/components/responses/NotFound' + 406: + $ref: '#/components/responses/NotAcceptable' + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://127.0.0.1:9443/api/apk/backoffice/v1/apis/7a2298c4-c905-403f-8fac-38c73301631f"' + operationId: getAPI + put: + tags: + - APIs + summary: Update an API + description: | + This operation can be used to update an existing API. + But the properties `name`, `version`, `context`, `provider`, `state` will not be changed by this operation. + parameters: + - $ref: '#/components/parameters/apiId' + - $ref: '#/components/parameters/If-Match' + requestBody: + content: + multipart/form-data: + schema: + $ref: '#/components/schemas/APIBody' + required: true + responses: + 200: + description: | + OK. + Successful response with updated API object + headers: + ETag: + description: | + Entity Tag of the response resource. Used by caches, or in conditional requests (Will be supported in future). + schema: + type: string + Last-Modified: + description: | + Date and time the resource has been modifed the last time. + Used by caches, or in conditional requests (Will be supported in future). + schema: + type: string + Location: + description: | + The URL of the newly created resource. + schema: + type: string + Content-Type: + description: | + The content type of the body. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/API' + 400: + $ref: '#/components/responses/BadRequest' + 403: + $ref: '#/components/responses/Forbidden' + 404: + $ref: '#/components/responses/NotFound' + 409: + $ref: '#/components/responses/Conflict' + 412: + $ref: '#/components/responses/PreconditionFailed' + x-code-samples: + - lang: Curl + source: 'curl -k -X PUT -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + -H "Content-Type: application/json" -d @data.json "https://127.0.0.1:9443/api/publisher/v3/apis/7a2298c4-c905-403f-8fac-38c73301631f"' + operationId: updateAPI + + delete: + tags: + - APIs + summary: Delete an API + description: | + This operation can be used to delete an existing API proving the Id of the API. + parameters: + - $ref: '#/components/parameters/apiId' + - $ref: '#/components/parameters/If-Match' + responses: + 200: + description: | + OK. + Resource successfully deleted. + content: {} + 403: + $ref: '#/components/responses/Forbidden' + 404: + $ref: '#/components/responses/NotFound' + 409: + $ref: '#/components/responses/Conflict' + 412: + $ref: '#/components/responses/PreconditionFailed' + x-code-samples: + - lang: Curl + source: 'curl -k -X DELETE -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://127.0.0.1:9443/api/publisher/v3/apis/7a2298c4-c905-403f-8fac-38c73301631f"' + operationId: deleteAPI + + /apis/{apiId}/definition: + put: + tags: + - APIs + summary: Update API Definition + description: | + This operation can be used to update the swagger definition of an existing API. Swagger definition to be updated is passed as a form data parameter `apiDefinition`. + parameters: + - $ref: '#/components/parameters/apiId' + - $ref: '#/components/parameters/If-Match' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/APIDefinition' + required: true + responses: + 200: + description: | + OK. + Successful response with updated Swagger definition + headers: + ETag: + description: | + Entity Tag of the response resource. Used by caches, or in conditional requests (Will be supported in future). + schema: + type: string + Last-Modified: + description: | + Date and time the resource has been modifed the last time. + Used by caches, or in conditional requests (Will be supported in future). + schema: + type: string + Location: + description: | + The URL of the newly created resource. + schema: + type: string + Content-Type: + description: | + The content type of the body. + schema: + type: string + content: + application/json: + schema: + type: string + example: "" + 400: + $ref: '#/components/responses/BadRequest' + 403: + $ref: '#/components/responses/Forbidden' + 404: + $ref: '#/components/responses/NotFound' + 412: + $ref: '#/components/responses/PreconditionFailed' + x-code-samples: + - lang: Curl + source: 'curl -k -X PUT -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + -F apiDefinition=@swagger.json "https://127.0.0.1:9443/api/publisher/v3/apis/96077508-fd01-4fae-bc64-5de0e2baf43c/swagger"' + operationId: updateAPISwagger + + +components: + schemas: + API: + title: API object + required: + - context + - name + - version + type: object + properties: + id: + type: string + description: | + UUID of the api registry artifact + readOnly: true + example: 01234567-0123-0123-0123-012345678901 + name: + maxLength: 60 + minLength: 1 + pattern: '(^[^~!@#;:%^*()+={}|\\<>"'',&$\[\]\/]*$)' + type: string + example: PizzaShackAPI + description: + maxLength: 32766 + type: string + example: This is a simple API for Pizza Shack online pizza delivery store. + context: + maxLength: 232 + minLength: 1 + type: string + example: pizza + version: + maxLength: 30 + minLength: 1 + type: string + pattern: '^[^~!@#;:%^*()+={}|\\<>"'',&/$\[\]\s+\/]+$' + example: 1.0.0 + provider: + maxLength: 50 + type: string + description: | + If the provider value is not given user invoking the api will be used as the provider. + example: admin + organization: + type: string + example: carbon.super + lifeCycleStatus: + type: string + example: CREATED + x-otherScopes: + - apim:api_publish + - apim:api_manage + wsdlInfo: + $ref: '#/components/schemas/WSDLInfo' + wsdlUrl: + type: string + readOnly: true + example: /apimgt/applicationdata/wsdls/admin--soap1.wsdl + responseCachingEnabled: + type: boolean + example: true + cacheTimeout: + type: integer + example: 300 + hasThumbnail: + type: boolean + example: false + isDefaultVersion: + type: boolean + example: false + isRevision: + type: boolean + example: false + revisionedApiId: + type: string + description: | + UUID of the api registry artifact + readOnly: true + example: 01234567-0123-0123-0123-012345678901 + revisionId: + type: integer + example: 1 + enableSchemaValidation: + type: boolean + example: false + type: + type: string + description: The api creation type to be used. Accepted values are HTTP, + WS, SOAPTOREST, GRAPHQL, WEBSUB, SSE, WEBHOOK, ASYNC + example: HTTP + default: HTTP + enum: + - HTTP + - WS + - SOAPTOREST + - SOAP + - GRAPHQL + - WEBSUB + - SSE + - WEBHOOK + - ASYNC + audience: + type: string + description: The audience of the API. Accepted values are PUBLIC, SINGLE + example: PUBLIC + enum: + - PUBLIC + - SINGLE + transport: + type: array + description: | + Supported transports for the API (http and/or https). + example: + - http + - https + items: + type: string + tags: + type: array + example: + - pizza + - food + items: + type: string + x-otherScopes: + - apim:api_publish + - apim:api_manage + policies: + type: array + example: + - Unlimited + items: + type: string + x-otherScopes: + - apim:api_publish + - apim:api_manage + apiThrottlingPolicy: + type: string + description: The API level throttling policy selected for the particular + API + example: Unlimited + x-otherScopes: + - apim:api_publish + - apim:api_manage + authorizationHeader: + type: string + pattern: '(^[^~!@#;:%^*()+={}|\\<>"'',&$\s+]*$)' + description: | + Name of the Authorization header used for invoking the API. If it is not set, Authorization header name specified + in tenant or system level will be used. + example: Authorization + securityScheme: + type: array + description: | + Types of API security, the current API secured with. It can be either OAuth2 or mutual SSL or both. If + it is not set OAuth2 will be set as the security for the current API. + example: + - oauth2 + items: + type: string + visibility: + type: string + description: The visibility level of the API. Accepts one of the following. + PUBLIC, PRIVATE, RESTRICTED. + example: PUBLIC + default: PUBLIC + enum: + - PUBLIC + - PRIVATE + - RESTRICTED + x-otherScopes: + - apim:api_publish + - apim:api_manage + visibleRoles: + type: array + description: The user roles that are able to access the API in Developer Portal + example: [] + items: + type: string + x-otherScopes: + - apim:api_publish + - apim:api_manage + visibleTenants: + type: array + example: [] + items: + type: string + subscriptionAvailability: + type: string + description: The subscription availability. Accepts one of the following. + CURRENT_TENANT, ALL_TENANTS or SPECIFIC_TENANTS. + example: CURRENT_TENANT + default: CURRENT_TENANT + enum: + - CURRENT_TENANT + - ALL_TENANTS + - SPECIFIC_TENANTS + x-otherScopes: + - apim:api_publish + - apim:api_manage + subscriptionAvailableTenants: + type: array + example: [] + items: + type: string + additionalProperties: + type: array + description: Map of custom properties of API + items: + type: object + properties: + name: + type: string + value: + type: string + display: + type: boolean + x-otherScopes: + - apim:api_publish + - apim:api_manage + additionalPropertiesMap: + type: object + additionalProperties: + type: object + properties: + name: + type: string + value: + type: string + display: + type: boolean + default: false + x-otherScopes: + - apim:api_publish + - apim:api_manage + accessControl: + type: string + description: | + Is the API is restricted to certain set of publishers or creators or is it visible to all the + publishers and creators. If the accessControl restriction is none, this API can be modified by all the + publishers and creators, if not it can only be viewable/modifiable by certain set of publishers and creators, + based on the restriction. + default: NONE + enum: + - NONE + - RESTRICTED + accessControlRoles: + type: array + description: The user roles that are able to view/modify as API publisher + or creator. + example: [] + items: + type: string + workflowStatus: + type: string + example: APPROVED + createdTime: + type: string + lastUpdatedTime: + type: string + x-otherScopes: + - apim:api_publish + - apim:api_manage + endpointConfig: + type: object + properties: {} + description: | + Endpoint configuration of the API. This can be used to provide different types of endpoints including Simple REST Endpoints, Loadbalanced and Failover. + + `Simple REST Endpoint` + { + "endpoint_type": "http", + "sandbox_endpoints": { + "url": "https://localhost:9443/sample/pizzashack/v3/api/" + }, + "production_endpoints": { + "url": "https://localhost:9443/sample/pizzashack/v3/api/" + } + } + + `Loadbalanced Endpoint` + + { + "endpoint_type": "load_balance", + "algoCombo": "org.apache.synapse.endpoints.algorithms.RoundRobin", + "sessionManagement": "", + "sandbox_endpoints": [ + { + "url": "https://localhost:9443/sample/pizzashack/v3/api/1" + }, + { + "endpoint_type": "http", + "template_not_supported": false, + "url": "https://localhost:9443/sample/pizzashack/v3/api/2" + } + ], + "production_endpoints": [ + { + "url": "https://localhost:9443/sample/pizzashack/v3/api/3" + }, + { + "endpoint_type": "http", + "template_not_supported": false, + "url": "https://localhost:9443/sample/pizzashack/v3/api/4" + } + ], + "sessionTimeOut": "", + "algoClassName": "org.apache.synapse.endpoints.algorithms.RoundRobin" + } + + `Failover Endpoint` + + { + "production_failovers":[ + { + "endpoint_type":"http", + "template_not_supported":false, + "url":"https://localhost:9443/sample/pizzashack/v3/api/1" + } + ], + "endpoint_type":"failover", + "sandbox_endpoints":{ + "url":"https://localhost:9443/sample/pizzashack/v3/api/2" + }, + "production_endpoints":{ + "url":"https://localhost:9443/sample/pizzashack/v3/api/3" + }, + "sandbox_failovers":[ + { + "endpoint_type":"http", + "template_not_supported":false, + "url":"https://localhost:9443/sample/pizzashack/v3/api/4" + } + ] + } + + `Default Endpoint` + + { + "endpoint_type":"default", + "sandbox_endpoints":{ + "url":"default" + }, + "production_endpoints":{ + "url":"default" + } + } + + `Endpoint from Endpoint Registry` + { + "endpoint_type": "Registry", + "endpoint_id": "{registry-name:entry-name:version}", + } + example: + endpoint_type: http + sandbox_endpoints: + url: https://localhost:9443/sample/pizzashack/v3/api/ + production_endpoints: + url: https://localhost:9443/sample/pizzashack/v3/api/ + endpointImplementationType: + type: string + example: INLINE + default: ENDPOINT + enum: + - INLINE + - ENDPOINT + - MOCKED_OAS + threatProtectionPolicies: + type: object + properties: + list: + type: array + items: + type: object + properties: + policyId: + type: string + priority: + type: integer + categories: + type: array + description: | + API categories + items: + type: string + example: "" + x-otherScopes: + - apim:api_publish + keyManagers: + type: object + properties: {} + description: | + API Key Managers + readOnly: true + serviceInfo: + type: object + properties: + key: + type: string + example: PetStore-1.0.0 + name: + type: string + example: PetStore + version: + type: string + example: 1.0.0 + outdated: + type: boolean + example: false + gatewayVendor: + title: field to identify gateway vendor + type: string + example: + wso2 + gatewayType: + title: Field to identify gateway type. + type: string + description: The gateway type selected for the API policies. Accepts one of the + following. wso2/synapse, wso2/choreo-connect. + example: wso2/synapse + asyncTransportProtocols: + type: array + description: | + Supported transports for the async API (http and/or https). + example: + - http + - https + items: + type: string + x-scopes: + - apim:api_create + - apim:api_import_export + - apim:api_manage + WSDLInfo: + title: WSDL information of the API. This is only available if the API is a SOAP + API. + type: object + properties: + type: + type: string + description: Indicates whether the WSDL is a single WSDL or an archive in + ZIP format + enum: + - WSDL + - ZIP + APIBody: + title: APIBody object + type: object + required: + - apiProperties + - Definition + properties: + apiProperties: + $ref: '#/components/schemas/API' + Definition: + type: object + description: Content of the definition + APIDefinition: + title: APIDefinition object + type: object + required: + - Definition + properties: + Definition: + type: object + description: Content of the definition + Error: + title: Error object returned with 4XX HTTP Status + required: + - code + - message + type: object + properties: + code: + type: integer + format: int64 + message: + type: string + description: Error message. + description: + type: string + description: | + A detail description about the error message. + moreInfo: + type: string + description: | + Preferably an url with more details about the error. + error: + type: array + description: | + If there are more than one error list them out. + For example, list out validation errors by each field. + items: + $ref: '#/components/schemas/ErrorListItem' + ErrorListItem: + title: Description of individual errors that may have occurred during a request. + required: + - code + - message + type: object + properties: + code: + type: string + message: + type: string + description: | + Description about individual errors occurred + description: + type: string + description: | + A detail description about the error message. + + responses: + BadRequest: + description: Bad Request. Invalid request or validation error. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + example: + code: 400 + message: Bad Request + description: Invalid request or validation error + moreInfo: "" + error: [] + Conflict: + description: Conflict. Specified resource already exists. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + example: + code: 409 + message: Conflict + description: Specified resource already exists + moreInfo: "" + error: [] + Forbidden: + description: Forbidden. The request must be conditional but no condition has + been specified. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + example: + code: 403 + message: Forbidden + description: The request must be conditional but no condition has been + specified + moreInfo: "" + error: [] + InternalServerError: + description: Internal Server Error. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + example: + code: 500 + message: Internal Server Error + description: The server encountered an internal error. Please contact + administrator. + moreInfo: "" + error: [] + NotAcceptable: + description: Not Acceptable. The requested media type is not supported. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + example: + code: 406 + message: Not Acceptable + description: The requested media type is not supported + moreInfo: "" + error: [] + NotFound: + description: Not Found. The specified resource does not exist. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + example: + code: 404 + message: Not Found + description: The specified resource does not exist + moreInfo: "" + error: [] + PreconditionFailed: + description: Precondition Failed. The request has not been performed because + one of the preconditions is not met. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + example: + code: 412 + message: Precondition Failed + description: The request has not been performed because one of the preconditions + is not met + moreInfo: "" + error: [] + Unauthorized: + description: Unauthorized. The user is not authorized. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + example: + code: 401 + message: Unauthorized + description: The user is not authorized + moreInfo: "" + error: [] + UnsupportedMediaType: + description: Unsupported Media Type. The entity of the request was not in a + supported format. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + example: + code: 415 + message: Unsupported media type + description: The entity of the request was not in a supported format + moreInfo: "" + error: [] + parameters: + replyLimit: + name: replyLimit + in: query + description: | + Maximum size of replies array to return. + schema: + type: integer + default: 25 + replyOffset: + name: replyOffset + in: query + description: | + Starting point within the complete list of replies. + schema: + type: integer + default: 0 + apiId: + name: apiId + in: path + description: | + **API ID** consisting of the **UUID** of the API. + required: true + schema: + type: string + apiId-Q: + name: apiId + in: query + description: | + **API ID** consisting of the **UUID** of the API. + The combination of the provider of the API, name of the API and the version is also accepted as a valid API I. + Should be formatted as **provider-name-version**. + required: true + schema: + type: string + apiId-Q-Opt: + name: apiId + in: query + description: | + **API ID** consisting of the **UUID** of the API. + The combination of the provider of the API, name of the API and the version is also accepted as a valid API I. + Should be formatted as **provider-name-version**. + schema: + type: string + labelType-Q: + name: labelType + in: query + description: | + **API ID** consisting of the **UUID** of the API. + The combination of the provider of the API, name of the API and the version is also accepted as a valid API I. + Should be formatted as **provider-name-version**. + schema: + type: string + name: + name: name + in: path + description: | + Name of the API + required: true + schema: + type: string + version: + name: version + in: path + description: | + Version of the API + required: true + schema: + type: string + apiName-Q: + name: name + in: query + description: | + Name of the API + schema: + type: string + apiVersion-Q: + name: version + in: query + description: | + Version of the API + schema: + type: string + apiProvider-Q: + name: providerName + in: query + description: | + Provider name of the API + schema: + type: string + + limit: + name: limit + in: query + description: | + Maximum size of resource array to return. + schema: + type: integer + default: 25 + Accept: + name: Accept + in: header + description: | + Media types acceptable for the response. Default is application/json. + schema: + type: string + default: application/json + offset: + name: offset + in: query + description: | + Starting point within the complete list of items qualified. + schema: + type: integer + default: 0 + sortBy: + name: sortBy + in: query + description: | + Criteria for sorting. + schema: + type: string + default: createdTime + enum: + - apiName + - version + - createdTime + - status + sortOrder: + name: sortOrder + in: query + description: | + Order of sorting(ascending/descending). + schema: + type: string + default: desc + enum: + - asc + - desc + If-None-Match: + name: If-None-Match + in: header + description: | + Validator for conditional requests; based on the ETag of the formerly retrieved + variant of the resource. + schema: + type: string + If-Match: + name: If-Match + in: header + description: | + Validator for conditional requests; based on ETag. + schema: + type: string + \ No newline at end of file diff --git a/backoffice/backoffice-domain-service/ballerina/notificationTypes.bal b/backoffice/backoffice-domain-service/ballerina/notificationTypes.bal new file mode 100644 index 000000000..2bc9155c4 --- /dev/null +++ b/backoffice/backoffice-domain-service/ballerina/notificationTypes.bal @@ -0,0 +1,70 @@ +// +// Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + +public type ApplicationGRPC record {| + string eventId = ""; + string name = ""; + string uuid = ""; + string owner = ""; + string policy = ""; + Application_Key[] keys = []; + string organization = ""; + string timeStamp = ""; + record {|string key; string value;|}[] attributes = []; +|}; + +public type Application_Key record {| + string key = ""; + string keyManager = ""; +|}; + +public type SubscriptionGRPC record {| + string eventId = ""; + string applicationRef = ""; + string apiRef = ""; + string policyId = ""; + string subStatus = ""; + string subscriber = ""; + string uuid = ""; + string timeStamp = ""; + string organization = ""; +|}; + +public type NotificationResponse record {| + NotificationResponse_StatusCode code = UNKNOWN; +|}; + +public enum NotificationResponse_StatusCode { + UNKNOWN, OK, FAILED +} + +public type SubscriptionInternal record { + # The UUID of the subscription + string subscriptionId?; + # The UUID of the application + string applicationId; + # The unique identifier of the API. + string apiId?; + APIInfo apiInfo?; + ApplicationInfo applicationInfo?; + string throttlingPolicy; + string requestedThrottlingPolicy?; + string status?; + # A url and other parameters the subscriber can be redirected. + string redirectionParams?; +}; diff --git a/backoffice/backoffice-domain-service/ballerina/tests/Config.toml b/backoffice/backoffice-domain-service/ballerina/tests/Config.toml new file mode 100644 index 000000000..b1fb10b18 --- /dev/null +++ b/backoffice/backoffice-domain-service/ballerina/tests/Config.toml @@ -0,0 +1,25 @@ +[wso2.backoffice_service] +BACKOFFICE_PORT = 9443 + +# Sample configurations +[wso2.backoffice_service.datasourceConfiguration] +description = "Database for backoffice" +url = "jdbc:postgresql://localhost:10320/WSO2AM_DB" +host = "localhost" +port = 10320 +databaseName = "WSO2AM_DB" +username = "wso2carbon" +password = "wso2carbon" +validationTimeout = 250 +testQuery = "SELECT 1" +driver = "org.postgresql.Driver" +[wso2.backoffice_service.keyStores.tls] +keyFilePath = "./tests/resources/wso2carbon.key" +certFilePath = "./tests/resources/wso2carbon.crt" +[wso2.backoffice_service.k8sConfig] +host = "localhost:9090" +serviceAccountPath = "tests/resources/serviceAccount" +[wso2.backoffice_service.managementServerConfig] +serviceName = "apk-test-wso2-apk-management-server" +namespace = "apk" +certPath = "/home/wso2apk/backoffice/security/truststore/management-server.pem" diff --git a/backoffice/backoffice-domain-service/ballerina/tests/apiCategoryTest.bal b/backoffice/backoffice-domain-service/ballerina/tests/apiCategoryTest.bal new file mode 100644 index 000000000..ed421b034 --- /dev/null +++ b/backoffice/backoffice-domain-service/ballerina/tests/apiCategoryTest.bal @@ -0,0 +1,30 @@ +// +// Copyright (c) 2022, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + +import ballerina/test; +import wso2/apk_common_lib as commons; + +@test:Config {} +function getAllCategoryTest() { + APICategory[]|commons:APKError updateAPI = getAPICategoriesDAO("carbon.super"); + if updateAPI is APICategory[] { + test:assertTrue(true, "Successfully retrive all API categories"); + } else if updateAPI is commons:APKError { + test:assertFail("Error occured while retrive API categories"); + } +} \ No newline at end of file diff --git a/backoffice/backoffice-domain-service/ballerina/tests/apiDocumentTests.bal b/backoffice/backoffice-domain-service/ballerina/tests/apiDocumentTests.bal new file mode 100644 index 000000000..d69974866 --- /dev/null +++ b/backoffice/backoffice-domain-service/ballerina/tests/apiDocumentTests.bal @@ -0,0 +1,120 @@ +// +// Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + +import ballerina/test; +import ballerina/http; +import wso2/apk_common_lib as commons; + +string documentId = ""; +@test:Config {dependsOn: [createAPITest]} +function addDocumentMetaDataTest() { + Document documentBody = { + name:"NewDoc", + documentType: "HOWTO", + summary: "Doc summary", + sourceType: "INLINE", + visibility: "API_LEVEL", + sourceUrl: "", + otherTypeName: "sdds", + inlineContent: "" + }; + + Document|commons:APKError createdDocument = createDocument("01ed75e2-b30b-18c8-wwf2-25da7edd2231", documentBody); + if createdDocument is Document { + documentId = createdDocument.documentId; + test:assertTrue(true, "Successfully added the thumbnail"); + } else { + test:assertFail("Error occured while adding the Document"); + } +} + +@test:Config {dependsOn: [addDocumentMetaDataTest]} +function updateDocumentMetaDataTest() { + Document updatedDocumentBody = { + name:"NewDoc", + documentType: "HOWTO", + summary: "Doc summary updated", + sourceType: "INLINE", + visibility: "API_LEVEL", + sourceUrl: "", + otherTypeName: "sdds", + inlineContent: "" + }; + + Document|NotFoundError|commons:APKError|error updatedDocument = UpdateDocumentMetaData("01ed75e2-b30b-18c8-wwf2-25da7edd2231", documentId, updatedDocumentBody); + if updatedDocument is Document { + test:assertTrue(true, "Successfully added the thumbnail"); + test:assertEquals(updatedDocumentBody.summary, updatedDocument.summary, "Updated value should be equal"); + } else { + test:assertFail("Error occured while adding the Document"); + } +} + +@test:Config {dependsOn: [createAPITest, addDocumentMetaDataTest]} +function addDocumentContentTest() { + http:Request|error request = createRequestWithImageFormData("invalidThumbnail.pdf", "application/pdf"); + if request is http:Request { + Document|NotFoundError|commons:APKError|error addedContent = addDocumentContent("01ed75e2-b30b-18c8-wwf2-25da7edd2231", documentId, request); + if addedContent is Document { + test:assertTrue(true, "Successfully added the Document content"); + } else { + test:assertFail("Error occured while adding Document content"); + } + } +} + +@test:Config {dependsOn: [addDocumentMetaDataTest]} +function getDocumentMetaDataTest() { + Document|NotFoundError|commons:APKError docMetaData = getDocumentMetaData("01ed75e2-b30b-18c8-wwf2-25da7edd2231", documentId); + if docMetaData is Document { + test:assertTrue(true, "Successfully getting the Document meta data"); + } else { + test:assertFail("Error occured while getting the Document meta data"); + } +} + +@test:Config {dependsOn: [addDocumentContentTest]} +function getDocumentContentTest() { + http:Response|NotFoundError|commons:APKError docContent = getDocumentContent("01ed75e2-b30b-18c8-wwf2-25da7edd2231", documentId); + if docContent is http:Response { + test:assertTrue(true, "Successfully getting the Document content"); + } else { + test:assertFail("Error occured while getting the Document content"); + } +} + +@test:Config {dependsOn: [addDocumentMetaDataTest]} +function getDocumentListTest() { + DocumentList|commons:APKError documentList = getDocumentList("01ed75e2-b30b-18c8-wwf2-25da7edd2231", 25, 0); + if documentList is DocumentList { + test:assertTrue(true, "Successfully getting the Document List"); + test:assertEquals(documentList.count, 1, "Document count should be equal to 1"); + } else { + test:assertFail("Error occured while getting the Document List"); + } +} + +@test:Config {} +function deleteDocumentTest() { + http:Ok|NotFoundError|commons:APKError deletdeDoc = deleteDocument("01ed75e2-b30b-18c8-wwf2-25da7edd2231", documentId); + if deletdeDoc is http:Ok { + test:assertTrue(true, "Successfully deleted the Document"); + } else { + test:assertFail("Error occured while deleting the Document"); + } +} diff --git a/backoffice/backoffice-domain-service/ballerina/tests/apiLifeCycleTests.bal b/backoffice/backoffice-domain-service/ballerina/tests/apiLifeCycleTests.bal new file mode 100644 index 000000000..c49b34cec --- /dev/null +++ b/backoffice/backoffice-domain-service/ballerina/tests/apiLifeCycleTests.bal @@ -0,0 +1,51 @@ +// +// Copyright (c) 2022, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + +import ballerina/test; + + +@test:Config {dependsOn: [createAPITest]} +function changeLCStateTest() { + LifecycleState|error lcState1 = changeLifeCyleState("PUBLISHED", "01ed75e2-b30b-18c8-wwf2-25da7edd2231", "carbon.super"); + if lcState1 is LifecycleState { + test:assertTrue(true, "Successfully change the LC state"); + } else { + test:assertFail("Error occured while changing LC state"); + } +} + + +@test:Config {dependsOn: [createAPITest, changeLCStateTest]} +function getLcEventHistoryTest() { + LifecycleHistory|error? lcState = getLcEventHistory("01ed75e2-b30b-18c8-wwf2-25da7edd2231"); + if lcState is LifecycleHistory { + test:assertTrue(true, "Successfully retrive the LC events"); + } else { + test:assertFail("Error occured while retrive LC events"); + } +} + +@test:Config {} +function getLifeCyleStateTest() { + LifecycleState|error lcState1 = getLifeCyleState("01ed75e2-b30b-18c8-wwf2-25da7edd2231"); + if lcState1 is LifecycleState { + test:assertTrue(true, "Successfully getting the LC state"); + } else { + test:assertFail("Error occured while getting LC state"); + } +} diff --git a/backoffice/backoffice-domain-service/ballerina/tests/apiTests.bal b/backoffice/backoffice-domain-service/ballerina/tests/apiTests.bal new file mode 100644 index 000000000..f2777ff88 --- /dev/null +++ b/backoffice/backoffice-domain-service/ballerina/tests/apiTests.bal @@ -0,0 +1,82 @@ +// +// Copyright (c) 2022, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + +import ballerina/log; +import ballerina/test; +import wso2/apk_common_lib as commons; + +@test:Config {dependsOn: [createAPITest]} +function getAPITest() { + APIList|commons:APKError getAPI = getAPIList(25,0,"content:pizza","carbon.super"); + if getAPI is APIList { + test:assertTrue(true, "Successfully retrieve APIs"); + log:printInfo(getAPI.toString()); + } else if getAPI is commons:APKError { + log:printError(getAPI.toString()); + test:assertFail("Error occured while creating API"); + } +} + +@test:Config {dependsOn: [createAPITest]} +function getAPIByIdTest() { + API|commons:APKError getAPIById = getAPI("01ed75e2-b30b-18c8-wwf2-25da7edd2231"); + if getAPIById is API { + test:assertTrue(true, "Successfully retrieve API"); + log:printInfo(getAPIById.toString()); + } else if getAPIById is commons:APKError { + log:printError(getAPIById.toString()); + test:assertFail("Error occured while creating API"); + } +} + +@test:Config {dependsOn: [createAPITest]} +function getAPIDefinitionTest() { + APIDefinition|commons:APKError getAPIDef = getAPIDefinition("01ed75e2-b30b-18c8-wwf2-25da7edd2231"); + if getAPIDef is API { + test:assertTrue(true, "Successfully retrieve API Definition"); + log:printInfo(getAPIDef.toString()); + } else if getAPIDef is commons:APKError { + log:printError(getAPIDef.toString()); + test:assertFail("Error occured while retrieve API Definition"); + } +} + +@test:Config {dependsOn: [createAPITest]} +function updateAPITest() { + ModifiableAPI payload = { + "name": "PizzaShask", + "description": "chnage description", + "sdk": [ + "java", "android" + ], + "categories": [ + "cloud","open" + ], + "Policies": [ + "mysub1","mysub2" + ] + }; + API|commons:APKError updateAPICr = updateAPI("01ed75e2-b30b-18c8-wwf2-25da7edd2231", payload); + if updateAPICr is API { + test:assertTrue(true, "Successfully Update API"); + log:printInfo(updateAPICr.toString()); + } else if updateAPICr is commons:APKError { + log:printError(updateAPICr.toString()); + test:assertFail("Error occured while updating API"); + } +} diff --git a/backoffice/backoffice-domain-service/ballerina/tests/apiThumbnailTests.bal b/backoffice/backoffice-domain-service/ballerina/tests/apiThumbnailTests.bal new file mode 100644 index 000000000..2d9cd59e9 --- /dev/null +++ b/backoffice/backoffice-domain-service/ballerina/tests/apiThumbnailTests.bal @@ -0,0 +1,83 @@ +// +// Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + +import ballerina/test; +import ballerina/http; +import wso2/apk_common_lib as commons; + +@test:Config {dependsOn: [createAPITest]} +function addThumbnailTest() { + http:Request|error request = createRequestWithImageFormData("thumbnail.png", RESOURCE_DATA_TYPE_PNG_IMAGE); + if request is http:Request { + FileInfo|NotFoundError|PreconditionFailedError|commons:APKError|error thumbnail = updateThumbnail("01ed75e2-b30b-18c8-wwf2-25da7edd2231", request); + if thumbnail is FileInfo { + test:assertTrue(true, "Successfully added the thumbnail"); + } else { + test:assertFail("Error occured while adding the thumbnail"); + } + } +} + +@test:Config {dependsOn: [createAPITest, addThumbnailTest]} +function updateThumbnailTest() { + http:Request|error request = createRequestWithImageFormData("thumbnail.png", RESOURCE_DATA_TYPE_PNG_IMAGE); + if request is http:Request { + FileInfo|NotFoundError|PreconditionFailedError|commons:APKError|error thumbnail = updateThumbnail("01ed75e2-b30b-18c8-wwf2-25da7edd2231", request); + if thumbnail is FileInfo { + test:assertTrue(true, "Successfully updated the thumbnail"); + } else { + test:assertFail("Error occured while updating the thumbnail"); + } + } +} + +@test:Config {dependsOn: [createAPITest, addThumbnailTest]} +function addThumbnaiGreaterThan1MB() { + http:Request|error request = createRequestWithImageFormData("largeThumbnail.jpg", RESOURCE_DATA_TYPE_JPG_IMAGE); + if request is http:Request { + FileInfo|NotFoundError|PreconditionFailedError|commons:APKError|error thumbnail = updateThumbnail("01ed75e2-b30b-18c8-wwf2-25da7edd2231", request); + if thumbnail is PreconditionFailedError { + test:assertEquals(thumbnail.body.message, "Thumbnail size should be less than 1MB"); + } else { + test:assertFail("Thumbnail size which is greater than 1MB is added"); + } + } +} + +@test:Config {dependsOn: [createAPITest, addThumbnailTest]} +function addInvalidThumbnaiFileFormat() { + http:Request|error request = createRequestWithImageFormData("invalidThumbnail.pdf", "application/pdf"); + if request is http:Request { + FileInfo|NotFoundError|PreconditionFailedError|commons:APKError|error thumbnail = updateThumbnail("01ed75e2-b30b-18c8-wwf2-25da7edd2231", request); + if thumbnail is PreconditionFailedError { + test:assertEquals(thumbnail.body.message, "Thumbnail file extension is not allowed. Supported extensions are .jpg, .png, .jpeg .svg and .gif"); + } else { + test:assertFail("Thumbnail which has invalid file format is added"); + } + } +} + +@test:Config {} +function gethumbnailTest() { + http:Response|NotFoundError|commons:APKError thumbnail = getThumbnail("01ed75e2-b30b-18c8-wwf2-25da7edd2231"); + if thumbnail is http:Response { + test:assertTrue(true, "Successfully getting the thumbnail"); + } else { + test:assertFail("Error occured while getting the thumbnail"); + } +} diff --git a/backoffice/backoffice-domain-service/ballerina/tests/internalAPITests.bal b/backoffice/backoffice-domain-service/ballerina/tests/internalAPITests.bal new file mode 100644 index 000000000..63a48a6eb --- /dev/null +++ b/backoffice/backoffice-domain-service/ballerina/tests/internalAPITests.bal @@ -0,0 +1,243 @@ +// +// Copyright (c) 2022, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + +import ballerina/log; +import ballerina/test; + +import wso2/apk_common_lib as commons; + +@test:Config {} +function createAPITest() { + APIBody body = { + "apiProperties":{ + "id": "01ed75e2-b30b-18c8-wwf2-25da7edd2231", + "name":"PizzaShask", + "context":"pizzssa", + "version":"1.0.0", + "provider":"admin", + "organization":"1111-1111-1111-1111", + "lifeCycleStatus":"CREATED", + "type":"HTTP" + }, + "Definition" : { + "openapi": "3.0.0", + "info": { + "title": "Sample API", + "description": "Optional multiline or single-line description in [CommonMark](http://commonmark.org/help/) or HTML.", + "version": "0.1.9" + }, + "servers": [ + { + "url": "http://api.example.com/v1", + "description": "Optional server description, e.g. Main (production) server" + }, + { + "url": "http://staging-api.example.com", + "description": "Optional server description, e.g. Internal staging server for testing" + } + ], + "paths": { + "/users": { + "get": { + "summary": "Returns a list of users.", + "description": "Optional extended description in CommonMark or HTML.", + "responses": { + "200": { + "description": "A JSON array of user names", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + } + } + } + } + } + }; + API|error createdAPI = createAPI(body); + if createdAPI is API { + test:assertTrue(true, "Successfully created API"); + } else if createdAPI is error { + log:printError(createdAPI.toString()); + test:assertFail("Error occured while creating API"); + } + +} + +@test:Config {dataProvider: getApiDataProvider} +public function testGetApi(string apiId, string organization, anydata expectedData) { + API|commons:APKError|error getAPI = getAPI_internal(apiId); + if getAPI is API { + test:assertEquals(getAPI.toBalString(), expectedData); + } else if getAPI is commons:APKError { + test:assertEquals(getAPI.toBalString(), expectedData); + } else { + test:assertFail("Error while retrieving API data"); + } +} + +public function getApiDataProvider() returns map<[string, string, anydata]> { + + commons:APKError notfound = error commons:APKError( "API not found in the database", + code = 909603, + message = "API not found in the database", + statusCode = 404, + description = "API not found in the database" + ); + map<[string, string, anydata]> dataset = { + "1": [ + "01ed75e2-b30b-18c8-wwf2-25da7edd2231", + "1111-1111-1111-1111", + { + "id": "01ed75e2-b30b-18c8-wwf2-25da7edd2231", + "name": "PizzaShask", + "context": "pizzssa", + "version": "1.0.0", + "organization": "1111-1111-1111-1111", + "type": "HTTP", + "state": "CREATED", + "status": "CREATED" + }.toBalString() + ], + "2": ["11111", "carbon.super", notfound.toBalString()] + }; + return dataset; +} + +@test:Config {} +function updateInternalAPITest() { + APIBody updateBody = { + "apiProperties":{ + "name":"PizzaShask", + "context":"pizzssa", + "version":"1.0.0", + "lifeCycleStatus":"CREATED", + "organization":"1111-1111-1111-1111", + "type":"HTTP" + }, + "Definition" : { + "openapi": "3.0.0", + "info": { + "title": "Sample API Change", + "description": "Optional multiline or single-line description in [CommonMark](http://commonmark.org/help/) or HTML.", + "version": "0.1.9" + }, + "servers": [ + { + "url": "http://api.example.com/v1", + "description": "Optional server description, e.g. Main (production) server" + }, + { + "url": "http://staging-api.example.com", + "description": "Optional server description, e.g. Internal staging server for testing" + } + ], + "paths": { + "/users": { + "get": { + "summary": "Returns a list of users.", + "description": "Optional extended description in CommonMark or HTML.", + "responses": { + "200": { + "description": "A JSON array of user names", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + } + } + } + } + } + }; + API|commons:APKError|error updateAPI = updateAPI_internal("01ed75e2-b30b-18c8-wwf2-25da7edd2231", updateBody); + if updateAPI is API { + test:assertTrue(true, "Successfully updtaing API"); + } else if updateAPI is error { + log:printError(updateAPI.toString()); + test:assertFail("Error occured while updtaing API"); + } +} + +@test:Config {} +function updateAPIDefinitionTest() { + APIDefinition1 apiDefinition = { + "Definition" : { + "openapi": "3.0.0", + "info": { + "title": "Sample API Change", + "description": "Optional multiline or single-line description in [CommonMark](http://commonmark.org/help/) or HTML.", + "version": "0.1.9" + }, + "servers": [ + { + "url": "http://api.example.com/v1", + "description": "Optional server description, e.g. Main (production) server" + }, + { + "url": "http://staging-api.example.com", + "description": "Optional server description, e.g. Internal staging server for testing" + } + ], + "paths": { + "/users": { + "get": { + "summary": "Returns a list of users.", + "description": "Optional extended description in CommonMark or HTML.", + "responses": { + "200": { + "description": "A JSON array of user names", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + } + } + } + } + } + }; + APIDefinition1|error? updateAPI = updateDefinition(apiDefinition, "01ed75e2-b30b-18c8-wwf2-25da7edd2231"); + if updateAPI is API { + test:assertTrue(true, "Successfully updtaing API Definition"); + } else if updateAPI is error { + log:printError(updateAPI.toString()); + test:assertFail("Error occured while updtaing API Definition"); + } +} diff --git a/backoffice/backoffice-domain-service/ballerina/tests/resources/invalidThumbnail.pdf b/backoffice/backoffice-domain-service/ballerina/tests/resources/invalidThumbnail.pdf new file mode 100644 index 000000000..970940266 Binary files /dev/null and b/backoffice/backoffice-domain-service/ballerina/tests/resources/invalidThumbnail.pdf differ diff --git a/backoffice/backoffice-domain-service/ballerina/tests/resources/largeThumbnail.jpg b/backoffice/backoffice-domain-service/ballerina/tests/resources/largeThumbnail.jpg new file mode 100644 index 000000000..fcc9c8cb1 Binary files /dev/null and b/backoffice/backoffice-domain-service/ballerina/tests/resources/largeThumbnail.jpg differ diff --git a/backoffice/backoffice-domain-service/ballerina/tests/resources/serviceAccount/ca.crt b/backoffice/backoffice-domain-service/ballerina/tests/resources/serviceAccount/ca.crt new file mode 100644 index 000000000..caa74a133 --- /dev/null +++ b/backoffice/backoffice-domain-service/ballerina/tests/resources/serviceAccount/ca.crt @@ -0,0 +1,15 @@ +-----BEGIN CERTIFICATE----- +MIICTDCCAbUCFBmlzXvk8t7eLJZW7bZNZK4koJHSMA0GCSqGSIb3DQEBCwUAMGUx +CzAJBgNVBAYTAkxLMQswCQYDVQQIDAJXUDEQMA4GA1UEBwwHQ29sb21ibzENMAsG +A1UECgwEV1NPMjEUMBIGA1UECwwLRW5naW5lZXRpbmcxEjAQBgNVBAMMCWxvY2Fs +aG9zdDAeFw0yMjEyMTQwODM3MzhaFw0yMzEyMTQwODM3MzhaMGUxCzAJBgNVBAYT +AkxLMQswCQYDVQQIDAJXUDEQMA4GA1UEBwwHQ29sb21ibzENMAsGA1UECgwEV1NP +MjEUMBIGA1UECwwLRW5naW5lZXRpbmcxEjAQBgNVBAMMCWxvY2FsaG9zdDCBnzAN +BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwLPJQmKc8mWjt2ZO7b6NANIaL5cdY14+ +3wpX/rpyYG0FeMfcEU09XwApzLI0cH61HmZRAxSkOEvw5zwgLsTcgt4Z3TmbCoMq +KYtdfRVpiWK3TpmkS346mwTBsS4+tSYtqO2g3r1mcUaVqL2xaWE9Wq5sM0Vs2pjO +22IsA6BvJbcCAwEAATANBgkqhkiG9w0BAQsFAAOBgQAG9q+pkvJFuv8vdFz3XWro +aym512HJcI7pE2H+ailBR04Td63xvrq2vAINO7/0kv2CoAm8sJBLAdTxsKnhbWCh +9Pd5OSdLIgymCA/qvV24T2YTbclMyhdR95gjmYJnqJNn3YAPq2GrcjtSdEg7Lg5N +wMzx3MH2sIWDPxbYugP6EQ== +-----END CERTIFICATE----- diff --git a/backoffice/backoffice-domain-service/ballerina/tests/resources/serviceAccount/namespace b/backoffice/backoffice-domain-service/ballerina/tests/resources/serviceAccount/namespace new file mode 100644 index 000000000..909025ff4 --- /dev/null +++ b/backoffice/backoffice-domain-service/ballerina/tests/resources/serviceAccount/namespace @@ -0,0 +1 @@ +apk-platform \ No newline at end of file diff --git a/backoffice/backoffice-domain-service/ballerina/tests/resources/serviceAccount/token b/backoffice/backoffice-domain-service/ballerina/tests/resources/serviceAccount/token new file mode 100644 index 000000000..34bf3e982 --- /dev/null +++ b/backoffice/backoffice-domain-service/ballerina/tests/resources/serviceAccount/token @@ -0,0 +1 @@ +eyJhbGciOiJSUzI1NiIsImtpZCI6IkYyRnBLWThqdkFtVmlGdFRUd0RBLTh5ZXlCRFppRFVKQVAySnhQUC1LejgifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJhcGstcGxhdGZvcm0iLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlY3JldC5uYW1lIjoid3NvMmFway1wbGF0Zm9ybS10b2tlbi1kbmptbCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50Lm5hbWUiOiJ3c28yYXBrLXBsYXRmb3JtIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQudWlkIjoiYjlmYjIyMmQtNjVlMi00MGMyLWE4NGItZWY0YmFhOTdjNmQ3Iiwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50OmFway1wbGF0Zm9ybTp3c28yYXBrLXBsYXRmb3JtIn0.GzoqQGKIv7cOtgmk0qcYfRMB8f_58bmmqEVoMuHWg4jUxcCSO3KiMVhIqWZpgDYjtySrF0VNYZbmVmg4lM_jSOamAs-PZOeYVnMgRylAiRsYgPUxKmZaC8HDf_xbFeuOFCAEzhNLDiW6SCJuwIq7oxzTtEmVMxDuYGy9lRP7Uc0GktK6boW-hemTlsRT2Rv3ehO3FhTvVRzC5KES94Vy7vdJLg1r0ccxVWO_svj87SApNySFXUoZbgJe2mKIQ7trjqYludGZ7_wmw7Ba0bdGnDUqDwl41WUAP6OFMg3cN4RpPafoJoSX7zGnMt_CP5h4w46S6yOx0q6pJjRq0tO29g \ No newline at end of file diff --git a/backoffice/backoffice-domain-service/ballerina/tests/resources/thumbnail.png b/backoffice/backoffice-domain-service/ballerina/tests/resources/thumbnail.png new file mode 100644 index 000000000..035660d52 Binary files /dev/null and b/backoffice/backoffice-domain-service/ballerina/tests/resources/thumbnail.png differ diff --git a/backoffice/backoffice-domain-service/ballerina/tests/resources/thumbnail2.png b/backoffice/backoffice-domain-service/ballerina/tests/resources/thumbnail2.png new file mode 100644 index 000000000..017ecbc8f Binary files /dev/null and b/backoffice/backoffice-domain-service/ballerina/tests/resources/thumbnail2.png differ diff --git a/backoffice/backoffice-domain-service/ballerina/tests/resources/wso2carbon.crt b/backoffice/backoffice-domain-service/ballerina/tests/resources/wso2carbon.crt new file mode 100644 index 000000000..caa74a133 --- /dev/null +++ b/backoffice/backoffice-domain-service/ballerina/tests/resources/wso2carbon.crt @@ -0,0 +1,15 @@ +-----BEGIN CERTIFICATE----- +MIICTDCCAbUCFBmlzXvk8t7eLJZW7bZNZK4koJHSMA0GCSqGSIb3DQEBCwUAMGUx +CzAJBgNVBAYTAkxLMQswCQYDVQQIDAJXUDEQMA4GA1UEBwwHQ29sb21ibzENMAsG +A1UECgwEV1NPMjEUMBIGA1UECwwLRW5naW5lZXRpbmcxEjAQBgNVBAMMCWxvY2Fs +aG9zdDAeFw0yMjEyMTQwODM3MzhaFw0yMzEyMTQwODM3MzhaMGUxCzAJBgNVBAYT +AkxLMQswCQYDVQQIDAJXUDEQMA4GA1UEBwwHQ29sb21ibzENMAsGA1UECgwEV1NP +MjEUMBIGA1UECwwLRW5naW5lZXRpbmcxEjAQBgNVBAMMCWxvY2FsaG9zdDCBnzAN +BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwLPJQmKc8mWjt2ZO7b6NANIaL5cdY14+ +3wpX/rpyYG0FeMfcEU09XwApzLI0cH61HmZRAxSkOEvw5zwgLsTcgt4Z3TmbCoMq +KYtdfRVpiWK3TpmkS346mwTBsS4+tSYtqO2g3r1mcUaVqL2xaWE9Wq5sM0Vs2pjO +22IsA6BvJbcCAwEAATANBgkqhkiG9w0BAQsFAAOBgQAG9q+pkvJFuv8vdFz3XWro +aym512HJcI7pE2H+ailBR04Td63xvrq2vAINO7/0kv2CoAm8sJBLAdTxsKnhbWCh +9Pd5OSdLIgymCA/qvV24T2YTbclMyhdR95gjmYJnqJNn3YAPq2GrcjtSdEg7Lg5N +wMzx3MH2sIWDPxbYugP6EQ== +-----END CERTIFICATE----- diff --git a/backoffice/backoffice-domain-service/ballerina/tests/resources/wso2carbon.key b/backoffice/backoffice-domain-service/ballerina/tests/resources/wso2carbon.key new file mode 100644 index 000000000..aa746b158 --- /dev/null +++ b/backoffice/backoffice-domain-service/ballerina/tests/resources/wso2carbon.key @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICWwIBAAKBgQDAs8lCYpzyZaO3Zk7tvo0A0hovlx1jXj7fClf+unJgbQV4x9wR +TT1fACnMsjRwfrUeZlEDFKQ4S/DnPCAuxNyC3hndOZsKgyopi119FWmJYrdOmaRL +fjqbBMGxLj61Ji2o7aDevWZxRpWovbFpYT1armwzRWzamM7bYiwDoG8ltwIDAQAB +AoGAPkJYBgDCYHaCPKDrY1irSdaX60RRlGdAvOMkpwIqLglLOUipS1W/PFBbMO1q +j+YAMoAwMGSc4it2+96rLzEfZQD87RFH8WxSp8NIxuCcSZBvNxLaiIhjxvU7B5LC +/S3Ao2bjM26iYalPpW8Pw/FLG6QXZEtOzmfyFAknzQR5wDECQQDsVKPFOUMNU89F ++zznViTiRj2+Z3kLfY7BmP2B/0/O9qnne98RQDRI9hu8SL4o6ll3P3wucOv7I+o6 +bqh5clq7AkEA0L2VK0vEKyR6pksJDj1wxtic9TyKEINcYnkXteOPBOHRcwXA5tBS +LTgSsQSfHe41bl3SQqQWYkY65CH4LYHHNQJAa1lS/r4w9/fO2gHyOz7FCEdRupBz +ykVhOA1PceJQFTm0GaMJw2M/nLi2BoOgZSN2OhWLSekfN/eraJllS60nCwJAch5D +UAFDBOcTmphJIhza7Ar+fGAVhwOZ3Ugge1MmHGAsdrq9hDJ9yrTuGxLQvrc9RNJM +Ihy9FAsbJR+hI5fgxQJAK+oeuE/LxSI9lVFe/wl4so0AsA98aYjK0lB+qBT6F7Zf +QEN6sCv+4Peulp4pIm160LuYt2+/iJ1G/ezRyfbctw== +-----END RSA PRIVATE KEY----- diff --git a/backoffice/backoffice-domain-service/ballerina/tests/subscriptionTest.bal b/backoffice/backoffice-domain-service/ballerina/tests/subscriptionTest.bal new file mode 100644 index 000000000..492fe7844 --- /dev/null +++ b/backoffice/backoffice-domain-service/ballerina/tests/subscriptionTest.bal @@ -0,0 +1,30 @@ +// +// Copyright (c) 2022, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + +import ballerina/test; +import wso2/apk_common_lib as commons; + +@test:Config {dependsOn: [createAPITest]} +function getAllSubcriptions() { + SubscriptionList|commons:APKError getSub = getSubscriptions("01ed75e2-b30b-18c8-wwf2-25da7edd2231"); + if getSub is SubscriptionList { + test:assertTrue(true, "Successfully retrive all subscriptions"); + } else if getSub is commons:APKError { + test:assertFail("Error occured while retrive subscriptions"); + } +} diff --git a/backoffice/backoffice-domain-service/ballerina/tests/testUtils.bal b/backoffice/backoffice-domain-service/ballerina/tests/testUtils.bal new file mode 100644 index 000000000..a353181b1 --- /dev/null +++ b/backoffice/backoffice-domain-service/ballerina/tests/testUtils.bal @@ -0,0 +1,45 @@ +// +// Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + +import ballerina/http; +import ballerina/mime; +import ballerina/io; + +# Create http request including image form data +# +# + thumnailImageName - image name +# + imageContentType - image content type +# + return - http:Request | error +isolated function createRequestWithImageFormData(string thumnailImageName, string imageContentType) returns http:Request|error { + mime:Entity imageBodyPart = new; + byte[] imageBytes = check io:fileReadBytes("./tests/resources/" + thumnailImageName); + imageBodyPart.setByteArray(imageBytes); + mime:InvalidContentTypeError? contentType = imageBodyPart.setContentType(imageContentType); + if contentType is mime:InvalidContentTypeError { + return contentType; + } + mime:ContentDisposition contentDisposition = new; + contentDisposition.disposition = "form-data"; + contentDisposition.name = "file"; + contentDisposition.fileName = thumnailImageName; + imageBodyPart.setContentDisposition(contentDisposition); + mime:Entity[] bodyParts = [imageBodyPart]; + http:Request request = new; + request.setBodyParts(bodyParts); + return request; +} diff --git a/backoffice/backoffice-domain-service/ballerina/types.bal b/backoffice/backoffice-domain-service/ballerina/types.bal new file mode 100644 index 000000000..c802bda53 --- /dev/null +++ b/backoffice/backoffice-domain-service/ballerina/types.bal @@ -0,0 +1,678 @@ +import ballerina/http; +import ballerina/constraint; + +public type NotAcceptableError record {| + *http:NotAcceptable; + Error body; +|}; + +public type UnsupportedMediaTypeError record {| + *http:UnsupportedMediaType; + Error body; +|}; + +public type ForbiddenError record {| + *http:Forbidden; + Error body; +|}; + +public type InternalServerErrorError record {| + *http:InternalServerError; + Error body; +|}; + +public type ConflictError record {| + *http:Conflict; + Error body; +|}; + +public type PreconditionFailedError record {| + *http:PreconditionFailed; + Error body; +|}; + +public type CreatedComment record {| + *http:Created; + Comment body; +|}; + +public type NotFoundError record {| + *http:NotFound; + Error body; +|}; + +public type CreatedDocument record {| + *http:Created; + Document body; +|}; + +public type BadRequestError record {| + *http:BadRequest; + Error body; +|}; + +public type UnauthorizedError record {| + *http:Unauthorized; + Error body; +|}; + +public type DocumentList record { + # Number of Documents returned. + int count?; + Document[] list?; + Pagination pagination?; +}; + +public type UsageLimitBase record { + # Unit of the time. Allowed values are "sec", "min", "hour", "day" + string timeUnit; + # Time limit that the usage limit applies. + int unitTime; +}; + +public type APIScope record { + Scope scope; +}; + +public type Document record { + string documentId?; + @constraint:String {maxLength: 60, minLength: 1} + string name; + string documentType; + @constraint:String {maxLength: 32766, minLength: 1} + string summary?; + string sourceType; + string sourceUrl?; + string fileName?; + string inlineContent?; + string otherTypeName?; + string visibility; + string createdTime?; + string createdBy?; + string lastUpdatedTime?; + string lastUpdatedBy?; +}; + +public type ExternalStore record { + # The external store identifier, which is a unique value. + string id?; + # The name of the external API Store that is displayed in the Publisher UI. + string displayName?; + # The type of the Store. This can be a WSO2-specific API Store or an external one. + string 'type?; + # The endpoint URL of the external store + string endpoint?; +}; + +public type Pagination record { + int offset?; + int 'limit?; + int total?; + # Link to the next subset of resources qualified. + # Empty if no more resources are to be returned. + string next?; + # Link to the previous subset of resources qualified. + # Empty if current subset is the first subset returned. + string previous?; +}; + +public type EventCountLimit record { + *UsageLimitBase; + # Maximum number of events allowed + int eventCount; +}; + +public type ResourcePath record { + int id; + string resourcePath?; + string httpVerb?; +}; + +public type API_additionalProperties record { + string name?; + string value?; + boolean display?; +}; + +public type FileInfo record { + # relative location of the file (excluding the base context and host of the Publisher API) + string fileName?; + # media-type of the file + string mediaType?; +}; + +public type APIOperations record { + string id?; + string target?; + string verb?; + string usagePlan?; +}; + +public type APIList record { + # Number of APIs returned. + int count?; + API[] list?; + Pagination pagination?; +}; + +public type BusinessPlan record { + *Policy; + *GraphQLQuery; + ThrottleLimit defaultLimit; + # Burst control request count + int rateLimitCount?; + # Burst control time unit + string rateLimitTimeUnit?; + # Number of subscriptions allowed + int subscriberCount?; + # Custom attributes added to the Subscription Throttling Policy + CustomAttribute[] customAttributes?; + BusinessPlanPermission permissions?; +}; + +public type Policy record { + # Id of plan + string planId?; + # Name of plan + @constraint:String {maxLength: 60, minLength: 1} + string planName; + # Display name of the policy + @constraint:String {maxLength: 512} + string displayName?; + # Description of the policy + @constraint:String {maxLength: 1024} + string description?; + # Indicates whether the policy is deployed successfully or not. + boolean isDeployed = false; + # Indicates the type of throttle policy + string 'type?; +}; + +public type GraphQLQuery record { + # Maximum Complexity of the GraphQL query + int graphQLMaxComplexity?; + # Maximum Depth of the GraphQL query + int graphQLMaxDepth?; +}; + +public type APIMonetizationUsage record { + # Map of custom properties related to monetization usage + record {} properties?; +}; + +public type Subscription record { + string subscriptionId; + ApplicationInfo applicationInfo; + string usagePlan; + string subscriptionStatus; +}; + +public type Settings record { + # The Developer Portal URL + string devportalUrl?; + Environment[] environment?; + string[] scopes?; + MonetizationAttribute[] monetizationAttributes?; + # Is Document Visibility configuration enabled + boolean docVisibilityEnabled?; + # Authorization Header + string authorizationHeader?; +}; + +public type APIRevision record { + string displayName?; + string id?; + @constraint:String {maxLength: 255} + string description?; + string createdTime?; +}; + +public type BusinessPlanList record { + # Number of Business Plans returned. + int count?; + BusinessPlan[] list?; +}; + +public type APIExternalStoreList record { + # Number of external stores returned. + int count?; + APIExternalStore[] list?; +}; + +public type ResourcePathList record { + # Number of API Resource Paths returned. + int count?; + ResourcePath[] list?; + Pagination pagination?; +}; + +public type APIBusinessInformation record { + @constraint:String {maxLength: 120} + string businessOwner?; + string businessOwnerEmail?; + @constraint:String {maxLength: 120} + string technicalOwner?; + string technicalOwnerEmail?; +}; + +public type APIMonetizationInfo record { + # Flag to indicate the monetization status + boolean enabled; + # Map of custom properties related to monetization + record {} properties?; +}; + +public type ThrottleLimit record { + # Type of the throttling limit. Allowed values are "REQUESTCOUNTLIMIT" and "BANDWIDTHLIMIT". + # Please see schemas of "RequestCountLimit" and "BandwidthLimit" throttling limit types in + # Definitions section. + string 'type; + RequestCountLimit requestCount?; + BandwidthLimit bandwidth?; + EventCountLimit eventCount?; +}; + +public type LifecycleHistoryItem record { + string previousState?; + string postState?; + string user?; + string updatedTime?; +}; + +public type UsagePlanList record { + # Number of Usage Plans returned. + int count?; + # Array of Usage Policies + UsagePlan[] list?; + Pagination pagination?; +}; + +public type APIDeployment record { + @constraint:String {maxLength: 255, minLength: 1} + string name?; + string deployedTime?; +}; + +public type MonetizationAttribute record { + # Is attribute required + boolean required?; + # Name of the attribute + string name?; + # Display name of the attribute + string displayName?; + # Description of the attribute + string description?; + # Is attribute hidden + boolean hidden?; + # Default value of the attribute + string default?; +}; + +public type APIDefinition record { + string 'type; + string schemaDefinition?; +}; + +public type CommenterInfo record { + string firstName?; + string lastName?; + string fullName?; +}; + +public type Environment record { + string id; + string name; + string displayName?; + string 'type; + string serverUrl; + string provider?; + boolean showInApiConsole; + GatewayEnvironmentProtocolURI[] endpointURIs?; + AdditionalProperty[] additionalProperties?; +}; + +public type CommentList record { + # Number of Comments returned. + int count?; + Comment[] list?; + Pagination pagination?; +}; + +public type BusinessPlanPermission record { + string permissionType; + string[] roles; +}; + +public type CustomAttribute record { + # Name of the custom attribute + string name; + # Value of the custom attribute + string value; +}; + +public type ErrorListItem record { + string code; + # Description about individual errors occurred + string message; + # A detail description about the error message. + string description?; +}; + +public type APIRevenue record { + # Map of custom properties related to API revenue + record {} properties?; +}; + +public type APICategoryList record { + # Number of API categories returned. + int count?; + APICategory[] list?; +}; + +public type DocumentId_content_body record { + # Document to upload + string file?; + # Inline content of the document + string inlineContent?; +}; + +public type ApplicationInfo record { + string applicationId?; + string name?; + string subscriber?; + string description?; + int subscriptionCount?; +}; + +public type ModifiableAPI record { + # UUID of the API + string id?; + # Name of the API + @constraint:String {maxLength: 50, minLength: 1} + string name; + @constraint:String {maxLength: 60, minLength: 1} + string context?; + # A brief description about the API + string description?; + boolean hasThumbnail?; + # State of the API. Only published APIs are visible on the Developer Portal + string state = "CREATED"; + string[] tags?; + record {} additionalProperties?; + APIMonetizationInfo monetization?; + APIBusinessInformation businessInformation?; + # API categories + string[] categories?; + # Supported SDK + string[] sdk?; + string[] policies?; +}; + +public type LifecycleState record { + string state?; + LifecycleState_availableTransitions[] availableTransitions?; +}; + +public type ApiId_thumbnail_body record { + # Image to upload + string file; +}; + +public type SubscriptionThrottlePolicyPermission record { + string permissionType; + string[] roles; +}; + +public type SearchResultList record { + # Number of results returned. + int count?; + record {}[] list?; + Pagination pagination?; +}; + +public type LifecycleHistory record { + int count?; + LifecycleHistoryItem[] list?; +}; + +public type LifecycleState_availableTransitions record { + string event?; + string targetState?; +}; + +public type ExternalStoreList record { + # Number of external stores returned. + int count?; + ExternalStore[] list?; +}; + +public type UsagePlan record { + # Id of policy + int policyId?; + # policy uuid + string uuid?; + # Name of policy + @constraint:String {maxLength: 60, minLength: 1} + string policyName?; + # Display name of the policy + @constraint:String {maxLength: 512} + string displayName?; + # Description of the policy + @constraint:String {maxLength: 1024} + string description?; + # Usage policy organization + string organization?; + UsageLimit defaultLimit; + # Burst control request count + int rateLimitCount?; + # Burst control time unit + string rateLimitTimeUnit?; + # Number of subscriptions allowed + int subscriberCount?; + # Custom attributes added to the Usage plan + CustomAttribute[] customAttributes?; + # This indicates the action to be taken when a user goes beyond the allocated quota. If checked, the user's requests will be dropped. If unchecked, the requests will be allowed to pass through. + boolean stopOnQuotaReach = false; + # define whether this is Paid or a Free plan. Allowed values are FREE or COMMERCIAL. + string billingPlan?; + SubscriptionThrottlePolicyPermission permissions?; +}; + +public type Comment record { + string id?; + @constraint:String {maxLength: 512} + string content; + string createdTime?; + string createdBy?; + string updatedTime?; + string category = "general"; + string parentCommentId?; + string entryPoint?; + CommenterInfo commenterInfo?; + CommentList replies?; +}; + +public type RequestCountLimit record { + *UsageLimitBase; + # Maximum number of requests allowed + int requestCount; +}; + +public type ThreatProtectionPolicy record { + # Policy ID + string uuid?; + # Name of the policy + string name; + # Type of the policy + string 'type; + # policy as a json string + string policy; +}; + +public type APIInfo record { + string id?; + string name?; + string description?; + string context?; + string 'version?; + string 'type?; + string createdTime?; + string updatedTime?; + boolean hasThumbnail?; + # State of the API. Only published APIs are visible on the Developer Portal + string state?; +}; + +public type APIExternalStore record { + # The external store identifier, which is a unique value. + string id?; + # The recent timestamp which a given API is updated in the external store. + string lastUpdatedTime?; +}; + +public type Error record { + int code; + # Error message. + string message; + # A detail description about the error message. + string description?; + # Preferably an url with more details about the error. + string moreInfo?; + # If there are more than one error list them out. + # For example, list out validation errors by each field. + ErrorListItem[] 'error?; +}; + +public type SearchResult record { + string id?; + string name; + string 'type?; + # Accepted values are HTTP, WS, SOAPTOREST, GRAPHQL + string transportType?; +}; + +public type GatewayEnvironmentProtocolURI record { + string protocol; + string endpointURI; +}; + +public type UsageLimit record { + # Type of the usage limit. Allowed values are "REQUESTCOUNTLIMIT" and "BANDWIDTHLIMIT". + # Please see schemas of "RequestCountLimit" and "BandwidthLimit" usage limit types in + # Definitions section. + string 'type; + RequestCountLimit requestCount?; + BandwidthLimit bandwidth?; + EventCountLimit eventCount?; +}; + +public type Scope record { + # UUID of the Scope. Valid only for shared scopes. + string id?; + # name of Scope + @constraint:String {maxLength: 255, minLength: 1} + string name; + # display name of Scope + @constraint:String {maxLength: 255} + string displayName?; + # description of Scope + @constraint:String {maxLength: 512} + string description?; + # role bindings list of the Scope + string[] bindings?; + # usage count of Scope + int usageCount?; +}; + +public type PatchRequestBody record { + # Content of the comment + @constraint:String {maxLength: 512} + string content?; + # Category of the comment + string category?; +}; + +public type PostRequestBody record { + # Content of the comment + @constraint:String {maxLength: 512} + string content; + # Category of the comment + string category?; +}; + +public type SubscriptionList record { + # Number of Subscriptions returned. + int count?; + Subscription[] list?; + Pagination pagination?; +}; + +public type WorkflowResponse record { + # This attribute declares whether this workflow task is approved or rejected. + string workflowStatus; + # Attributes that returned after the workflow execution + string jsonPayload?; + LifecycleState lifecycleState?; +}; + +public type API record { + # UUID of the API + string id?; + @constraint:String {maxLength: 60, minLength: 1} + string name; + @constraint:String {maxLength: 32766} + string description?; + @constraint:String {maxLength: 232, minLength: 1} + string context; + @constraint:String {maxLength: 30, minLength: 1} + string 'version; + string organization; + # The api creation type to be used. Accepted values are HTTP, WS, SOAPTOREST, GRAPHQL, WEBSUB, SSE, WEBHOOK, ASYNC + string 'type = "HTTP"; + # Supported transports for the API (http and/or https). + string[] transport?; + boolean hasThumbnail?; + # State of the API. Only published APIs are visible on the Developer Portal + string state = "CREATED"; + string[] tags?; + # API categories + string[] categories?; + # Supported SDK + string[] sdk?; + string[] policies?; + string provider?; + string lifeCycleStatus?; + record {} additionalProperties?; + string createdTime?; + string lastUpdatedTime?; + APIOperations[] operations?; + # The API level usage policy selected for the particular Runtime API + string apiUsagePolicy?; + APIMonetizationInfo monetization?; + APIBusinessInformation businessInformation?; + APIRevision revision?; + APIDeployment[] deployments?; +}; + +public type AdditionalProperty record { + string 'key?; + string value?; +}; + +public type APICategory record { + string id?; + string name; + string description?; +}; + +public type SubscriberInfo record { + string name?; +}; + +public type BandwidthLimit record { + *UsageLimitBase; + # Amount of data allowed to be transfered + int dataAmount; + # Unit of data allowed to be transfered. Allowed values are "KB", "MB" and "GB" + string dataUnit; +}; diff --git a/backoffice/backoffice-domain-service/ballerina/types_internal.bal b/backoffice/backoffice-domain-service/ballerina/types_internal.bal new file mode 100644 index 000000000..f46def320 --- /dev/null +++ b/backoffice/backoffice-domain-service/ballerina/types_internal.bal @@ -0,0 +1,49 @@ +import ballerina/http; + + + +public type CreatedAPI record {| + *http:Created; + API body; +|}; + + +public type APIBody record { + API apiProperties; + # Content of the definition + record {} Definition; +}; + +public type WSDLInfo record { + # Indicates whether the WSDL is a single WSDL or an archive in ZIP format + string 'type?; +}; + +public type API_threatProtectionPolicies_list record { + string policyId?; + int priority?; +}; + + +public type API_serviceInfo record { + string 'key?; + string name?; + string 'version?; + boolean outdated?; +}; + +public type APIDefinition1 record { + # Content of the definition + record {} Definition; +}; + + +public type API_additionalPropertiesMap record { + string name?; + string value?; + boolean display?; +}; + +public type API_threatProtectionPolicies record { + API_threatProtectionPolicies_list[] list?; +}; diff --git a/backoffice/backoffice-domain-service/build.gradle b/backoffice/backoffice-domain-service/build.gradle new file mode 100644 index 000000000..24f9196b9 --- /dev/null +++ b/backoffice/backoffice-domain-service/build.gradle @@ -0,0 +1,40 @@ +// +// Copyright (c) 2022, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + +plugins { + id 'net.researchgate.release' version '2.8.0' +} +allprojects { + group = project.group + version = project.version +} + +release { + tagTemplate = 'backoffice-domain-service-$version' + + git { + requireBranch= "main" + pushToRemote= "origin" + } +} + +unSnapshotVersion.finalizedBy ":ballerina:commit_toml_files" +afterReleaseBuild.dependsOn ":docker:docker_push" +task build{ + dependsOn("docker:build") +} \ No newline at end of file diff --git a/backoffice/backoffice-domain-service/docker/Dockerfile b/backoffice/backoffice-domain-service/docker/Dockerfile new file mode 100644 index 000000000..c2daaeae3 --- /dev/null +++ b/backoffice/backoffice-domain-service/docker/Dockerfile @@ -0,0 +1,81 @@ +#--------------------------------------------------------------- +# +# Copyright (c) 2022, WSO2 LLC. (http://www.wso2.com). +# +# WSO2 LLC. licenses this file to you 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. +# +#--------------------------------------------------------------- + +FROM ubuntu:20.04 + +ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en' LC_ALL='en_US.UTF-8' + +# install JDK Dependencies +RUN apt-get update \ + && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends tzdata curl wget ca-certificates fontconfig locales \ + && echo "en_US.UTF-8 UTF-8" >> /etc/locale.gen \ + && locale-gen en_US.UTF-8 \ + && rm -rf /var/lib/apt/lists/* + +ENV JAVA_VERSION jdk-11.0.17+8 + +RUN set -eux; \ + ARCH="$(dpkg --print-architecture)"; \ + case "${ARCH}" in \ + amd64|i386:x86-64) \ + ESUM='752616097e09d7f60a3ad8bd312f90eaf50ac72577e55df229fe6e8091148f79'; \ + BINARY_URL='https://github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.17%2B8/OpenJDK11U-jre_x64_linux_hotspot_11.0.17_8.tar.gz'; \ + ;; \ + aarch64|arm64) \ + ESUM='bd6efe3290c8b5a42f695a55a26f3e3c9c284288574879d4b7089f31f5114177'; \ + BINARY_URL='https://github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.17%2B8/OpenJDK11U-jre_aarch64_linux_hotspot_11.0.17_8.tar.gz'; \ + ;; \ + *) \ + echo "Unsupported arch: ${ARCH}"; \ + exit 1; \ + ;; \ + esac; \ + curl -LfsSo /tmp/openjdk.tar.gz ${BINARY_URL}; \ + echo "${ESUM} */tmp/openjdk.tar.gz" | sha256sum -c -; \ + mkdir -p /opt/java/openjdk; \ + cd /opt/java/openjdk; \ + tar -xf /tmp/openjdk.tar.gz --strip-components=1; \ + rm -rf /tmp/openjdk.tar.gz; + +ENV JAVA_HOME=/opt/java/openjdk \ + PATH="/opt/java/openjdk/bin:$PATH" + +RUN echo Verifying install ... \ + && echo java --version && java --version \ + && echo Complete. + +ARG USER=wso2apk +ARG USER_ID=802 +ARG USER_GROUP=wso2 +ARG USER_GROUP_ID=802 +ARG USER_HOME=/home/${USER} + +RUN groupadd --system -g ${USER_GROUP_ID} ${USER_GROUP} && useradd --system --create-home --home-dir ${USER_HOME} --no-log-init -g ${USER_GROUP_ID} -u ${USER_ID} ${USER} + +COPY docker-entrypoint.sh ${USER_HOME} +ADD backoffice ${USER_HOME}/backoffice +RUN chown -R ${USER} ${USER_HOME}/backoffice +RUN chown ${USER} /home/${USER}/docker-entrypoint.sh + +EXPOSE 9443 +USER wso2apk +WORKDIR ${USER_HOME} + +ENTRYPOINT ["sh", "/home/wso2apk/docker-entrypoint.sh"] \ No newline at end of file diff --git a/backoffice/backoffice-domain-service/docker/backoffice/backoffice.sh b/backoffice/backoffice-domain-service/docker/backoffice/backoffice.sh new file mode 100755 index 000000000..5244b6a24 --- /dev/null +++ b/backoffice/backoffice-domain-service/docker/backoffice/backoffice.sh @@ -0,0 +1,106 @@ +# resolve links - $0 may be a softlink +PRG="$0" + +while [ -h "$PRG" ]; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '.*/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`/"$link" + fi +done + +# Get standard environment variables +PRGDIR=`dirname "$PRG"` + +[ -z "$BACKOFFICE_HOME" ] && BACKOFFICE_HOME=`cd "$PRGDIR" ; pwd` + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD=java + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." + echo " Admin cannot execute $JAVACMD" + exit 1 +fi + +# if JAVA_HOME is not set we're not happy +if [ -z "$JAVA_HOME" ]; then + echo "You must set the JAVA_HOME variable before running Admin." + exit 1 +fi +# ----- Process the input command ---------------------------------------------- +args="" +for c in $* +do + if [ "$c" = "--debug" ] || [ "$c" = "-debug" ] || [ "$c" = "debug" ]; then + CMD="--debug" + continue + elif [ "$CMD" = "--debug" ]; then + if [ -z "$PORT" ]; then + PORT=$c + fi + fi +done + +if [ "$CMD" = "--debug" ]; then + if [ "$PORT" = "" ]; then + echo " Please specify the debug port after the --debug option" + exit 1 + fi + if [ -n "$JAVA_OPTS" ]; then + echo "Warning !!!. User specified JAVA_OPTS will be ignored, once you give the --debug option." + fi + CMD="RUN" + JAVA_OPTS="-Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=$PORT" + echo "Please start the remote debugging client to continue..." +fi + +CLASSPATH="" +if [ -e "$JAVA_HOME/lib/tools.jar" ]; then + CLASSPATH="$JAVA_HOME/lib/tools.jar" +fi +for t in "$BACKOFFICE_HOME"/lib/*.jar +do + CLASSPATH="$CLASSPATH":$t +done + +# ----- Execute The Requested Command ----------------------------------------- + +echo JAVA_HOME environment variable is set to $JAVA_HOME +echo BACKOFFICE_HOME environment variable is set to "$BACKOFFICE_HOME" +export BAL_CONFIG_FILES=$BACKOFFICE_HOME/conf/Config.toml +cd "$BACKOFFICE_HOME" + +TMP_DIR="$BACKOFFICE_HOME"/tmp +if [ -d "$TMP_DIR" ]; then +rm -rf "$TMP_DIR"/* +fi + +START_EXIT_STATUS=121 +status=$START_EXIT_STATUS + +if [ -z "$JVM_MEM_OPTS" ]; then + java_version=$("$JAVACMD" -version 2>&1 | awk -F '"' '/version/ {print $2}') + JVM_MEM_OPTS="-Xms256m -Xmx1024m" +fi +echo "Using Java memory options: $JVM_MEM_OPTS" + +$JAVACMD \ + $JVM_MEM_OPTS \ + $JAVA_OPTS \ + -classpath "$CLASSPATH" \ + -Djava.io.tmpdir="$BACKOFFICE_HOME/tmp" \ + -jar backoffice_service.jar $* + status=$? \ No newline at end of file diff --git a/backoffice/backoffice-domain-service/docker/backoffice/conf/Config.toml b/backoffice/backoffice-domain-service/docker/backoffice/conf/Config.toml new file mode 100644 index 000000000..f9556f060 --- /dev/null +++ b/backoffice/backoffice-domain-service/docker/backoffice/conf/Config.toml @@ -0,0 +1,19 @@ + [wso2.backoffice_service.datasourceConfiguration] + description = "Database for admin" + url = "jdbc:postgresql://10.102.56.192:5432/WSO2AM_DB" + username = "wso2carbon" + password = "wso2carbon" + validationTimeout = 250 + testQuery = "SELECT 1" + driver = "org.postgresql.Driver" + host = "10.102.56.192" + port = 5432 + databaseName = "WSO2AM_DB" + [wso2.backoffice_service.k8sConfig] + host = "localhost:9090" + serviceAccountPath = "tests/resources/serviceAccount" + + [wso2.backoffice_service.managementServerConfig] + serviceName = "apk-test-wso2-apk-management-server" + namespace = "apk" + certPath = "/home/wso2apk/backoffice/security/truststore/management-server.pem" diff --git a/backoffice/backoffice-domain-service/docker/backoffice/security/.gitkeep b/backoffice/backoffice-domain-service/docker/backoffice/security/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/backoffice/backoffice-domain-service/docker/build.gradle b/backoffice/backoffice-domain-service/docker/build.gradle new file mode 100644 index 000000000..21b206b39 --- /dev/null +++ b/backoffice/backoffice-domain-service/docker/build.gradle @@ -0,0 +1,36 @@ +// +// Copyright (c) 2022, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + +apply from: "$rootDir/../../common-gradle-scripts/docker.gradle" +apply from: "$rootDir/../../common-gradle-scripts/copy.gradle" + +tasks.named('copy_dist').configure{ + finalizedBy docker_build +} + +tasks.register('build') { + group 'build' + description 'Build docker image' + dependsOn 'copy_dist' + dependsOn 'docker_build' +} + +build.configure{ + mustRunAfter(":ballerina:build") + dependsOn(":ballerina:build") + } \ No newline at end of file diff --git a/backoffice/backoffice-domain-service/docker/docker-entrypoint.sh b/backoffice/backoffice-domain-service/docker/docker-entrypoint.sh new file mode 100644 index 000000000..cd56dbf75 --- /dev/null +++ b/backoffice/backoffice-domain-service/docker/docker-entrypoint.sh @@ -0,0 +1,20 @@ +#!/bin/bash +# +# Copyright (c) 2022, WSO2 LLC. (http://www.wso2.com). +# +# WSO2 LLC. licenses this file to you 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. +# + +sh /home/wso2apk/backoffice/backoffice.sh \ No newline at end of file diff --git a/backoffice/backoffice-domain-service/gradle.properties b/backoffice/backoffice-domain-service/gradle.properties new file mode 100644 index 000000000..da8d3aebd --- /dev/null +++ b/backoffice/backoffice-domain-service/gradle.properties @@ -0,0 +1,6 @@ +group=org.wso2.apk +version=0.0.1-SNAPSHOT +docker_image_name = backoffice-domain-service +jar_name = backoffice_service.jar +dist_name = backoffice + diff --git a/backoffice/backoffice-domain-service/gradle/wrapper/gradle-wrapper.properties b/backoffice/backoffice-domain-service/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..f398c33c4 --- /dev/null +++ b/backoffice/backoffice-domain-service/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip +networkTimeout=10000 +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/backoffice/backoffice-domain-service/gradlew b/backoffice/backoffice-domain-service/gradlew new file mode 100755 index 000000000..a69d9cb6c --- /dev/null +++ b/backoffice/backoffice-domain-service/gradlew @@ -0,0 +1,240 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# 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 +# +# https://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. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/backoffice/backoffice-domain-service/gradlew.bat b/backoffice/backoffice-domain-service/gradlew.bat new file mode 100644 index 000000000..f127cfd49 --- /dev/null +++ b/backoffice/backoffice-domain-service/gradlew.bat @@ -0,0 +1,91 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/backoffice/backoffice-domain-service/settings.gradle b/backoffice/backoffice-domain-service/settings.gradle new file mode 100644 index 000000000..655414ef1 --- /dev/null +++ b/backoffice/backoffice-domain-service/settings.gradle @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2022, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. + * + * 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. + * + */ + +rootProject.name = 'backoffice-domain-service' + +include ':ballerina' +include ':docker' +project(':ballerina').projectDir = file('ballerina') +project(':docker').projectDir = file('docker') + +dependencyResolutionManagement { + versionCatalogs { + libs { + from(files("$rootDir/../../libs.versions.toml")) + } + } +} + diff --git a/database/postgres/Dockerfile b/database/postgres/Dockerfile index b5fd58aae..2a0ef107d 100644 --- a/database/postgres/Dockerfile +++ b/database/postgres/Dockerfile @@ -24,6 +24,7 @@ ENV POSTGRES_USER wso2carbon ENV POSTGRES_PASSWORD wso2carbon ENV POSTGRES_DB WSO2AM_DB ENV PGDATA /tmp/data1 +COPY db.sql /docker-entrypoint-initdb.d/ COPY idp.sql /docker-entrypoint-initdb.d/ USER root diff --git a/database/postgres/db.sql b/database/postgres/db.sql new file mode 100644 index 000000000..bb0889b75 --- /dev/null +++ b/database/postgres/db.sql @@ -0,0 +1,370 @@ +GRANT ALL PRIVILEGES ON DATABASE "WSO2AM_DB" TO wso2carbon; + \c "WSO2AM_DB" + BEGIN TRANSACTION; + + CREATE TABLE IF NOT EXISTS INTERNAL_USER ( + UUID VARCHAR(100) NOT NULL, + IDP_USER_NAME VARCHAR(255) NOT NULL, + PRIMARY KEY (UUID), + UNIQUE (IDP_USER_NAME) + ); + + CREATE TABLE IF NOT EXISTS APPLICATION ( + NAME VARCHAR(100), + USER_UUID VARCHAR(100), + APPLICATION_TIER VARCHAR(50) DEFAULT 'Unlimited', + CALLBACK_URL VARCHAR(512), + DESCRIPTION VARCHAR(512), + APPLICATION_STATUS VARCHAR(50) DEFAULT 'APPROVED', + GROUP_ID VARCHAR(100), + CREATED_BY VARCHAR(100), + CREATED_TIME TIMESTAMP, + UPDATED_BY VARCHAR(100), + UPDATED_TIME TIMESTAMP, + UUID VARCHAR(256), + TOKEN_TYPE VARCHAR(10), + ORGANIZATION VARCHAR(100), + FOREIGN KEY(USER_UUID) REFERENCES INTERNAL_USER(UUID) ON UPDATE CASCADE ON DELETE RESTRICT, + PRIMARY KEY(UUID), + UNIQUE(NAME,USER_UUID,ORGANIZATION) + ); + + CREATE TABLE IF NOT EXISTS API ( + UUID VARCHAR(256), + API_NAME VARCHAR(256), + API_VERSION VARCHAR(30), + CONTEXT VARCHAR(256), + CONTEXT_TEMPLATE VARCHAR(256), + API_TIER VARCHAR(256), + API_TYPE VARCHAR(10), + ORGANIZATION VARCHAR(100), + GATEWAY_VENDOR VARCHAR(100) DEFAULT 'wso2', + CREATED_BY VARCHAR(100), + CREATED_TIME TIMESTAMP, + UPDATED_BY VARCHAR(100), + UPDATED_TIME TIMESTAMP, + STATUS VARCHAR(30), + VERSION_COMPARABLE VARCHAR(15), + LOG_LEVEL VARCHAR(255) DEFAULT 'OFF', + REVISIONS_CREATED INTEGER DEFAULT 0, + SDK JSONB, + CATEGORIES JSONB, + ARTIFACT JSONB NOT NULL, + DEFAULT_API_VERSION VARCHAR(30), + PRIMARY KEY(UUID), + UNIQUE(API_NAME,API_VERSION,ORGANIZATION) + ); + + CREATE TABLE API_ARTIFACT ( + ORGANIZATION VARCHAR(100) NOT NULL, + API_UUID VARCHAR(256) NOT NULL, + API_DEFINITION BYTEA, + MEDIA_TYPE VARCHAR(100), + FOREIGN KEY(API_UUID) REFERENCES API(UUID) ON UPDATE CASCADE ON DELETE CASCADE + ); + + CREATE SEQUENCE RESOURCE_CATEGORIES_seq; + CREATE TABLE RESOURCE_CATEGORIES ( + RESOURCE_CATEGORY_ID INTEGER DEFAULT NEXTVAL ('RESOURCE_CATEGORIES_seq'), + RESOURCE_CATEGORY VARCHAR(255), + PRIMARY KEY (RESOURCE_CATEGORY_ID), + UNIQUE (RESOURCE_CATEGORY) + ); + + CREATE TABLE API_RESOURCES ( + UUID VARCHAR(255), + API_UUID VARCHAR(256), + RESOURCE_CATEGORY_ID INTEGER, + DATA_TYPE VARCHAR(255), + RESOURCE_CONTENT TSVECTOR, + RESOURCE_BINARY_VALUE BYTEA, + CREATED_BY VARCHAR(100), + CREATED_TIME TIMESTAMP(6) DEFAULT CURRENT_TIMESTAMP, + UPDATED_BY VARCHAR(100), + LAST_UPDATED_TIME TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY(UUID), + FOREIGN KEY(API_UUID) REFERENCES API(UUID) ON + UPDATE CASCADE ON DELETE CASCADE, + FOREIGN KEY (RESOURCE_CATEGORY_ID) REFERENCES RESOURCE_CATEGORIES(RESOURCE_CATEGORY_ID) + ); + + CREATE TABLE API_DOC_META_DATA( + UUID VARCHAR(255), + RESOURCE_UUID VARCHAR(255), + API_UUID VARCHAR(256), + NAME VARCHAR(255), + SUMMARY VARCHAR(1024), + TYPE VARCHAR(255), + OTHER_TYPE_NAME VARCHAR(255), + SOURCE_URL VARCHAR(255), + FILE_NAME VARCHAR(255), + SOURCE_TYPE VARCHAR(255), + VISIBILITY VARCHAR(30), + CREATED_BY VARCHAR(100), + CREATED_TIME TIMESTAMP(6) DEFAULT CURRENT_TIMESTAMP, + UPDATED_BY VARCHAR(100), + LAST_UPDATED_TIME TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY(UUID), + FOREIGN KEY(API_UUID) REFERENCES API(UUID) ON + UPDATE CASCADE ON DELETE CASCADE, + FOREIGN KEY(RESOURCE_UUID) REFERENCES API_RESOURCES(UUID) ON + UPDATE CASCADE ON DELETE CASCADE + ); + + CREATE SEQUENCE API_URL_MAPPING_SEQUENCE START WITH 1 INCREMENT BY 1; + CREATE TABLE IF NOT EXISTS API_URL_MAPPING ( + URL_MAPPING_ID INTEGER DEFAULT nextval('api_url_mapping_sequence'), + API_UUID VARCHAR(256) NOT NULL, + HTTP_METHOD VARCHAR(20) NULL, + AUTH_SCHEME VARCHAR(50) NULL, + URL_PATTERN VARCHAR(512) NULL, + THROTTLING_TIER_UNIT_TIME VARCHAR(255) DEFAULT NULL, + THROTTLING_TIER_UNIT_VALUE VARCHAR(255) DEFAULT NULL, + PRIMARY KEY(URL_MAPPING_ID), + FOREIGN KEY(API_UUID) REFERENCES API(UUID) ON UPDATE CASCADE ON DELETE CASCADE + ); + + CREATE TABLE IF NOT EXISTS API_RESOURCE_SCOPE_MAPPING ( + SCOPE_NAME VARCHAR(256) NOT NULL, + URL_MAPPING_ID INTEGER NOT NULL, + FOREIGN KEY(URL_MAPPING_ID) REFERENCES API_URL_MAPPING(URL_MAPPING_ID) ON DELETE CASCADE, + PRIMARY KEY(SCOPE_NAME, URL_MAPPING_ID) + ); + + CREATE TABLE IF NOT EXISTS SUBSCRIPTION ( + UUID VARCHAR(256), + TIER_ID VARCHAR(50), + TIER_ID_PENDING VARCHAR(50), + API_UUID VARCHAR(256), + LAST_ACCESSED TIMESTAMP NULL, + APPLICATION_UUID VARCHAR(256), + SUB_STATUS VARCHAR(50), + SUBS_CREATE_STATE VARCHAR(50) DEFAULT 'SUBSCRIBE', + CREATED_BY VARCHAR(100), + CREATED_TIME TIMESTAMP, + UPDATED_BY VARCHAR(100), + UPDATED_TIME TIMESTAMP, + FOREIGN KEY(APPLICATION_UUID) REFERENCES APPLICATION(UUID) ON UPDATE CASCADE ON DELETE CASCADE, + FOREIGN KEY(API_UUID) REFERENCES API(UUID) ON + UPDATE CASCADE ON DELETE CASCADE, + PRIMARY KEY (UUID) + ); + + CREATE TABLE APPLICATION_KEY_MAPPING ( + UUID VARCHAR(100), + APPLICATION_UUID VARCHAR(256), + CONSUMER_KEY VARCHAR(512), + KEY_TYPE VARCHAR(512) NOT NULL, + CREATE_MODE VARCHAR(30) DEFAULT 'CREATED', + APP_INFO BYTEA DEFAULT NULL, + KEY_MANAGER_UUID VARCHAR(100), + FOREIGN KEY(APPLICATION_UUID) REFERENCES APPLICATION(UUID) ON UPDATE CASCADE ON DELETE CASCADE, + -- FOREIGN KEY(KEY_MANAGER_UUID) REFERENCES KEY_MANAGER(UUID) ON UPDATE CASCADE ON DELETE CASCADE, -- + PRIMARY KEY(APPLICATION_UUID,KEY_TYPE,KEY_MANAGER_UUID) + ); + + CREATE SEQUENCE API_LC_EVENT_SEQUENCE START WITH 1 INCREMENT BY 1; + CREATE TABLE IF NOT EXISTS API_LC_EVENT ( + EVENT_ID INTEGER DEFAULT nextval('api_lc_event_sequence'), + API_UUID VARCHAR(256) NOT NULL, + PREVIOUS_STATE VARCHAR(50), + NEW_STATE VARCHAR(50) NOT NULL, + USER_UUID VARCHAR(100) NOT NULL, + ORGANIZATION VARCHAR(100) NOT NULL, + EVENT_DATE TIMESTAMP NOT NULL, + FOREIGN KEY(API_UUID) REFERENCES API(UUID) ON + UPDATE CASCADE ON DELETE CASCADE, + FOREIGN KEY(USER_UUID) REFERENCES INTERNAL_USER(UUID) ON UPDATE CASCADE ON DELETE CASCADE, + PRIMARY KEY (EVENT_ID) + ); + + CREATE TABLE IF NOT EXISTS API_COMMENTS ( + COMMENT_ID VARCHAR(64) NOT NULL, + COMMENT_TEXT VARCHAR(512), + CREATED_BY VARCHAR(255), + CREATED_TIME TIMESTAMP NOT NULL, + UPDATED_TIME TIMESTAMP, + API_UUID VARCHAR(256), + PARENT_COMMENT_ID VARCHAR(64) DEFAULT NULL, + ENTRY_POINT VARCHAR(20), + CATEGORY VARCHAR(20) DEFAULT 'general', + FOREIGN KEY(API_UUID) REFERENCES API(UUID) ON DELETE CASCADE, + FOREIGN KEY(PARENT_COMMENT_ID) REFERENCES API_COMMENTS(COMMENT_ID), + PRIMARY KEY(COMMENT_ID) + ); + + CREATE TABLE IF NOT EXISTS API_RATINGS ( + RATING_UUID VARCHAR(255) NOT NULL, + API_UUID VARCHAR(256), + RATING INTEGER, + USER_UUID VARCHAR(100), + FOREIGN KEY(API_UUID) REFERENCES API(UUID) ON UPDATE CASCADE ON DELETE CASCADE, + FOREIGN KEY(USER_UUID) REFERENCES INTERNAL_USER(UUID) ON + UPDATE CASCADE ON DELETE RESTRICT, + PRIMARY KEY (RATING_UUID) + ); + + CREATE TABLE IF NOT EXISTS BUSINESS_PLAN ( + UUID VARCHAR(256), + NAME VARCHAR(512) NOT NULL, + DISPLAY_NAME VARCHAR(512) NULL DEFAULT NULL, + ORGANIZATION VARCHAR(100) NOT NULL, + DESCRIPTION VARCHAR(1024) NULL DEFAULT NULL, + QUOTA_TYPE VARCHAR(25) NOT NULL, + QUOTA INTEGER NOT NULL, + QUOTA_UNIT VARCHAR(10) NULL, + UNIT_TIME INTEGER NOT NULL, + TIME_UNIT VARCHAR(25) NOT NULL, + RATE_LIMIT_COUNT INTEGER NULL DEFAULT NULL, + RATE_LIMIT_TIME_UNIT VARCHAR(25) NULL DEFAULT NULL, + IS_DEPLOYED BOOLEAN NOT NULL DEFAULT '0', + CUSTOM_ATTRIBUTES BYTEA DEFAULT NULL, + STOP_ON_QUOTA_REACH BOOLEAN NOT NULL DEFAULT '0', + BILLING_PLAN VARCHAR(20) NOT NULL, + MONETIZATION_PLAN VARCHAR(25) NULL DEFAULT NULL, + FIXED_RATE VARCHAR(15) NULL DEFAULT NULL, + BILLING_CYCLE VARCHAR(15) NULL DEFAULT NULL, + PRICE_PER_REQUEST VARCHAR(15) NULL DEFAULT NULL, + CURRENCY VARCHAR(15) NULL DEFAULT NULL, + MAX_COMPLEXITY INTEGER NOT NULL DEFAULT 0, + MAX_DEPTH INTEGER NOT NULL DEFAULT 0, + CONNECTIONS_COUNT INTEGER NOT NULL DEFAULT 0, + PRIMARY KEY(UUID), + UNIQUE(NAME, ORGANIZATION) + ); + + CREATE TABLE IF NOT EXISTS APPLICATION_USAGE_PLAN ( + NAME VARCHAR(512) NOT NULL, + DISPLAY_NAME VARCHAR(512) NULL DEFAULT NULL, + ORGANIZATION VARCHAR(100) NOT NULL, + DESCRIPTION VARCHAR(1024) NULL DEFAULT NULL, + QUOTA_TYPE VARCHAR(25) NOT NULL, + QUOTA INTEGER NOT NULL, + QUOTA_UNIT VARCHAR(10) NULL DEFAULT NULL, + UNIT_TIME INTEGER NOT NULL, + TIME_UNIT VARCHAR(25) NOT NULL, + IS_DEPLOYED BOOLEAN NOT NULL DEFAULT '0', + CUSTOM_ATTRIBUTES BYTEA DEFAULT NULL, + UUID VARCHAR(256), + PRIMARY KEY(UUID), + UNIQUE(NAME, ORGANIZATION) + ); + + CREATE TABLE BLOCK_CONDITION ( + TYPE varchar(45) DEFAULT NULL, + BLOCK_CONDITION varchar(512) DEFAULT NULL, + ENABLED varchar(45) DEFAULT NULL, + ORGANIZATION varchar(100) DEFAULT NULL, + UUID VARCHAR(256), + PRIMARY KEY (UUID) + ); + + CREATE TABLE APPLICATION_GROUP_MAPPING ( + APPLICATION_UUID VARCHAR(256) NOT NULL, + GROUP_ID VARCHAR(512) NOT NULL, + ORGANIZATION VARCHAR(100) DEFAULT NULL, + PRIMARY KEY (APPLICATION_UUID,GROUP_ID,ORGANIZATION), + FOREIGN KEY (APPLICATION_UUID) REFERENCES APPLICATION(UUID) ON DELETE CASCADE ON UPDATE CASCADE + ); + + CREATE TABLE IF NOT EXISTS APPLICATION_ATTRIBUTES ( + APPLICATION_UUID VARCHAR(256) NOT NULL, + NAME VARCHAR(255) NOT NULL, + APP_ATTRIBUTE VARCHAR(1024) NOT NULL, + ORGANIZATION VARCHAR(100) NOT NULL, + PRIMARY KEY(APPLICATION_UUID,NAME), + FOREIGN KEY(APPLICATION_UUID) REFERENCES APPLICATION(UUID) ON + DELETE CASCADE ON UPDATE CASCADE + ); + + CREATE TABLE IF NOT EXISTS API_CATEGORIES ( + UUID VARCHAR(50), + NAME VARCHAR(255), + DESCRIPTION VARCHAR(1024), + ORGANIZATION VARCHAR(100), + UNIQUE(NAME,ORGANIZATION), + PRIMARY KEY(UUID) + ); + + CREATE TABLE IF NOT EXISTS ORGANIZATION ( + UUID VARCHAR(50), + NAME VARCHAR(255), + DISPLAY_NAME VARCHAR(255), + STATUS BOOLEAN NOT NULL DEFAULT 'TRUE', + NAMESPACE JSONB, + WORKFLOWS BYTEA, + UNIQUE(NAME), + PRIMARY KEY(UUID) + ); + + CREATE TABLE IF NOT EXISTS ORGANIZATION_CLAIM_MAPPING ( + UUID VARCHAR(50), + CLAIM_KEY VARCHAR(255), + CLAIM_VALUE VARCHAR(255), + FOREIGN KEY(UUID) REFERENCES ORGANIZATION(UUID) ON UPDATE CASCADE ON DELETE CASCADE, + UNIQUE(UUID,CLAIM_KEY) + ); + + CREATE TABLE IF NOT EXISTS ORGANIZATION_VHOST ( + UUID VARCHAR(50), + VHOST VARCHAR(255), + TYPE VARCHAR(50), + FOREIGN KEY(UUID) REFERENCES ORGANIZATION(UUID) ON UPDATE CASCADE ON DELETE CASCADE, + UNIQUE(UUID, VHOST, TYPE) + ); + + CREATE TABLE IF NOT EXISTS WORKFLOWS( + UUID VARCHAR(255) NOT NULL , + WF_REFERENCE VARCHAR(255) NOT NULL, + WF_TYPE VARCHAR(255) NOT NULL, + WF_STATUS VARCHAR(255) NOT NULL, + WF_CREATED_TIME TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + WF_UPDATED_TIME TIMESTAMP DEFAULT CURRENT_TIMESTAMP , + ORGANIZATION VARCHAR(255), + PRIMARY KEY (UUID) + ); + + CREATE TABLE IF NOT EXISTS KEY_MANAGER ( + UUID VARCHAR(100) NOT NULL, + NAME VARCHAR(100) NULL, + DISPLAY_NAME VARCHAR(100) NULL, + ISSUER VARCHAR(100) NOT NULL, + DESCRIPTION VARCHAR(256) NULL, + TYPE VARCHAR(45) NULL, + CONFIGURATION BYTEA NULL, + ENABLED BOOLEAN DEFAULT '1', + ORGANIZATION VARCHAR(100) NULL, + PRIMARY KEY(UUID), + UNIQUE(NAME,ORGANIZATION) + ); + + -- End of APK Tables -- + + -- Performance indexes start-- + + create index IDX_AI_CTX on API (CONTEXT); + create index IDX_AI_ORG on API (ORGANIZATION); + create index IDX_AKM_CK on APPLICATION_KEY_MAPPING (CONSUMER_KEY); + create index IDX_AUM_AI on API_URL_MAPPING (API_UUID); + -- create index IDX_AUM_TT on API_URL_MAPPING (THROTTLING_TIER); -- + create index IDX_BP_QT on BUSINESS_PLAN (QUOTA_TYPE); + create index IDX_S_AITIAI on SUBSCRIPTION (API_UUID,TIER_ID,APPLICATION_UUID); + create index IDX_AUP_QT on APPLICATION_USAGE_PLAN (QUOTA_TYPE); + create index IDX_A_AT_CB on APPLICATION (APPLICATION_TIER,CREATED_BY); + create index IDX_SUB_APP_ID on SUBSCRIPTION (APPLICATION_UUID, UUID); + + GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO wso2carbon; + GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO wso2carbon; + GRANT ALL PRIVILEGES ON ALL FUNCTIONS IN SCHEMA public TO wso2carbon; + + -- Insert Initial APK data --- + INSERT INTO RESOURCE_CATEGORIES (RESOURCE_CATEGORY) VALUES ('Thumbnail'); + INSERT INTO RESOURCE_CATEGORIES (RESOURCE_CATEGORY) VALUES ('Document'); + -- End Insert Initial APK data + + -- Insert Demo APK data --- + INSERT INTO INTERNAL_USER(uuid, IDP_USER_NAME) VALUES ( 'apkuser', 'apkuser'); + INSERT INTO organization(uuid, name, display_name, status, workflows) VALUES ( 'a3b58ccf-6ecc-4557-b5bb-0a35cce38256', 'default', 'default', true, ''); + INSERT INTO organization_claim_mapping(uuid, claim_key, claim_value) VALUES ( 'a3b58ccf-6ecc-4557-b5bb-0a35cce38256', 'organizationClaimValue', 'default'); + -- End Insert Demo APK data + commit; \ No newline at end of file diff --git a/devportal/devportal-domain-service/README.md b/devportal/devportal-domain-service/README.md new file mode 100644 index 000000000..cd55ffad3 --- /dev/null +++ b/devportal/devportal-domain-service/README.md @@ -0,0 +1 @@ +## Devportal Domain Service \ No newline at end of file diff --git a/devportal/devportal-domain-service/ballerina/Ballerina.toml b/devportal/devportal-domain-service/ballerina/Ballerina.toml new file mode 100644 index 000000000..141ccf57e --- /dev/null +++ b/devportal/devportal-domain-service/ballerina/Ballerina.toml @@ -0,0 +1,475 @@ +[package] +org = "wso2" +name = "devportal_service" +version = "0.0.1-SNAPSHOT" +distribution = "2201.5.0" + +[build-options] +observabilityIncluded = true + +[[platform.java11.dependency]] +groupId = "org.postgresql" +artifactId = "postgresql" +version = "42.5.0" + +[[dependency]] +org = "wso2" +name = "apk_common_lib" +version = "0.0.1-SNAPSHOT" +repository = "local" + +[[dependency]] +org = "wso2" +name = "notification_grpc_client" +version = "0.0.1-SNAPSHOT" +repository = "local" + +[[dependency]] +org= "wso2" +name = "apk_keymanager_libs" +version = "0.0.1-SNAPSHOT" +repository="local" + +[[platform.java11.dependency]] +groupId = "org.wso2.apk" +artifactId = "org.wso2.apk.devportal" +version = "0.0.1-SNAPSHOT" +path = "../java/build/libs/org.wso2.apk.devportal-0.0.1-SNAPSHOT.jar" + +# transitive dependency of org.wso2.apk:org.wso2.apk.devportal:0.0.1-SNAPSHOT +[[platform.java11.dependency]] +groupId = "commons-logging" +artifactId = "commons-logging" +version = "1.1.1" + +# transitive dependency of org.wso2.apk:org.wso2.apk.devportal:0.0.1-SNAPSHOT +[[platform.java11.dependency]] +groupId = "commons-validator" +artifactId = "commons-validator" +version = "1.7" + +# transitive dependency of commons-validator:commons-validator:1.7 +[[platform.java11.dependency]] +groupId = "commons-beanutils" +artifactId = "commons-beanutils" +version = "1.9.4" + +# transitive dependency of commons-validator:commons-validator:1.7 +[[platform.java11.dependency]] +groupId = "commons-digester" +artifactId = "commons-digester" +version = "2.1" + +# transitive dependency of commons-validator:commons-validator:1.7 +[[platform.java11.dependency]] +groupId = "commons-collections" +artifactId = "commons-collections" +version = "3.2.2" + +# transitive dependency of org.wso2.apk:org.wso2.apk.devportal:0.0.1-SNAPSHOT +[[platform.java11.dependency]] +groupId = "org.openapitools" +artifactId = "openapi-generator" +version = "6.2.1" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "io.swagger.parser.v3" +artifactId = "swagger-parser" +version = "2.1.6" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "io.swagger.parser.v3" +artifactId = "swagger-parser-v2-converter" +version = "2.1.6" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "io.swagger" +artifactId = "swagger-core" +version = "1.6.8" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "io.swagger" +artifactId = "swagger-models" +version = "1.6.8" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "io.swagger" +artifactId = "swagger-annotations" +version = "1.6.8" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "javax.validation" +artifactId = "validation-api" +version = "1.1.0.Final" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "io.swagger" +artifactId = "swagger-parser" +version = "1.0.63" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "io.swagger" +artifactId = "swagger-compat-spec-parser" +version = "1.0.63" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "com.github.java-json-tools" +artifactId = "json-schema-validator" +version = "2.2.14" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "com.github.java-json-tools" +artifactId = "jackson-coreutils-equivalence" +version = "1.0" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "com.github.java-json-tools" +artifactId = "json-schema-core" +version = "1.2.14" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "com.github.java-json-tools" +artifactId = "uri-template" +version = "0.10" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "org.mozilla" +artifactId = "rhino" +version = "1.7.7.2" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "com.sun.mail" +artifactId = "mailapi" +version = "1.6.2" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "com.googlecode.libphonenumber" +artifactId = "libphonenumber" +version = "8.11.1" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "net.sf.jopt-simple" +artifactId = "jopt-simple" +version = "5.0.4" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "com.github.java-json-tools" +artifactId = "json-patch" +version = "1.13" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "com.github.java-json-tools" +artifactId = "msg-simple" +version = "1.2" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "com.github.java-json-tools" +artifactId = "btf" +version = "1.3" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "com.github.java-json-tools" +artifactId = "jackson-coreutils" +version = "2.0" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "org.apache.httpcomponents" +artifactId = "httpclient" +version = "4.5.13" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "org.apache.httpcomponents" +artifactId = "httpcore" +version = "4.4.13" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "commons-codec" +artifactId = "commons-codec" +version = "1.11" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "io.swagger.core.v3" +artifactId = "swagger-models" +version = "2.2.4" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "io.swagger.parser.v3" +artifactId = "swagger-parser-core" +version = "2.1.6" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "io.swagger.parser.v3" +artifactId = "swagger-parser-v3" +version = "2.1.6" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "io.swagger.core.v3" +artifactId = "swagger-core" +version = "2.2.4" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "jakarta.xml.bind" +artifactId = "jakarta.xml.bind-api" +version = "2.3.2" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "jakarta.activation" +artifactId = "jakarta.activation-api" +version = "1.2.1" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "com.fasterxml.jackson.datatype" +artifactId = "jackson-datatype-jsr310" +version = "2.13.4" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "io.swagger.core.v3" +artifactId = "swagger-annotations" +version = "2.2.4" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "jakarta.validation" +artifactId = "jakarta.validation-api" +version = "2.0.2" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "com.fasterxml.jackson.dataformat" +artifactId = "jackson-dataformat-yaml" +version = "2.13.4" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "org.yaml" +artifactId = "snakeyaml" +version = "1.33" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "com.samskivert" +artifactId = "jmustache" +version = "1.14" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "com.github.jknack" +artifactId = "handlebars" +version = "4.2.1" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "com.github.jknack" +artifactId = "handlebars-jackson2" +version = "4.2.1" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "commons-io" +artifactId = "commons-io" +version = "2.11.0" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "org.slf4j" +artifactId = "slf4j-ext" +version = "1.7.36" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "org.slf4j" +artifactId = "slf4j-api" +version = "1.7.36" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "org.slf4j" +artifactId = "slf4j-simple" +version = "1.7.36" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "org.apache.commons" +artifactId = "commons-lang3" +version = "3.12.0" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "org.apache.commons" +artifactId = "commons-text" +version = "1.10.0" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "commons-cli" +artifactId = "commons-cli" +version = "1.4" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "com.google.guava" +artifactId = "guava" +version = "30.1.1-jre" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "com.google.guava" +artifactId = "failureaccess" +version = "1.0.1" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "com.google.guava" +artifactId = "listenablefuture" +version = "9999.0-empty-to-avoid-conflict-with-guava" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "com.google.code.findbugs" +artifactId = "jsr305" +version = "3.0.2" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "org.checkerframework" +artifactId = "checker-qual" +version = "3.8.0" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "com.google.errorprone" +artifactId = "error_prone_annotations" +version = "2.5.1" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "com.google.j2objc" +artifactId = "j2objc-annotations" +version = "1.3" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "com.fasterxml.jackson.datatype" +artifactId = "jackson-datatype-guava" +version = "2.13.4" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "com.fasterxml.jackson.core" +artifactId = "jackson-core" +version = "2.13.4" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "com.atlassian.commonmark" +artifactId = "commonmark" +version = "0.11.0" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "com.github.mifmif" +artifactId = "generex" +version = "1.0.2" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "dk.brics.automaton" +artifactId = "automaton" +version = "1.11-8" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "com.github.curious-odd-man" +artifactId = "rgxgen" +version = "1.3" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "com.fasterxml.jackson.core" +artifactId = "jackson-databind" +version = "2.13.4.2" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "com.fasterxml.jackson.core" +artifactId = "jackson-annotations" +version = "2.13.4" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "com.fasterxml.jackson.datatype" +artifactId = "jackson-datatype-joda" +version = "2.13.4" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "joda-time" +artifactId = "joda-time" +version = "2.10.8" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "com.github.joschi.jackson" +artifactId = "jackson-datatype-threetenbp" +version = "2.10.0" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "org.threeten" +artifactId = "threetenbp" +version = "1.4.0" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "org.openapitools" +artifactId = "openapi-generator-core" +version = "6.2.1" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "net.java.dev.jna" +artifactId = "jna" +version = "5.5.0" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "com.github.ben-manes.caffeine" +artifactId = "caffeine" +version = "2.8.1" + +# transitive dependency of org.wso2.apk:org.wso2.apk.devportal:0.0.1-SNAPSHOT +[[platform.java11.dependency]] +groupId = "commons-lang" +artifactId = "commons-lang" +version = "2.4" diff --git a/devportal/devportal-domain-service/ballerina/Ballerina.toml.template b/devportal/devportal-domain-service/ballerina/Ballerina.toml.template new file mode 100644 index 000000000..126c5ba49 --- /dev/null +++ b/devportal/devportal-domain-service/ballerina/Ballerina.toml.template @@ -0,0 +1,475 @@ +[package] +org = "wso2" +name = "devportal_service" +version = "PROJECT_VERSION" +distribution = "2201.5.0" + +[build-options] +observabilityIncluded = true + +[[platform.java11.dependency]] +groupId = "org.postgresql" +artifactId = "postgresql" +version = "42.5.0" + +[[dependency]] +org = "wso2" +name = "apk_common_lib" +version = "0.0.1-SNAPSHOT" +repository = "local" + +[[dependency]] +org = "wso2" +name = "notification_grpc_client" +version = "0.0.1-SNAPSHOT" +repository = "local" + +[[dependency]] +org= "wso2" +name = "apk_keymanager_libs" +version = "0.0.1-SNAPSHOT" +repository="local" + +[[platform.java11.dependency]] +groupId = "org.wso2.apk" +artifactId = "org.wso2.apk.devportal" +version = "PROJECT_VERSION" +path = "../java/build/libs/org.wso2.apk.devportal-PROJECT_VERSION.jar" + +# transitive dependency of org.wso2.apk:org.wso2.apk.devportal:0.0.1-SNAPSHOT +[[platform.java11.dependency]] +groupId = "commons-logging" +artifactId = "commons-logging" +version = "1.1.1" + +# transitive dependency of org.wso2.apk:org.wso2.apk.devportal:0.0.1-SNAPSHOT +[[platform.java11.dependency]] +groupId = "commons-validator" +artifactId = "commons-validator" +version = "1.7" + +# transitive dependency of commons-validator:commons-validator:1.7 +[[platform.java11.dependency]] +groupId = "commons-beanutils" +artifactId = "commons-beanutils" +version = "1.9.4" + +# transitive dependency of commons-validator:commons-validator:1.7 +[[platform.java11.dependency]] +groupId = "commons-digester" +artifactId = "commons-digester" +version = "2.1" + +# transitive dependency of commons-validator:commons-validator:1.7 +[[platform.java11.dependency]] +groupId = "commons-collections" +artifactId = "commons-collections" +version = "3.2.2" + +# transitive dependency of org.wso2.apk:org.wso2.apk.devportal:0.0.1-SNAPSHOT +[[platform.java11.dependency]] +groupId = "org.openapitools" +artifactId = "openapi-generator" +version = "6.2.1" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "io.swagger.parser.v3" +artifactId = "swagger-parser" +version = "2.1.6" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "io.swagger.parser.v3" +artifactId = "swagger-parser-v2-converter" +version = "2.1.6" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "io.swagger" +artifactId = "swagger-core" +version = "1.6.8" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "io.swagger" +artifactId = "swagger-models" +version = "1.6.8" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "io.swagger" +artifactId = "swagger-annotations" +version = "1.6.8" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "javax.validation" +artifactId = "validation-api" +version = "1.1.0.Final" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "io.swagger" +artifactId = "swagger-parser" +version = "1.0.63" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "io.swagger" +artifactId = "swagger-compat-spec-parser" +version = "1.0.63" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "com.github.java-json-tools" +artifactId = "json-schema-validator" +version = "2.2.14" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "com.github.java-json-tools" +artifactId = "jackson-coreutils-equivalence" +version = "1.0" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "com.github.java-json-tools" +artifactId = "json-schema-core" +version = "1.2.14" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "com.github.java-json-tools" +artifactId = "uri-template" +version = "0.10" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "org.mozilla" +artifactId = "rhino" +version = "1.7.7.2" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "com.sun.mail" +artifactId = "mailapi" +version = "1.6.2" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "com.googlecode.libphonenumber" +artifactId = "libphonenumber" +version = "8.11.1" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "net.sf.jopt-simple" +artifactId = "jopt-simple" +version = "5.0.4" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "com.github.java-json-tools" +artifactId = "json-patch" +version = "1.13" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "com.github.java-json-tools" +artifactId = "msg-simple" +version = "1.2" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "com.github.java-json-tools" +artifactId = "btf" +version = "1.3" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "com.github.java-json-tools" +artifactId = "jackson-coreutils" +version = "2.0" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "org.apache.httpcomponents" +artifactId = "httpclient" +version = "4.5.13" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "org.apache.httpcomponents" +artifactId = "httpcore" +version = "4.4.13" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "commons-codec" +artifactId = "commons-codec" +version = "1.11" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "io.swagger.core.v3" +artifactId = "swagger-models" +version = "2.2.4" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "io.swagger.parser.v3" +artifactId = "swagger-parser-core" +version = "2.1.6" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "io.swagger.parser.v3" +artifactId = "swagger-parser-v3" +version = "2.1.6" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "io.swagger.core.v3" +artifactId = "swagger-core" +version = "2.2.4" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "jakarta.xml.bind" +artifactId = "jakarta.xml.bind-api" +version = "2.3.2" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "jakarta.activation" +artifactId = "jakarta.activation-api" +version = "1.2.1" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "com.fasterxml.jackson.datatype" +artifactId = "jackson-datatype-jsr310" +version = "2.13.4" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "io.swagger.core.v3" +artifactId = "swagger-annotations" +version = "2.2.4" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "jakarta.validation" +artifactId = "jakarta.validation-api" +version = "2.0.2" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "com.fasterxml.jackson.dataformat" +artifactId = "jackson-dataformat-yaml" +version = "2.13.4" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "org.yaml" +artifactId = "snakeyaml" +version = "1.33" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "com.samskivert" +artifactId = "jmustache" +version = "1.14" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "com.github.jknack" +artifactId = "handlebars" +version = "4.2.1" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "com.github.jknack" +artifactId = "handlebars-jackson2" +version = "4.2.1" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "commons-io" +artifactId = "commons-io" +version = "2.11.0" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "org.slf4j" +artifactId = "slf4j-ext" +version = "1.7.36" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "org.slf4j" +artifactId = "slf4j-api" +version = "1.7.36" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "org.slf4j" +artifactId = "slf4j-simple" +version = "1.7.36" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "org.apache.commons" +artifactId = "commons-lang3" +version = "3.12.0" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "org.apache.commons" +artifactId = "commons-text" +version = "1.10.0" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "commons-cli" +artifactId = "commons-cli" +version = "1.4" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "com.google.guava" +artifactId = "guava" +version = "30.1.1-jre" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "com.google.guava" +artifactId = "failureaccess" +version = "1.0.1" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "com.google.guava" +artifactId = "listenablefuture" +version = "9999.0-empty-to-avoid-conflict-with-guava" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "com.google.code.findbugs" +artifactId = "jsr305" +version = "3.0.2" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "org.checkerframework" +artifactId = "checker-qual" +version = "3.8.0" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "com.google.errorprone" +artifactId = "error_prone_annotations" +version = "2.5.1" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "com.google.j2objc" +artifactId = "j2objc-annotations" +version = "1.3" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "com.fasterxml.jackson.datatype" +artifactId = "jackson-datatype-guava" +version = "2.13.4" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "com.fasterxml.jackson.core" +artifactId = "jackson-core" +version = "2.13.4" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "com.atlassian.commonmark" +artifactId = "commonmark" +version = "0.11.0" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "com.github.mifmif" +artifactId = "generex" +version = "1.0.2" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "dk.brics.automaton" +artifactId = "automaton" +version = "1.11-8" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "com.github.curious-odd-man" +artifactId = "rgxgen" +version = "1.3" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "com.fasterxml.jackson.core" +artifactId = "jackson-databind" +version = "2.13.4.2" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "com.fasterxml.jackson.core" +artifactId = "jackson-annotations" +version = "2.13.4" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "com.fasterxml.jackson.datatype" +artifactId = "jackson-datatype-joda" +version = "2.13.4" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "joda-time" +artifactId = "joda-time" +version = "2.10.8" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "com.github.joschi.jackson" +artifactId = "jackson-datatype-threetenbp" +version = "2.10.0" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "org.threeten" +artifactId = "threetenbp" +version = "1.4.0" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "org.openapitools" +artifactId = "openapi-generator-core" +version = "6.2.1" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "net.java.dev.jna" +artifactId = "jna" +version = "5.5.0" + +# transitive dependency of org.openapitools:openapi-generator:6.2.1 +[[platform.java11.dependency]] +groupId = "com.github.ben-manes.caffeine" +artifactId = "caffeine" +version = "2.8.1" + +# transitive dependency of org.wso2.apk:org.wso2.apk.devportal:0.0.1-SNAPSHOT +[[platform.java11.dependency]] +groupId = "commons-lang" +artifactId = "commons-lang" +version = "2.4" diff --git a/devportal/devportal-domain-service/ballerina/Config.toml b/devportal/devportal-domain-service/ballerina/Config.toml new file mode 100644 index 000000000..df601d1ad --- /dev/null +++ b/devportal/devportal-domain-service/ballerina/Config.toml @@ -0,0 +1,43 @@ +[wso2.devportal_service] +DEVPORTAL_PORT = 9443 + +[wso2.devportal_service.datasourceConfiguration] +description = "Database for devportal" +url = "jdbc:postgresql://localhost:5432/APKDB" +host = "localhost" +port = 5432 +databaseName = "APKDB" +username = "admin" +password = "admin" +validationTimeout = 250 +testQuery = "SELECT 1" +driver = "org.postgresql.Driver" + +[wso2.devportal_service.throttleConfig.blockCondition] +enabled = true + +[wso2.devportal_service.k8sConfig] +host = "localhost:9090" +serviceAccountPath = "tests/resources/serviceAccount" + +[wso2.devportal_service.keyStores.tls] +path = "/home/wso2apk/devportal/security/wso2carbon.key" +[wso2.devportal_service.keyStores.signing] +path = "/home/wso2apk/devportal/security/wso2carbon.key" + +[wso2.devportal_service.issuerConfig] +issuer = "https://apim.wso2.com/oauth2/token" +audience = "https://apim.wso2.com/oauth2/token" +keyId = "gateway_certificate_alias" +expTime = 3600.0 + +[wso2.devportal_service.sdkConfig] +groupId = "org.wso2" +artifactId = "org.wso2.client." +modelPackage = "org.wso2.client.model." +apiPackage = "org.wso2.client.api." + +[wso2.devportal_service.managementServerConfig] +serviceName = "apk-test-wso2-apk-management-server" +namespace = "apk" +certPath = "/home/wso2apk/devportal/security/truststore/management-server.pem" diff --git a/devportal/devportal-domain-service/ballerina/Constants.bal b/devportal/devportal-domain-service/ballerina/Constants.bal new file mode 100644 index 000000000..7c69b909a --- /dev/null +++ b/devportal/devportal-domain-service/ballerina/Constants.bal @@ -0,0 +1,19 @@ +// +// Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + +const string RESOURCE_TYPE_THUMBNAIL = "Thumbnail"; diff --git a/devportal/devportal-domain-service/ballerina/Dependencies.toml b/devportal/devportal-domain-service/ballerina/Dependencies.toml new file mode 100644 index 000000000..5ec27bfd6 --- /dev/null +++ b/devportal/devportal-domain-service/ballerina/Dependencies.toml @@ -0,0 +1,509 @@ +# AUTO-GENERATED FILE. DO NOT MODIFY. + +# This file is auto-generated by Ballerina for managing dependency versions. +# It should not be modified by hand. + +[ballerina] +dependencies-toml-version = "2" +distribution-version = "2201.5.0" + +[[package]] +org = "ballerina" +name = "auth" +version = "2.7.0" +dependencies = [ + {org = "ballerina", name = "crypto"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.array"}, + {org = "ballerina", name = "lang.string"}, + {org = "ballerina", name = "log"}, + {org = "ballerina", name = "regex"} +] + +[[package]] +org = "ballerina" +name = "cache" +version = "3.4.0" +dependencies = [ + {org = "ballerina", name = "constraint"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "task"}, + {org = "ballerina", name = "time"} +] +modules = [ + {org = "ballerina", packageName = "cache", moduleName = "cache"} +] + +[[package]] +org = "ballerina" +name = "constraint" +version = "1.1.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] +modules = [ + {org = "ballerina", packageName = "constraint", moduleName = "constraint"} +] + +[[package]] +org = "ballerina" +name = "crypto" +version = "2.3.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "time"} +] + +[[package]] +org = "ballerina" +name = "file" +version = "1.7.0" +dependencies = [ + {org = "ballerina", name = "io"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "log"}, + {org = "ballerina", name = "os"}, + {org = "ballerina", name = "regex"}, + {org = "ballerina", name = "time"} +] +modules = [ + {org = "ballerina", packageName = "file", moduleName = "file"} +] + +[[package]] +org = "ballerina" +name = "grpc" +version = "1.7.0" +dependencies = [ + {org = "ballerina", name = "auth"}, + {org = "ballerina", name = "crypto"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "jwt"}, + {org = "ballerina", name = "lang.runtime"}, + {org = "ballerina", name = "log"}, + {org = "ballerina", name = "oauth2"}, + {org = "ballerina", name = "protobuf"}, + {org = "ballerina", name = "regex"}, + {org = "ballerina", name = "time"} +] + +[[package]] +org = "ballerina" +name = "http" +version = "2.7.0" +dependencies = [ + {org = "ballerina", name = "auth"}, + {org = "ballerina", name = "cache"}, + {org = "ballerina", name = "constraint"}, + {org = "ballerina", name = "crypto"}, + {org = "ballerina", name = "file"}, + {org = "ballerina", name = "io"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "jwt"}, + {org = "ballerina", name = "lang.array"}, + {org = "ballerina", name = "lang.decimal"}, + {org = "ballerina", name = "lang.int"}, + {org = "ballerina", name = "lang.runtime"}, + {org = "ballerina", name = "lang.string"}, + {org = "ballerina", name = "lang.value"}, + {org = "ballerina", name = "log"}, + {org = "ballerina", name = "mime"}, + {org = "ballerina", name = "oauth2"}, + {org = "ballerina", name = "observe"}, + {org = "ballerina", name = "regex"}, + {org = "ballerina", name = "time"}, + {org = "ballerina", name = "url"} +] +modules = [ + {org = "ballerina", packageName = "http", moduleName = "http"} +] + +[[package]] +org = "ballerina" +name = "io" +version = "1.4.1" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.value"} +] +modules = [ + {org = "ballerina", packageName = "io", moduleName = "io"} +] + +[[package]] +org = "ballerina" +name = "jballerina.java" +version = "0.0.0" +modules = [ + {org = "ballerina", packageName = "jballerina.java", moduleName = "jballerina.java"} +] + +[[package]] +org = "ballerina" +name = "jballerina.java.arrays" +version = "1.2.3" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] +modules = [ + {org = "ballerina", packageName = "jballerina.java.arrays", moduleName = "jballerina.java.arrays"} +] + +[[package]] +org = "ballerina" +name = "jwt" +version = "2.7.0" +dependencies = [ + {org = "ballerina", name = "cache"}, + {org = "ballerina", name = "crypto"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.int"}, + {org = "ballerina", name = "lang.string"}, + {org = "ballerina", name = "log"}, + {org = "ballerina", name = "regex"}, + {org = "ballerina", name = "time"} +] +modules = [ + {org = "ballerina", packageName = "jwt", moduleName = "jwt"} +] + +[[package]] +org = "ballerina" +name = "lang.__internal" +version = "0.0.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.object"} +] + +[[package]] +org = "ballerina" +name = "lang.array" +version = "0.0.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.__internal"} +] + +[[package]] +org = "ballerina" +name = "lang.decimal" +version = "0.0.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] + +[[package]] +org = "ballerina" +name = "lang.int" +version = "0.0.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.__internal"}, + {org = "ballerina", name = "lang.object"} +] + +[[package]] +org = "ballerina" +name = "lang.object" +version = "0.0.0" + +[[package]] +org = "ballerina" +name = "lang.regexp" +version = "0.0.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] + +[[package]] +org = "ballerina" +name = "lang.runtime" +version = "0.0.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] + +[[package]] +org = "ballerina" +name = "lang.string" +version = "0.0.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.regexp"} +] + +[[package]] +org = "ballerina" +name = "lang.value" +version = "0.0.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] +modules = [ + {org = "ballerina", packageName = "lang.value", moduleName = "lang.value"} +] + +[[package]] +org = "ballerina" +name = "log" +version = "2.7.0" +dependencies = [ + {org = "ballerina", name = "io"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.value"}, + {org = "ballerina", name = "observe"} +] +modules = [ + {org = "ballerina", packageName = "log", moduleName = "log"} +] + +[[package]] +org = "ballerina" +name = "mime" +version = "2.7.0" +dependencies = [ + {org = "ballerina", name = "io"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.int"} +] + +[[package]] +org = "ballerina" +name = "oauth2" +version = "2.7.0" +dependencies = [ + {org = "ballerina", name = "cache"}, + {org = "ballerina", name = "crypto"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "log"}, + {org = "ballerina", name = "time"}, + {org = "ballerina", name = "url"} +] + +[[package]] +org = "ballerina" +name = "observe" +version = "1.0.7" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] + +[[package]] +org = "ballerina" +name = "os" +version = "1.6.0" +dependencies = [ + {org = "ballerina", name = "io"}, + {org = "ballerina", name = "jballerina.java"} +] + +[[package]] +org = "ballerina" +name = "protobuf" +version = "1.3.2" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "time"} +] + +[[package]] +org = "ballerina" +name = "regex" +version = "1.4.3" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.string"} +] +modules = [ + {org = "ballerina", packageName = "regex", moduleName = "regex"} +] + +[[package]] +org = "ballerina" +name = "sql" +version = "1.8.0" +dependencies = [ + {org = "ballerina", name = "io"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.object"}, + {org = "ballerina", name = "time"} +] +modules = [ + {org = "ballerina", packageName = "sql", moduleName = "sql"} +] + +[[package]] +org = "ballerina" +name = "task" +version = "2.3.2" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "time"} +] + +[[package]] +org = "ballerina" +name = "test" +version = "0.0.0" +scope = "testOnly" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] +modules = [ + {org = "ballerina", packageName = "test", moduleName = "test"} +] + +[[package]] +org = "ballerina" +name = "time" +version = "2.2.4" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] +modules = [ + {org = "ballerina", packageName = "time", moduleName = "time"} +] + +[[package]] +org = "ballerina" +name = "url" +version = "2.2.3" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] +modules = [ + {org = "ballerina", packageName = "url", moduleName = "url"} +] + +[[package]] +org = "ballerina" +name = "uuid" +version = "1.5.0" +dependencies = [ + {org = "ballerina", name = "crypto"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.int"}, + {org = "ballerina", name = "regex"}, + {org = "ballerina", name = "time"} +] +modules = [ + {org = "ballerina", packageName = "uuid", moduleName = "uuid"} +] + +[[package]] +org = "ballerinai" +name = "observe" +version = "0.0.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "observe"} +] +modules = [ + {org = "ballerinai", packageName = "observe", moduleName = "observe"} +] + +[[package]] +org = "ballerinax" +name = "postgresql" +version = "1.8.0" +dependencies = [ + {org = "ballerina", name = "crypto"}, + {org = "ballerina", name = "io"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "sql"}, + {org = "ballerina", name = "time"} +] +modules = [ + {org = "ballerinax", packageName = "postgresql", moduleName = "postgresql"} +] + +[[package]] +org = "wso2" +name = "apk_common_lib" +version = "0.0.1-SNAPSHOT" +dependencies = [ + {org = "ballerina", name = "http"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "jballerina.java.arrays"}, + {org = "ballerina", name = "jwt"}, + {org = "ballerina", name = "lang.value"}, + {org = "ballerina", name = "log"}, + {org = "ballerina", name = "os"}, + {org = "ballerina", name = "sql"}, + {org = "ballerina", name = "uuid"}, + {org = "ballerinax", name = "postgresql"} +] +modules = [ + {org = "wso2", packageName = "apk_common_lib", moduleName = "apk_common_lib"}, + {org = "wso2", packageName = "apk_common_lib", moduleName = "apk_common_lib.java.io"}, + {org = "wso2", packageName = "apk_common_lib", moduleName = "apk_common_lib.java.lang"} +] + +[[package]] +org = "wso2" +name = "apk_keymanager_libs" +version = "0.0.1-SNAPSHOT" +dependencies = [ + {org = "ballerina", name = "file"}, + {org = "ballerina", name = "io"}, + {org = "ballerina", name = "log"}, + {org = "wso2", name = "apk_common_lib"} +] +modules = [ + {org = "wso2", packageName = "apk_keymanager_libs", moduleName = "apk_keymanager_libs"} +] + +[[package]] +org = "wso2" +name = "devportal_service" +version = "0.0.1-SNAPSHOT" +dependencies = [ + {org = "ballerina", name = "cache"}, + {org = "ballerina", name = "constraint"}, + {org = "ballerina", name = "file"}, + {org = "ballerina", name = "http"}, + {org = "ballerina", name = "io"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "jballerina.java.arrays"}, + {org = "ballerina", name = "jwt"}, + {org = "ballerina", name = "lang.value"}, + {org = "ballerina", name = "log"}, + {org = "ballerina", name = "regex"}, + {org = "ballerina", name = "sql"}, + {org = "ballerina", name = "test"}, + {org = "ballerina", name = "time"}, + {org = "ballerina", name = "url"}, + {org = "ballerina", name = "uuid"}, + {org = "ballerinai", name = "observe"}, + {org = "ballerinax", name = "postgresql"}, + {org = "wso2", name = "apk_common_lib"}, + {org = "wso2", name = "apk_keymanager_libs"}, + {org = "wso2", name = "notification_grpc_client"} +] +modules = [ + {org = "wso2", packageName = "devportal_service", moduleName = "devportal_service"}, + {org = "wso2", packageName = "devportal_service", moduleName = "devportal_service.java.lang"}, + {org = "wso2", packageName = "devportal_service", moduleName = "devportal_service.java.util"}, + {org = "wso2", packageName = "devportal_service", moduleName = "devportal_service.java.util.function"}, + {org = "wso2", packageName = "devportal_service", moduleName = "devportal_service.kmclient"}, + {org = "wso2", packageName = "devportal_service", moduleName = "devportal_service.nonprodidp"}, + {org = "wso2", packageName = "devportal_service", moduleName = "devportal_service.org.wso2.apk.devportal.sdk"}, + {org = "wso2", packageName = "devportal_service", moduleName = "devportal_service.types"}, + {org = "wso2", packageName = "devportal_service", moduleName = "devportal_service.utils"} +] + +[[package]] +org = "wso2" +name = "notification_grpc_client" +version = "0.0.1-SNAPSHOT" +dependencies = [ + {org = "ballerina", name = "grpc"}, + {org = "ballerina", name = "io"}, + {org = "ballerina", name = "log"}, + {org = "ballerina", name = "protobuf"} +] +modules = [ + {org = "wso2", packageName = "notification_grpc_client", moduleName = "notification_grpc_client"} +] + diff --git a/devportal/devportal-domain-service/ballerina/Dependencies.toml.template b/devportal/devportal-domain-service/ballerina/Dependencies.toml.template new file mode 100644 index 000000000..5ec27bfd6 --- /dev/null +++ b/devportal/devportal-domain-service/ballerina/Dependencies.toml.template @@ -0,0 +1,509 @@ +# AUTO-GENERATED FILE. DO NOT MODIFY. + +# This file is auto-generated by Ballerina for managing dependency versions. +# It should not be modified by hand. + +[ballerina] +dependencies-toml-version = "2" +distribution-version = "2201.5.0" + +[[package]] +org = "ballerina" +name = "auth" +version = "2.7.0" +dependencies = [ + {org = "ballerina", name = "crypto"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.array"}, + {org = "ballerina", name = "lang.string"}, + {org = "ballerina", name = "log"}, + {org = "ballerina", name = "regex"} +] + +[[package]] +org = "ballerina" +name = "cache" +version = "3.4.0" +dependencies = [ + {org = "ballerina", name = "constraint"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "task"}, + {org = "ballerina", name = "time"} +] +modules = [ + {org = "ballerina", packageName = "cache", moduleName = "cache"} +] + +[[package]] +org = "ballerina" +name = "constraint" +version = "1.1.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] +modules = [ + {org = "ballerina", packageName = "constraint", moduleName = "constraint"} +] + +[[package]] +org = "ballerina" +name = "crypto" +version = "2.3.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "time"} +] + +[[package]] +org = "ballerina" +name = "file" +version = "1.7.0" +dependencies = [ + {org = "ballerina", name = "io"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "log"}, + {org = "ballerina", name = "os"}, + {org = "ballerina", name = "regex"}, + {org = "ballerina", name = "time"} +] +modules = [ + {org = "ballerina", packageName = "file", moduleName = "file"} +] + +[[package]] +org = "ballerina" +name = "grpc" +version = "1.7.0" +dependencies = [ + {org = "ballerina", name = "auth"}, + {org = "ballerina", name = "crypto"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "jwt"}, + {org = "ballerina", name = "lang.runtime"}, + {org = "ballerina", name = "log"}, + {org = "ballerina", name = "oauth2"}, + {org = "ballerina", name = "protobuf"}, + {org = "ballerina", name = "regex"}, + {org = "ballerina", name = "time"} +] + +[[package]] +org = "ballerina" +name = "http" +version = "2.7.0" +dependencies = [ + {org = "ballerina", name = "auth"}, + {org = "ballerina", name = "cache"}, + {org = "ballerina", name = "constraint"}, + {org = "ballerina", name = "crypto"}, + {org = "ballerina", name = "file"}, + {org = "ballerina", name = "io"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "jwt"}, + {org = "ballerina", name = "lang.array"}, + {org = "ballerina", name = "lang.decimal"}, + {org = "ballerina", name = "lang.int"}, + {org = "ballerina", name = "lang.runtime"}, + {org = "ballerina", name = "lang.string"}, + {org = "ballerina", name = "lang.value"}, + {org = "ballerina", name = "log"}, + {org = "ballerina", name = "mime"}, + {org = "ballerina", name = "oauth2"}, + {org = "ballerina", name = "observe"}, + {org = "ballerina", name = "regex"}, + {org = "ballerina", name = "time"}, + {org = "ballerina", name = "url"} +] +modules = [ + {org = "ballerina", packageName = "http", moduleName = "http"} +] + +[[package]] +org = "ballerina" +name = "io" +version = "1.4.1" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.value"} +] +modules = [ + {org = "ballerina", packageName = "io", moduleName = "io"} +] + +[[package]] +org = "ballerina" +name = "jballerina.java" +version = "0.0.0" +modules = [ + {org = "ballerina", packageName = "jballerina.java", moduleName = "jballerina.java"} +] + +[[package]] +org = "ballerina" +name = "jballerina.java.arrays" +version = "1.2.3" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] +modules = [ + {org = "ballerina", packageName = "jballerina.java.arrays", moduleName = "jballerina.java.arrays"} +] + +[[package]] +org = "ballerina" +name = "jwt" +version = "2.7.0" +dependencies = [ + {org = "ballerina", name = "cache"}, + {org = "ballerina", name = "crypto"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.int"}, + {org = "ballerina", name = "lang.string"}, + {org = "ballerina", name = "log"}, + {org = "ballerina", name = "regex"}, + {org = "ballerina", name = "time"} +] +modules = [ + {org = "ballerina", packageName = "jwt", moduleName = "jwt"} +] + +[[package]] +org = "ballerina" +name = "lang.__internal" +version = "0.0.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.object"} +] + +[[package]] +org = "ballerina" +name = "lang.array" +version = "0.0.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.__internal"} +] + +[[package]] +org = "ballerina" +name = "lang.decimal" +version = "0.0.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] + +[[package]] +org = "ballerina" +name = "lang.int" +version = "0.0.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.__internal"}, + {org = "ballerina", name = "lang.object"} +] + +[[package]] +org = "ballerina" +name = "lang.object" +version = "0.0.0" + +[[package]] +org = "ballerina" +name = "lang.regexp" +version = "0.0.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] + +[[package]] +org = "ballerina" +name = "lang.runtime" +version = "0.0.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] + +[[package]] +org = "ballerina" +name = "lang.string" +version = "0.0.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.regexp"} +] + +[[package]] +org = "ballerina" +name = "lang.value" +version = "0.0.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] +modules = [ + {org = "ballerina", packageName = "lang.value", moduleName = "lang.value"} +] + +[[package]] +org = "ballerina" +name = "log" +version = "2.7.0" +dependencies = [ + {org = "ballerina", name = "io"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.value"}, + {org = "ballerina", name = "observe"} +] +modules = [ + {org = "ballerina", packageName = "log", moduleName = "log"} +] + +[[package]] +org = "ballerina" +name = "mime" +version = "2.7.0" +dependencies = [ + {org = "ballerina", name = "io"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.int"} +] + +[[package]] +org = "ballerina" +name = "oauth2" +version = "2.7.0" +dependencies = [ + {org = "ballerina", name = "cache"}, + {org = "ballerina", name = "crypto"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "log"}, + {org = "ballerina", name = "time"}, + {org = "ballerina", name = "url"} +] + +[[package]] +org = "ballerina" +name = "observe" +version = "1.0.7" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] + +[[package]] +org = "ballerina" +name = "os" +version = "1.6.0" +dependencies = [ + {org = "ballerina", name = "io"}, + {org = "ballerina", name = "jballerina.java"} +] + +[[package]] +org = "ballerina" +name = "protobuf" +version = "1.3.2" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "time"} +] + +[[package]] +org = "ballerina" +name = "regex" +version = "1.4.3" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.string"} +] +modules = [ + {org = "ballerina", packageName = "regex", moduleName = "regex"} +] + +[[package]] +org = "ballerina" +name = "sql" +version = "1.8.0" +dependencies = [ + {org = "ballerina", name = "io"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.object"}, + {org = "ballerina", name = "time"} +] +modules = [ + {org = "ballerina", packageName = "sql", moduleName = "sql"} +] + +[[package]] +org = "ballerina" +name = "task" +version = "2.3.2" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "time"} +] + +[[package]] +org = "ballerina" +name = "test" +version = "0.0.0" +scope = "testOnly" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] +modules = [ + {org = "ballerina", packageName = "test", moduleName = "test"} +] + +[[package]] +org = "ballerina" +name = "time" +version = "2.2.4" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] +modules = [ + {org = "ballerina", packageName = "time", moduleName = "time"} +] + +[[package]] +org = "ballerina" +name = "url" +version = "2.2.3" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] +modules = [ + {org = "ballerina", packageName = "url", moduleName = "url"} +] + +[[package]] +org = "ballerina" +name = "uuid" +version = "1.5.0" +dependencies = [ + {org = "ballerina", name = "crypto"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.int"}, + {org = "ballerina", name = "regex"}, + {org = "ballerina", name = "time"} +] +modules = [ + {org = "ballerina", packageName = "uuid", moduleName = "uuid"} +] + +[[package]] +org = "ballerinai" +name = "observe" +version = "0.0.0" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "observe"} +] +modules = [ + {org = "ballerinai", packageName = "observe", moduleName = "observe"} +] + +[[package]] +org = "ballerinax" +name = "postgresql" +version = "1.8.0" +dependencies = [ + {org = "ballerina", name = "crypto"}, + {org = "ballerina", name = "io"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "sql"}, + {org = "ballerina", name = "time"} +] +modules = [ + {org = "ballerinax", packageName = "postgresql", moduleName = "postgresql"} +] + +[[package]] +org = "wso2" +name = "apk_common_lib" +version = "0.0.1-SNAPSHOT" +dependencies = [ + {org = "ballerina", name = "http"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "jballerina.java.arrays"}, + {org = "ballerina", name = "jwt"}, + {org = "ballerina", name = "lang.value"}, + {org = "ballerina", name = "log"}, + {org = "ballerina", name = "os"}, + {org = "ballerina", name = "sql"}, + {org = "ballerina", name = "uuid"}, + {org = "ballerinax", name = "postgresql"} +] +modules = [ + {org = "wso2", packageName = "apk_common_lib", moduleName = "apk_common_lib"}, + {org = "wso2", packageName = "apk_common_lib", moduleName = "apk_common_lib.java.io"}, + {org = "wso2", packageName = "apk_common_lib", moduleName = "apk_common_lib.java.lang"} +] + +[[package]] +org = "wso2" +name = "apk_keymanager_libs" +version = "0.0.1-SNAPSHOT" +dependencies = [ + {org = "ballerina", name = "file"}, + {org = "ballerina", name = "io"}, + {org = "ballerina", name = "log"}, + {org = "wso2", name = "apk_common_lib"} +] +modules = [ + {org = "wso2", packageName = "apk_keymanager_libs", moduleName = "apk_keymanager_libs"} +] + +[[package]] +org = "wso2" +name = "devportal_service" +version = "0.0.1-SNAPSHOT" +dependencies = [ + {org = "ballerina", name = "cache"}, + {org = "ballerina", name = "constraint"}, + {org = "ballerina", name = "file"}, + {org = "ballerina", name = "http"}, + {org = "ballerina", name = "io"}, + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "jballerina.java.arrays"}, + {org = "ballerina", name = "jwt"}, + {org = "ballerina", name = "lang.value"}, + {org = "ballerina", name = "log"}, + {org = "ballerina", name = "regex"}, + {org = "ballerina", name = "sql"}, + {org = "ballerina", name = "test"}, + {org = "ballerina", name = "time"}, + {org = "ballerina", name = "url"}, + {org = "ballerina", name = "uuid"}, + {org = "ballerinai", name = "observe"}, + {org = "ballerinax", name = "postgresql"}, + {org = "wso2", name = "apk_common_lib"}, + {org = "wso2", name = "apk_keymanager_libs"}, + {org = "wso2", name = "notification_grpc_client"} +] +modules = [ + {org = "wso2", packageName = "devportal_service", moduleName = "devportal_service"}, + {org = "wso2", packageName = "devportal_service", moduleName = "devportal_service.java.lang"}, + {org = "wso2", packageName = "devportal_service", moduleName = "devportal_service.java.util"}, + {org = "wso2", packageName = "devportal_service", moduleName = "devportal_service.java.util.function"}, + {org = "wso2", packageName = "devportal_service", moduleName = "devportal_service.kmclient"}, + {org = "wso2", packageName = "devportal_service", moduleName = "devportal_service.nonprodidp"}, + {org = "wso2", packageName = "devportal_service", moduleName = "devportal_service.org.wso2.apk.devportal.sdk"}, + {org = "wso2", packageName = "devportal_service", moduleName = "devportal_service.types"}, + {org = "wso2", packageName = "devportal_service", moduleName = "devportal_service.utils"} +] + +[[package]] +org = "wso2" +name = "notification_grpc_client" +version = "0.0.1-SNAPSHOT" +dependencies = [ + {org = "ballerina", name = "grpc"}, + {org = "ballerina", name = "io"}, + {org = "ballerina", name = "log"}, + {org = "ballerina", name = "protobuf"} +] +modules = [ + {org = "wso2", packageName = "notification_grpc_client", moduleName = "notification_grpc_client"} +] + diff --git a/devportal/devportal-domain-service/ballerina/Error.bal b/devportal/devportal-domain-service/ballerina/Error.bal new file mode 100644 index 000000000..e69de29bb diff --git a/devportal/devportal-domain-service/ballerina/JWTGenerator.bal b/devportal/devportal-domain-service/ballerina/JWTGenerator.bal new file mode 100644 index 000000000..be2c23c7c --- /dev/null +++ b/devportal/devportal-domain-service/ballerina/JWTGenerator.bal @@ -0,0 +1,98 @@ +// +// Copyright (c) 2022, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + +import ballerina/jwt; +import ballerina/uuid; +import wso2/apk_common_lib as commons; + +isolated function generateToken(JWTTokenInfo jwtInfo) returns string|error { + TokenIssuerConfiguration & readonly issuerConfiguration = issuerConfig.cloneReadOnly(); + commons:KeyStore & readonly signingCert = keyStores.signing; + string jwtid = uuid:createType1AsString(); + jwt:IssuerConfig issuerConfig = { + issuer: issuerConfiguration.issuer, + audience: issuerConfiguration.audience, + expTime: issuerConfiguration.expTime, + jwtId: jwtid, + keyId: issuerConfiguration.keyId, + signatureConfig: { + config: {keyFile: signingCert.keyFilePath} + } + }; + issuerConfig.username = jwtInfo.subscriber; + + issuerConfig.customClaims = handleCustomClaims(jwtInfo); + return jwt:issue(issuerConfig); +} + +# This function used to handle internal token custom tokens. +# +# + jwtInfo- invoked API +# + return - Return list of custom claims +isolated function handleCustomClaims(JWTTokenInfo jwtInfo) returns map { + map claims = {}; + claims["keytype"] = jwtInfo.keyType; + claims["permittedReferer"] = jwtInfo.permittedReferrer; + claims["permittedIp"] = jwtInfo.permittedIP; + claims["token_type"] = "APIKey"; + claims["tierInfo"] = ""; + claims["subscribedAPIs"] = createSubscribedAPIJSON(jwtInfo.subscribedAPIs); + claims["application"] = createApplicationJSON(jwtInfo.application); + return claims; +} + +# This GenerateSubscribedAPIS Element. +# +# + apis - subscribed APIs. +# + return - Return SubscribedAPI. +isolated function createSubscribedAPIJSON(API[] apis) returns json { + //return apis.toJson(); + map[] strippedAPIs = []; + foreach API api in apis { + map subscribedAPI = {}; + subscribedAPI["name"] = api.name; + subscribedAPI["context"] = api.context; + subscribedAPI["version"] = api.'version; + subscribedAPI["publisher"] = "apkuser"; + string? uuid = api.id; + if uuid is string { + subscribedAPI["uuid"] = uuid; + } + strippedAPIs.push(subscribedAPI); + } + return strippedAPIs.toJson(); +} + +# This GenerateApplication Element. +# +# + app - Application. +# + return - Return Application. +isolated function createApplicationJSON(Application app) returns json { + map application = {}; + string? uuid = app.applicationId; + string? owner = app.owner; + application["name"] = app.name; + if uuid is string{ + application["uuid"] = uuid; + } + if owner is string { + application["owner"] = owner; + } + application["tierQuotaType"] = ""; + return application; +} diff --git a/devportal/devportal-domain-service/ballerina/K8sClient.bal b/devportal/devportal-domain-service/ballerina/K8sClient.bal new file mode 100644 index 000000000..a0c9cd39d --- /dev/null +++ b/devportal/devportal-domain-service/ballerina/K8sClient.bal @@ -0,0 +1,82 @@ +// +// Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + +import ballerina/io; +import ballerina/http; +import ballerina/log; +import wso2/apk_common_lib as commons; +const string K8S_API_ENDPOINT = "/api/v1"; +final string token = check io:fileReadString(k8sConfig.serviceAccountPath + "/token"); +final string caCertPath = k8sConfig.serviceAccountPath + "/ca.crt"; +string namespaceFile = k8sConfig.serviceAccountPath + "/namespace"; +final string currentNameSpace = check io:fileReadString(namespaceFile); +final http:Client k8sApiServerEp = check initializeK8sClient(); + +# This initialize the k8s Client. +# + return - k8s http client +public function initializeK8sClient() returns http:Client|error { + http:Client k8sApiClient = check new ("https://" + k8sConfig.host, + auth = { + token: token + }, + secureSocket = { + cert: caCertPath + + } + ); + return k8sApiClient; +} + +# This returns Pod value according to given name and namespace. +# +# + name - Name of Pod +# + namespace - Namespace of Pod +# + return - Return Pod value for a given name and namespace +isolated function getPodFromNameAndNamespace(string name, string namespace) returns string[]|commons:APKError { + string endpoint = "/api/v1/namespaces/" + namespace + "/endpoints/" + name; + http:Response|error response = k8sApiServerEp->get(endpoint, targetType = http:Response); + if response is http:Response { + json|http:ClientError podValue = response.getJsonPayload(); + if podValue is json{ + do { + log:printDebug(podValue.toString()); + json[] subsets = check podValue.subsets; + json[] addresses = check subsets[0].addresses; + string[] hosts =[]; + foreach json item in addresses { + string ip = check item.ip; + hosts.push(ip); + } + log:printDebug(hosts.toString()); + return hosts; + } on fail var e { + string message ="Error while retrieving host. Error while retrieving pod information for pod: " + name; + log:printError(message + e.toBalString()); + return error(message,e, message = message, description = message, code = 909000, statusCode = 500); + } + } else { + string message ="Response isn't a json. Error while retrieving pod information for pod: " + name; + log:printError(message); + return error(message, message = message, description = message, code = 909000, statusCode = 500); + } + } else { + string message ="Error while retrieving pod information for pod" + name; + log:printError(message); + return error(message, message = message, description = message, code = 909000, statusCode = 500); + } +} diff --git a/devportal/devportal-domain-service/ballerina/KMUtils.bal b/devportal/devportal-domain-service/ballerina/KMUtils.bal new file mode 100644 index 000000000..155cd039d --- /dev/null +++ b/devportal/devportal-domain-service/ballerina/KMUtils.bal @@ -0,0 +1,34 @@ +import devportal_service.types; +import ballerina/cache; +import devportal_service.nonprodidp; +import wso2/apk_common_lib as commons; +import devportal_service.kmclient; + +final cache:Cache kmClientCache = new (capacity = 50, evictionFactor = 0.2); + +public isolated function getKmClient(types:KeyManager keyManagerConfig) returns kmclient:KeyManagerClient|commons:APKError { + do { + if (kmClientCache.hasKey(keyManagerConfig.id)) { + lock { + return check kmClientCache.get(keyManagerConfig.id); + } + } else { + if (kmClientCache.hasKey(keyManagerConfig.id)) { + lock { + return check kmClientCache.get(keyManagerConfig.id); + } + } + lock { + if keyManagerConfig.'type == "nonProdIdp" { + nonprodidp:NonProdIdpKeyManagerClient nonProdIdpClient = check new (keyManagerConfig); + _ = check kmClientCache.put(keyManagerConfig.id, nonProdIdpClient); + return nonProdIdpClient; + } else { + return error("Unsupported key manager type", code = 900959, description = "Unsupported key manager type", statusCode = 400, message = "Unsupported key manager type"); + } + } + } + } on fail var e { + return error("Internal Server Error", code = 900500, description = e.message(), statusCode = 500, message = e.message()); + } +} diff --git a/devportal/devportal-domain-service/ballerina/Resource.bal b/devportal/devportal-domain-service/ballerina/Resource.bal new file mode 100644 index 000000000..a6a517218 --- /dev/null +++ b/devportal/devportal-domain-service/ballerina/Resource.bal @@ -0,0 +1,42 @@ +// +// Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + +type Resource record {| + string resourceUUID; + string apiUuid; + int resourceCategoryId; + string dataType; + string resourceContent; + byte[] resourceBinaryValue; +|}; + +type Thumbnail record {| + string imageType; + byte[] imageContent; +|}; + +type DocumentMetaData record {| + string documentId?; + string resourceId?; + string name; + string documentType; + string summary?; + string sourceType; + string sourceUrl?; + string otherTypeName?; +|}; \ No newline at end of file diff --git a/devportal/devportal-domain-service/ballerina/apiDAO.bal b/devportal/devportal-domain-service/ballerina/apiDAO.bal new file mode 100644 index 000000000..9de3af949 --- /dev/null +++ b/devportal/devportal-domain-service/ballerina/apiDAO.bal @@ -0,0 +1,242 @@ +// +// Copyright (c) 2022, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + +import ballerina/log; +import ballerinax/postgresql; +import ballerina/sql; +import wso2/apk_common_lib as commons; +final string PUBLISHED = "PUBLISHED"; +final string PROTOTYPED = "PROTOTYPED"; +final string DEPRECATED = "DEPRECATED"; + +isolated function getAPIByIdDAO(string apiId) returns API|commons:APKError|NotFoundError { + postgresql:Client | error dbClient = getConnection(); + if dbClient is error { + string message = "Error while retrieving connection"; + return error(message, dbClient, message = message, description = message, code = 909000, statusCode = 500); + } else { + sql:ParameterizedQuery query = `SELECT UUID AS ID, + API_NAME as NAME, API_VERSION as VERSION,CONTEXT, ORGANIZATION,STATUS, API_TYPE as TYPE, string_to_array(SDK::text,',')::text[] AS SDK , ARTIFACT as ARTIFACT + FROM API WHERE UUID =${apiId} AND + STATUS IN (${PUBLISHED},${PROTOTYPED},${DEPRECATED})`; + API | sql:Error result = dbClient->queryRow(query); + if result is sql:NoRowsError { + log:printDebug(result.toString()); + NotFoundError nfe = {body:{code: 90915, message: "API Not Found for provided API ID"}}; + return nfe; + } else if result is API { + log:printDebug(result.toString()); + return result; + } else { + log:printDebug(result.toString()); + string message = "Error while retrieving API"; + return error(message, result, message = message, description = message, code = 909000, statusCode = 500); + } + } +} + +isolated function getAPIsDAO(string org) returns API[]|commons:APKError { + postgresql:Client | error dbClient = getConnection(); + if dbClient is error { + string message = "Error while retrieving connection"; + return error(message, dbClient, message = message, description = message, code = 909000, statusCode = 500); + } else { + do { + sql:ParameterizedQuery query = `SELECT UUID AS ID, + API_NAME as NAME, API_VERSION as VERSION,CONTEXT, ORGANIZATION,STATUS, + API_TYPE as TYPE, ARTIFACT as ARTIFACT FROM API WHERE ORGANIZATION =${org} AND + STATUS IN (${PUBLISHED},${PROTOTYPED},${DEPRECATED})`; + stream apisStream = dbClient->query(query); + API[] apis = check from API api in apisStream select api; + check apisStream.close(); + return apis; + } on fail var e { + string message = "Internal Error occured while retrieving APIs"; + return error(message, e, message = message, description = message, code = 909001, statusCode = 500); + } + } +} + +isolated function getAPIsByQueryDAO(string payload, string org) returns API[]|commons:APKError { + postgresql:Client | error dbClient = getConnection(); + if dbClient is error { + string message = "Error while retrieving connection"; + return error(message, dbClient, message = message, description = message, code = 909000, statusCode = 500); + } else { + do { + sql:ParameterizedQuery query = `SELECT DISTINCT UUID AS ID, + API_NAME as NAME, API_VERSION as VERSION,CONTEXT, ORGANIZATION,STATUS, + API_TYPE as TYPE, ARTIFACT as ARTIFACT FROM API JOIN JSONB_EACH_TEXT(ARTIFACT) e ON true + WHERE ORGANIZATION =${org} AND e.value LIKE ${payload} AND + STATUS IN (${PUBLISHED},${PROTOTYPED},${DEPRECATED})`; + stream apisStream = dbClient->query(query); + API[] apis = check from API api in apisStream select api; + check apisStream.close(); + return apis; + } on fail var e { + string message = "Internal Error occured while retrieving APIs"; + return error(message, e, message = message, description = message, code = 909001, statusCode = 500); + } + } +} + +isolated function getAPIDefinitionDAO(string apiId) returns APIDefinition|NotFoundError|commons:APKError { + postgresql:Client | error dbClient = getConnection(); + if dbClient is error { + string message = "Error while retrieving connection"; + return error(message, dbClient, message = message, description = message, code = 909000, statusCode = 500); + } else { + sql:ParameterizedQuery query = `SELECT encode(API_DEFINITION, 'escape')::text AS schemaDefinition, MEDIA_TYPE as type + FROM API_ARTIFACT WHERE API_UUID =${apiId}`; + APIDefinition | sql:Error result = dbClient->queryRow(query); + if result is sql:NoRowsError { + log:printDebug(result.toString()); + NotFoundError nfe = {body:{code: 90915, message: "API Definition Not Found for provided API ID"}}; + return nfe; + } else if result is APIDefinition { + log:printDebug(result.toString()); + return result; + } else { + log:printError(result.toString()); + string message = "Internal Error while retrieving API Definition"; + return error(message, result, message = message, description = message, code = 909001, statusCode = 500); + } + } +} + +isolated function getResourceCategoryIdByCategoryTypeDAO(string resourceType) returns int|commons:APKError { + postgresql:Client | error db_Client = getConnection(); + if db_Client is error { + string message = "Error while retrieving connection"; + return error(message, db_Client, message = message, description = message, code = 909000, statusCode = 500); + } else { + sql:ParameterizedQuery GET_RESOURCE_CATEGORY_Prefix = `SELECT RESOURCE_CATEGORY_ID FROM RESOURCE_CATEGORIES where RESOURCE_CATEGORY = `; + sql:ParameterizedQuery values = `${resourceType}`; + sql:ParameterizedQuery sqlQuery = sql:queryConcat(GET_RESOURCE_CATEGORY_Prefix, values); + int|sql:Error result = db_Client->queryRow(sqlQuery); + if result is int { + return result; + } else { + log:printError(result.toString()); + string message = "Internal Error while retrieving resource category"; + return error(message, result, message = message, description = message, code = 909001, statusCode = 500); + } + } +} + +isolated function getResourceByResourceCategoryDAO(string apiId, int resourceCategoryId) returns Resource|NotFoundError|commons:APKError { + postgresql:Client | error db_Client = getConnection(); + if db_Client is error { + string message = "Error while retrieving connection"; + return error(message, db_Client, message = message, description = message, code = 909000, statusCode = 500); + } else { + sql:ParameterizedQuery sqlQuery = `SELECT UUID AS resourceUUID, API_UUID AS apiUuid, RESOURCE_CATEGORY_ID AS resourceCategoryId, DATA_TYPE AS dataType, + RESOURCE_CONTENT AS resourceContent, RESOURCE_BINARY_VALUE AS resourceBinaryValue + FROM API_RESOURCES where API_UUID = ${apiId} AND RESOURCE_CATEGORY_ID = ${resourceCategoryId}`; + Resource|sql:Error result = db_Client->queryRow(sqlQuery); + + if result is sql:NoRowsError { + log:printDebug(result.toString()); + NotFoundError nfe = {body:{code: 90915, message: "Thumbnail Not Found for provided API ID"}}; + return nfe; + } else if result is Resource { + return result; + } else { + log:printError(result.toString()); + string message = "Internal Error while retrieving resource"; + return error(message, result, message = message, description = message, code = 909001, statusCode = 500); + } + } +} + +isolated function getDocumentByDocumentIdDAO(string documentId, string apiId) returns DocumentMetaData|NotFoundError|commons:APKError { + postgresql:Client|error db_Client = getConnection(); + if db_Client is error { + string message = "Error while retrieving connection"; + return error(message, db_Client, message = message, description = message, code = 909000, statusCode = 500); + } else { + sql:ParameterizedQuery GET_DOCUMENT_Prefix = `SELECT UUID AS documentId, RESOURCE_UUID AS resourceId, NAME AS name, SUMMARY AS summary, + TYPE AS documentType, OTHER_TYPE_NAME AS otherTypeName, SOURCE_URL AS sourceUrl, + SOURCE_TYPE AS sourceType FROM API_DOC_META_DATA where UUID = `; + sql:ParameterizedQuery values = `${documentId}`; + sql:ParameterizedQuery sqlQuery = sql:queryConcat(GET_DOCUMENT_Prefix, values); + DocumentMetaData|sql:Error result = db_Client->queryRow(sqlQuery); + if result is sql:NoRowsError { + log:printDebug(result.toString()); + NotFoundError nfe = {body: {code: 90915, message: "Document Not Found for provided Document ID"}}; + return nfe; + } else if result is DocumentMetaData { + return result; + } else { + log:printError(result.toString()); + string message = "Internal Error while retrieving Document"; + return error(message, result, message = message, description = message, code = 909001, statusCode = 500); + } + } +} + +isolated function getDocumentsDAO(string apiId) returns Document[]|commons:APKError { + postgresql:Client|error db_Client = getConnection(); + if db_Client is error { + string message = "Error while retrieving connection"; + return error(message, db_Client, message = message, description = message, code = 909000, statusCode = 500); + } else { + do { + sql:ParameterizedQuery GET_DOCUMENTS_Query = `SELECT UUID AS documentId, NAME AS name, SUMMARY AS summary, + TYPE AS documentType, OTHER_TYPE_NAME AS otherTypeName, SOURCE_URL AS sourceUrl, + SOURCE_TYPE AS sourceType FROM API_DOC_META_DATA where API_UUID = ${apiId}`; + stream documentStream = db_Client->query(GET_DOCUMENTS_Query); + Document[]|sql:Error documents = from Document document in documentStream + select document; + sql:Error?? close = documentStream.close(); + if documents is sql:Error { + log:printError(documents.toString()); + string message = "Internal Error while retrieving Document List"; + return error(message, documents, message = message, description = message, code = 909001, statusCode = 500); + } else if close is sql:Error { + log:printError(close.toString()); + string message = "Internal Error while retrieving Document List"; + return error(message, close, message = message, description = message, code = 909001, statusCode = 500); + } else { + return documents; + } + } + } +} + +isolated function getResourceByResourceIdDAO(string resourceId) returns Resource|commons:APKError { + postgresql:Client|error db_Client = getConnection(); + if db_Client is error { + string message = "Error while retrieving connection"; + return error(message, db_Client, message = message, description = message, code = 909000, statusCode = 500); + } else { + sql:ParameterizedQuery GET_RESOURCE_Prefix = `SELECT UUID AS resourceUUID, API_UUID AS apiUuid, RESOURCE_CATEGORY_ID AS resourceCategoryId, DATA_TYPE AS dataType, + RESOURCE_CONTENT AS resourceContent, RESOURCE_BINARY_VALUE AS resourceBinaryValue + FROM API_RESOURCES where UUID = `; + sql:ParameterizedQuery values = `${resourceId}`; + sql:ParameterizedQuery sqlQuery = sql:queryConcat(GET_RESOURCE_Prefix, values); + Resource|sql:Error result = db_Client->queryRow(sqlQuery); + if result is Resource { + return result; + } else { + log:printError(result.toString()); + string message = "Internal Error while retrieving resource category"; + return error(message, result, message = message, description = message, code = 909001, statusCode = 500); + } + } +} diff --git a/devportal/devportal-domain-service/ballerina/apiImpl.bal b/devportal/devportal-domain-service/ballerina/apiImpl.bal new file mode 100644 index 000000000..1d598e057 --- /dev/null +++ b/devportal/devportal-domain-service/ballerina/apiImpl.bal @@ -0,0 +1,247 @@ +// +// Copyright (c) 2022, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + +import ballerina/jballerina.java; +import devportal_service.org.wso2.apk.devportal.sdk as sdk; +import devportal_service.java.util as javautil; +import devportal_service.java.lang as javalang; +import ballerina/http; +import wso2/apk_common_lib as commons; + +isolated function getAPIByAPIId(string apiId) returns API|NotFoundError|commons:APKError { + API|commons:APKError|NotFoundError api = getAPIByIdDAO(apiId); + return api; +} + +isolated function getAPIList(int 'limit, int offset, string? query, commons:Organization organization) returns APIList|commons:APKError { + if query !is string { + API[]|commons:APKError apis = getAPIsDAO(organization.uuid); + if apis is API[] { + API[] limitSet = []; + if apis.length() > offset { + foreach int i in offset ... (apis.length() - 1) { + if limitSet.length() < 'limit { + limitSet.push(apis[i]); + } + } + } + APIList apisList = {count: limitSet.length(), list: limitSet, pagination: {total: apis.length(), 'limit: 'limit, offset: offset}}; + return apisList; + } else { + return apis; + } + } else { + boolean hasPrefix = query.startsWith("content"); + if hasPrefix { + int? index = query.indexOf(":"); + if index is int { + string modifiedQuery = "%" + query.substring(index + 1) + "%"; + API[]|commons:APKError apis = getAPIsByQueryDAO(modifiedQuery, organization.uuid); + if apis is API[] { + API[] limitSet = []; + if apis.length() > offset { + foreach int i in offset ... (apis.length() - 1) { + if limitSet.length() < 'limit { + limitSet.push(apis[i]); + } + } + } + APIList apisList = {count: limitSet.length(), list: limitSet, pagination: {total: apis.length(), 'limit: 'limit, offset: offset}}; + return apisList; + } else { + return apis; + } + } else { + string message = "Invalid Content Search Text Provided. Missing :"; + commons:APKError e = error(message, message = message, description = message, code = 90911, statusCode = 400); + return e; + } + } else { + string message = "Invalid Content Search Text Provided. Missing content keyword"; + commons:APKError e = error(message, message = message, description = message, code = 90911, statusCode = 400); + return e; + } + } +} + +isolated function getAPIDefinition(string apiId) returns APIDefinition|NotFoundError|commons:APKError { + APIDefinition|NotFoundError|commons:APKError apiDefinition = getAPIDefinitionDAO(apiId); + return apiDefinition; +} + +isolated function generateSDKImpl(string apiId, string language) returns http:Response|NotFoundError|commons:APKError { + sdk:APIClientGenerationManager sdkClient = new sdk:APIClientGenerationManager(newSDKClient()); + string apiName; + string apiVersion; + API|NotFoundError api = check getAPIByAPIId(apiId); + if api is API { + apiName = api.name; + apiVersion = api.'version; + APIDefinition|NotFoundError|commons:APKError apiDefinition = getAPIDefinition(apiId); + if apiDefinition is APIDefinition { + string? schema = apiDefinition.schemaDefinition; + if schema is string { + javautil:Map|sdk:APIClientGenerationException sdkMap = sdkClient.generateSDK(language, apiName, apiVersion, schema, + sdkConfig.groupId, sdkConfig.artifactId, sdkConfig.modelPackage, sdkConfig.apiPackage); + if sdkMap is javautil:Map { + string path = readMap(sdkMap, "zipFilePath"); + string fileName = readMap(sdkMap, "zipFileName"); + http:Response response = new; + response.setFileAsPayload(path); + response.addHeader("Content-Disposition", "attachment; filename=" + fileName); + return response; + } else { + commons:APKError e = error("Unable to generate SDK", message = "Unable to generate SDK", description = "Unable to generate SDK", code = 90911, statusCode = 500); + return e; + } + } else { + string message = "Unable to retrieve schema mediation"; + commons:APKError e = error(message, message = message, description = message, code = 90911, statusCode = 500); + return e; + } + } + } else if api is NotFoundError|commons:APKError { + return api; + } + string message = "Unable to generate SDK"; + commons:APKError e = error(message, message = message, description = message, code = 90911, statusCode = 500); + return e; +} + +isolated function getSDKLanguages() returns string|json|commons:APKError { + sdk:APIClientGenerationManager sdkClient = new sdk:APIClientGenerationManager(newSDKClient()); + string? sdkLanguages = sdkClient.getSupportedSDKLanguages(); + return sdkLanguages; +} + +isolated function newSDKClient() returns handle = @java:Constructor { + 'class: "org.wso2.apk.devportal.sdk.APIClientGenerationManager" +} external; + +isolated function readMap(javautil:Map sdkMap, string key) returns string { + handle keyAsJavaStr = java:fromString(key); + javalang:Object keyAsObj = new (keyAsJavaStr); + javalang:Object value = sdkMap.get(keyAsObj); + // Above simplified to one line + // javalang:Object value = sdkMap.get(new (java:fromString("zipFilePath"))); + handle valueHandle = value.jObj; + string? valueStr = java:toString(valueHandle); + if valueStr is string { + return valueStr; + } else { + return ""; + } +} + +isolated function getThumbnail(string apiId) returns http:Response|NotFoundError|commons:APKError { + API|NotFoundError|commons:APKError api = getAPIByAPIId(apiId); + if api is API { + int|commons:APKError thumbnailCategoryId = getResourceCategoryIdByCategoryTypeDAO(RESOURCE_TYPE_THUMBNAIL); + if thumbnailCategoryId is int { + Resource|NotFoundError|commons:APKError thumbnail = getResourceByResourceCategoryDAO(apiId, thumbnailCategoryId); + if thumbnail is Resource { + http:Response outResponse = new; + outResponse.setBinaryPayload(thumbnail.resourceBinaryValue, thumbnail.dataType); + return outResponse; + } else { + return thumbnail; + } + } + return thumbnailCategoryId; + } else if api is NotFoundError|commons:APKError { + return api; + } + string message = "Unable to get the thumbnail"; + commons:APKError e = error(message, message = message, description = message, code = 90911, statusCode = 500); + return e; +} + +isolated function getDocumentMetaData(string apiId, string documentId) returns Document|NotFoundError|commons:APKError { + API|NotFoundError|commons:APKError api = getAPIByAPIId(apiId); + if api is API { + DocumentMetaData|NotFoundError|commons:APKError getDocumentMetaData = getDocumentByDocumentIdDAO(documentId, apiId); + if getDocumentMetaData is DocumentMetaData { + // Convert documentMetadata object to Document object + Document document = { + documentId: getDocumentMetaData.documentId, + name: getDocumentMetaData.name, + summary: getDocumentMetaData.summary, + sourceType: getDocumentMetaData.sourceType, + sourceUrl: getDocumentMetaData.sourceUrl, + documentType: getDocumentMetaData.documentType, + otherTypeName: getDocumentMetaData.otherTypeName + }; + return document; + } else { + return getDocumentMetaData; + } + } else if api is NotFoundError|commons:APKError { + return api; + } + string message = "Unable to get the Document meta data"; + commons:APKError e = error(message, message = message, description = message, code = 90911, statusCode = 500); + return e; +} + + +isolated function getDocumentContent(string apiId, string documentId) returns http:Response|NotFoundError|commons:APKError { + API|NotFoundError|commons:APKError api = getAPIByAPIId(apiId); + if api is API { + DocumentMetaData|NotFoundError|commons:APKError getDocumentMetaData = getDocumentByDocumentIdDAO(documentId, apiId); + if getDocumentMetaData is DocumentMetaData { + Resource|commons:APKError getDocumentResource = getResourceByResourceIdDAO(getDocumentMetaData.resourceId); + if getDocumentResource is Resource { + http:Response outResponse = new; + outResponse.setBinaryPayload(getDocumentResource.resourceBinaryValue, getDocumentResource.dataType); + return outResponse; + } else { + return getDocumentResource; + } + } else { + return getDocumentMetaData; + } + } else if api is NotFoundError|commons:APKError { + return api; + } + string message = "Unable to get the Document content"; + commons:APKError e = error(message, message = message, description = message, code = 90911, statusCode = 500); + return e; +} + +isolated function getDocumentList(string apiId, int 'limit, int offset) returns DocumentList|NotFoundError|commons:APKError { + API|NotFoundError|commons:APKError api = getAPIByAPIId(apiId); + if api is API { + Document[]|commons:APKError documents = getDocumentsDAO(apiId); + if documents is Document[] { + Document[] limitSet = []; + if documents.length() > offset { + foreach int i in offset ... (documents.length() - 1) { + if limitSet.length() < 'limit { + limitSet.push(documents[i]); + } + } + } + DocumentList documentList = {count: limitSet.length(), list: limitSet, pagination: {total: documents.length(), 'limit: 'limit, offset: offset}}; + return documentList; + } else { + return documents; + } + } else { + return api; + } +} diff --git a/devportal/devportal-domain-service/ballerina/applicationDAO.bal b/devportal/devportal-domain-service/ballerina/applicationDAO.bal new file mode 100644 index 000000000..a25d9df3a --- /dev/null +++ b/devportal/devportal-domain-service/ballerina/applicationDAO.bal @@ -0,0 +1,171 @@ +// +// Copyright (c) 2022, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + +import ballerina/log; +import ballerinax/postgresql; +import wso2/apk_common_lib as commons; +import ballerina/sql; + +isolated function addApplicationDAO(Application application, string subscriberId, string org) returns Application|commons:APKError { + postgresql:Client|error dbClient = getConnection(); + if dbClient is error { + string message = "Error while retrieving connection"; + return error(message, dbClient, message = message, description = message, code = 909000, statusCode = 500); + } else { + sql:ParameterizedQuery query = `INSERT INTO APPLICATION (NAME, USER_UUID, + DESCRIPTION, APPLICATION_STATUS, GROUP_ID, CREATED_BY, CREATED_TIME, UPDATED_TIME, + UUID, ORGANIZATION) VALUES (${application.name},${subscriberId}, + ${application.description},${application.status},${application.groups},${application.owner},${application.createdTime}, + ${application.updatedTime},${application.applicationId},${org})`; + sql:ExecutionResult|sql:Error result = dbClient->execute(query); + if result is sql:ExecutionResult { + return application; + } else { + log:printDebug(result.toString()); + string message = "Error while inserting data into Database"; + return error(message, result, message = message, description = message, code = 909000, statusCode = 500); + } + } +} + +isolated function getSubscriberIdDAO(string user, string org) returns string|NotFoundError|commons:APKError { + postgresql:Client|error dbClient = getConnection(); + if dbClient is error { + string message = "Error while retrieving connection"; + return error(message, dbClient, message = message, description = message, code = 909000, statusCode = 500); + } else { + sql:ParameterizedQuery query = `SELECT UUID FROM INTERNAL_USER WHERE UUID =${user}`; + string|sql:Error result = dbClient->queryRow(query); + if result is sql:NoRowsError { + log:printDebug(result.toString()); + NotFoundError nfe = {body: {code: 90916, message: "Subscriber Id not found"}}; + return nfe; + } else if result is string { + log:printDebug(result.toString()); + return result; + } else { + log:printDebug(result.toString()); + string message = "Error while retrieving Subscriber ID"; + return error(message, result, message = message, description = message, code = 909007, statusCode = 500); + } + } +} + +isolated function getApplicationUsagePlanByNameDAO(string policyName, string org) returns string?|error { + postgresql:Client|error dbClient = getConnection(); + if dbClient is error { + return error("Error while retrieving connection"); + } else { + sql:ParameterizedQuery query = `SELECT UUID FROM APPLICATION_USAGE_PLAN WHERE NAME =${policyName} AND ORGANIZATION =${org}`; + string|sql:Error result = dbClient->queryRow(query); + if result is sql:NoRowsError { + log:printDebug(result.toString()); + return error("Not Found"); + } else if result is string { + log:printDebug(result.toString()); + return result; + } else { + log:printDebug(result.toString()); + return error("Error while retrieving Application Usage Plan"); + } + } +} + +isolated function getApplicationByIdDAO(string appId, string org) returns Application|commons:APKError|NotFoundError { + postgresql:Client|error dbClient = getConnection(); + if dbClient is error { + string message = "Error while retrieving connection"; + return error(message, dbClient, message = message, description = message, code = 909000, statusCode = 500); + } else { + sql:ParameterizedQuery query = `SELECT NAME, UUID as APPLICATIONID, DESCRIPTION, APPLICATION_TIER as THROTTLINGPOLICY, TOKEN_TYPE as TOKENTYPE, ORGANIZATION, + APPLICATION_STATUS as STATUS FROM APPLICATION WHERE UUID =${appId} AND ORGANIZATION =${org}`; + Application|sql:Error result = dbClient->queryRow(query); + if result is sql:NoRowsError { + log:printDebug(result.toString()); + NotFoundError nfe = {body: {code: 90916, message: "Application Not Found"}}; + return nfe; + } else if result is Application { + log:printDebug(result.toString()); + return result; + } else { + log:printDebug(result.toString()); + string message = "Error while retrieving Application"; + return error(message, result, message = message, description = message, code = 909007, statusCode = 500); + } + } +} + +isolated function getApplicationsDAO(string org) returns Application[]|commons:APKError { + postgresql:Client|error dbClient = getConnection(); + if dbClient is error { + string message = "Error while retrieving connection"; + return error(message, dbClient, message = message, description = message, code = 909000, statusCode = 500); + } else { + do { + sql:ParameterizedQuery query = `SELECT NAME, UUID as APPLICATIONID, DESCRIPTION, APPLICATION_TIER as THROTTLINGPOLICY, TOKEN_TYPE as TOKENTYPE, ORGANIZATION, + APPLICATION_STATUS as STATUS FROM APPLICATION WHERE ORGANIZATION =${org}`; + stream applicationStream = dbClient->query(query); + Application[] applications = check from Application application in applicationStream + select application; + check applicationStream.close(); + return applications; + } on fail var e { + string message = "Internal Error occured while retrieving Applications"; + return error(message, e, message = message, description = message, code = 909001, statusCode = 500); + } + } +} + +isolated function updateApplicationDAO(Application application, string subscriberId, string org) returns Application|commons:APKError { + postgresql:Client|error dbClient = getConnection(); + if dbClient is error { + string message = "Error while retrieving connection"; + return error(message, dbClient, message = message, description = message, code = 909000, statusCode = 500); + } else { + sql:ParameterizedQuery query = `UPDATE APPLICATION SET NAME = ${application.name}, + DESCRIPTION = ${application.description}, USER_UUID = ${subscriberId}, + APPLICATION_STATUS = ${application.status}, GROUP_ID = ${application.groups},CREATED_BY = ${application.owner}, + CREATED_TIME = ${application.createdTime}, UPDATED_TIME = ${application.updatedTime} + WHERE UUID = ${application.applicationId} AND ORGANIZATION = ${org}`; + sql:ExecutionResult|sql:Error result = dbClient->execute(query); + if result is sql:ExecutionResult { + return application; + } else { + log:printError(result.toString()); + string message = "Error while updating data record in the Database"; + return error(message, result, message = message, description = message, code = 909001, statusCode = 500); + } + } +} + +isolated function deleteApplicationDAO(string appId, string org) returns boolean|commons:APKError { + postgresql:Client|error dbClient = getConnection(); + if dbClient is error { + string message = "Error while retrieving connection"; + return error(message, dbClient, message = message, description = message, code = 909000, statusCode = 500); + } else { + sql:ParameterizedQuery query = `DELETE FROM APPLICATION WHERE UUID = ${appId} AND ORGANIZATION = ${org}`; + sql:ExecutionResult|sql:Error result = dbClient->execute(query); + if result is sql:ExecutionResult { + return result.affectedRowCount == 1 ? true : false; + } else { + string message = "Error while deleting data record in the Database"; + return error(message, result, message = message, description = message, code = 909001, statusCode = 500); + } + } +} diff --git a/devportal/devportal-domain-service/ballerina/applicationImpl.bal b/devportal/devportal-domain-service/ballerina/applicationImpl.bal new file mode 100644 index 000000000..a82af97db --- /dev/null +++ b/devportal/devportal-domain-service/ballerina/applicationImpl.bal @@ -0,0 +1,547 @@ +// +// Copyright (c) 2022, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + +import ballerina/log; +import ballerina/uuid; +import wso2/apk_common_lib as commons; +import wso2/notification_grpc_client; +import devportal_service.types; +import devportal_service.kmclient; +import ballerina/time; + +isolated function addApplication(Application application, commons:Organization org, string user) returns NotFoundError|Application|commons:APKError { + string applicationId = uuid:createType1AsString(); + application.applicationId = applicationId; + // TODO: Removed Validate the policy + // string?|error policyId = validateApplicationUsagePolicy(application.throttlingPolicy, org); + // if policyId is error { + // string message = "Invalid Policy"; + // log:printError(message); + // return error(message, policyId, message = message, description = message, code = 909000, statusCode = 500); + // } + string|NotFoundError subscriberId = check getSubscriberIdDAO(user, org.uuid); + if subscriberId is string { + boolean|error isApplicationWorkflowEnable = isApplicationWorkflowEnabled(org.uuid); + if isApplicationWorkflowEnable is error { + string message = "Error while checking application workflow"; + return error(message, message = message, description = message, code = 909000, statusCode = 500); + } else if (isApplicationWorkflowEnable) { + string|error appworkflow = addApplicationCreationWorkflow(applicationId, org.uuid); + if appworkflow is error { + string message = "Error while creating application workflow"; + return error(message, appworkflow, message = message, description = message, code = 909000, statusCode = 500); + } + application.status = "CREATED"; + Application createdApp = check addApplicationDAO(application, subscriberId, org.uuid); + return createdApp; + } else { + application.status = "APPROVED"; + Application createdApp = check addApplicationDAO(application, subscriberId, org.uuid); + string[] hostList = check retrieveManagementServerHostsList(); + string eventId = uuid:createType1AsString(); + time:Utc currTime = time:utcNow(); + string date = time:utcToString(currTime); + ApplicationGRPC createApplicationRequest = { + eventId: eventId, + name: createdApp.name, + uuid: applicationId, + owner: user, + policy: "unlimited", + keys: [], + attributes: [], + timeStamp: date, + organization: org.uuid + }; + foreach string host in hostList { + log:printDebug("Retrieved Mgt Host:" + host); + string devportalPubCert = keyStores.tls.certFilePath; + string devportalKeyCert = keyStores.tls.keyFilePath; + string pubCertPath = managementServerConfig.certPath; + NotificationResponse|error applicationNotification = notification_grpc_client:createApplication(createApplicationRequest, + "https://" + host + ":8766", pubCertPath, devportalPubCert, devportalKeyCert); + if applicationNotification is error { + string message = "Error while sending application create grpc event"; + log:printError(applicationNotification.toString()); + return error(message, applicationNotification, message = message, description = message, code = 909000, statusCode = 500); + } + } + return application; + } + } else { + return subscriberId; + } +} + +isolated function validateApplicationUsagePolicy(string policyName, commons:Organization org) returns string?|error { + string?|error policy = getApplicationUsagePlanByNameDAO(policyName, org.uuid); + return policy; +} + +isolated function getApplicationById(string appId, commons:Organization org) returns Application|commons:APKError|NotFoundError { + Application|commons:APKError|NotFoundError application = getApplicationByIdDAO(appId, org.uuid); + return application; +} + +isolated function getApplicationList(string? sortBy, string? groupId, string? query, string? sortOrder, int 'limit, int offset, commons:Organization org) returns ApplicationList|commons:APKError { + Application[]|commons:APKError applications = getApplicationsDAO(org.uuid); + if applications is Application[] { + int count = applications.length(); + ApplicationList applicationsList = {count: count, list: applications}; + return applicationsList; + } else { + return applications; + } +} + +isolated function updateApplication(string appId, Application application, commons:Organization org, string user) returns Application|NotFoundError|commons:APKError { + Application|commons:APKError|NotFoundError existingApp = getApplicationByIdDAO(appId, org.uuid); + if existingApp is Application { + application.applicationId = appId; + } else { + Error err = {code: 9010101, message: "Application Not Found"}; + NotFoundError nfe = {body: err}; + return nfe; + } + // TODO: Removed Validate the policy + // string?|error policyId = validateApplicationUsagePolicy(application.throttlingPolicy, org); + // if policyId is error { + // string message = "Invalid Policy"; + // log:printError(message); + // return error(message, policyId, message = message, description = message, code = 909000, statusCode = 500); + // } + string|NotFoundError subscriberId = check getSubscriberIdDAO(user, org.uuid); + if subscriberId is string { + log:printDebug("subscriber id" + subscriberId.toString()); + Application updatedApp = check updateApplicationDAO(application, subscriberId, org.uuid); + string[] hostList = check retrieveManagementServerHostsList(); + string eventId = uuid:createType1AsString(); + time:Utc currTime = time:utcNow(); + string date = time:utcToString(currTime); + ApplicationGRPC createApplicationRequest = { + eventId: eventId, + name: updatedApp.name, + uuid: appId, + owner: user, + policy: "unlimited", + keys: [], + attributes: [], + timeStamp: date, + organization: org.uuid + }; + foreach string host in hostList { + log:printDebug("Retrieved Host:" + host); + string devportalPubCert = keyStores.tls.certFilePath; + string devportalKeyCert = keyStores.tls.keyFilePath; + string pubCertPath = managementServerConfig.certPath; + NotificationResponse|error applicationNotification = notification_grpc_client:createApplication(createApplicationRequest, + "https://" + host + ":8766", pubCertPath, devportalPubCert, devportalKeyCert); + if applicationNotification is error { + string message = "Error while sending application create grpc event"; + log:printError(applicationNotification.toString()); + return error(message, applicationNotification, message = message, description = message, code = 909000, statusCode = 500); + } + } + return updatedApp; + } else { + return subscriberId; + } +} + +isolated function deleteApplication(string appId, commons:Organization organization) returns boolean|commons:APKError { + check deleteOauthApps(appId, organization); + boolean status = check deleteApplicationDAO(appId, organization.uuid); + string[] hostList = check retrieveManagementServerHostsList(); + string eventId = uuid:createType1AsString(); + time:Utc currTime = time:utcNow(); + string date = time:utcToString(currTime); + ApplicationGRPC deleteApplicationRequest = {eventId: eventId, uuid: appId, timeStamp: date, organization: organization.uuid}; + string devportalPubCert = keyStores.tls.certFilePath; + string devportalKeyCert = keyStores.tls.keyFilePath; + string pubCertPath = managementServerConfig.certPath; + foreach string host in hostList { + NotificationResponse|error applicationNotification = notification_grpc_client:deleteApplication(deleteApplicationRequest, + "https://" + host + ":8766", pubCertPath, devportalPubCert, devportalKeyCert); + if applicationNotification is error { + string message = "Error while sending application delete grpc event"; + log:printError(applicationNotification.toString()); + return error(message, applicationNotification, message = message, description = message, code = 909000, statusCode = 500); + } + } + return status; +} + +isolated function deleteOauthApps(string appId, commons:Organization organization) returns commons:APKError? { + types:KeyMappingDaoEntry[] keyMappingEntriesByApplication = check getKeyMappingEntriesByApplication(appId); + foreach types:KeyMappingDaoEntry item in keyMappingEntriesByApplication { + KeyManagerDaoEntry keyManagerById = check getKeyManagerById(item.key_manager_uuid, organization); + types:KeyManager keyManagerConfig = check fromKeyManagerDaoEntryToKeyManagerModel(keyManagerById); + if keyManagerConfig.enabled && item.create_mode == "CREATED" { + kmclient:KeyManagerClient kmClient = check getKmClient(keyManagerConfig); + boolean _ = check kmClient.deleteOauthApplication(item.consumer_key); + } + } +} + +isolated function generateAPIKey(APIKeyGenerateRequest payload, string appId, string keyType, string user, commons:Organization org) returns APIKey|commons:APKError|NotFoundError { + Application|NotFoundError application = check getApplicationById(appId, org); + if application !is Application { + return application; + } else { + boolean userAllowed = checkUserAccessAllowedForApplication(application, user); + if userAllowed { + int validityPeriod = 0; + int? payloadValPeriod = payload.validityPeriod; + if payloadValPeriod is int { + validityPeriod = payloadValPeriod; + } else { + string message = "Invalid validity period"; + log:printError(message); + return error(message, payloadValPeriod, message = message, description = message, code = 909000, statusCode = 500); + } + record {} addProperties = {}; + record {}? payloadAddProperties = payload.additionalProperties; + if payloadAddProperties is record {} { + addProperties = payloadAddProperties; + } else { + string message = "Invalid Additional Properties"; + log:printError(message); + return error(message, payloadAddProperties, message = message, description = message, code = 909000, statusCode = 500); + } + + // retrieve subscribed APIs + SubscriptionList|NotFoundError subscriptions = check getSubscriptions(null, appId, null, 0, 0, org); + API[] apiList = []; + if subscriptions is SubscriptionList { + Subscription[]? subArray = subscriptions.list; + if subArray is Subscription[] { + foreach Subscription item in subArray { + string? apiUUID = item.apiId; + if apiUUID is string { + API|NotFoundError api = check getAPIByAPIId(apiUUID); + if api is API { + apiList.push(api); + } + } else { + string message = "Invalid API UUID found:" + apiUUID.toString(); + log:printError(message); + return error(message, apiUUID, message = message, description = message, code = 909000, statusCode = 500); + } + } + } + } + APIKey|commons:APKError apiKey = generateAPIKeyForApplication(user, application, apiList, keyType, validityPeriod, addProperties); + return apiKey; + } else { + string message = "User:" + user + " doesn't have permission to Application with application id:" + appId; + log:printError(message); + return error(message, message = message, description = message, code = 909000, statusCode = 500); + } + } +} + +isolated function generateAPIKeyForApplication(string username, Application application, API[] apiList, string keyType, int validityPeriod, record {} addProperties) returns APIKey|commons:APKError { + if keyType !is "PRODUCTION"|"SANDBOX" { + string message = "Invalid Key Type:" + keyType; + log:printError(message); + return error(message, message = message, description = message, code = 909000, statusCode = 400); + } + JWTTokenInfo jwtTokenInfoPayload = {application: application, subscriber: username, expireTime: "", keyType: keyType, permittedIP: "", permittedReferrer: "", subscribedAPIs: apiList}; + string|error token = generateToken(jwtTokenInfoPayload); + if token is string { + APIKey apiKey = {apikey: token, validityTime: 3600}; + return apiKey; + } else { + string message = "Error while generating token"; + log:printError(message); + return error(message, token, message = message, description = message, code = 909000, statusCode = 400); + } +} + +isolated function checkUserAccessAllowedForApplication(Application application, string user) returns boolean { + return true; +} + +isolated function retrieveManagementServerHostsList() returns string[]|commons:APKError { + string managementServerServiceName = managementServerConfig.serviceName; + string managementServerNamespace = managementServerConfig.namespace; + log:printDebug("Service:" + managementServerServiceName); + log:printDebug("Namespace:" + managementServerNamespace); + string[]|commons:APKError hostList = getPodFromNameAndNamespace(managementServerServiceName, managementServerNamespace); + return hostList; +} + +# Description +# +# + application - Parameter Description +# + applicationKeyGenRequest - Parameter Description +# + organization - Parameter Description +# + return - Return Value Description +public isolated function generateKeysForApplication(Application application, ApplicationKeyGenerateRequest applicationKeyGenRequest, commons:Organization organization) returns OkApplicationKey|commons:APKError { + string? keyManager = applicationKeyGenRequest.keyManager; + if keyManager is string { + if check isKeyMappingEntryByApplicationAndKeyManagerExist(application.applicationId, keyManager,applicationKeyGenRequest.keyType) { + return error("Key Mapping Entry already exists for application " + application.name + " and keyManager " + keyManager, message = "Key Mapping Entry already exists for application " + application.name + " and keyManager " + keyManager, description = "Key Mapping Entry already exists for application " + application.name + " and keyManager " + keyManager, code = 900950, statusCode = 400); + } + KeyManagerDaoEntry keyManagerById = check getKeyManagerById(keyManager, organization); + types:KeyManager keyManagerEntry = check fromKeyManagerDaoEntryToKeyManagerModel(keyManagerById); + if !keyManagerEntry.enabled { + return error("Key Manager is disabled", message = "Key Manager is disabled", description = "Key Manager is disabled", code = 900951, statusCode = 400); + } + if !keyManagerEntry.enableOAuthAppCreation { + return error("OAuth App Creation is disabled for keyManager " + keyManagerEntry.name + " in organization " + organization.uuid, message = "OAuth App Creation is disabled for keyManager " + keyManagerEntry.name + " in organization " + organization.uuid, description = "OAuth App Creation is disabled for keyManager " + keyManagerEntry.name + " in organization " + organization.uuid, code = 900952, statusCode = 400); + } + string[]? availableGrantTypes = keyManagerEntry.availableGrantTypes; + if availableGrantTypes is string[] { + foreach string item in applicationKeyGenRequest.grantTypesToBeSupported { + if availableGrantTypes.indexOf(item) is () { + return error("Grant Type " + item + " is not supported by keyManager " + keyManagerEntry.name + " in organization " + organization.uuid, message = "Grant Type " + item + " is not supported by keyManager " + keyManagerEntry.name + " in organization " + organization.uuid, description = "Grant Type " + item + " is not supported by keyManager " + keyManagerEntry.name + " in organization " + organization.uuid, code = 900953, statusCode = 400); + } + } + } + kmclient:KeyManagerClient kmClient = check getKmClient(keyManagerEntry); + kmclient:ClientRegistrationResponse oauthApplicationCreationResponse = check registerOauthApplication(kmClient, application, applicationKeyGenRequest); + types:KeyMappingDaoEntry keyMappingDaoEntry = { + application_uuid: application.applicationId, + consumer_key: oauthApplicationCreationResponse.client_id, + key_manager_uuid: keyManager, + key_type: applicationKeyGenRequest.keyType, + uuid: uuid:createType1AsString(), + app_info: oauthApplicationCreationResponse.toJsonString().toBytes(), + create_mode: "CREATED" + }; + check addKeyMappingEntryForApplication(keyMappingDaoEntry); + OkApplicationKey okApplicationKey = { + body: { + consumerKey: oauthApplicationCreationResponse.client_id, + consumerSecret: oauthApplicationCreationResponse.client_secret, + callbackUrls: oauthApplicationCreationResponse.redirect_uris, + supportedGrantTypes: oauthApplicationCreationResponse.grant_types, + keyManager: keyManager, + keyMappingId: keyMappingDaoEntry.uuid, + keyType: applicationKeyGenRequest.keyType, + keyState: "CREATED", + mode: "CREATED", + additionalProperties: oauthApplicationCreationResponse.additional_properties + } + }; + return okApplicationKey; + } else { + return error("Key Manager is not provided", message = "Key Manager is not provided", description = "Key Manager is not provided", code = 900953, statusCode = 400); + } +} + +isolated function registerOauthApplication(kmclient:KeyManagerClient keyManagerClient, Application application, ApplicationKeyGenerateRequest oauthAppRegistrationRequest) returns kmclient:ClientRegistrationResponse|commons:APKError { + kmclient:ClientRegistrationRequest clientRegistrationRequest = { + client_name: application.name, + grant_types: oauthAppRegistrationRequest.grantTypesToBeSupported, + redirect_uris: oauthAppRegistrationRequest.callbackUrls + }; + return keyManagerClient.registerOauthApplication(clientRegistrationRequest); +} + +public isolated function mapKeys(Application application, ApplicationKeyMappingRequest applicationKeyMappingRequest, commons:Organization organization) returns OkApplicationKey|commons:APKError { + string? keyManager = applicationKeyMappingRequest.keyManager; + if keyManager is string { + KeyManagerDaoEntry keyManagerById = check getKeyManagerById(keyManager, organization); + types:KeyManager keyManagerEntry = check fromKeyManagerDaoEntryToKeyManagerModel(keyManagerById); + if !keyManagerEntry.enabled { + commons:APKError e = error("Key Manager is disabled", message = "Key Manager is disabled", description = "Key Manager is disabled", code = 900951, statusCode = 400); + return e; + } + if !keyManagerEntry.enableMapOAuthConsumerApps { + commons:APKError e = error("OAuth App Mapping is disabled for keyManager " + keyManagerEntry.name + " in organization " + organization.uuid, message = "OAuth App Mapping is disabled for keyManager " + keyManagerEntry.name + " in organization " + organization.uuid, description = "OAuth App Mapping is disabled for keyManager " + keyManagerEntry.name + " in organization " + organization.uuid, code = 900952, statusCode = 400); + return e; + } + if keyManagerEntry.enableOauthAppValidation { + kmclient:KeyManagerClient kmClient = check getKmClient(keyManagerEntry); + kmclient:ClientRegistrationResponse|commons:APKError retrievedOauthApp = kmClient.retrieveOauthApplicationByClientId(applicationKeyMappingRequest.consumerKey); + if retrievedOauthApp is kmclient:ClientRegistrationResponse { + if retrievedOauthApp.client_secret != applicationKeyMappingRequest.consumerSecret { + commons:APKError e = error("Consumer Secret is not valid", message = "Consumer Secret is not valid", description = "Consumer Secret is not valid", code = 900953, statusCode = 400); + return e; + } + } else { + commons:APKError e = error("Consumer Key is not valid", message = "Consumer Key is not valid", description = "Consumer Key is not valid", code = 900953, statusCode = 400); + return e; + } + } + types:KeyMappingDaoEntry keyMappingDaoEntry = { + application_uuid: application.applicationId, + consumer_key: applicationKeyMappingRequest.consumerKey, + key_manager_uuid: keyManager, + key_type: applicationKeyMappingRequest.keyType, + uuid: uuid:createType1AsString(), + app_info: "".toBytes(), + create_mode: "MAPPED" + }; + check addKeyMappingEntryForApplication(keyMappingDaoEntry); + OkApplicationKey okApplicationKey = { + body: { + consumerKey: applicationKeyMappingRequest.consumerKey, + consumerSecret: applicationKeyMappingRequest.consumerSecret, + keyManager: keyManager, + keyMappingId: keyMappingDaoEntry.uuid, + keyType: applicationKeyMappingRequest.keyType, + keyState: "CREATED", + mode: "MAPPED" + } + }; + return okApplicationKey; + } else { + commons:APKError e = error("Key Manager is not provided", message = "Key Manager is not provided", description = "Key Manager is not provided", code = 900953, statusCode = 400); + return e; + } +} + +public isolated function oauthKeys(Application application, commons:Organization organization) returns ApplicationKeyList|commons:APKError { + types:KeyMappingDaoEntry[] keyMAppingEntries = check getKeyMappingEntriesByApplication(application.applicationId); + ApplicationKeyList applicationKeyList = {}; + ApplicationKey[] applicationKeys = []; + foreach types:KeyMappingDaoEntry item in keyMAppingEntries { + applicationKeys.push(fromKeyMappingDaoEntryToApplicationKey(item, ())); + } + applicationKeyList.list = applicationKeys; + applicationKeyList.count = applicationKeys.length(); + return applicationKeyList; +} + +public isolated function oauthKeyByMappingId(Application application, string keyMappingId, commons:Organization organization) returns ApplicationKey|commons:APKError { + types:KeyMappingDaoEntry keyMappingEntry = check getKeyMappingEntryByApplicationAndKeyMappingId(application.applicationId, keyMappingId); + types:KeyManager keyManagerEntry = check getKeymanagerByKeyManagerUUID(keyMappingEntry.key_manager_uuid, organization); + if keyMappingEntry.create_mode == "CREATED" { + kmclient:KeyManagerClient keyManagerClient = check getKmClient(keyManagerEntry); + kmclient:ClientRegistrationResponse|commons:APKError retrieveOauthApplicationByClientId = keyManagerClient.retrieveOauthApplicationByClientId(keyMappingEntry.consumer_key); + if retrieveOauthApplicationByClientId is kmclient:ClientRegistrationResponse { + return fromKeyMappingDaoEntryToApplicationKey(keyMappingEntry, retrieveOauthApplicationByClientId); + } + } + return fromKeyMappingDaoEntryToApplicationKey(keyMappingEntry, ()); +} + +isolated function fromKeyMappingDaoEntryToApplicationKey(types:KeyMappingDaoEntry item, kmclient:ClientRegistrationResponse? oauthAppResponse) returns ApplicationKey { + ApplicationKey applicationKey = { + keyMappingId: item.uuid, + consumerKey: item.consumer_key, + keyManager: item.key_manager_uuid, + keyType: item.key_type, + mode: item.create_mode, + keyState: "CREATED" + }; + if oauthAppResponse is kmclient:ClientRegistrationResponse { + applicationKey.consumerSecret = oauthAppResponse.client_secret; + applicationKey.supportedGrantTypes = oauthAppResponse.grant_types; + applicationKey.callbackUrls = oauthAppResponse.redirect_uris; + applicationKey.additionalProperties = oauthAppResponse.additional_properties; + } + return applicationKey; +} + +public isolated function generateApplicationToken(Application application, string keyMappingId, ApplicationTokenGenerateRequest payload, commons:Organization organization) returns OkApplicationToken|commons:APKError { + types:KeyMappingDaoEntry keyMappingEntry = check getKeyMappingEntryByApplicationAndKeyMappingId(application.applicationId, keyMappingId); + types:KeyManager keyManagerEntry = check getKeymanagerByKeyManagerUUID(keyMappingEntry.key_manager_uuid, organization); + if keyManagerEntry.enabled && keyManagerEntry.enableTokenGeneration { + kmclient:KeyManagerClient kmClient = check getKmClient(keyManagerEntry); + kmclient:TokenRequest tokenRequest = {client_id: keyMappingEntry.consumer_key, client_secret: payload.consumerSecret, scopes: payload.scopes}; + kmclient:TokenResponse generateAccessToken = check kmClient.generateAccessToken(tokenRequest); + OkApplicationToken applicationToken = {body: {accessToken: generateAccessToken.access_token, tokenScopes: generateAccessToken.scopes, validityTime: generateAccessToken.expires_in}}; + return applicationToken; + } else { + return error("Key Manager is disabled", message = "Key Manager is disabled", description = "Key Manager is disabled", code = 900951, statusCode = 400); + } +} + +isolated function getKeymanagerByKeyManagerUUID(string uuid, commons:Organization organization) returns types:KeyManager|commons:APKError { + KeyManagerDaoEntry keyManagerById = check getKeyManagerById(uuid, organization); + return check fromKeyManagerDaoEntryToKeyManagerModel(keyManagerById); +} + +public isolated function updateOauthApp(Application application, string keyMappingId, ApplicationKey payload, commons:Organization organization) returns ApplicationKey|commons:APKError { + do { + types:KeyMappingDaoEntry keyMappingEntry = check getKeyMappingEntryByApplicationAndKeyMappingId(application.applicationId, keyMappingId); + types:KeyManager keyManagerEntry = check getKeymanagerByKeyManagerUUID(keyMappingEntry.key_manager_uuid, organization); + if keyManagerEntry.enabled { + kmclient:KeyManagerClient kmClient = check getKmClient(keyManagerEntry); + kmclient:ClientRegistrationResponse retrieveOauthApplicationByClientId = check kmClient.retrieveOauthApplicationByClientId(keyMappingEntry.consumer_key); + kmclient:ClientUpdateRequest clientUpDateRquest = {...retrieveOauthApplicationByClientId}; + clientUpDateRquest.client_id = payload.consumerKey; + clientUpDateRquest.client_secret = payload.consumerSecret; + clientUpDateRquest.grant_types = payload.supportedGrantTypes; + clientUpDateRquest.redirect_uris = payload.callbackUrls; + record {}? additionalProperties = payload.additionalProperties; + if additionalProperties is record {} { + if additionalProperties.hasKey("application_type") { + clientUpDateRquest.application_type = additionalProperties["application_type"]; + _ = additionalProperties.removeIfHasKey("application_type"); + } + if additionalProperties.hasKey("client_name") { + clientUpDateRquest.client_name = additionalProperties["client_name"]; + _ = additionalProperties.removeIfHasKey("client_name"); + } + if additionalProperties.hasKey("logo_uri") { + clientUpDateRquest.logo_uri = additionalProperties["logo_uri"]; + _ = additionalProperties.removeIfHasKey("logo_uri"); + } + if additionalProperties.hasKey("client_uri") { + clientUpDateRquest.client_uri = additionalProperties["client_uri"]; + _ = additionalProperties.removeIfHasKey("client_uri"); + } + if additionalProperties.hasKey("policy_uri") { + clientUpDateRquest.policy_uri = additionalProperties["policy_uri"]; + _ = additionalProperties.removeIfHasKey("policy_uri"); + } + if additionalProperties.hasKey("tos_uri") { + clientUpDateRquest.tos_uri = additionalProperties["tos_uri"]; + _ = additionalProperties.removeIfHasKey("tos_uri"); + } + if additionalProperties.hasKey("jwks_uri") { + clientUpDateRquest.jwks_uri = additionalProperties["jwks_uri"]; + _ = additionalProperties.removeIfHasKey("jwks_uri"); + } + if additionalProperties.hasKey("subject_type") { + clientUpDateRquest.subject_type = additionalProperties["subject_type"]; + _ = additionalProperties.removeIfHasKey("subject_type"); + } + if additionalProperties.hasKey("token_endpoint_auth_method") { + clientUpDateRquest.token_endpoint_auth_method = additionalProperties["token_endpoint_auth_method"]; + _ = additionalProperties.removeIfHasKey("token_endpoint_auth_method"); + } + clientUpDateRquest.additional_properties = additionalProperties; + } + kmclient:ClientRegistrationResponse oauthApplicationByClientId = check kmClient.updateOauthApplicationByClientId(keyMappingEntry.consumer_key, clientUpDateRquest); + types:KeyMappingDaoEntry updatedKeyMappingentry = keyMappingEntry.clone(); + updatedKeyMappingentry.app_info = oauthApplicationByClientId.toJsonString().toBytes(); + check updateKeyMappingEntry(updatedKeyMappingentry); + return { + keyMappingId: keyMappingEntry.uuid, + consumerKey: oauthApplicationByClientId.client_id, + consumerSecret: oauthApplicationByClientId.client_secret, + keyManager: keyMappingEntry.key_manager_uuid, + keyType: keyMappingEntry.key_type, + mode: keyMappingEntry.create_mode, + keyState: "CREATED", + callbackUrls: oauthApplicationByClientId.redirect_uris, + supportedGrantTypes: oauthApplicationByClientId.grant_types, + additionalProperties: oauthApplicationByClientId.additional_properties + }; + } else { + return error("Key Manager is disabled", message = "Key Manager is disabled", description = "Key Manager is disabled", code = 900951, statusCode = 400); + } + } on fail var e { + return error("Internal Server Error", e, message = "Internal Server Error", description = "Internal Server Error", code = 900952, statusCode = 500); + } +} diff --git a/devportal/devportal-domain-service/ballerina/build.gradle b/devportal/devportal-domain-service/ballerina/build.gradle new file mode 100644 index 000000000..a4741998e --- /dev/null +++ b/devportal/devportal-domain-service/ballerina/build.gradle @@ -0,0 +1,43 @@ +// +// Copyright (c) 2022, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + + +apply from: "$rootDir/../../common-gradle-scripts/ballerina.gradle" +apply from: "$rootDir/../../common-gradle-scripts/docker.gradle" + +tasks.register('build') { + group 'build' + description 'Build ballerina component' + dependsOn 'test' + dependsOn 'bal_build' +} + +tasks.register('test') { + group 'test' + description 'Test ballerina component' + dependsOn('start_postgres_image') + mustRunAfter('start_postgres_image') + dependsOn('bal_test') + finalizedBy('stop_postgres_image') +} +task clean{ + dependsOn 'bal_clean' +} + +build.mustRunAfter ":org.wso2.apk.devportal:build" +build.dependsOn ":org.wso2.apk.devportal:build" diff --git a/devportal/devportal-domain-service/ballerina/config.bal b/devportal/devportal-domain-service/ballerina/config.bal new file mode 100644 index 000000000..c39e6d91b --- /dev/null +++ b/devportal/devportal-domain-service/ballerina/config.bal @@ -0,0 +1,76 @@ +// +// Copyright (c) 2022, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// +import wso2/apk_common_lib as commons; + +type ThrottlingConfiguration record { + BlockCondition blockCondition = { + enabled: true + }; + boolean enableUnlimitedTier = true; + boolean enableHeaderConditions = false; + boolean enableJWTClaimConditions = false; + boolean enableQueryParamConditions = false; + boolean enablePolicyDeployment = true; +}; + +type BlockCondition record { + boolean enabled = true; +}; + + + +type APKConfiguration record { + ThrottlingConfiguration throttlingConfiguration; + KeyStores keyStores; +}; + +public type TokenIssuerConfiguration record {| + string issuer = "https://apim.wso2.com/oauth2/token"; + string audience = "https://apim.wso2.com/oauth2/token"; + string keyId = "gateway_certificate_alias"; + decimal expTime = 3600; +|}; + + +public type SDKConfiguration record {| + string groupId = "org.wso2"; + string artifactId = "org.wso2.client."; + string modelPackage = "org.wso2.client.model."; + string apiPackage = "org.wso2.client.api."; +|}; +public type KeyStores record{| + commons:KeyStore tls; + commons:KeyStore signing; +|}; + +public type K8sConfiguration record {| + string host = "kubernetes.default"; + string serviceAccountPath = "/var/run/secrets/kubernetes.io/serviceaccount"; + decimal readTimeout = 5; +|}; + +public type ManagementServerConfiguration record {| + string serviceName = "apk-test-wso2-apk-management-server"; + string namespace = "apk"; + string certPath = "/home/wso2apk/devportal/security/truststore/management-server.pem"; +|}; +public type KeyManagerConfigs record {| + string serviceUrl = ""; + string 'type; + string certPath?; + |}; \ No newline at end of file diff --git a/devportal/devportal-domain-service/ballerina/devportal-api_service.bal b/devportal/devportal-domain-service/ballerina/devportal-api_service.bal new file mode 100644 index 000000000..7d8cd796d --- /dev/null +++ b/devportal/devportal-domain-service/ballerina/devportal-api_service.bal @@ -0,0 +1,840 @@ +// +// Copyright (c) 2022, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + +import ballerina/http; +import ballerina/log; +import wso2/apk_common_lib as commons; + +isolated service /api/devportal on ep0 { + # Retrieve/Search APIs + # + # + 'limit - Maximum size of resource array to return. + # + offset - Starting point within the complete list of items qualified. + # + 'x\-wso2\-tenant - For cross-tenant invocations, this is used to specify the tenant/organization domain, where the resource need to be retrieved from. + # + query - You can search in attributes by using an attribute modifier. + # + 'if\-none\-match - Validator for conditional requests; based on the ETag of the formerly retrieved variant of the resource. + # + return - returns can be any of following types + # APIList (OK. List of qualifying APIs is returned.) + # NotAcceptableError (Not Acceptable. The requested media type is not supported.) + isolated resource function get apis(http:RequestContext requestContext, @http:Header string? 'x\-wso2\-tenant, string? query, @http:Header string? 'if\-none\-match, int 'limit = 25, int offset = 0) returns APIList|BadRequestError|InternalServerErrorError|commons:APKError { + commons:UserContext authenticatedUserContext = check commons:getAuthenticatedUserContext(requestContext); + commons:Organization organization = authenticatedUserContext.organization; + APIList apiList = check getAPIList('limit, offset, query, organization); + log:printDebug(apiList.toString()); + return apiList; + } + # Get Details of an API + # + # + apiId - **API ID** consisting of the **UUID** of the API. + # + 'x\-wso2\-tenant - For cross-tenant invocations, this is used to specify the tenant/organization domain, where the resource need to be retrieved from. + # + 'if\-none\-match - Validator for conditional requests; based on the ETag of the formerly retrieved variant of the resource. + # + return - returns can be any of following types + # API (OK. Requested API is returned) + # http:NotModified (Not Modified. Empty body because the client has already the latest version of the requested resource.) + # NotFoundError (Not Found. The specified resource does not exist.) + # NotAcceptableError (Not Acceptable. The requested media type is not supported.) + isolated resource function get apis/[string apiId](@http:Header string? 'x\-wso2\-tenant, @http:Header string? 'if\-none\-match) returns API|http:NotModified|NotFoundError|BadRequestError|InternalServerErrorError|json|commons:APKError { + API|NotFoundError api = check getAPIByAPIId(apiId); + log:printDebug(api.toString()); + return api; + } + # Get the API Definition + # + # + apiId - **API ID** consisting of the **UUID** of the API. + # + 'if\-none\-match - Validator for conditional requests; based on the ETag of the formerly retrieved variant of the resource. + # + return - returns can be any of following types + # APIDefinition (OK. Requested definition document of the API is returned) + # http:NotModified (Not Modified. Empty body because the client has already the latest version of the requested resource.) + # NotFoundError (Not Found. The specified resource does not exist.) + # NotAcceptableError (Not Acceptable. The requested media type is not supported.) + isolated resource function get apis/[string apiId]/definition(@http:Header string? 'if\-none\-match) returns APIDefinition|http:NotModified|NotFoundError|BadRequestError|InternalServerErrorError|commons:APKError { + + APIDefinition|NotFoundError apiDefinition = check getAPIDefinition(apiId); + log:printDebug(apiDefinition.toString()); + return apiDefinition; + } + # Generate a SDK for an API + # + # + apiId - **API ID** consisting of the **UUID** of the API. + # + language - Programming language of the SDK that is required. Languages supported by default are **Java**, **Javascript**, **Android** and **JMeter**. + # + 'x\-wso2\-tenant - For cross-tenant invocations, this is used to specify the tenant/organization domain, where the resource need to be retrieved from. + # + return - returns can be any of following types + # anydata (OK. SDK generated successfully.) + # BadRequestError (Bad Request. Invalid request or validation error.) + # NotFoundError (Not Found. The specified resource does not exist.) + # InternalServerErrorError (Internal Server Error.) + isolated resource function get apis/[string apiId]/sdks/[string language](@http:Header string? 'x\-wso2\-tenant) returns NotFoundError|http:Response|commons:APKError|InternalServerErrorError { + return check generateSDKImpl(apiId, language); + } + # Get a List of Documents of an API + # + # + apiId - **API ID** consisting of the **UUID** of the API. + # + 'limit - Maximum size of resource array to return. + # + offset - Starting point within the complete list of items qualified. + # + 'x\-wso2\-tenant - For cross-tenant invocations, this is used to specify the tenant/organization domain, where the resource need to be retrieved from. + # + 'if\-none\-match - Validator for conditional requests; based on the ETag of the formerly retrieved variant of the resource. + # + return - returns can be any of following types + # DocumentList (OK. Document list is returned.) + # http:NotModified (Not Modified. Empty body because the client has already the latest version of the requested resource.) + # NotFoundError (Not Found. The specified resource does not exist.) + # NotAcceptableError (Not Acceptable. The requested media type is not supported.) + resource function get apis/[string apiId]/documents(@http:Header string? 'x\-wso2\-tenant, @http:Header string? 'if\-none\-match, int 'limit = 25, int offset = 0) returns DocumentList|http:NotModified|NotFoundError|NotAcceptableError|commons:APKError { + return getDocumentList(apiId, 'limit, offset); + } + # Get a Document of an API + # + # + apiId - **API ID** consisting of the **UUID** of the API. + # + documentId - Document Identifier + # + 'x\-wso2\-tenant - For cross-tenant invocations, this is used to specify the tenant/organization domain, where the resource need to be retrieved from. + # + 'if\-none\-match - Validator for conditional requests; based on the ETag of the formerly retrieved variant of the resource. + # + return - returns can be any of following types + # Document (OK. Document returned.) + # http:NotModified (Not Modified. Empty body because the client has already the latest version of the requested resource.) + # NotFoundError (Not Found. The specified resource does not exist.) + # NotAcceptableError (Not Acceptable. The requested media type is not supported.) + resource function get apis/[string apiId]/documents/[string documentId](@http:Header string? 'x\-wso2\-tenant, @http:Header string? 'if\-none\-match) returns Document|http:NotModified|NotFoundError|NotAcceptableError|commons:APKError { + return getDocumentMetaData(apiId, documentId); + } + # Get the Content of an API Document + # + # + apiId - **API ID** consisting of the **UUID** of the API. + # + documentId - Document Identifier + # + 'x\-wso2\-tenant - For cross-tenant invocations, this is used to specify the tenant/organization domain, where the resource need to be retrieved from. + # + 'if\-none\-match - Validator for conditional requests; based on the ETag of the formerly retrieved variant of the resource. + # + return - returns can be any of following types + # http:Ok (OK. File or inline content returned.) + # http:SeeOther (See Other. Source can be retrieved from the URL specified at the Location header.) + # http:NotModified (Not Modified. Empty body because the client has already the latest version of the requested resource.) + # NotFoundError (Not Found. The specified resource does not exist.) + # NotAcceptableError (Not Acceptable. The requested media type is not supported.) + resource function get apis/[string apiId]/documents/[string documentId]/content(@http:Header string? 'x\-wso2\-tenant, @http:Header string? 'if\-none\-match) returns http:Response|http:Ok|http:SeeOther|http:NotModified|NotFoundError|NotAcceptableError|commons:APKError { + return getDocumentContent(apiId, documentId); + } + # Get Thumbnail Image + # + # + apiId - **API ID** consisting of the **UUID** of the API. + # + 'x\-wso2\-tenant - For cross-tenant invocations, this is used to specify the tenant/organization domain, where the resource need to be retrieved from. + # + 'if\-none\-match - Validator for conditional requests; based on the ETag of the formerly retrieved variant of the resource. + # + return - returns can be any of following types + # http:Ok (OK. Thumbnail image returned) + # http:NotModified (Not Modified. Empty body because the client has already the latest version of the requested resource.) + # NotFoundError (Not Found. The specified resource does not exist.) + # NotAcceptableError (Not Acceptable. The requested media type is not supported.) + resource function get apis/[string apiId]/thumbnail(@http:Header string? 'x\-wso2\-tenant, @http:Header string? 'if\-none\-match) returns http:Response|http:NotModified|NotFoundError|NotAcceptableError|commons:APKError { + return getThumbnail(apiId); + } + # Retrieve API Ratings + # + # + apiId - **API ID** consisting of the **UUID** of the API. + # + 'limit - Maximum size of resource array to return. + # + offset - Starting point within the complete list of items qualified. + # + 'x\-wso2\-tenant - For cross-tenant invocations, this is used to specify the tenant/organization domain, where the resource need to be retrieved from. + # + return - returns can be any of following types + # RatingList (OK. Rating list returned.) + # NotAcceptableError (Not Acceptable. The requested media type is not supported.) + // resource function get apis/[string apiId]/ratings(@http:Header string? 'x\-wso2\-tenant, int 'limit = 25, int offset = 0) returns RatingList|NotAcceptableError { + // } + # Retrieve API Rating of User + # + # + apiId - **API ID** consisting of the **UUID** of the API. + # + 'x\-wso2\-tenant - For cross-tenant invocations, this is used to specify the tenant/organization domain, where the resource need to be retrieved from. + # + 'if\-none\-match - Validator for conditional requests; based on the ETag of the formerly retrieved variant of the resource. + # + return - returns can be any of following types + # Rating (OK. Rating returned.) + # http:NotModified (Not Modified. Empty body because the client already has the latest version of the requested resource.) + # NotFoundError (Not Found. The specified resource does not exist.) + # NotAcceptableError (Not Acceptable. The requested media type is not supported.) + // resource function get apis/[string apiId]/'user\-rating(@http:Header string? 'x\-wso2\-tenant, @http:Header string? 'if\-none\-match) returns Rating|http:NotModified|NotFoundError|NotAcceptableError { + // } + # Add or Update Logged in User's Rating for an API + # + # + apiId - **API ID** consisting of the **UUID** of the API. + # + 'x\-wso2\-tenant - For cross-tenant invocations, this is used to specify the tenant/organization domain, where the resource need to be retrieved from. + # + payload - Rating object that should to be added + # + return - returns can be any of following types + # Rating (OK. Successful response with the newly created or updated object as entity in the body.) + # BadRequestError (Bad Request. Invalid request or validation error.) + # UnsupportedMediaTypeError (Unsupported Media Type. The entity of the request was not in a supported format.) + // resource function put apis/[string apiId]/'user\-rating(@http:Header string? 'x\-wso2\-tenant, @http:Payload Rating payload) returns Rating|BadRequestError|UnsupportedMediaTypeError { + // } + # Delete User API Rating + # + # + apiId - **API ID** consisting of the **UUID** of the API. + # + 'x\-wso2\-tenant - For cross-tenant invocations, this is used to specify the tenant/organization domain, where the resource need to be retrieved from. + # + 'if\-match - Validator for conditional requests; based on ETag. + # + return - OK. Resource successfully deleted. + // resource function delete apis/[string apiId]/'user\-rating(@http:Header string? 'x\-wso2\-tenant, @http:Header string? 'if\-match) returns http:Ok { + // } + # Retrieve API Comments + # + # + apiId - **API ID** consisting of the **UUID** of the API. + # + 'x\-wso2\-tenant - For cross-tenant invocations, this is used to specify the tenant/organization domain, where the resource need to be retrieved from. + # + 'limit - Maximum size of resource array to return. + # + offset - Starting point within the complete list of items qualified. + # + includeCommenterInfo - Whether we need to display commenter details. + # + return - returns can be any of following types + # CommentList (OK. Comments list is returned.) + # NotFoundError (Not Found. The specified resource does not exist.) + # InternalServerErrorError (Internal Server Error.) + // resource function get apis/[string apiId]/comments(@http:Header string? 'x\-wso2\-tenant, int 'limit = 25, int offset = 0, boolean includeCommenterInfo = false) returns CommentList|NotFoundError|InternalServerErrorError { + // } + # Add an API Comment + # + # + apiId - **API ID** consisting of the **UUID** of the API. + # + replyTo - ID of the parent comment. + # + payload - Comment object that should to be added + # + return - returns can be any of following types + # Comment (Created. Successful response with the newly created object as entity in the body. Location header contains URL of newly created entity.) + # BadRequestError (Bad Request. Invalid request or validation error.) + # UnauthorizedError (Unauthorized. The user is not authorized.) + # NotFoundError (Not Found. The specified resource does not exist.) + # UnsupportedMediaTypeError (Unsupported Media Type. The entity of the request was not in a supported format.) + # InternalServerErrorError (Internal Server Error.) + // resource function post apis/[string apiId]/comments(string? replyTo, @http:Payload 'postRequestBody payload) returns Comment|BadRequestError|UnauthorizedError|NotFoundError|UnsupportedMediaTypeError|InternalServerErrorError { + // } + # Get Details of an API Comment + # + # + apiId - **API ID** consisting of the **UUID** of the API. + # + commentId - Comment Id + # + 'x\-wso2\-tenant - For cross-tenant invocations, this is used to specify the tenant/organization domain, where the resource need to be retrieved from. + # + 'if\-none\-match - Validator for conditional requests; based on the ETag of the formerly retrieved variant of the resource. + # + includeCommenterInfo - Whether we need to display commenter details. + # + replyLimit - Maximum size of replies array to return. + # + replyOffset - Starting point within the complete list of replies. + # + return - returns can be any of following types + # Comment (OK. Comment returned.) + # UnauthorizedError (Unauthorized. The user is not authorized.) + # NotFoundError (Not Found. The specified resource does not exist.) + # NotAcceptableError (Not Acceptable. The requested media type is not supported.) + # InternalServerErrorError (Internal Server Error.) + // resource function get apis/[string apiId]/comments/[string commentId](@http:Header string? 'x\-wso2\-tenant, @http:Header string? 'if\-none\-match, boolean includeCommenterInfo = false, int replyLimit = 25, int replyOffset = 0) returns Comment|UnauthorizedError|NotFoundError|NotAcceptableError|InternalServerErrorError { + // } + # Delete an API Comment + # + # + apiId - **API ID** consisting of the **UUID** of the API. + # + commentId - Comment Id + # + 'if\-match - Validator for conditional requests; based on ETag. + # + return - returns can be any of following types + # http:Ok (OK. Resource successfully deleted.) + # UnauthorizedError (Unauthorized. The user is not authorized.) + # http:Forbidden (Forbidden. The request must be conditional but no condition has been specified.) + # NotFoundError (Not Found. The specified resource does not exist.) + # http:MethodNotAllowed (MethodNotAllowed. Request method is known by the server but is not supported by the target resource.) + # InternalServerErrorError (Internal Server Error.) + // resource function delete apis/[string apiId]/comments/[string commentId](@http:Header string? 'if\-match) returns http:Ok|UnauthorizedError|http:Forbidden|NotFoundError|http:MethodNotAllowed|InternalServerErrorError { + // } + # Edit a comment + # + # + apiId - **API ID** consisting of the **UUID** of the API. + # + commentId - Comment Id + # + payload - Comment object that should to be updated + # + return - returns can be any of following types + # Comment (OK. Comment updated.) + # BadRequestError (Bad Request. Invalid request or validation error.) + # UnauthorizedError (Unauthorized. The user is not authorized.) + # http:Forbidden (Forbidden. The request must be conditional but no condition has been specified.) + # NotFoundError (Not Found. The specified resource does not exist.) + # UnsupportedMediaTypeError (Unsupported Media Type. The entity of the request was not in a supported format.) + # InternalServerErrorError (Internal Server Error.) + // resource function patch apis/[string apiId]/comments/[string commentId](@http:Payload 'patchRequestBody payload) returns Comment|BadRequestError|UnauthorizedError|http:Forbidden|NotFoundError|UnsupportedMediaTypeError|InternalServerErrorError { + // } + # Get replies of a comment + # + # + apiId - **API ID** consisting of the **UUID** of the API. + # + commentId - Comment Id + # + 'x\-wso2\-tenant - For cross-tenant invocations, this is used to specify the tenant/organization domain, where the resource need to be retrieved from. + # + 'limit - Maximum size of resource array to return. + # + offset - Starting point within the complete list of items qualified. + # + 'if\-none\-match - Validator for conditional requests; based on the ETag of the formerly retrieved variant of the resource. + # + includeCommenterInfo - Whether we need to display commenter details. + # + return - returns can be any of following types + # CommentList (OK. Comment returned.) + # UnauthorizedError (Unauthorized. The user is not authorized.) + # NotFoundError (Not Found. The specified resource does not exist.) + # NotAcceptableError (Not Acceptable. The requested media type is not supported.) + # InternalServerErrorError (Internal Server Error.) + // resource function get apis/[string apiId]/comments/[string commentId]/replies(@http:Header string? 'x\-wso2\-tenant, @http:Header string? 'if\-none\-match, int 'limit = 25, int offset = 0, boolean includeCommenterInfo = false) returns CommentList|UnauthorizedError|NotFoundError|NotAcceptableError|InternalServerErrorError { + // } + # Get a list of available topics for a given Async API + # + # + apiId - **API ID** consisting of the **UUID** of the API. + # + 'x\-wso2\-tenant - For cross-tenant invocations, this is used to specify the tenant/organization domain, where the resource need to be retrieved from. + # + return - returns can be any of following types + # TopicList (OK. Topic list returned.) + # NotFoundError (Not Found. The specified resource does not exist.) + # InternalServerErrorError (Internal Server Error.) + // resource function get apis/[string apiId]/topics(@http:Header string? 'x\-wso2\-tenant) returns TopicList|NotFoundError|InternalServerErrorError { + // } + # Get Details of the Subscription Throttling Policies of an API + # + # + apiId - **API ID** consisting of the **UUID** of the API. + # + 'x\-wso2\-tenant - For cross-tenant invocations, this is used to specify the tenant/organization domain, where the resource need to be retrieved from. + # + 'if\-none\-match - Validator for conditional requests; based on the ETag of the formerly retrieved variant of the resource. + # + return - returns can be any of following types + # ThrottlingPolicy (OK. Throttling Policy returned) + # http:NotModified (Not Modified. Empty body because the client has already the latest version of the requested resource.) + # NotFoundError (Not Found. The specified resource does not exist.) + # NotAcceptableError (Not Acceptable. The requested media type is not supported.) + // resource function get apis/[string apiId]/'subscription\-policies(@http:Header string? 'x\-wso2\-tenant, @http:Header string? 'if\-none\-match) returns ThrottlingPolicy|http:NotModified|NotFoundError|NotAcceptableError { + // } + # Retrieve/Search Applications + # + # + groupId - Application Group Id + # + query - You can search for an application by specifying the name as "query" attribute. + # + sortBy - parameter description + # + sortOrder - parameter description + # + 'limit - Maximum size of resource array to return. + # + offset - Starting point within the complete list of items qualified. + # + 'if\-none\-match - Validator for conditional requests; based on the ETag of the formerly retrieved variant of the resource. + # + return - returns can be any of following types + # ApplicationList (OK. Application list returned.) + # http:NotModified (Not Modified. Empty body because the client has already the latest version of the requested resource.) + # BadRequestError (Bad Request. Invalid request or validation error.) + # NotAcceptableError (Not Acceptable. The requested media type is not supported.) + isolated resource function get applications(http:RequestContext requestContext, string? groupId, string? query, string? sortBy, string? sortOrder, @http:Header string? 'if\-none\-match, int 'limit = 25, int offset = 0) returns ApplicationList|http:NotModified|BadRequestError|NotAcceptableError|InternalServerErrorError|commons:APKError { + commons:UserContext authenticatedUserContext = check commons:getAuthenticatedUserContext(requestContext); + commons:Organization organization = authenticatedUserContext.organization; + ApplicationList applicationList = check getApplicationList(sortBy, groupId, query, sortOrder, 'limit, offset, organization); + log:printDebug(applicationList.toString()); + return applicationList; + } + # Create a New Application + # + # + payload - Application object that is to be created. + # + return - returns can be any of following types + # Application (Created. Successful response with the newly created object as entity in the body. Location header contains URL of newly created entity.) + # AcceptedWorkflowResponse (Accepted. The request has been accepted.) + # BadRequestError (Bad Request. Invalid request or validation error.) + # ConflictError (Conflict. Specified resource already exists.) + # UnsupportedMediaTypeError (Unsupported Media Type. The entity of the request was not in a supported format.) + isolated resource function post applications(http:RequestContext requestContext, @http:Payload Application payload) returns Application|AcceptedWorkflowResponse|BadRequestError|ConflictError|NotFoundError|InternalServerErrorError|commons:APKError { + commons:UserContext authenticatedUserContext = check commons:getAuthenticatedUserContext(requestContext); + commons:Organization organization = authenticatedUserContext.organization; + return check addApplication(payload, organization, authenticatedUserContext.userId); + } + # Get Details of an Application + # + # + applicationId - Application Identifier consisting of the UUID of the Application. + # + 'if\-none\-match - Validator for conditional requests; based on the ETag of the formerly retrieved variant of the resource. + # + 'x\-wso2\-tenant - For cross-tenant invocations, this is used to specify the tenant/organization domain, where the resource need to be retrieved from. + # + return - returns can be any of following types + # Application (OK. Application returned.) + # http:NotModified (Not Modified. Empty body because the client has already the latest version of the requested resource.) + # NotFoundError (Not Found. The specified resource does not exist.) + # NotAcceptableError (Not Acceptable. The requested media type is not supported.) + isolated resource function get applications/[string applicationId](http:RequestContext requestContext, @http:Header string? 'if\-none\-match, @http:Header string? 'x\-wso2\-tenant) returns Application|http:NotModified|NotFoundError|BadRequestError|InternalServerErrorError|commons:APKError { + commons:UserContext authenticatedUserContext = check commons:getAuthenticatedUserContext(requestContext); + commons:Organization organization = authenticatedUserContext.organization; + return getApplicationById(applicationId, organization); + } + # Update an Application + # + # + applicationId - Application Identifier consisting of the UUID of the Application. + # + 'if\-match - Validator for conditional requests; based on ETag. + # + payload - Application object that needs to be updated + # + return - returns can be any of following types + # Application (OK. Application updated.) + # BadRequestError (Bad Request. Invalid request or validation error.) + # NotFoundError (Not Found. The specified resource does not exist.) + # PreconditionFailedError (Precondition Failed. The request has not been performed because one of the preconditions is not met.) + isolated resource function put applications/[string applicationId](http:RequestContext requestContext, @http:Header string? 'if\-match, @http:Payload Application payload) returns Application|BadRequestError|NotFoundError|PreconditionFailedError|InternalServerErrorError|commons:APKError { + commons:UserContext authenticatedUserContext = check commons:getAuthenticatedUserContext(requestContext); + commons:Organization organization = authenticatedUserContext.organization; + Application|NotFoundError application = check updateApplication(applicationId, payload, organization, authenticatedUserContext.userId); + if application is Application|NotFoundError { + log:printDebug(application.toString()); + return application; + } + } + # Remove an Application + # + # + applicationId - Application Identifier consisting of the UUID of the Application. + # + 'if\-match - Validator for conditional requests; based on ETag. + # + return - returns can be any of following types + # http:Ok (OK. Resource successfully deleted.) + # AcceptedWorkflowResponse (Accepted. The request has been accepted.) + # NotFoundError (Not Found. The specified resource does not exist.) + # PreconditionFailedError (Precondition Failed. The request has not been performed because one of the preconditions is not met.) + isolated resource function delete applications/[string applicationId](http:RequestContext requestContext, @http:Header string? 'if\-match) returns http:Ok|AcceptedWorkflowResponse|NotFoundError|BadRequestError|PreconditionFailedError|InternalServerErrorError|commons:APKError { + commons:UserContext authenticatedUserContext = check commons:getAuthenticatedUserContext(requestContext); + commons:Organization organization = authenticatedUserContext.organization; + _ = check deleteApplication(applicationId, organization); + return http:OK; + } + + # Generate Application Keys + # + # + applicationId - Application Identifier consisting of the UUID of the Application. + # + 'x\-wso2\-tenant - For cross-tenant invocations, this is used to specify the tenant/organization domain, where the resource need to be retrieved from. + # + payload - Application key generation request object + # + return - returns can be any of following types + # OkApplicationKey (OK. Keys are generated.) + # BadRequestError (Bad Request. Invalid request or validation error.) + # NotFoundError (Not Found. The specified resource does not exist.) + # PreconditionFailedError (Precondition Failed. The request has not been performed because one of the preconditions is not met.) + isolated resource function post applications/[string applicationId]/'generate\-keys(@http:Header string? 'x\-wso2\-tenant, @http:Payload ApplicationKeyGenerateRequest payload, http:RequestContext requestContext) returns OkApplicationKey|BadRequestError|NotFoundError|PreconditionFailedError|commons:APKError { + commons:UserContext authenticatedUserContext = check commons:getAuthenticatedUserContext(requestContext); + commons:Organization organization = authenticatedUserContext.organization; + Application|NotFoundError applicationById = check getApplicationById(applicationId, organization); + if applicationById is NotFoundError { + return applicationById; + } + return check generateKeysForApplication(applicationById, payload, organization); + } + # Map Application Keys + # + # + applicationId - Application Identifier consisting of the UUID of the Application. + # + 'x\-wso2\-tenant - For cross-tenant invocations, this is used to specify the tenant/organization domain, where the resource need to be retrieved from. + # + payload - Application key mapping request object + # + return - returns can be any of following types + # OkApplicationKey (OK. Keys are mapped.) + # BadRequestError (Bad Request. Invalid request or validation error.) + # NotFoundError (Not Found. The specified resource does not exist.) + # PreconditionFailedError (Precondition Failed. The request has not been performed because one of the preconditions is not met.) + resource function post applications/[string applicationId]/'map\-keys(@http:Header string? 'x\-wso2\-tenant, @http:Payload ApplicationKeyMappingRequest payload, http:RequestContext requestContext) returns OkApplicationKey|BadRequestError|NotFoundError|PreconditionFailedError|commons:APKError { + commons:UserContext authenticatedUserContext = check commons:getAuthenticatedUserContext(requestContext); + commons:Organization organization = authenticatedUserContext.organization; + Application|NotFoundError applicationById = check getApplicationById(applicationId, organization); + if applicationById is NotFoundError { + return applicationById; + } + return check mapKeys(applicationById, payload, organization); + } + # Retrieve All Application Keys + # + # + applicationId - Application Identifier consisting of the UUID of the Application. + # + 'x\-wso2\-tenant - For cross-tenant invocations, this is used to specify the tenant/organization domain, where the resource need to be retrieved from. + # + return - returns can be any of following types + # ApplicationKeyList (OK. Keys are returned.) + # BadRequestError (Bad Request. Invalid request or validation error.) + # NotFoundError (Not Found. The specified resource does not exist.) + # PreconditionFailedError (Precondition Failed. The request has not been performed because one of the preconditions is not met.) + resource function get applications/[string applicationId]/'oauth\-keys(@http:Header string? 'x\-wso2\-tenant, http:RequestContext requestContext) returns ApplicationKeyList|BadRequestError|NotFoundError|PreconditionFailedError|commons:APKError { + commons:UserContext authenticatedUserContext = check commons:getAuthenticatedUserContext(requestContext); + commons:Organization organization = authenticatedUserContext.organization; + Application|NotFoundError applicationById = check getApplicationById(applicationId, organization); + if applicationById is NotFoundError { + return applicationById; + } + + return check oauthKeys(applicationById, organization); + } + # Get Key Details of a Given Type + # + # + applicationId - Application Identifier consisting of the UUID of the Application. + # + keyMappingId - OAuth Key Identifier consisting of the UUID of the Oauth Key Mapping. + # + return - returns can be any of following types + # ApplicationKey (OK. Keys of given type are returned.) + # BadRequestError (Bad Request. Invalid request or validation error.) + # NotFoundError (Not Found. The specified resource does not exist.) + # PreconditionFailedError (Precondition Failed. The request has not been performed because one of the preconditions is not met.) + isolated resource function get applications/[string applicationId]/'oauth\-keys/[string keyMappingId](http:RequestContext requestContext) returns ApplicationKey|BadRequestError|NotFoundError|PreconditionFailedError|commons:APKError { + commons:UserContext authenticatedUserContext = check commons:getAuthenticatedUserContext(requestContext); + commons:Organization organization = authenticatedUserContext.organization; + Application|NotFoundError applicationById = check getApplicationById(applicationId, organization); + if applicationById is NotFoundError { + return applicationById; + } + return check oauthKeyByMappingId(applicationById, keyMappingId, organization); + } + # Update Grant Types and Callback URL of an Application + # + # + applicationId - Application Identifier consisting of the UUID of the Application. + # + keyMappingId - OAuth Key Identifier consisting of the UUID of the Oauth Key Mapping. + # + payload - Grant types/Callback URL update request object + # + return - returns can be any of following types + # ApplicationKey (Ok. Grant types or/and callback url is/are updated.) + # BadRequestError (Bad Request. Invalid request or validation error.) + # NotFoundError (Not Found. The specified resource does not exist.) + # PreconditionFailedError (Precondition Failed. The request has not been performed because one of the preconditions is not met.) + isolated resource function put applications/[string applicationId]/'oauth\-keys/[string keyMappingId](@http:Payload ApplicationKey payload,http:RequestContext requestContext) returns ApplicationKey|BadRequestError|NotFoundError|PreconditionFailedError|commons:APKError { + commons:UserContext authenticatedUserContext = check commons:getAuthenticatedUserContext(requestContext); + commons:Organization organization = authenticatedUserContext.organization; + Application|NotFoundError applicationById = check getApplicationById(applicationId, organization); + if applicationById is NotFoundError { + return applicationById; + } + return check updateOauthApp(applicationById,keyMappingId,payload,organization); + } + # Re-Generate Consumer Secret + # + # + applicationId - Application Identifier consisting of the UUID of the Application. + # + keyMappingId - OAuth Key Identifier consisting of the UUID of the Oauth Key Mapping. + # + return - returns can be any of following types + # OkApplicationKeyReGenerateResponse (OK. Keys are re generated.) + # BadRequestError (Bad Request. Invalid request or validation error.) + # NotFoundError (Not Found. The specified resource does not exist.) + # PreconditionFailedError (Precondition Failed. The request has not been performed because one of the preconditions is not met.) + // resource function post applications/[string applicationId]/'oauth\-keys/[string keyMappingId]/'regenerate\-secret() returns OkApplicationKeyReGenerateResponse|BadRequestError|NotFoundError|PreconditionFailedError { + // } + # Clean-Up Application Keys + # + # + applicationId - Application Identifier consisting of the UUID of the Application. + # + keyMappingId - OAuth Key Identifier consisting of the UUID of the Oauth Key Mapping. + # + 'if\-match - Validator for conditional requests; based on ETag. + # + return - returns can be any of following types + # http:Ok (OK. Clean up is performed) + # BadRequestError (Bad Request. Invalid request or validation error.) + # NotFoundError (Not Found. The specified resource does not exist.) + # PreconditionFailedError (Precondition Failed. The request has not been performed because one of the preconditions is not met.) + // resource function post applications/[string applicationId]/'oauth\-keys/[string keyMappingId]/'clean\-up(@http:Header string? 'if\-match) returns http:Ok|BadRequestError|NotFoundError|PreconditionFailedError { + // } + # Generate Application Token + # + # + applicationId - Application Identifier consisting of the UUID of the Application. + # + keyMappingId - OAuth Key Identifier consisting of the UUID of the Oauth Key Mapping. + # + 'if\-match - Validator for conditional requests; based on ETag. + # + payload - Application token generation request object + # + return - returns can be any of following types + # OkApplicationToken (OK. Token is generated.) + # BadRequestError (Bad Request. Invalid request or validation error.) + # NotFoundError (Not Found. The specified resource does not exist.) + # PreconditionFailedError (Precondition Failed. The request has not been performed because one of the preconditions is not met.) + isolated resource function post applications/[string applicationId]/'oauth\-keys/[string keyMappingId]/'generate\-token(@http:Header string? 'if\-match, @http:Payload ApplicationTokenGenerateRequest payload, http:RequestContext requestContext) returns OkApplicationToken|BadRequestError|NotFoundError|PreconditionFailedError|commons:APKError { + commons:UserContext authenticatedUserContext = check commons:getAuthenticatedUserContext(requestContext); + commons:Organization organization = authenticatedUserContext.organization; + Application|NotFoundError applicationById = check getApplicationById(applicationId, organization); + if applicationById is NotFoundError { + return applicationById; + } + return generateApplicationToken(applicationById, keyMappingId, payload, organization); + } + # Generate API Key + # + # + applicationId - Application Identifier consisting of the UUID of the Application. + # + keyType - **Application Key Type** standing for the type of the keys (i.e. Production or Sandbox). + # + 'if\-match - Validator for conditional requests; based on ETag. + # + payload - API Key generation request object + # + return - returns can be any of following types + # OkAPIKey (OK. apikey generated.) + # BadRequestError (Bad Request. Invalid request or validation error.) + # NotFoundError (Not Found. The specified resource does not exist.) + # PreconditionFailedError (Precondition Failed. The request has not been performed because one of the preconditions is not met.) + isolated resource function post applications/[string applicationId]/'api\-keys/[string keyType]/generate(http:RequestContext requestContext, @http:Header string? 'if\-match, @http:Payload APIKeyGenerateRequest payload) returns APIKey|BadRequestError|NotFoundError|PreconditionFailedError|InternalServerErrorError|commons:APKError { + commons:UserContext authenticatedUserContext = check commons:getAuthenticatedUserContext(requestContext); + commons:Organization organization = authenticatedUserContext.organization; + APIKey|NotFoundError apiKey = check generateAPIKey(payload, applicationId, keyType, authenticatedUserContext.userId, organization); + return apiKey; + } + # Revoke API Key + # + # + applicationId - Application Identifier consisting of the UUID of the Application. + # + keyType - **Application Key Type** standing for the type of the keys (i.e. Production or Sandbox). + # + 'if\-match - Validator for conditional requests; based on ETag. + # + payload - API Key revoke request object + # + return - returns can be any of following types + # http:Ok (OK. apikey revoked successfully.) + # BadRequestError (Bad Request. Invalid request or validation error.) + # PreconditionFailedError (Precondition Failed. The request has not been performed because one of the preconditions is not met.) + // resource function post applications/[string applicationId]/'api\-keys/[string keyType]/revoke(@http:Header string? 'if\-match, @http:Payload APIKeyRevokeRequest payload) returns http:Ok|BadRequestError|PreconditionFailedError { + // } + # Export an Application + # + # + appName - Application Name + # + appOwner - Owner of the Application + # + withKeys - Export application keys + # + format - Format of output documents. Can be YAML or JSON. + # + return - returns can be any of following types + # anydata (OK. Export Successful.) + # BadRequestError (Bad Request. Invalid request or validation error.) + # NotFoundError (Not Found. The specified resource does not exist.) + # NotAcceptableError (Not Acceptable. The requested media type is not supported.) + // resource function get applications/export(string appName, string appOwner, boolean? withKeys, string? format) returns anydata { + // } + # Import an Application + # + # + preserveOwner - Preserve Original Creator of the Application + # + skipSubscriptions - Skip importing Subscriptions of the Application + # + appOwner - Expected Owner of the Application in the Import Environment + # + skipApplicationKeys - Skip importing Keys of the Application + # + update - Update if application exists + # + request - parameter description + # + return - returns can be any of following types + # OkApplicationInfo (OK. Successful response with the updated object information as entity in the body.) + # BadRequestError (Bad Request. Invalid request or validation error.) + # NotAcceptableError (Not Acceptable. The requested media type is not supported.) + // resource function post applications/'import(boolean? preserveOwner, boolean? skipSubscriptions, string? appOwner, boolean? skipApplicationKeys, boolean? update, http:Request request) returns OkApplicationInfo|BadRequestError|NotAcceptableError { + // } + # Get All Subscriptions + # + # + apiId - **API ID** consisting of the **UUID** of the API. + # + applicationId - **Application Identifier** consisting of the UUID of the Application. + # + groupId - Application Group Id + # + 'x\-wso2\-tenant - For cross-tenant invocations, this is used to specify the tenant/organization domain, where the resource need to be retrieved from. + # + offset - Starting point within the complete list of items qualified. + # + 'limit - Maximum size of resource array to return. + # + 'if\-none\-match - Validator for conditional requests; based on the ETag of the formerly retrieved variant of the resource. + # + return - returns can be any of following types + # SubscriptionList (OK. Subscription list returned.) + # http:NotModified (Not Modified. Empty body because the client has already the latest version of the requested resource.) + # NotAcceptableError (Not Acceptable. The requested media type is not supported.) + isolated resource function get subscriptions(http:RequestContext requestContext, string? apiId, string? applicationId, string? groupId, @http:Header string? 'x\-wso2\-tenant, @http:Header string? 'if\-none\-match, int offset = 0, int 'limit = 25) returns SubscriptionList|http:NotModified|NotFoundError|BadRequestError|InternalServerErrorError|commons:APKError { + commons:UserContext authenticatedUserContext = check commons:getAuthenticatedUserContext(requestContext); + commons:Organization organization = authenticatedUserContext.organization; + SubscriptionList|NotFoundError subscriptionList = check getSubscriptions(apiId, applicationId, groupId, offset, 'limit, organization); + log:printDebug(subscriptionList.toString()); + return subscriptionList; + } + # Add a New Subscription + # + # + 'x\-wso2\-tenant - For cross-tenant invocations, this is used to specify the tenant/organization domain, where the resource need to be retrieved from. + # + payload - Subscription object that should to be added + # + return - returns can be any of following types + # Subscription (Created. Successful response with the newly created object as entity in the body. Location header contains URL of newly created entity.) + # AcceptedWorkflowResponse (Accepted. The request has been accepted.) + # BadRequestError (Bad Request. Invalid request or validation error.) + # UnsupportedMediaTypeError (Unsupported Media Type. The entity of the request was not in a supported format.) + isolated resource function post subscriptions(http:RequestContext requestContext, @http:Header string? 'x\-wso2\-tenant, @http:Payload Subscription payload) returns Subscription|AcceptedWorkflowResponse|BadRequestError|NotFoundError|InternalServerErrorError|json|commons:APKError { + commons:UserContext authenticatedUserContext = check commons:getAuthenticatedUserContext(requestContext); + commons:Organization organization = authenticatedUserContext.organization; + return check addSubscription(payload, organization, authenticatedUserContext.userId); + } + # Add New Subscriptions + # + # + 'x\-wso2\-tenant - For cross-tenant invocations, this is used to specify the tenant/organization domain, where the resource need to be retrieved from. + # + payload - Subscription objects that should to be added + # + return - returns can be any of following types + # OkSubscription (OK. Successful response with the newly created objects as entity in the body.) + # BadRequestError (Bad Request. Invalid request or validation error.) + # UnsupportedMediaTypeError (Unsupported Media Type. The entity of the request was not in a supported format.) + isolated resource function post subscriptions/multiple(http:RequestContext requestContext, @http:Header string? 'x\-wso2\-tenant, @http:Payload Subscription[] payload) returns Subscription[]|BadRequestError|UnsupportedMediaTypeError|NotFoundError|InternalServerErrorError|commons:APKError { + commons:UserContext authenticatedUserContext = check commons:getAuthenticatedUserContext(requestContext); + commons:Organization organization = authenticatedUserContext.organization; + Subscription[]|NotFoundError subscriptions = check addMultipleSubscriptions(payload, organization, authenticatedUserContext.userId); + log:printDebug(subscriptions.toString()); + return subscriptions; + } + # Get Additional Information of subscriptions attached to an API. + # + # + apiId - **API ID** consisting of the **UUID** of the API. + # + groupId - Application Group Id + # + 'x\-wso2\-tenant - For cross-tenant invocations, this is used to specify the tenant/organization domain, where the resource need to be retrieved from. + # + offset - Starting point within the complete list of items qualified. + # + 'limit - Maximum size of resource array to return. + # + 'if\-none\-match - Validator for conditional requests; based on the ETag of the formerly retrieved variant of the resource. + # + return - returns can be any of following types + # AdditionalSubscriptionInfoList (OK. Types and fields returned successfully.) + # http:NotFound (Not Found. Retrieving types and fields failed.) + // resource function get subscriptions/[string apiId]/additionalInfo(string? groupId, @http:Header string? 'x\-wso2\-tenant, @http:Header string? 'if\-none\-match, int offset = 0, int 'limit = 25) returns AdditionalSubscriptionInfoList|http:NotFound { + // } + # Get Details of a Subscription + # + # + subscriptionId - Subscription Id + # + 'if\-none\-match - Validator for conditional requests; based on the ETag of the formerly retrieved variant of the resource. + # + return - returns can be any of following types + # Subscription (OK. Subscription returned) + # http:NotModified (Not Modified. Empty body because the client has already the latest version of the requested resource.) + # NotFoundError (Not Found. The specified resource does not exist.) + isolated resource function get subscriptions/[string subscriptionId](http:RequestContext requestContext, @http:Header string? 'if\-none\-match) returns Subscription|http:NotModified|NotFoundError|BadRequestError|InternalServerErrorError|commons:APKError { + commons:UserContext authenticatedUserContext = check commons:getAuthenticatedUserContext(requestContext); + commons:Organization organization = authenticatedUserContext.organization; + Subscription|NotFoundError subscription = check getSubscriptionById(subscriptionId, organization); + log:printDebug(subscription.toString()); + return subscription; + } + # Update Existing Subscription + # + # + subscriptionId - Subscription Id + # + 'x\-wso2\-tenant - For cross-tenant invocations, this is used to specify the tenant/organization domain, where the resource need to be retrieved from. + # + payload - Subscription object that should to be added + # + return - returns can be any of following types + # Subscription (Subscription Updated. Successful response with the updated object as entity in the body. Location header contains URL of newly updates entity.) + # AcceptedWorkflowResponse (Accepted. The request has been accepted.) + # http:NotModified (Not Modified. Empty body because the client has already the latest version of the requested resource.) + # BadRequestError (Bad Request. Invalid request or validation error.) + # http:NotFound (Not Found. Requested Subscription does not exist.) + # http:UnsupportedMediaType (Unsupported media type. The entity of the request was in a not supported format.) + isolated resource function put subscriptions/[string subscriptionId](http:RequestContext requestContext, @http:Header string? 'x\-wso2\-tenant, @http:Payload Subscription payload) returns Subscription|AcceptedWorkflowResponse|http:NotModified|BadRequestError|NotFoundError|http:UnsupportedMediaType|InternalServerErrorError|json|commons:APKError { + commons:UserContext authenticatedUserContext = check commons:getAuthenticatedUserContext(requestContext); + commons:Organization organization = authenticatedUserContext.organization; + Subscription|NotFoundError subscription = check updateSubscription(subscriptionId, payload, organization, authenticatedUserContext.userId); + log:printDebug(subscription.toString()); + return subscription; + } + # Remove a Subscription + # + # + subscriptionId - Subscription Id + # + 'if\-match - Validator for conditional requests; based on ETag. + # + return - returns can be any of following types + # http:Ok (OK. Resource successfully deleted.) + # AcceptedWorkflowResponse (Accepted. The request has been accepted.) + # NotFoundError (Not Found. The specified resource does not exist.) + # PreconditionFailedError (Precondition Failed. The request has not been performed because one of the preconditions is not met.) + isolated resource function delete subscriptions/[string subscriptionId](http:RequestContext requestContext, @http:Header string? 'if\-match) returns http:Ok|AcceptedWorkflowResponse|NotFoundError|PreconditionFailedError|BadRequestError|InternalServerErrorError|commons:APKError { + commons:UserContext authenticatedUserContext = check commons:getAuthenticatedUserContext(requestContext); + commons:Organization organization = authenticatedUserContext.organization; + check deleteSubscription(subscriptionId, organization); + return http:OK; + } + # Get Details of a Pending Invoice for a Monetized Subscription with Metered Billing. + # + # + subscriptionId - Subscription Id + # + return - returns can be any of following types + # APIMonetizationUsage (OK. Details of a pending invoice returned.) + # http:NotModified (Not Modified. Empty body because the client has already the latest version of the requested resource (Will be supported in future).) + # NotFoundError (Not Found. The specified resource does not exist.) + // resource function get subscriptions/[string subscriptionId]/usage() returns APIMonetizationUsage|http:NotModified|NotFoundError { + // } + # Get All Available Throttling Policies + # + # + policyLevel - List Application or Subscription type thro. + # + 'limit - Maximum size of resource array to return. + # + offset - Starting point within the complete list of items qualified. + # + 'if\-none\-match - Validator for conditional requests; based on the ETag of the formerly retrieved variant of the resource. + # + 'x\-wso2\-tenant - For cross-tenant invocations, this is used to specify the tenant/organization domain, where the resource need to be retrieved from. + # + return - returns can be any of following types + # ThrottlingPolicyList (OK. List of throttling policies returned.) + # http:NotModified (Not Modified. Empty body because the client has already the latest version of the requested resource.) + # NotAcceptableError (Not Acceptable. The requested media type is not supported.) + // resource function get 'throttling\-policies/[string policyLevel](@http:Header string? 'if\-none\-match, @http:Header string? 'x\-wso2\-tenant, int 'limit = 25, int offset = 0) returns ThrottlingPolicyList|http:NotModified|NotAcceptableError { + // } + # Get Details of a Throttling Policy + # + # + policyLevel - List Application or Subscription type thro. + # + policyId - The name of the policy + # + 'x\-wso2\-tenant - For cross-tenant invocations, this is used to specify the tenant/organization domain, where the resource need to be retrieved from. + # + 'if\-none\-match - Validator for conditional requests; based on the ETag of the formerly retrieved variant of the resource. + # + return - returns can be any of following types + # ThrottlingPolicy (OK. Throttling Policy returned) + # http:NotModified (Not Modified. Empty body because the client has already the latest version of the requested resource.) + # NotFoundError (Not Found. The specified resource does not exist.) + # NotAcceptableError (Not Acceptable. The requested media type is not supported.) + // resource function get 'throttling\-policies/[string policyLevel]/[string policyId](@http:Header string? 'x\-wso2\-tenant, @http:Header string? 'if\-none\-match) returns ThrottlingPolicy|http:NotModified|NotFoundError|NotAcceptableError { + // } + # Get All Tags + # + # + 'limit - Maximum size of resource array to return. + # + offset - Starting point within the complete list of items qualified. + # + 'x\-wso2\-tenant - For cross-tenant invocations, this is used to specify the tenant/organization domain, where the resource need to be retrieved from. + # + 'if\-none\-match - Validator for conditional requests; based on the ETag of the formerly retrieved variant of the resource. + # + return - returns can be any of following types + # TagList (OK. Tag list is returned.) + # http:NotModified (Not Modified. Empty body because the client has already the latest version of the requested resource.) + # NotFoundError (Not Found. The specified resource does not exist.) + # NotAcceptableError (Not Acceptable. The requested media type is not supported.) + // resource function get tags(@http:Header string? 'x\-wso2\-tenant, @http:Header string? 'if\-none\-match, int 'limit = 25, int offset = 0) returns TagList|http:NotModified|NotFoundError|NotAcceptableError { + // } + # Retrieve/Search APIs and API Documents by Content + # + # + 'limit - Maximum size of resource array to return. + # + offset - Starting point within the complete list of items qualified. + # + 'x\-wso2\-tenant - For cross-tenant invocations, this is used to specify the tenant/organization domain, where the resource need to be retrieved from. + # + query - You can search by using providing the search term in the query parameters. + # + 'if\-none\-match - Validator for conditional requests; based on the ETag of the formerly retrieved variant of the resource. + # + return - returns can be any of following types + # SearchResultList (OK. List of qualifying APIs and docs is returned.) + # http:NotModified (Not Modified. Empty body because the client has already the latest version of the requested resource (Will be supported in future).) + # NotAcceptableError (Not Acceptable. The requested media type is not supported.) + // resource function get search(@http:Header string? 'x\-wso2\-tenant, string? query, @http:Header string? 'if\-none\-match, int 'limit = 25, int offset = 0) returns SearchResultList|http:NotModified|NotAcceptableError { + // } + # Get a List of Supported SDK Languages + # + # + return - returns can be any of following types + # json (OK. List of supported languages for generating SDKs.) + # NotFoundError (Not Found. The specified resource does not exist.) + # InternalServerErrorError (Internal Server Error.) + isolated resource function get 'sdk\-gen/languages() returns json|NotFoundError|InternalServerErrorError|BadRequestError|commons:APKError { + string|json sdkLanguages = check getSDKLanguages(); + return sdkLanguages; + } + # Get available web hook subscriptions for a given application. + # + # + applicationId - **Application Identifier** consisting of the UUID of the Application. + # + apiId - **API ID** consisting of the **UUID** of the API. + # + 'x\-wso2\-tenant - For cross-tenant invocations, this is used to specify the tenant/organization domain, where the resource need to be retrieved from. + # + return - returns can be any of following types + # WebhookSubscriptionList (OK. Topic list returned.) + # NotFoundError (Not Found. The specified resource does not exist.) + # InternalServerErrorError (Internal Server Error.) + // resource function get webhooks/subscriptions(string? applicationId, string? apiId, @http:Header string? 'x\-wso2\-tenant) returns WebhookSubscriptionList|NotFoundError|InternalServerErrorError { + // } + # Retrieve Developer Portal settings + # + # + 'x\-wso2\-tenant - For cross-tenant invocations, this is used to specify the tenant/organization domain, where the resource need to be retrieved from. + # + return - returns can be any of following types + # Settings (OK. Settings returned) + # NotFoundError (Not Found. The specified resource does not exist.) + // resource function get settings(@http:Header string? 'x\-wso2\-tenant) returns Settings|NotFoundError { + // } + # Get All Application Attributes from Configuration + # + # + 'if\-none\-match - Validator for conditional requests; based on the ETag of the formerly retrieved variant of the resource. + # + return - returns can be any of following types + # ApplicationAttributeList (OK. Application attributes returned.) + # NotFoundError (Not Found. The specified resource does not exist.) + # NotAcceptableError (Not Acceptable. The requested media type is not supported.) + // resource function get settings/'application\-attributes(@http:Header string? 'if\-none\-match) returns ApplicationAttributeList|NotFoundError|NotAcceptableError { + // } + # Get Tenants by State + # + # + state - The state represents the current state of the tenant + # + 'limit - Maximum size of resource array to return. + # + offset - Starting point within the complete list of items qualified. + # + return - returns can be any of following types + # TenantList (OK. Tenant names returned.) + # NotFoundError (Not Found. The specified resource does not exist.) + # NotAcceptableError (Not Acceptable. The requested media type is not supported.) + // resource function get tenants(string state = "active", int 'limit = 25, int offset = 0) returns TenantList|NotFoundError|NotAcceptableError { + // } + # Give API Recommendations for a User + # + # + return - returns can be any of following types + # Recommendations (OK. Requested recommendations are returned) + # NotFoundError (Not Found. The specified resource does not exist.) + // resource function get recommendations() returns Recommendations|NotFoundError { + // } + # Get All API Categories + # + # + 'x\-wso2\-tenant - For cross-tenant invocations, this is used to specify the tenant/organization domain, where the resource need to be retrieved from. + # + return - OK. Categories returned + // resource function get 'api\-categories(@http:Header string? 'x\-wso2\-tenant) returns APICategoryList { + // } + # Get All Key Managers + # + # + 'x\-wso2\-tenant - For cross-tenant invocations, this is used to specify the tenant/organization domain, where the resource need to be retrieved from. + # + return - OK. Key Manager list returned + // resource function get 'key\-managers(@http:Header string? 'x\-wso2\-tenant) returns KeyManagerList { + // } + # Get the Complexity Related Details of an API + # + # + apiId - **API ID** consisting of the **UUID** of the API. + # + return - returns can be any of following types + # GraphQLQueryComplexityInfo (OK. Requested complexity details returned.) + # http:NotFound (Not Found. Requested API does not contain any complexity details.) + // resource function get apis/[string apiId]/'graphql\-policies/complexity() returns GraphQLQueryComplexityInfo|http:NotFound { + // } + # Retrieve Types and Fields of a GraphQL Schema + # + # + apiId - **API ID** consisting of the **UUID** of the API. + # + return - returns can be any of following types + # GraphQLSchemaTypeList (OK. Types and fields returned successfully.) + # http:NotFound (Not Found. Retrieving types and fields failed.) + // resource function get apis/[string apiId]/'graphql\-policies/complexity/types() returns GraphQLSchemaTypeList|http:NotFound { + // } + # Change the Password of the user + # + # + payload - Current and new password of the user + # + return - returns can be any of following types + # http:Ok (OK. User password changed successfully) + # BadRequestError (Bad Request. Invalid request or validation error.) + isolated resource function post me/'change\-password(@http:Payload CurrentAndNewPasswords payload) returns http:Ok|BadRequestError { + BadRequestError badRequest = {body: {code: 400, message: "Invalid request or validation error."}}; + return badRequest; + } + +} diff --git a/devportal/devportal-domain-service/ballerina/health_service.bal b/devportal/devportal-domain-service/ballerina/health_service.bal new file mode 100644 index 000000000..3f709738f --- /dev/null +++ b/devportal/devportal-domain-service/ballerina/health_service.bal @@ -0,0 +1,25 @@ +// +// Copyright (c) 2022, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// +import ballerina/http; + +service / on ep0 { + resource function get health() returns http:Ok { + json status = {"health": "Ok"}; + return {body: status}; + } +} diff --git a/devportal/devportal-domain-service/ballerina/init.bal b/devportal/devportal-domain-service/ballerina/init.bal new file mode 100644 index 000000000..770629f1f --- /dev/null +++ b/devportal/devportal-domain-service/ballerina/init.bal @@ -0,0 +1,76 @@ +// +// Copyright (c) 2022, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + +import ballerina/log; +import ballerinax/postgresql; +import ballerina/sql; +import ballerina/http; +import wso2/apk_keymanager_libs; +import wso2/apk_common_lib as commons; + +configurable commons:DatasourceConfiguration datasourceConfiguration = ?; +configurable ThrottlingConfiguration throttleConfig = ?; +configurable TokenIssuerConfiguration & readonly issuerConfig = ?; +configurable KeyStores & readonly keyStores = { + tls: {certFilePath: "/home/wso2apk/devportal/security/devportal.pem", keyFilePath: "/home/wso2apk/devportal/security/devportal.key"}, + signing: {keyFilePath: "/home/wso2apk/devportal/security/mg.pem"} +}; +configurable SDKConfiguration & readonly sdkConfig = ?; +configurable K8sConfiguration k8sConfig = ?; +configurable ManagementServerConfiguration & readonly managementServerConfig = ?; + +final postgresql:Client|sql:Error dbClient; +configurable int DEVPORTAL_PORT = 9443; +configurable commons:IDPConfiguration & readonly idpConfiguration = { + publicKey: {keyFilePath: "/home/wso2apk/devportal/security/mg.pem"} +}; +configurable KeyManagerConfigs[] keyManagerConfigs = []; +commons:DBBasedOrgResolver organizationResolver = new (datasourceConfiguration); +commons:JWTValidationInterceptor jwtValidationInterceptor = new (idpConfiguration, organizationResolver); +commons:RequestErrorInterceptor requestErrorInterceptor = new; +commons:ResponseErrorInterceptor responseErrorInterceptor = new; +apk_keymanager_libs:KeyManagerTypeInitializer keyManagerTypeInitializer = new (); +commons:UserRegistrationInterceptor userRegistrationInterceptor = new (datasourceConfiguration); +listener http:Listener ep0 = new (DEVPORTAL_PORT, secureSocket = { + 'key: { + certFile: keyStores.tls.certFilePath, + keyFile: keyStores.tls.keyFilePath + } +}, interceptors = [jwtValidationInterceptor, userRegistrationInterceptor, requestErrorInterceptor, responseErrorInterceptor]); +configurable string keyManagerConntectorConfigurationFilePath = "/home/wso2apk/devportal/keymanager"; +listener http:Listener keyManagerConnectorListener = new (9445); + +function init() returns error? { + log:printInfo("Starting APK Devportal Domain Service..."); + _ = check keyManagerTypeInitializer.initialize(keyManagerConntectorConfigurationFilePath); + dbClient = + new (host = datasourceConfiguration.host, + username = datasourceConfiguration.username, + password = datasourceConfiguration.password, + database = datasourceConfiguration.databaseName, + port = datasourceConfiguration.port, + connectionPool = {maxOpenConnections: datasourceConfiguration.maxPoolSize} + ); + if dbClient is error { + return log:printError("Error while connecting to database"); + } +} + +public isolated function getConnection() returns postgresql:Client|error { + return dbClient; +} diff --git a/devportal/devportal-domain-service/ballerina/jwtTokenInfo.bal b/devportal/devportal-domain-service/ballerina/jwtTokenInfo.bal new file mode 100644 index 000000000..4f3b4bfeb --- /dev/null +++ b/devportal/devportal-domain-service/ballerina/jwtTokenInfo.bal @@ -0,0 +1,27 @@ +// +// Copyright (c) 2022, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + +public type JWTTokenInfo record { + Application application; + API[] subscribedAPIs; + string subscriber; + string expireTime; + string keyType; + string permittedIP; + string permittedReferrer; +}; diff --git a/devportal/devportal-domain-service/ballerina/keymanagerDao.bal b/devportal/devportal-domain-service/ballerina/keymanagerDao.bal new file mode 100644 index 000000000..473a39928 --- /dev/null +++ b/devportal/devportal-domain-service/ballerina/keymanagerDao.bal @@ -0,0 +1,202 @@ +import wso2/apk_common_lib as commons; +import ballerinax/postgresql; +import ballerina/sql; +import devportal_service.types; +import ballerina/log; + +isolated function getAllKeyManagersByOrganization(commons:Organization organization) returns KeyManagerListingDaoEntry[]|commons:APKError { + postgresql:Client|error dbClient = getConnection(); + if dbClient is error { + string message = "Error while retrieving connection"; + return error(message, dbClient, message = message, description = message, code = 909000, statusCode = 500); + } else { + do { + sql:ParameterizedQuery query = `SELECT UUID,NAME,DESCRIPTION,TYPE,ENABLED FROM KEY_MANAGER WHERE ORGANIZATION = ${organization.uuid}`; + stream keyManagerListStream = dbClient->query(query); + KeyManagerListingDaoEntry[] keYmanagerList = check from KeyManagerListingDaoEntry keyManager in keyManagerListStream + select keyManager; + check keyManagerListStream.close(); + return keYmanagerList; + } on fail var e { + return error("Internal Error occured while retrieving KeyManagers", e, + code = 909432, + message = "Internal Error occured while retrieving KeyManagers", + statusCode = 500, + description = "Internal Error occured while retrieving KeyManagers"); + } + } +} + +isolated function getKeyManagerById(string id, commons:Organization organization) returns KeyManagerDaoEntry|commons:APKError { + postgresql:Client|error dbClient = getConnection(); + if dbClient is error { + string message = "Error while retrieving connection"; + return error(message, dbClient, message = message, description = message, code = 909000, statusCode = 500); + } else { + sql:ParameterizedQuery query = `SELECT UUID,NAME,DISPLAY_NAME,ISSUER,DESCRIPTION,TYPE,CONFIGURATION,ENABLED FROM KEY_MANAGER WHERE ORGANIZATION = ${organization.uuid} AND UUID = ${id}`; + KeyManagerDaoEntry|sql:Error result = dbClient->queryRow(query); + if result is sql:NoRowsError { + return e909439(id, organization.uuid); + } else if result is KeyManagerDaoEntry { + return result; + } else { + log:printError("Error while getting key manager by id", result); + return e909433(result); + } + } +} + +public isolated function addKeyMappingEntryForApplication(types:KeyMappingDaoEntry keyMappingDaoEntry) returns commons:APKError? { + postgresql:Client|error dbClient = getConnection(); + if dbClient is error { + string message = "Error while retrieving connection"; + return error(message, dbClient, message = message, description = message, code = 909000, statusCode = 500); + } else { + // Insert into SUBSCRIPTION table + sql:ParameterizedQuery query = `INSERT INTO APPLICATION_KEY_MAPPING (UUID,APPLICATION_UUID,CONSUMER_KEY, + KEY_TYPE,CREATE_MODE, APP_INFO,KEY_MANAGER_UUID) VALUES (${keyMappingDaoEntry.uuid},${keyMappingDaoEntry.application_uuid},${keyMappingDaoEntry.consumer_key}, + ${keyMappingDaoEntry.key_type},${keyMappingDaoEntry.create_mode},${keyMappingDaoEntry.app_info},${keyMappingDaoEntry.key_manager_uuid})`; + sql:ExecutionResult|sql:Error result = dbClient->execute(query); + if result is sql:ExecutionResult { + if result.affectedRowCount == 0 { + return error("Error while inserting data into Database", message = "Error while inserting data into Database", description = "Error while inserting data into Database", code = 900954, statusCode = 500); + } else { + return; + } + } else { + log:printDebug(result.toString()); + string message = "Error while inserting data into Database"; + return error(message, result, message = message, description = message, code = 909000, statusCode = 500); + } + } +} + +public isolated function getKeyMappingEntriesByApplication(string applicationId) returns types:KeyMappingDaoEntry[]|commons:APKError { + postgresql:Client|error dbClient = getConnection(); + if dbClient is error { + string message = "Error while retrieving connection"; + return error(message, dbClient, message = message, description = message, code = 909000, statusCode = 500); + } else { + do { + sql:ParameterizedQuery query = `SELECT UUID,APPLICATION_UUID,CONSUMER_KEY,KEY_TYPE,CREATE_MODE,APP_INFO,KEY_MANAGER_UUID FROM APPLICATION_KEY_MAPPING WHERE APPLICATION_UUID = ${applicationId}`; + stream keyMappingListStream = dbClient->query(query); + types:KeyMappingDaoEntry[] keyMappingList = check from types:KeyMappingDaoEntry keyMapping in keyMappingListStream + select keyMapping; + check keyMappingListStream.close(); + return keyMappingList; + } on fail var e { + return error("Internal Error occured while retrieving KeyMapping", e, message = "Internal Error occured while retrieving KeyMapping", description = "Internal Error occured while retrieving KeyMapping", code = 909432, statusCode = 500); + } + } +} + +public isolated function getKeyMappingEntryByApplicationAndKeyMappingId(string applicationId, string keyMappingId) returns types:KeyMappingDaoEntry|commons:APKError { + postgresql:Client|error dbClient = getConnection(); + if dbClient is error { + string message = "Error while retrieving connection"; + return error(message, dbClient, message = message, description = message, code = 909000, statusCode = 500); + } else { + do { + sql:ParameterizedQuery query = `SELECT UUID,APPLICATION_UUID,CONSUMER_KEY,KEY_TYPE,CREATE_MODE,APP_INFO,KEY_MANAGER_UUID FROM APPLICATION_KEY_MAPPING WHERE APPLICATION_UUID = ${applicationId} AND UUID = ${keyMappingId}`; + types:KeyMappingDaoEntry|sql:Error keyMappingEntry = dbClient->queryRow(query); + if keyMappingEntry is types:KeyMappingDaoEntry { + return keyMappingEntry; + } else if keyMappingEntry is sql:NoRowsError { + return error("KeyMapping from " + keyMappingId + " not exist in application " + applicationId, + code = 909439, + message = "KeyMapping from " + keyMappingId + " not exist in application " + applicationId, + statusCode = 404, + description = "KeyMapping from " + keyMappingId + " not exist in application " + applicationId); + } else { + return error("Internal Error occured while retrieving KeyMapping", keyMappingEntry, message = "Internal Error occured while retrieving KeyMapping", description = "Internal Error occured while retrieving KeyMapping", code = 909432, statusCode = 500); + } + } on fail var e { + return error("Internal Error occured while retrieving KeyMapping", e, message = "Internal Error occured while retrieving KeyMapping", description = "Internal Error occured while retrieving KeyMapping", code = 909432, statusCode = 500); + } + } +} + +public isolated function updateKeyMappingEntry(types:KeyMappingDaoEntry keyMappingentry) returns commons:APKError? { + postgresql:Client|error dbClient = getConnection(); + if dbClient is error { + string message = "Error while retrieving connection"; + return error(message, dbClient, message = message, description = message, code = 909000, statusCode = 500); + } else { + do { + sql:ParameterizedQuery query = `UPDATE APPLICATION_KEY_MAPPING SET APP_INFO = ${keyMappingentry.app_info} WHERE APPLICATION_UUID = ${keyMappingentry.application_uuid} AND UUID = ${keyMappingentry.uuid}`; + sql:ExecutionResult result = check dbClient->execute(query); + if result.affectedRowCount == 0 { + return error("KeyMapping from " + keyMappingentry.uuid + " not exist in application " + keyMappingentry.application_uuid, + code = 909439, + message = "KeyMapping from " + keyMappingentry.uuid + " not exist in application " + keyMappingentry.application_uuid, + statusCode = 404, + description = "KeyMapping from " + keyMappingentry.uuid + " not exist in application " + keyMappingentry.application_uuid); + } + } on fail var e { + return error("Internal Error occured while retrieving KeyMapping", e, message = "Internal Error occured while retrieving KeyMapping", description = "Internal Error occured while retrieving KeyMapping", code = 909432, statusCode = 500); + } + } +} + +public isolated function isKeyMappingEntryByApplicationAndKeyManagerExist(string applicationId, string keyManagerId,string keyType) returns boolean|commons:APKError { + postgresql:Client|error dbClient = getConnection(); + if dbClient is error { + string message = "Error while retrieving connection"; + return error(message, dbClient, message = message, description = message, code = 909000, statusCode = 500); + } else { + sql:ParameterizedQuery query = `select exists(SELECT 1 FROM APPLICATION_KEY_MAPPING WHERE APPLICATION_UUID = ${applicationId} AND KEY_MANAGER_UUID = ${keyManagerId} AND KEY_TYPE = ${keyType})`; + boolean|sql:Error result = dbClient->queryRow(query); + if result is boolean { + return result; + } else { + return error("Internal Error occured while retrieving KeyMapping", result, message = "Internal Error occured while retrieving KeyMapping", description = "Internal Error occured while retrieving KeyMapping", code = 909432, statusCode = 500); + } + } +} + +public type KeyManagerListingDaoEntry record {| + string uuid; + string name; + string display_name?; + string description?; + string 'type; + boolean enabled; +|}; + +public type KeyManagerDaoEntry record {| + string uuid?; + string name; + string display_name?; + string issuer; + string description?; + string 'type; + byte[] configuration?; + boolean enabled; +|}; + +isolated function e909439(string id, string organization) returns commons:APKError { + return error commons:APKError("KeyManager from " + id + " not exist in organization " + organization, + code = 909439, + message = "KeyManager from " + id + " not exist in organization " + organization, + statusCode = 404, + description = "KeyManager from " + id + " not exist in organization " + organization + ); +} + +public isolated function e909433(error e) returns commons:APKError { + return error commons:APKError("Internal Error occured while retrieving KeyManager", e, + code = 909433, + message = "Internal Error occured while retrieving KeyManager", + statusCode = 500, + description = "Internal Error occured while retrieving KeyManager" + ); +} + +isolated function e909440(string id, string organization, error? e) returns commons:APKError { + return error commons:APKError("Internal Error occured while deleting keymanager " + id + " from organization " + organization, e, + code = 909440, + message = "Internal Error occured while deleting keymanager " + id + " from organization " + organization, + statusCode = 500, + description = "Internal Error occured while deleting keymanager " + id + " from organization " + organization + ); +} diff --git a/devportal/devportal-domain-service/ballerina/keymanagerImpl.bal b/devportal/devportal-domain-service/ballerina/keymanagerImpl.bal new file mode 100644 index 000000000..c59dd062e --- /dev/null +++ b/devportal/devportal-domain-service/ballerina/keymanagerImpl.bal @@ -0,0 +1,77 @@ +import ballerina/lang.value; +import wso2/apk_common_lib as commons; +import devportal_service.types; + +isolated function fromKeyManagerDaoEntryToKeyManagerModel(KeyManagerDaoEntry keyManagerDaoEntry) returns types:KeyManager|commons:APKError { + do { + string additionalPropertiesString = check string:fromBytes(keyManagerDaoEntry.configuration); + json additionalPropertiesJson = check value:fromJsonString(additionalPropertiesString); + types:KeyManager keymanager = { + id: keyManagerDaoEntry.uuid, + name: keyManagerDaoEntry.name, + 'type: keyManagerDaoEntry.'type, + description: keyManagerDaoEntry.description, + issuer: keyManagerDaoEntry.issuer, + enabled: keyManagerDaoEntry.enabled + }; + map endpoints = {}; + record {} additionalProperties = check additionalPropertiesJson.cloneWithType(); + if additionalProperties.hasKey("endpoints") { + record {} endpointsInRecord = additionalProperties.get("endpoints"); + foreach string key in endpointsInRecord.keys() { + endpoints[key] = endpointsInRecord[key]; + } + _ = additionalProperties.removeIfHasKey("endpoints"); + keymanager.endpoints = endpoints; + } + if additionalProperties.hasKey("grantTypes") { + string[] grantTypes = additionalProperties.get("grantTypes"); + keymanager.availableGrantTypes = grantTypes; + _ = additionalProperties.removeIfHasKey("grantTypes"); + } + if additionalProperties.hasKey("consumerKeyClaim") { + keymanager.consumerKeyClaim = additionalProperties.get("consumerKeyClaim"); + _ = additionalProperties.removeIfHasKey("consumerKeyClaim"); + } + if additionalProperties.hasKey("scopesClaim") { + keymanager.scopesClaim = additionalProperties.get("scopesClaim"); + _ = additionalProperties.removeIfHasKey("scopesClaim"); + } + if additionalProperties.hasKey("tls_certificate") { + string certificateValue = additionalProperties.get("tls_certificate"); + byte[] encodedBytes = check commons:EncoderUtil_decodeBase64(certificateValue.toBytes()); + certificateValue = check string:fromBytes(encodedBytes); + keymanager.tlsCertficate = certificateValue; + _ = additionalProperties.removeIfHasKey("tls_certificate"); + } + if additionalProperties.hasKey("mapOAuthConsumerApps") { + keymanager.enableMapOAuthConsumerApps = additionalProperties.get("mapOAuthConsumerApps"); + _ = additionalProperties.removeIfHasKey("mapOAuthConsumerApps"); + } + if additionalProperties.hasKey("enableTokenGeneration") { + keymanager.enableTokenGeneration = additionalProperties.get("enableTokenGeneration"); + _ = additionalProperties.removeIfHasKey("enableTokenGeneration"); + } + if additionalProperties.hasKey("enableOauthAppCreation") { + keymanager.enableOAuthAppCreation = additionalProperties.get("enableOauthAppCreation"); + _ = additionalProperties.removeIfHasKey("enableOauthAppCreation"); + } + if additionalProperties.hasKey("enableOauthAppValidation") { + keymanager.enableOauthAppValidation = additionalProperties.get("enableOauthAppValidation"); + _ = additionalProperties.removeIfHasKey("enableOauthAppValidation"); + } + keymanager.additionalProperties = additionalProperties; + return keymanager; + } on fail var e { + return e909438(e); + } +} + +isolated function e909438(error? e) returns commons:APKError { + return error commons:APKError("Internal Server Error", e, + code = 909438, + message = "Internal Server Error", + statusCode = 500, + description = "Internal Server Error" + ); +} diff --git a/devportal/devportal-domain-service/ballerina/modules/java.lang/Class.bal b/devportal/devportal-domain-service/ballerina/modules/java.lang/Class.bal new file mode 100644 index 000000000..7896cde37 --- /dev/null +++ b/devportal/devportal-domain-service/ballerina/modules/java.lang/Class.bal @@ -0,0 +1,38 @@ +// This is an empty Ballerina class autogenerated to represent the `java.lang.Class` Java class. +// +// If you need the implementation of this class generated, please use the following command. +// +// $ bal bindgen [(-cp|--classpath) ...] +// [(-mvn|--maven) ::] +// [(-o|--output) ] +// [--public] +// (...) +// +// E.g. $ bal bindgen java.lang.Class + +import ballerina/jballerina.java; + +# Ballerina class mapping for the Java `java.lang.Class` class. +@java:Binding {'class: "java.lang.Class"} +public distinct class Class { + + *java:JObject; + + # The `handle` field that stores the reference to the `java.lang.Class` object. + public handle jObj; + + # The init function of the Ballerina class mapping the `java.lang.Class` Java class. + # + # + obj - The `handle` value containing the Java reference of the object. + public function init(handle obj) { + self.jObj = obj; + } + + # The function to retrieve the string representation of the Ballerina class mapping the `java.lang.Class` Java class. + # + # + return - The `string` form of the Java object instance. + public function toString() returns string { + return java:toString(self.jObj) ?: "null"; + } +} + diff --git a/devportal/devportal-domain-service/ballerina/modules/java.lang/InterruptedException.bal b/devportal/devportal-domain-service/ballerina/modules/java.lang/InterruptedException.bal new file mode 100644 index 000000000..17cae5713 --- /dev/null +++ b/devportal/devportal-domain-service/ballerina/modules/java.lang/InterruptedException.bal @@ -0,0 +1,10 @@ +// Ballerina error type for `java.lang.InterruptedException`. + +public const INTERRUPTEDEXCEPTION = "InterruptedException"; + +type InterruptedExceptionData record { + string message; +}; + +public type InterruptedException distinct error; + diff --git a/devportal/devportal-domain-service/ballerina/modules/java.lang/Object.bal b/devportal/devportal-domain-service/ballerina/modules/java.lang/Object.bal new file mode 100644 index 000000000..bfed60309 --- /dev/null +++ b/devportal/devportal-domain-service/ballerina/modules/java.lang/Object.bal @@ -0,0 +1,158 @@ +import ballerina/jballerina.java; + +# Ballerina class mapping for the Java `java.lang.Object` class. +@java:Binding {'class: "java.lang.Object"} +public distinct class Object { + + *java:JObject; + + # The `handle` field that stores the reference to the `java.lang.Object` object. + public handle jObj; + + # The init function of the Ballerina class mapping the `java.lang.Object` Java class. + # + # + obj - The `handle` value containing the Java reference of the object. + public isolated function init(handle obj) { + self.jObj = obj; + } + + # The function to retrieve the string representation of the Ballerina class mapping the `java.lang.Object` Java class. + # + # + return - The `string` form of the Java object instance. + public function toString() returns string { + return java:toString(self.jObj) ?: "null"; + } + # The function that maps to the `equals` method of `java.lang.Object`. + # + # + arg0 - The `Object` value required to map with the Java method parameter. + # + return - The `boolean` value returning from the Java mapping. + public function 'equals(Object arg0) returns boolean { + return java_lang_Object_equals(self.jObj, arg0.jObj); + } + + # The function that maps to the `getClass` method of `java.lang.Object`. + # + # + return - The `Class` value returning from the Java mapping. + public function getClass() returns Class { + handle externalObj = java_lang_Object_getClass(self.jObj); + Class newObj = new (externalObj); + return newObj; + } + + # The function that maps to the `hashCode` method of `java.lang.Object`. + # + # + return - The `int` value returning from the Java mapping. + public function hashCode() returns int { + return java_lang_Object_hashCode(self.jObj); + } + + # The function that maps to the `notify` method of `java.lang.Object`. + public function notify() { + java_lang_Object_notify(self.jObj); + } + + # The function that maps to the `notifyAll` method of `java.lang.Object`. + public function notifyAll() { + java_lang_Object_notifyAll(self.jObj); + } + + # The function that maps to the `wait` method of `java.lang.Object`. + # + # + return - The `InterruptedException` value returning from the Java mapping. + public function 'wait() returns InterruptedException? { + error|() externalObj = java_lang_Object_wait(self.jObj); + if (externalObj is error) { + InterruptedException e = error InterruptedException(INTERRUPTEDEXCEPTION, externalObj, message = externalObj.message()); + return e; + } + } + + # The function that maps to the `wait` method of `java.lang.Object`. + # + # + arg0 - The `int` value required to map with the Java method parameter. + # + return - The `InterruptedException` value returning from the Java mapping. + public function wait2(int arg0) returns InterruptedException? { + error|() externalObj = java_lang_Object_wait2(self.jObj, arg0); + if (externalObj is error) { + InterruptedException e = error InterruptedException(INTERRUPTEDEXCEPTION, externalObj, message = externalObj.message()); + return e; + } + } + + # The function that maps to the `wait` method of `java.lang.Object`. + # + # + arg0 - The `int` value required to map with the Java method parameter. + # + arg1 - The `int` value required to map with the Java method parameter. + # + return - The `InterruptedException` value returning from the Java mapping. + public function wait3(int arg0, int arg1) returns InterruptedException? { + error|() externalObj = java_lang_Object_wait3(self.jObj, arg0, arg1); + if (externalObj is error) { + InterruptedException e = error InterruptedException(INTERRUPTEDEXCEPTION, externalObj, message = externalObj.message()); + return e; + } + } + +} + +# The constructor function to generate an object of `java.lang.Object`. +# +# + return - The new `Object` class generated. +public function newObject1() returns Object { + handle externalObj = java_lang_Object_newObject1(); + Object newObj = new (externalObj); + return newObj; +} + +function java_lang_Object_equals(handle receiver, handle arg0) returns boolean = @java:Method { + name: "equals", + 'class: "java.lang.Object", + paramTypes: ["java.lang.Object"] +} external; + +function java_lang_Object_getClass(handle receiver) returns handle = @java:Method { + name: "getClass", + 'class: "java.lang.Object", + paramTypes: [] +} external; + +function java_lang_Object_hashCode(handle receiver) returns int = @java:Method { + name: "hashCode", + 'class: "java.lang.Object", + paramTypes: [] +} external; + +function java_lang_Object_notify(handle receiver) = @java:Method { + name: "notify", + 'class: "java.lang.Object", + paramTypes: [] +} external; + +function java_lang_Object_notifyAll(handle receiver) = @java:Method { + name: "notifyAll", + 'class: "java.lang.Object", + paramTypes: [] +} external; + +function java_lang_Object_wait(handle receiver) returns error? = @java:Method { + name: "wait", + 'class: "java.lang.Object", + paramTypes: [] +} external; + +function java_lang_Object_wait2(handle receiver, int arg0) returns error? = @java:Method { + name: "wait", + 'class: "java.lang.Object", + paramTypes: ["long"] +} external; + +function java_lang_Object_wait3(handle receiver, int arg0, int arg1) returns error? = @java:Method { + name: "wait", + 'class: "java.lang.Object", + paramTypes: ["long", "int"] +} external; + +function java_lang_Object_newObject1() returns handle = @java:Constructor { + 'class: "java.lang.Object", + paramTypes: [] +} external; + diff --git a/devportal/devportal-domain-service/ballerina/modules/java.util.function/BiConsumer.bal b/devportal/devportal-domain-service/ballerina/modules/java.util.function/BiConsumer.bal new file mode 100644 index 000000000..8c376394e --- /dev/null +++ b/devportal/devportal-domain-service/ballerina/modules/java.util.function/BiConsumer.bal @@ -0,0 +1,38 @@ +// This is an empty Ballerina class autogenerated to represent the `java.util.function.BiConsumer` Java interface. +// +// If you need the implementation of this class generated, please use the following command. +// +// $ bal bindgen [(-cp|--classpath) ...] +// [(-mvn|--maven) ::] +// [(-o|--output) ] +// [--public] +// (...) +// +// E.g. $ bal bindgen java.util.function.BiConsumer + +import ballerina/jballerina.java; + +# Ballerina class mapping for the Java `java.util.function.BiConsumer` interface. +@java:Binding {'class: "java.util.function.BiConsumer"} +public distinct class BiConsumer { + + *java:JObject; + + # The `handle` field that stores the reference to the `java.util.function.BiConsumer` object. + public handle jObj; + + # The init function of the Ballerina class mapping the `java.util.function.BiConsumer` Java interface. + # + # + obj - The `handle` value containing the Java reference of the object. + public function init(handle obj) { + self.jObj = obj; + } + + # The function to retrieve the string representation of the Ballerina class mapping the `java.util.function.BiConsumer` Java interface. + # + # + return - The `string` form of the Java object instance. + public function toString() returns string { + return java:toString(self.jObj) ?: "null"; + } +} + diff --git a/devportal/devportal-domain-service/ballerina/modules/java.util.function/BiFunction.bal b/devportal/devportal-domain-service/ballerina/modules/java.util.function/BiFunction.bal new file mode 100644 index 000000000..7bacd2a3c --- /dev/null +++ b/devportal/devportal-domain-service/ballerina/modules/java.util.function/BiFunction.bal @@ -0,0 +1,38 @@ +// This is an empty Ballerina class autogenerated to represent the `java.util.function.BiFunction` Java interface. +// +// If you need the implementation of this class generated, please use the following command. +// +// $ bal bindgen [(-cp|--classpath) ...] +// [(-mvn|--maven) ::] +// [(-o|--output) ] +// [--public] +// (...) +// +// E.g. $ bal bindgen java.util.function.BiFunction + +import ballerina/jballerina.java; + +# Ballerina class mapping for the Java `java.util.function.BiFunction` interface. +@java:Binding {'class: "java.util.function.BiFunction"} +public distinct class BiFunction { + + *java:JObject; + + # The `handle` field that stores the reference to the `java.util.function.BiFunction` object. + public handle jObj; + + # The init function of the Ballerina class mapping the `java.util.function.BiFunction` Java interface. + # + # + obj - The `handle` value containing the Java reference of the object. + public function init(handle obj) { + self.jObj = obj; + } + + # The function to retrieve the string representation of the Ballerina class mapping the `java.util.function.BiFunction` Java interface. + # + # + return - The `string` form of the Java object instance. + public function toString() returns string { + return java:toString(self.jObj) ?: "null"; + } +} + diff --git a/devportal/devportal-domain-service/ballerina/modules/java.util.function/Function.bal b/devportal/devportal-domain-service/ballerina/modules/java.util.function/Function.bal new file mode 100644 index 000000000..51852535b --- /dev/null +++ b/devportal/devportal-domain-service/ballerina/modules/java.util.function/Function.bal @@ -0,0 +1,38 @@ +// This is an empty Ballerina class autogenerated to represent the `java.util.function.Function` Java interface. +// +// If you need the implementation of this class generated, please use the following command. +// +// $ bal bindgen [(-cp|--classpath) ...] +// [(-mvn|--maven) ::] +// [(-o|--output) ] +// [--public] +// (...) +// +// E.g. $ bal bindgen java.util.function.Function + +import ballerina/jballerina.java; + +# Ballerina class mapping for the Java `java.util.function.Function` interface. +@java:Binding {'class: "java.util.function.Function"} +public distinct class Function { + + *java:JObject; + + # The `handle` field that stores the reference to the `java.util.function.Function` object. + public handle jObj; + + # The init function of the Ballerina class mapping the `java.util.function.Function` Java interface. + # + # + obj - The `handle` value containing the Java reference of the object. + public function init(handle obj) { + self.jObj = obj; + } + + # The function to retrieve the string representation of the Ballerina class mapping the `java.util.function.Function` Java interface. + # + # + return - The `string` form of the Java object instance. + public function toString() returns string { + return java:toString(self.jObj) ?: "null"; + } +} + diff --git a/devportal/devportal-domain-service/ballerina/modules/java.util/Collection.bal b/devportal/devportal-domain-service/ballerina/modules/java.util/Collection.bal new file mode 100644 index 000000000..178c77196 --- /dev/null +++ b/devportal/devportal-domain-service/ballerina/modules/java.util/Collection.bal @@ -0,0 +1,38 @@ +// This is an empty Ballerina class autogenerated to represent the `java.util.Collection` Java interface. +// +// If you need the implementation of this class generated, please use the following command. +// +// $ bal bindgen [(-cp|--classpath) ...] +// [(-mvn|--maven) ::] +// [(-o|--output) ] +// [--public] +// (...) +// +// E.g. $ bal bindgen java.util.Collection + +import ballerina/jballerina.java; + +# Ballerina class mapping for the Java `java.util.Collection` interface. +@java:Binding {'class: "java.util.Collection"} +public distinct class Collection { + + *java:JObject; + + # The `handle` field that stores the reference to the `java.util.Collection` object. + public handle jObj; + + # The init function of the Ballerina class mapping the `java.util.Collection` Java interface. + # + # + obj - The `handle` value containing the Java reference of the object. + public function init(handle obj) { + self.jObj = obj; + } + + # The function to retrieve the string representation of the Ballerina class mapping the `java.util.Collection` Java interface. + # + # + return - The `string` form of the Java object instance. + public function toString() returns string { + return java:toString(self.jObj) ?: "null"; + } +} + diff --git a/devportal/devportal-domain-service/ballerina/modules/java.util/Entry.bal b/devportal/devportal-domain-service/ballerina/modules/java.util/Entry.bal new file mode 100644 index 000000000..10ee6b746 --- /dev/null +++ b/devportal/devportal-domain-service/ballerina/modules/java.util/Entry.bal @@ -0,0 +1,38 @@ +// This is an empty Ballerina class autogenerated to represent the `java.util.Map$Entry` Java interface. +// +// If you need the implementation of this class generated, please use the following command. +// +// $ bal bindgen [(-cp|--classpath) ...] +// [(-mvn|--maven) ::] +// [(-o|--output) ] +// [--public] +// (...) +// +// E.g. $ bal bindgen java.util.Map\$Entry + +import ballerina/jballerina.java; + +# Ballerina class mapping for the Java `java.util.Map$Entry` interface. +@java:Binding {'class: "java.util.Map$Entry"} +public distinct class Entry { + + *java:JObject; + + # The `handle` field that stores the reference to the `java.util.Map$Entry` object. + public handle jObj; + + # The init function of the Ballerina class mapping the `java.util.Map$Entry` Java interface. + # + # + obj - The `handle` value containing the Java reference of the object. + public function init(handle obj) { + self.jObj = obj; + } + + # The function to retrieve the string representation of the Ballerina class mapping the `java.util.Map$Entry` Java interface. + # + # + return - The `string` form of the Java object instance. + public function toString() returns string { + return java:toString(self.jObj) ?: "null"; + } +} + diff --git a/devportal/devportal-domain-service/ballerina/modules/java.util/Map.bal b/devportal/devportal-domain-service/ballerina/modules/java.util/Map.bal new file mode 100644 index 000000000..f6909d658 --- /dev/null +++ b/devportal/devportal-domain-service/ballerina/modules/java.util/Map.bal @@ -0,0 +1,729 @@ +import ballerina/jballerina.java; +import ballerina/jballerina.java.arrays as jarrays; +import devportal_service.java.lang as javalang; +import devportal_service.java.util.'function as javautilfunction; + +# Ballerina class mapping for the Java `java.util.Map` interface. +@java:Binding {'class: "java.util.Map"} +public distinct class Map { + + *java:JObject; + + # The `handle` field that stores the reference to the `java.util.Map` object. + public handle jObj; + + # The init function of the Ballerina class mapping the `java.util.Map` Java interface. + # + # + obj - The `handle` value containing the Java reference of the object. + public isolated function init(handle obj) { + self.jObj = obj; + } + + # The function to retrieve the string representation of the Ballerina class mapping the `java.util.Map` Java interface. + # + # + return - The `string` form of the Java object instance. + public function toString() returns string { + return java:toString(self.jObj) ?: "null"; + } + # The function that maps to the `clear` method of `java.util.Map`. + public function clear() { + java_util_Map_clear(self.jObj); + } + + # The function that maps to the `compute` method of `java.util.Map`. + # + # + arg0 - The `javalang:Object` value required to map with the Java method parameter. + # + arg1 - The `javautilfunction:BiFunction` value required to map with the Java method parameter. + # + return - The `javalang:Object` value returning from the Java mapping. + public function compute(javalang:Object arg0, javautilfunction:BiFunction arg1) returns javalang:Object { + handle externalObj = java_util_Map_compute(self.jObj, arg0.jObj, arg1.jObj); + javalang:Object newObj = new (externalObj); + return newObj; + } + + # The function that maps to the `computeIfAbsent` method of `java.util.Map`. + # + # + arg0 - The `javalang:Object` value required to map with the Java method parameter. + # + arg1 - The `javautilfunction:Function` value required to map with the Java method parameter. + # + return - The `javalang:Object` value returning from the Java mapping. + public function computeIfAbsent(javalang:Object arg0, javautilfunction:Function arg1) returns javalang:Object { + handle externalObj = java_util_Map_computeIfAbsent(self.jObj, arg0.jObj, arg1.jObj); + javalang:Object newObj = new (externalObj); + return newObj; + } + + # The function that maps to the `computeIfPresent` method of `java.util.Map`. + # + # + arg0 - The `javalang:Object` value required to map with the Java method parameter. + # + arg1 - The `javautilfunction:BiFunction` value required to map with the Java method parameter. + # + return - The `javalang:Object` value returning from the Java mapping. + public function computeIfPresent(javalang:Object arg0, javautilfunction:BiFunction arg1) returns javalang:Object { + handle externalObj = java_util_Map_computeIfPresent(self.jObj, arg0.jObj, arg1.jObj); + javalang:Object newObj = new (externalObj); + return newObj; + } + + # The function that maps to the `containsKey` method of `java.util.Map`. + # + # + arg0 - The `javalang:Object` value required to map with the Java method parameter. + # + return - The `boolean` value returning from the Java mapping. + public function containsKey(javalang:Object arg0) returns boolean { + return java_util_Map_containsKey(self.jObj, arg0.jObj); + } + + # The function that maps to the `containsValue` method of `java.util.Map`. + # + # + arg0 - The `javalang:Object` value required to map with the Java method parameter. + # + return - The `boolean` value returning from the Java mapping. + public function containsValue(javalang:Object arg0) returns boolean { + return java_util_Map_containsValue(self.jObj, arg0.jObj); + } + + # The function that maps to the `entrySet` method of `java.util.Map`. + # + # + return - The `Set` value returning from the Java mapping. + public function entrySet() returns Set { + handle externalObj = java_util_Map_entrySet(self.jObj); + Set newObj = new (externalObj); + return newObj; + } + + # The function that maps to the `equals` method of `java.util.Map`. + # + # + arg0 - The `javalang:Object` value required to map with the Java method parameter. + # + return - The `boolean` value returning from the Java mapping. + public function 'equals(javalang:Object arg0) returns boolean { + return java_util_Map_equals(self.jObj, arg0.jObj); + } + + # The function that maps to the `forEach` method of `java.util.Map`. + # + # + arg0 - The `javautilfunction:BiConsumer` value required to map with the Java method parameter. + public function forEach(javautilfunction:BiConsumer arg0) { + java_util_Map_forEach(self.jObj, arg0.jObj); + } + + # The function that maps to the `get` method of `java.util.Map`. + # + # + arg0 - The `javalang:Object` value required to map with the Java method parameter. + # + return - The `javalang:Object` value returning from the Java mapping. + public isolated function get(javalang:Object arg0) returns javalang:Object { + handle externalObj = java_util_Map_get(self.jObj, arg0.jObj); + javalang:Object newObj = new (externalObj); + return newObj; + } + + # The function that maps to the `getOrDefault` method of `java.util.Map`. + # + # + arg0 - The `javalang:Object` value required to map with the Java method parameter. + # + arg1 - The `javalang:Object` value required to map with the Java method parameter. + # + return - The `javalang:Object` value returning from the Java mapping. + public function getOrDefault(javalang:Object arg0, javalang:Object arg1) returns javalang:Object { + handle externalObj = java_util_Map_getOrDefault(self.jObj, arg0.jObj, arg1.jObj); + javalang:Object newObj = new (externalObj); + return newObj; + } + + # The function that maps to the `hashCode` method of `java.util.Map`. + # + # + return - The `int` value returning from the Java mapping. + public function hashCode() returns int { + return java_util_Map_hashCode(self.jObj); + } + + # The function that maps to the `isEmpty` method of `java.util.Map`. + # + # + return - The `boolean` value returning from the Java mapping. + public function isEmpty() returns boolean { + return java_util_Map_isEmpty(self.jObj); + } + + # The function that maps to the `keySet` method of `java.util.Map`. + # + # + return - The `Set` value returning from the Java mapping. + public function keySet() returns Set { + handle externalObj = java_util_Map_keySet(self.jObj); + Set newObj = new (externalObj); + return newObj; + } + + # The function that maps to the `merge` method of `java.util.Map`. + # + # + arg0 - The `javalang:Object` value required to map with the Java method parameter. + # + arg1 - The `javalang:Object` value required to map with the Java method parameter. + # + arg2 - The `javautilfunction:BiFunction` value required to map with the Java method parameter. + # + return - The `javalang:Object` value returning from the Java mapping. + public function merge(javalang:Object arg0, javalang:Object arg1, javautilfunction:BiFunction arg2) returns javalang:Object { + handle externalObj = java_util_Map_merge(self.jObj, arg0.jObj, arg1.jObj, arg2.jObj); + javalang:Object newObj = new (externalObj); + return newObj; + } + + # The function that maps to the `put` method of `java.util.Map`. + # + # + arg0 - The `javalang:Object` value required to map with the Java method parameter. + # + arg1 - The `javalang:Object` value required to map with the Java method parameter. + # + return - The `javalang:Object` value returning from the Java mapping. + public function put(javalang:Object arg0, javalang:Object arg1) returns javalang:Object { + handle externalObj = java_util_Map_put(self.jObj, arg0.jObj, arg1.jObj); + javalang:Object newObj = new (externalObj); + return newObj; + } + + # The function that maps to the `putAll` method of `java.util.Map`. + # + # + arg0 - The `Map` value required to map with the Java method parameter. + public function putAll(Map arg0) { + java_util_Map_putAll(self.jObj, arg0.jObj); + } + + # The function that maps to the `putIfAbsent` method of `java.util.Map`. + # + # + arg0 - The `javalang:Object` value required to map with the Java method parameter. + # + arg1 - The `javalang:Object` value required to map with the Java method parameter. + # + return - The `javalang:Object` value returning from the Java mapping. + public function putIfAbsent(javalang:Object arg0, javalang:Object arg1) returns javalang:Object { + handle externalObj = java_util_Map_putIfAbsent(self.jObj, arg0.jObj, arg1.jObj); + javalang:Object newObj = new (externalObj); + return newObj; + } + + # The function that maps to the `remove` method of `java.util.Map`. + # + # + arg0 - The `javalang:Object` value required to map with the Java method parameter. + # + return - The `javalang:Object` value returning from the Java mapping. + public function remove(javalang:Object arg0) returns javalang:Object { + handle externalObj = java_util_Map_remove(self.jObj, arg0.jObj); + javalang:Object newObj = new (externalObj); + return newObj; + } + + # The function that maps to the `remove` method of `java.util.Map`. + # + # + arg0 - The `javalang:Object` value required to map with the Java method parameter. + # + arg1 - The `javalang:Object` value required to map with the Java method parameter. + # + return - The `boolean` value returning from the Java mapping. + public function remove2(javalang:Object arg0, javalang:Object arg1) returns boolean { + return java_util_Map_remove2(self.jObj, arg0.jObj, arg1.jObj); + } + + # The function that maps to the `replace` method of `java.util.Map`. + # + # + arg0 - The `javalang:Object` value required to map with the Java method parameter. + # + arg1 - The `javalang:Object` value required to map with the Java method parameter. + # + return - The `javalang:Object` value returning from the Java mapping. + public function replace(javalang:Object arg0, javalang:Object arg1) returns javalang:Object { + handle externalObj = java_util_Map_replace(self.jObj, arg0.jObj, arg1.jObj); + javalang:Object newObj = new (externalObj); + return newObj; + } + + # The function that maps to the `replace` method of `java.util.Map`. + # + # + arg0 - The `javalang:Object` value required to map with the Java method parameter. + # + arg1 - The `javalang:Object` value required to map with the Java method parameter. + # + arg2 - The `javalang:Object` value required to map with the Java method parameter. + # + return - The `boolean` value returning from the Java mapping. + public function replace2(javalang:Object arg0, javalang:Object arg1, javalang:Object arg2) returns boolean { + return java_util_Map_replace2(self.jObj, arg0.jObj, arg1.jObj, arg2.jObj); + } + + # The function that maps to the `replaceAll` method of `java.util.Map`. + # + # + arg0 - The `javautilfunction:BiFunction` value required to map with the Java method parameter. + public function replaceAll(javautilfunction:BiFunction arg0) { + java_util_Map_replaceAll(self.jObj, arg0.jObj); + } + + # The function that maps to the `size` method of `java.util.Map`. + # + # + return - The `int` value returning from the Java mapping. + public function size() returns int { + return java_util_Map_size(self.jObj); + } + + # The function that maps to the `values` method of `java.util.Map`. + # + # + return - The `Collection` value returning from the Java mapping. + public function values() returns Collection { + handle externalObj = java_util_Map_values(self.jObj); + Collection newObj = new (externalObj); + return newObj; + } + +} + +# The function that maps to the `copyOf` method of `java.util.Map`. +# +# + arg0 - The `Map` value required to map with the Java method parameter. +# + return - The `Map` value returning from the Java mapping. +public function Map_copyOf(Map arg0) returns Map { + handle externalObj = java_util_Map_copyOf(arg0.jObj); + Map newObj = new (externalObj); + return newObj; +} + +# The function that maps to the `entry` method of `java.util.Map`. +# +# + arg0 - The `javalang:Object` value required to map with the Java method parameter. +# + arg1 - The `javalang:Object` value required to map with the Java method parameter. +# + return - The `Entry` value returning from the Java mapping. +public function Map_entry(javalang:Object arg0, javalang:Object arg1) returns Entry { + handle externalObj = java_util_Map_entry(arg0.jObj, arg1.jObj); + Entry newObj = new (externalObj); + return newObj; +} + +# The function that maps to the `of` method of `java.util.Map`. +# +# + return - The `Map` value returning from the Java mapping. +public function Map_of() returns Map { + handle externalObj = java_util_Map_of(); + Map newObj = new (externalObj); + return newObj; +} + +# The function that maps to the `of` method of `java.util.Map`. +# +# + arg0 - The `javalang:Object` value required to map with the Java method parameter. +# + arg1 - The `javalang:Object` value required to map with the Java method parameter. +# + arg2 - The `javalang:Object` value required to map with the Java method parameter. +# + arg3 - The `javalang:Object` value required to map with the Java method parameter. +# + arg4 - The `javalang:Object` value required to map with the Java method parameter. +# + arg5 - The `javalang:Object` value required to map with the Java method parameter. +# + arg6 - The `javalang:Object` value required to map with the Java method parameter. +# + arg7 - The `javalang:Object` value required to map with the Java method parameter. +# + arg8 - The `javalang:Object` value required to map with the Java method parameter. +# + arg9 - The `javalang:Object` value required to map with the Java method parameter. +# + arg10 - The `javalang:Object` value required to map with the Java method parameter. +# + arg11 - The `javalang:Object` value required to map with the Java method parameter. +# + arg12 - The `javalang:Object` value required to map with the Java method parameter. +# + arg13 - The `javalang:Object` value required to map with the Java method parameter. +# + arg14 - The `javalang:Object` value required to map with the Java method parameter. +# + arg15 - The `javalang:Object` value required to map with the Java method parameter. +# + arg16 - The `javalang:Object` value required to map with the Java method parameter. +# + arg17 - The `javalang:Object` value required to map with the Java method parameter. +# + return - The `Map` value returning from the Java mapping. +public function Map_of10(javalang:Object arg0, javalang:Object arg1, javalang:Object arg2, javalang:Object arg3, javalang:Object arg4, javalang:Object arg5, javalang:Object arg6, javalang:Object arg7, javalang:Object arg8, javalang:Object arg9, javalang:Object arg10, javalang:Object arg11, javalang:Object arg12, javalang:Object arg13, javalang:Object arg14, javalang:Object arg15, javalang:Object arg16, javalang:Object arg17) returns Map { + handle externalObj = java_util_Map_of10(arg0.jObj, arg1.jObj, arg2.jObj, arg3.jObj, arg4.jObj, arg5.jObj, arg6.jObj, arg7.jObj, arg8.jObj, arg9.jObj, arg10.jObj, arg11.jObj, arg12.jObj, arg13.jObj, arg14.jObj, arg15.jObj, arg16.jObj, arg17.jObj); + Map newObj = new (externalObj); + return newObj; +} + +# The function that maps to the `of` method of `java.util.Map`. +# +# + arg0 - The `javalang:Object` value required to map with the Java method parameter. +# + arg1 - The `javalang:Object` value required to map with the Java method parameter. +# + arg2 - The `javalang:Object` value required to map with the Java method parameter. +# + arg3 - The `javalang:Object` value required to map with the Java method parameter. +# + arg4 - The `javalang:Object` value required to map with the Java method parameter. +# + arg5 - The `javalang:Object` value required to map with the Java method parameter. +# + arg6 - The `javalang:Object` value required to map with the Java method parameter. +# + arg7 - The `javalang:Object` value required to map with the Java method parameter. +# + arg8 - The `javalang:Object` value required to map with the Java method parameter. +# + arg9 - The `javalang:Object` value required to map with the Java method parameter. +# + arg10 - The `javalang:Object` value required to map with the Java method parameter. +# + arg11 - The `javalang:Object` value required to map with the Java method parameter. +# + arg12 - The `javalang:Object` value required to map with the Java method parameter. +# + arg13 - The `javalang:Object` value required to map with the Java method parameter. +# + arg14 - The `javalang:Object` value required to map with the Java method parameter. +# + arg15 - The `javalang:Object` value required to map with the Java method parameter. +# + arg16 - The `javalang:Object` value required to map with the Java method parameter. +# + arg17 - The `javalang:Object` value required to map with the Java method parameter. +# + arg18 - The `javalang:Object` value required to map with the Java method parameter. +# + arg19 - The `javalang:Object` value required to map with the Java method parameter. +# + return - The `Map` value returning from the Java mapping. +public function Map_of11(javalang:Object arg0, javalang:Object arg1, javalang:Object arg2, javalang:Object arg3, javalang:Object arg4, javalang:Object arg5, javalang:Object arg6, javalang:Object arg7, javalang:Object arg8, javalang:Object arg9, javalang:Object arg10, javalang:Object arg11, javalang:Object arg12, javalang:Object arg13, javalang:Object arg14, javalang:Object arg15, javalang:Object arg16, javalang:Object arg17, javalang:Object arg18, javalang:Object arg19) returns Map { + handle externalObj = java_util_Map_of11(arg0.jObj, arg1.jObj, arg2.jObj, arg3.jObj, arg4.jObj, arg5.jObj, arg6.jObj, arg7.jObj, arg8.jObj, arg9.jObj, arg10.jObj, arg11.jObj, arg12.jObj, arg13.jObj, arg14.jObj, arg15.jObj, arg16.jObj, arg17.jObj, arg18.jObj, arg19.jObj); + Map newObj = new (externalObj); + return newObj; +} + +# The function that maps to the `of` method of `java.util.Map`. +# +# + arg0 - The `javalang:Object` value required to map with the Java method parameter. +# + arg1 - The `javalang:Object` value required to map with the Java method parameter. +# + return - The `Map` value returning from the Java mapping. +public function Map_of2(javalang:Object arg0, javalang:Object arg1) returns Map { + handle externalObj = java_util_Map_of2(arg0.jObj, arg1.jObj); + Map newObj = new (externalObj); + return newObj; +} + +# The function that maps to the `of` method of `java.util.Map`. +# +# + arg0 - The `javalang:Object` value required to map with the Java method parameter. +# + arg1 - The `javalang:Object` value required to map with the Java method parameter. +# + arg2 - The `javalang:Object` value required to map with the Java method parameter. +# + arg3 - The `javalang:Object` value required to map with the Java method parameter. +# + return - The `Map` value returning from the Java mapping. +public function Map_of3(javalang:Object arg0, javalang:Object arg1, javalang:Object arg2, javalang:Object arg3) returns Map { + handle externalObj = java_util_Map_of3(arg0.jObj, arg1.jObj, arg2.jObj, arg3.jObj); + Map newObj = new (externalObj); + return newObj; +} + +# The function that maps to the `of` method of `java.util.Map`. +# +# + arg0 - The `javalang:Object` value required to map with the Java method parameter. +# + arg1 - The `javalang:Object` value required to map with the Java method parameter. +# + arg2 - The `javalang:Object` value required to map with the Java method parameter. +# + arg3 - The `javalang:Object` value required to map with the Java method parameter. +# + arg4 - The `javalang:Object` value required to map with the Java method parameter. +# + arg5 - The `javalang:Object` value required to map with the Java method parameter. +# + return - The `Map` value returning from the Java mapping. +public function Map_of4(javalang:Object arg0, javalang:Object arg1, javalang:Object arg2, javalang:Object arg3, javalang:Object arg4, javalang:Object arg5) returns Map { + handle externalObj = java_util_Map_of4(arg0.jObj, arg1.jObj, arg2.jObj, arg3.jObj, arg4.jObj, arg5.jObj); + Map newObj = new (externalObj); + return newObj; +} + +# The function that maps to the `of` method of `java.util.Map`. +# +# + arg0 - The `javalang:Object` value required to map with the Java method parameter. +# + arg1 - The `javalang:Object` value required to map with the Java method parameter. +# + arg2 - The `javalang:Object` value required to map with the Java method parameter. +# + arg3 - The `javalang:Object` value required to map with the Java method parameter. +# + arg4 - The `javalang:Object` value required to map with the Java method parameter. +# + arg5 - The `javalang:Object` value required to map with the Java method parameter. +# + arg6 - The `javalang:Object` value required to map with the Java method parameter. +# + arg7 - The `javalang:Object` value required to map with the Java method parameter. +# + return - The `Map` value returning from the Java mapping. +public function Map_of5(javalang:Object arg0, javalang:Object arg1, javalang:Object arg2, javalang:Object arg3, javalang:Object arg4, javalang:Object arg5, javalang:Object arg6, javalang:Object arg7) returns Map { + handle externalObj = java_util_Map_of5(arg0.jObj, arg1.jObj, arg2.jObj, arg3.jObj, arg4.jObj, arg5.jObj, arg6.jObj, arg7.jObj); + Map newObj = new (externalObj); + return newObj; +} + +# The function that maps to the `of` method of `java.util.Map`. +# +# + arg0 - The `javalang:Object` value required to map with the Java method parameter. +# + arg1 - The `javalang:Object` value required to map with the Java method parameter. +# + arg2 - The `javalang:Object` value required to map with the Java method parameter. +# + arg3 - The `javalang:Object` value required to map with the Java method parameter. +# + arg4 - The `javalang:Object` value required to map with the Java method parameter. +# + arg5 - The `javalang:Object` value required to map with the Java method parameter. +# + arg6 - The `javalang:Object` value required to map with the Java method parameter. +# + arg7 - The `javalang:Object` value required to map with the Java method parameter. +# + arg8 - The `javalang:Object` value required to map with the Java method parameter. +# + arg9 - The `javalang:Object` value required to map with the Java method parameter. +# + return - The `Map` value returning from the Java mapping. +public function Map_of6(javalang:Object arg0, javalang:Object arg1, javalang:Object arg2, javalang:Object arg3, javalang:Object arg4, javalang:Object arg5, javalang:Object arg6, javalang:Object arg7, javalang:Object arg8, javalang:Object arg9) returns Map { + handle externalObj = java_util_Map_of6(arg0.jObj, arg1.jObj, arg2.jObj, arg3.jObj, arg4.jObj, arg5.jObj, arg6.jObj, arg7.jObj, arg8.jObj, arg9.jObj); + Map newObj = new (externalObj); + return newObj; +} + +# The function that maps to the `of` method of `java.util.Map`. +# +# + arg0 - The `javalang:Object` value required to map with the Java method parameter. +# + arg1 - The `javalang:Object` value required to map with the Java method parameter. +# + arg2 - The `javalang:Object` value required to map with the Java method parameter. +# + arg3 - The `javalang:Object` value required to map with the Java method parameter. +# + arg4 - The `javalang:Object` value required to map with the Java method parameter. +# + arg5 - The `javalang:Object` value required to map with the Java method parameter. +# + arg6 - The `javalang:Object` value required to map with the Java method parameter. +# + arg7 - The `javalang:Object` value required to map with the Java method parameter. +# + arg8 - The `javalang:Object` value required to map with the Java method parameter. +# + arg9 - The `javalang:Object` value required to map with the Java method parameter. +# + arg10 - The `javalang:Object` value required to map with the Java method parameter. +# + arg11 - The `javalang:Object` value required to map with the Java method parameter. +# + return - The `Map` value returning from the Java mapping. +public function Map_of7(javalang:Object arg0, javalang:Object arg1, javalang:Object arg2, javalang:Object arg3, javalang:Object arg4, javalang:Object arg5, javalang:Object arg6, javalang:Object arg7, javalang:Object arg8, javalang:Object arg9, javalang:Object arg10, javalang:Object arg11) returns Map { + handle externalObj = java_util_Map_of7(arg0.jObj, arg1.jObj, arg2.jObj, arg3.jObj, arg4.jObj, arg5.jObj, arg6.jObj, arg7.jObj, arg8.jObj, arg9.jObj, arg10.jObj, arg11.jObj); + Map newObj = new (externalObj); + return newObj; +} + +# The function that maps to the `of` method of `java.util.Map`. +# +# + arg0 - The `javalang:Object` value required to map with the Java method parameter. +# + arg1 - The `javalang:Object` value required to map with the Java method parameter. +# + arg2 - The `javalang:Object` value required to map with the Java method parameter. +# + arg3 - The `javalang:Object` value required to map with the Java method parameter. +# + arg4 - The `javalang:Object` value required to map with the Java method parameter. +# + arg5 - The `javalang:Object` value required to map with the Java method parameter. +# + arg6 - The `javalang:Object` value required to map with the Java method parameter. +# + arg7 - The `javalang:Object` value required to map with the Java method parameter. +# + arg8 - The `javalang:Object` value required to map with the Java method parameter. +# + arg9 - The `javalang:Object` value required to map with the Java method parameter. +# + arg10 - The `javalang:Object` value required to map with the Java method parameter. +# + arg11 - The `javalang:Object` value required to map with the Java method parameter. +# + arg12 - The `javalang:Object` value required to map with the Java method parameter. +# + arg13 - The `javalang:Object` value required to map with the Java method parameter. +# + return - The `Map` value returning from the Java mapping. +public function Map_of8(javalang:Object arg0, javalang:Object arg1, javalang:Object arg2, javalang:Object arg3, javalang:Object arg4, javalang:Object arg5, javalang:Object arg6, javalang:Object arg7, javalang:Object arg8, javalang:Object arg9, javalang:Object arg10, javalang:Object arg11, javalang:Object arg12, javalang:Object arg13) returns Map { + handle externalObj = java_util_Map_of8(arg0.jObj, arg1.jObj, arg2.jObj, arg3.jObj, arg4.jObj, arg5.jObj, arg6.jObj, arg7.jObj, arg8.jObj, arg9.jObj, arg10.jObj, arg11.jObj, arg12.jObj, arg13.jObj); + Map newObj = new (externalObj); + return newObj; +} + +# The function that maps to the `of` method of `java.util.Map`. +# +# + arg0 - The `javalang:Object` value required to map with the Java method parameter. +# + arg1 - The `javalang:Object` value required to map with the Java method parameter. +# + arg2 - The `javalang:Object` value required to map with the Java method parameter. +# + arg3 - The `javalang:Object` value required to map with the Java method parameter. +# + arg4 - The `javalang:Object` value required to map with the Java method parameter. +# + arg5 - The `javalang:Object` value required to map with the Java method parameter. +# + arg6 - The `javalang:Object` value required to map with the Java method parameter. +# + arg7 - The `javalang:Object` value required to map with the Java method parameter. +# + arg8 - The `javalang:Object` value required to map with the Java method parameter. +# + arg9 - The `javalang:Object` value required to map with the Java method parameter. +# + arg10 - The `javalang:Object` value required to map with the Java method parameter. +# + arg11 - The `javalang:Object` value required to map with the Java method parameter. +# + arg12 - The `javalang:Object` value required to map with the Java method parameter. +# + arg13 - The `javalang:Object` value required to map with the Java method parameter. +# + arg14 - The `javalang:Object` value required to map with the Java method parameter. +# + arg15 - The `javalang:Object` value required to map with the Java method parameter. +# + return - The `Map` value returning from the Java mapping. +public function Map_of9(javalang:Object arg0, javalang:Object arg1, javalang:Object arg2, javalang:Object arg3, javalang:Object arg4, javalang:Object arg5, javalang:Object arg6, javalang:Object arg7, javalang:Object arg8, javalang:Object arg9, javalang:Object arg10, javalang:Object arg11, javalang:Object arg12, javalang:Object arg13, javalang:Object arg14, javalang:Object arg15) returns Map { + handle externalObj = java_util_Map_of9(arg0.jObj, arg1.jObj, arg2.jObj, arg3.jObj, arg4.jObj, arg5.jObj, arg6.jObj, arg7.jObj, arg8.jObj, arg9.jObj, arg10.jObj, arg11.jObj, arg12.jObj, arg13.jObj, arg14.jObj, arg15.jObj); + Map newObj = new (externalObj); + return newObj; +} + +# The function that maps to the `ofEntries` method of `java.util.Map`. +# +# + arg0 - The `Entry[]` value required to map with the Java method parameter. +# + return - The `Map` value returning from the Java mapping. +public function Map_ofEntries(Entry[] arg0) returns Map|error { + handle externalObj = java_util_Map_ofEntries(check jarrays:toHandle(arg0, "java.util.Map$Entry")); + Map newObj = new (externalObj); + return newObj; +} + +function java_util_Map_clear(handle receiver) = @java:Method { + name: "clear", + 'class: "java.util.Map", + paramTypes: [] +} external; + +function java_util_Map_compute(handle receiver, handle arg0, handle arg1) returns handle = @java:Method { + name: "compute", + 'class: "java.util.Map", + paramTypes: ["java.lang.Object", "java.util.function.BiFunction"] +} external; + +function java_util_Map_computeIfAbsent(handle receiver, handle arg0, handle arg1) returns handle = @java:Method { + name: "computeIfAbsent", + 'class: "java.util.Map", + paramTypes: ["java.lang.Object", "java.util.function.Function"] +} external; + +function java_util_Map_computeIfPresent(handle receiver, handle arg0, handle arg1) returns handle = @java:Method { + name: "computeIfPresent", + 'class: "java.util.Map", + paramTypes: ["java.lang.Object", "java.util.function.BiFunction"] +} external; + +function java_util_Map_containsKey(handle receiver, handle arg0) returns boolean = @java:Method { + name: "containsKey", + 'class: "java.util.Map", + paramTypes: ["java.lang.Object"] +} external; + +function java_util_Map_containsValue(handle receiver, handle arg0) returns boolean = @java:Method { + name: "containsValue", + 'class: "java.util.Map", + paramTypes: ["java.lang.Object"] +} external; + +function java_util_Map_copyOf(handle arg0) returns handle = @java:Method { + name: "copyOf", + 'class: "java.util.Map", + paramTypes: ["java.util.Map"] +} external; + +function java_util_Map_entry(handle arg0, handle arg1) returns handle = @java:Method { + name: "entry", + 'class: "java.util.Map", + paramTypes: ["java.lang.Object", "java.lang.Object"] +} external; + +function java_util_Map_entrySet(handle receiver) returns handle = @java:Method { + name: "entrySet", + 'class: "java.util.Map", + paramTypes: [] +} external; + +function java_util_Map_equals(handle receiver, handle arg0) returns boolean = @java:Method { + name: "equals", + 'class: "java.util.Map", + paramTypes: ["java.lang.Object"] +} external; + +function java_util_Map_forEach(handle receiver, handle arg0) = @java:Method { + name: "forEach", + 'class: "java.util.Map", + paramTypes: ["java.util.function.BiConsumer"] +} external; + +isolated function java_util_Map_get(handle receiver, handle arg0) returns handle = @java:Method { + name: "get", + 'class: "java.util.Map", + paramTypes: ["java.lang.Object"] +} external; + +function java_util_Map_getOrDefault(handle receiver, handle arg0, handle arg1) returns handle = @java:Method { + name: "getOrDefault", + 'class: "java.util.Map", + paramTypes: ["java.lang.Object", "java.lang.Object"] +} external; + +function java_util_Map_hashCode(handle receiver) returns int = @java:Method { + name: "hashCode", + 'class: "java.util.Map", + paramTypes: [] +} external; + +function java_util_Map_isEmpty(handle receiver) returns boolean = @java:Method { + name: "isEmpty", + 'class: "java.util.Map", + paramTypes: [] +} external; + +function java_util_Map_keySet(handle receiver) returns handle = @java:Method { + name: "keySet", + 'class: "java.util.Map", + paramTypes: [] +} external; + +function java_util_Map_merge(handle receiver, handle arg0, handle arg1, handle arg2) returns handle = @java:Method { + name: "merge", + 'class: "java.util.Map", + paramTypes: ["java.lang.Object", "java.lang.Object", "java.util.function.BiFunction"] +} external; + +function java_util_Map_of() returns handle = @java:Method { + name: "of", + 'class: "java.util.Map", + paramTypes: [] +} external; + +function java_util_Map_of10(handle arg0, handle arg1, handle arg2, handle arg3, handle arg4, handle arg5, handle arg6, handle arg7, handle arg8, handle arg9, handle arg10, handle arg11, handle arg12, handle arg13, handle arg14, handle arg15, handle arg16, handle arg17) returns handle = @java:Method { + name: "of", + 'class: "java.util.Map", + paramTypes: ["java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object"] +} external; + +function java_util_Map_of11(handle arg0, handle arg1, handle arg2, handle arg3, handle arg4, handle arg5, handle arg6, handle arg7, handle arg8, handle arg9, handle arg10, handle arg11, handle arg12, handle arg13, handle arg14, handle arg15, handle arg16, handle arg17, handle arg18, handle arg19) returns handle = @java:Method { + name: "of", + 'class: "java.util.Map", + paramTypes: ["java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object"] +} external; + +function java_util_Map_of2(handle arg0, handle arg1) returns handle = @java:Method { + name: "of", + 'class: "java.util.Map", + paramTypes: ["java.lang.Object", "java.lang.Object"] +} external; + +function java_util_Map_of3(handle arg0, handle arg1, handle arg2, handle arg3) returns handle = @java:Method { + name: "of", + 'class: "java.util.Map", + paramTypes: ["java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object"] +} external; + +function java_util_Map_of4(handle arg0, handle arg1, handle arg2, handle arg3, handle arg4, handle arg5) returns handle = @java:Method { + name: "of", + 'class: "java.util.Map", + paramTypes: ["java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object"] +} external; + +function java_util_Map_of5(handle arg0, handle arg1, handle arg2, handle arg3, handle arg4, handle arg5, handle arg6, handle arg7) returns handle = @java:Method { + name: "of", + 'class: "java.util.Map", + paramTypes: ["java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object"] +} external; + +function java_util_Map_of6(handle arg0, handle arg1, handle arg2, handle arg3, handle arg4, handle arg5, handle arg6, handle arg7, handle arg8, handle arg9) returns handle = @java:Method { + name: "of", + 'class: "java.util.Map", + paramTypes: ["java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object"] +} external; + +function java_util_Map_of7(handle arg0, handle arg1, handle arg2, handle arg3, handle arg4, handle arg5, handle arg6, handle arg7, handle arg8, handle arg9, handle arg10, handle arg11) returns handle = @java:Method { + name: "of", + 'class: "java.util.Map", + paramTypes: ["java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object"] +} external; + +function java_util_Map_of8(handle arg0, handle arg1, handle arg2, handle arg3, handle arg4, handle arg5, handle arg6, handle arg7, handle arg8, handle arg9, handle arg10, handle arg11, handle arg12, handle arg13) returns handle = @java:Method { + name: "of", + 'class: "java.util.Map", + paramTypes: ["java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object"] +} external; + +function java_util_Map_of9(handle arg0, handle arg1, handle arg2, handle arg3, handle arg4, handle arg5, handle arg6, handle arg7, handle arg8, handle arg9, handle arg10, handle arg11, handle arg12, handle arg13, handle arg14, handle arg15) returns handle = @java:Method { + name: "of", + 'class: "java.util.Map", + paramTypes: ["java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object", "java.lang.Object"] +} external; + +function java_util_Map_ofEntries(handle arg0) returns handle = @java:Method { + name: "ofEntries", + 'class: "java.util.Map", + paramTypes: ["[Ljava.util.Map$Entry;"] +} external; + +function java_util_Map_put(handle receiver, handle arg0, handle arg1) returns handle = @java:Method { + name: "put", + 'class: "java.util.Map", + paramTypes: ["java.lang.Object", "java.lang.Object"] +} external; + +function java_util_Map_putAll(handle receiver, handle arg0) = @java:Method { + name: "putAll", + 'class: "java.util.Map", + paramTypes: ["java.util.Map"] +} external; + +function java_util_Map_putIfAbsent(handle receiver, handle arg0, handle arg1) returns handle = @java:Method { + name: "putIfAbsent", + 'class: "java.util.Map", + paramTypes: ["java.lang.Object", "java.lang.Object"] +} external; + +function java_util_Map_remove(handle receiver, handle arg0) returns handle = @java:Method { + name: "remove", + 'class: "java.util.Map", + paramTypes: ["java.lang.Object"] +} external; + +function java_util_Map_remove2(handle receiver, handle arg0, handle arg1) returns boolean = @java:Method { + name: "remove", + 'class: "java.util.Map", + paramTypes: ["java.lang.Object", "java.lang.Object"] +} external; + +function java_util_Map_replace(handle receiver, handle arg0, handle arg1) returns handle = @java:Method { + name: "replace", + 'class: "java.util.Map", + paramTypes: ["java.lang.Object", "java.lang.Object"] +} external; + +function java_util_Map_replace2(handle receiver, handle arg0, handle arg1, handle arg2) returns boolean = @java:Method { + name: "replace", + 'class: "java.util.Map", + paramTypes: ["java.lang.Object", "java.lang.Object", "java.lang.Object"] +} external; + +function java_util_Map_replaceAll(handle receiver, handle arg0) = @java:Method { + name: "replaceAll", + 'class: "java.util.Map", + paramTypes: ["java.util.function.BiFunction"] +} external; + +function java_util_Map_size(handle receiver) returns int = @java:Method { + name: "size", + 'class: "java.util.Map", + paramTypes: [] +} external; + +function java_util_Map_values(handle receiver) returns handle = @java:Method { + name: "values", + 'class: "java.util.Map", + paramTypes: [] +} external; + diff --git a/devportal/devportal-domain-service/ballerina/modules/java.util/Set.bal b/devportal/devportal-domain-service/ballerina/modules/java.util/Set.bal new file mode 100644 index 000000000..5e8bd10a7 --- /dev/null +++ b/devportal/devportal-domain-service/ballerina/modules/java.util/Set.bal @@ -0,0 +1,38 @@ +// This is an empty Ballerina class autogenerated to represent the `java.util.Set` Java interface. +// +// If you need the implementation of this class generated, please use the following command. +// +// $ bal bindgen [(-cp|--classpath) ...] +// [(-mvn|--maven) ::] +// [(-o|--output) ] +// [--public] +// (...) +// +// E.g. $ bal bindgen java.util.Set + +import ballerina/jballerina.java; + +# Ballerina class mapping for the Java `java.util.Set` interface. +@java:Binding {'class: "java.util.Set"} +public distinct class Set { + + *java:JObject; + + # The `handle` field that stores the reference to the `java.util.Set` object. + public handle jObj; + + # The init function of the Ballerina class mapping the `java.util.Set` Java interface. + # + # + obj - The `handle` value containing the Java reference of the object. + public function init(handle obj) { + self.jObj = obj; + } + + # The function to retrieve the string representation of the Ballerina class mapping the `java.util.Set` Java interface. + # + # + return - The `string` form of the Java object instance. + public function toString() returns string { + return java:toString(self.jObj) ?: "null"; + } +} + diff --git a/devportal/devportal-domain-service/ballerina/modules/kmclient/KeymanagerClients.bal b/devportal/devportal-domain-service/ballerina/modules/kmclient/KeymanagerClients.bal new file mode 100644 index 000000000..36180cf36 --- /dev/null +++ b/devportal/devportal-domain-service/ballerina/modules/kmclient/KeymanagerClients.bal @@ -0,0 +1,10 @@ +import wso2/apk_common_lib as commons; + +# Description +public type KeyManagerClient isolated object { + public isolated function registerOauthApplication(ClientRegistrationRequest clientRegistrationRequst) returns ClientRegistrationResponse|commons:APKError; + public isolated function retrieveOauthApplicationByClientId(string clientId) returns ClientRegistrationResponse|commons:APKError; + public isolated function updateOauthApplicationByClientId(string clientId, ClientUpdateRequest clientUpdateRequest) returns ClientRegistrationResponse|commons:APKError; + public isolated function deleteOauthApplication(string clientId) returns boolean|commons:APKError; + public isolated function generateAccessToken(TokenRequest tokenRequest) returns TokenResponse|commons:APKError; +}; diff --git a/devportal/devportal-domain-service/ballerina/modules/kmclient/client.bal b/devportal/devportal-domain-service/ballerina/modules/kmclient/client.bal new file mode 100644 index 000000000..e69c61d5a --- /dev/null +++ b/devportal/devportal-domain-service/ballerina/modules/kmclient/client.bal @@ -0,0 +1,96 @@ +import ballerina/http; + +# Key Manager Proxy Service +public isolated client class Client { + final http:Client clientEp; + # Gets invoked to initialize the `connector`. + # + # + config - The configurations to be used when initializing the `connector` + # + serviceUrl - URL of the target service + # + return - An error if connector initialization failed + public isolated function init(string serviceUrl, ConnectionConfig config = {}) returns error? { + http:ClientConfiguration httpClientConfig = {httpVersion: config.httpVersion, timeout: config.timeout, forwarded: config.forwarded, poolConfig: config.poolConfig, compression: config.compression, circuitBreaker: config.circuitBreaker, retryConfig: config.retryConfig, validation: config.validation}; + do { + if config.http1Settings is ClientHttp1Settings { + ClientHttp1Settings settings = check config.http1Settings.ensureType(ClientHttp1Settings); + httpClientConfig.http1Settings = {...settings}; + } + if config.http2Settings is http:ClientHttp2Settings { + httpClientConfig.http2Settings = check config.http2Settings.ensureType(http:ClientHttp2Settings); + } + if config.cache is http:CacheConfig { + httpClientConfig.cache = check config.cache.ensureType(http:CacheConfig); + } + if config.responseLimits is http:ResponseLimitConfigs { + httpClientConfig.responseLimits = check config.responseLimits.ensureType(http:ResponseLimitConfigs); + } + if config.secureSocket is http:ClientSecureSocket { + httpClientConfig.secureSocket = check config.secureSocket.ensureType(http:ClientSecureSocket); + } + if config.proxy is http:ProxyConfig { + httpClientConfig.proxy = check config.proxy.ensureType(http:ProxyConfig); + } + } + http:Client httpEp = check new (serviceUrl, httpClientConfig); + self.clientEp = httpEp; + return; + } + # Register Client. + # + # + return - Successful operation + resource isolated function post register(ClientRegistrationRequest payload) returns ClientRegistrationResponse|error { + string resourcePath = string `/register`; + http:Request request = new; + json jsonBody = payload.toJson(); + request.setPayload(jsonBody, "application/json"); + ClientRegistrationResponse response = check self.clientEp->post(resourcePath, request); + return response; + } + # Get Client. + # + # + client_id - Client Id + # + return - Successful operation + resource isolated function get register(string client_id) returns ClientRegistrationResponse|error { + string resourcePath = string `/register/${getEncodedUri(client_id)}`; + map queryParam = {"client_id": client_id}; + resourcePath = resourcePath + check getPathForQueryParam(queryParam); + ClientRegistrationResponse response = check self.clientEp->get(resourcePath); + return response; + } + # Update Client + # + # + client_id - Client Id + # + return - Successful operation + resource isolated function put register(string client_id, ClientUpdateRequest payload) returns ClientRegistrationResponse|error { + string resourcePath = string `/register/${getEncodedUri(client_id)}`; + map queryParam = {"client_id": client_id}; + resourcePath = resourcePath + check getPathForQueryParam(queryParam); + http:Request request = new; + json jsonBody = payload.toJson(); + request.setPayload(jsonBody, "application/json"); + ClientRegistrationResponse response = check self.clientEp->put(resourcePath, request); + return response; + } + # Delete Client. + # + # + client_id - Client Id + # + return - Successful operation + resource isolated function delete register(string client_id) returns http:Response|error { + string resourcePath = string `/register/${getEncodedUri(client_id)}`; + map queryParam = {"client_id": client_id}; + resourcePath = resourcePath + check getPathForQueryParam(queryParam); + http:Response response = check self.clientEp-> delete(resourcePath); + return response; + } + # Get Token. + # + # + return - Successful operation + resource isolated function post token(TokenRequest payload) returns TokenResponse|error { + string resourcePath = string `/token`; + http:Request request = new; + string encodedRequestBody = createFormURLEncodedRequestBody(payload); + request.setPayload(encodedRequestBody, "application/x-www-form-urlencoded"); + TokenResponse response = check self.clientEp->post(resourcePath, request); + return response; + } +} diff --git a/devportal/devportal-domain-service/ballerina/modules/kmclient/types.bal b/devportal/devportal-domain-service/ballerina/modules/kmclient/types.bal new file mode 100644 index 000000000..b1f6b4b60 --- /dev/null +++ b/devportal/devportal-domain-service/ballerina/modules/kmclient/types.bal @@ -0,0 +1,124 @@ +import ballerina/http; + +# Provides a set of configurations for controlling the behaviours when communicating with a remote HTTP endpoint. +@display {label: "Connection Config"} +public type ConnectionConfig record {| + # The HTTP version understood by the client + http:HttpVersion httpVersion = http:HTTP_2_0; + # Configurations related to HTTP/1.x protocol + ClientHttp1Settings http1Settings?; + # Configurations related to HTTP/2 protocol + http:ClientHttp2Settings http2Settings?; + # The maximum time to wait (in seconds) for a response before closing the connection + decimal timeout = 60; + # The choice of setting `forwarded`/`x-forwarded` header + string forwarded = "disable"; + # Configurations associated with request pooling + http:PoolConfiguration poolConfig?; + # HTTP caching related configurations + http:CacheConfig cache?; + # Specifies the way of handling compression (`accept-encoding`) header + http:Compression compression = http:COMPRESSION_AUTO; + # Configurations associated with the behaviour of the Circuit Breaker + http:CircuitBreakerConfig circuitBreaker?; + # Configurations associated with retrying + http:RetryConfig retryConfig?; + # Configurations associated with inbound response size limits + http:ResponseLimitConfigs responseLimits?; + # SSL/TLS-related options + http:ClientSecureSocket secureSocket?; + # Proxy server related options + http:ProxyConfig proxy?; + # Enables the inbound payload validation functionality which provided by the constraint package. Enabled by default + boolean validation = true; +|}; + +# Provides settings related to HTTP/1.x protocol. +public type ClientHttp1Settings record {| + # Specifies whether to reuse a connection for multiple requests + http:KeepAlive keepAlive = http:KEEPALIVE_AUTO; + # The chunking behaviour of the request + http:Chunking chunking = http:CHUNKING_AUTO; + # Proxy server related options + ProxyConfig proxy?; +|}; + +# Proxy server configurations to be used with the HTTP client endpoint. +public type ProxyConfig record {| + # Host name of the proxy server + string host = ""; + # Proxy server port + int port = 0; + # Proxy server username + string userName = ""; + # Proxy server password + @display {label: "", kind: "password"} + string password = ""; +|}; + +public type TokenResponse record { + string access_token?; + string token_type?; + int expires_in?; + string refresh_token?; + string[] scopes?; + string id_token?; + record {} additional_properties?; +}; + +public type ErrorListItem record { + # Error code + string code; + # Description about individual errors occurred + string message; +}; + +public type ClientRegistrationResponse record { + *ClientRegistrationRequest; + string client_secret?; + string client_id?; + int client_secret_expires_at?; + string registration_access_token?; +}; + +public type TokenRequest record { + string client_id?; + string client_secret?; + string[] scopes?; +}; + +public type Error record { + # Error code + int code; + # Error message. + string message; + # A detail description about the error message. + string description?; + # Preferably an url with more details about the error. + string moreInfo?; + # If there are more than one error list them out. + # For example, list out validation errors by each field. + ErrorListItem[] 'error?; +}; + +public type ClientRegistrationRequest record { + string[] redirect_uris?; + string[] response_types?; + string[] grant_types?; + string application_type?; + string client_name?; + string logo_uri?; + string client_uri?; + string policy_uri?; + string tos_uri?; + string jwks_uri?; + string subject_type?; + string token_endpoint_auth_method?; + record {} additional_properties?; +}; + +public type ClientUpdateRequest record { + *ClientRegistrationRequest; + string client_secret?; + string client_id?; +}; diff --git a/devportal/devportal-domain-service/ballerina/modules/kmclient/utils.bal b/devportal/devportal-domain-service/ballerina/modules/kmclient/utils.bal new file mode 100644 index 000000000..538028936 --- /dev/null +++ b/devportal/devportal-domain-service/ballerina/modules/kmclient/utils.bal @@ -0,0 +1,226 @@ +import ballerina/url; + +type SimpleBasicType string|boolean|int|float|decimal; + +# Represents encoding mechanism details. +type Encoding record { + # Defines how multiple values are delimited + string style = FORM; + # Specifies whether arrays and objects should generate as separate fields + boolean explode = true; + # Specifies the custom content type + string contentType?; + # Specifies the custom headers + map headers?; +}; + +enum EncodingStyle { + DEEPOBJECT, FORM, SPACEDELIMITED, PIPEDELIMITED +} + +final Encoding & readonly defaultEncoding = {}; + +# Generate client request when the media type is given as application/x-www-form-urlencoded. +# +# + encodingMap - Includes the information about the encoding mechanism +# + anyRecord - Record to be serialized +# + return - Serialized request body or query parameter as a string +isolated function createFormURLEncodedRequestBody(record {|anydata...;|} anyRecord, map encodingMap = {}) returns string { + string[] payload = []; + foreach [string, anydata] [key, value] in anyRecord.entries() { + Encoding encodingData = encodingMap.hasKey(key) ? encodingMap.get(key) : defaultEncoding; + if value is SimpleBasicType { + payload.push(key, "=", getEncodedUri(value.toString())); + } else if value is SimpleBasicType[] { + payload.push(getSerializedArray(key, value, encodingData.style, encodingData.explode)); + } else if (value is record {}) { + if encodingData.style == DEEPOBJECT { + payload.push(getDeepObjectStyleRequest(key, value)); + } else { + payload.push(getFormStyleRequest(key, value)); + } + } else if (value is record {}[]) { + payload.push(getSerializedRecordArray(key, value, encodingData.style, encodingData.explode)); + } + payload.push("&"); + } + _ = payload.pop(); + return string:'join("", ...payload); +} + +# Serialize the record according to the deepObject style. +# +# + parent - Parent record name +# + anyRecord - Record to be serialized +# + return - Serialized record as a string +isolated function getDeepObjectStyleRequest(string parent, record {} anyRecord) returns string { + string[] recordArray = []; + foreach [string, anydata] [key, value] in anyRecord.entries() { + if value is SimpleBasicType { + recordArray.push(parent + "[" + key + "]" + "=" + getEncodedUri(value.toString())); + } else if value is SimpleBasicType[] { + recordArray.push(getSerializedArray(parent + "[" + key + "]" + "[]", value, DEEPOBJECT, true)); + } else if value is record {} { + string nextParent = parent + "[" + key + "]"; + recordArray.push(getDeepObjectStyleRequest(nextParent, value)); + } else if value is record {}[] { + string nextParent = parent + "[" + key + "]"; + recordArray.push(getSerializedRecordArray(nextParent, value, DEEPOBJECT)); + } + recordArray.push("&"); + } + _ = recordArray.pop(); + return string:'join("", ...recordArray); +} + +# Serialize the record according to the form style. +# +# + parent - Parent record name +# + anyRecord - Record to be serialized +# + explode - Specifies whether arrays and objects should generate separate parameters +# + return - Serialized record as a string +isolated function getFormStyleRequest(string parent, record {} anyRecord, boolean explode = true) returns string { + string[] recordArray = []; + if explode { + foreach [string, anydata] [key, value] in anyRecord.entries() { + if (value is SimpleBasicType) { + recordArray.push(key, "=", getEncodedUri(value.toString())); + } else if (value is SimpleBasicType[]) { + recordArray.push(getSerializedArray(key, value, explode = explode)); + } else if (value is record {}) { + recordArray.push(getFormStyleRequest(parent, value, explode)); + } + recordArray.push("&"); + } + _ = recordArray.pop(); + } else { + foreach [string, anydata] [key, value] in anyRecord.entries() { + if (value is SimpleBasicType) { + recordArray.push(key, ",", getEncodedUri(value.toString())); + } else if (value is SimpleBasicType[]) { + recordArray.push(getSerializedArray(key, value, explode = false)); + } else if (value is record {}) { + recordArray.push(getFormStyleRequest(parent, value, explode)); + } + recordArray.push(","); + } + _ = recordArray.pop(); + } + return string:'join("", ...recordArray); +} + +# Serialize arrays. +# +# + arrayName - Name of the field with arrays +# + anyArray - Array to be serialized +# + style - Defines how multiple values are delimited +# + explode - Specifies whether arrays and objects should generate separate parameters +# + return - Serialized array as a string +isolated function getSerializedArray(string arrayName, anydata[] anyArray, string style = "form", boolean explode = true) returns string { + string key = arrayName; + string[] arrayValues = []; + if (anyArray.length() > 0) { + if (style == FORM && !explode) { + arrayValues.push(key, "="); + foreach anydata i in anyArray { + arrayValues.push(getEncodedUri(i.toString()), ","); + } + } else if (style == SPACEDELIMITED && !explode) { + arrayValues.push(key, "="); + foreach anydata i in anyArray { + arrayValues.push(getEncodedUri(i.toString()), "%20"); + } + } else if (style == PIPEDELIMITED && !explode) { + arrayValues.push(key, "="); + foreach anydata i in anyArray { + arrayValues.push(getEncodedUri(i.toString()), "|"); + } + } else if (style == DEEPOBJECT) { + foreach anydata i in anyArray { + arrayValues.push(key, "[]", "=", getEncodedUri(i.toString()), "&"); + } + } else { + foreach anydata i in anyArray { + arrayValues.push(key, "=", getEncodedUri(i.toString()), "&"); + } + } + _ = arrayValues.pop(); + } + return string:'join("", ...arrayValues); +} + +# Serialize the array of records according to the form style. +# +# + parent - Parent record name +# + value - Array of records to be serialized +# + style - Defines how multiple values are delimited +# + explode - Specifies whether arrays and objects should generate separate parameters +# + return - Serialized record as a string +isolated function getSerializedRecordArray(string parent, record {}[] value, string style = FORM, boolean explode = true) returns string { + string[] serializedArray = []; + if style == DEEPOBJECT { + int arayIndex = 0; + foreach var recordItem in value { + serializedArray.push(getDeepObjectStyleRequest(parent + "[" + arayIndex.toString() + "]", recordItem), "&"); + arayIndex = arayIndex + 1; + } + } else { + if (!explode) { + serializedArray.push(parent, "="); + } + foreach var recordItem in value { + serializedArray.push(getFormStyleRequest(parent, recordItem, explode), ","); + } + } + _ = serializedArray.pop(); + return string:'join("", ...serializedArray); +} + +# Get Encoded URI for a given value. +# +# + value - Value to be encoded +# + return - Encoded string +isolated function getEncodedUri(anydata value) returns string { + string|error encoded = url:encode(value.toString(), "UTF8"); + if (encoded is string) { + return encoded; + } else { + return value.toString(); + } +} + +# Generate query path with query parameter. +# +# + queryParam - Query parameter map +# + encodingMap - Details on serialization mechanism +# + return - Returns generated Path or error at failure of client initialization +isolated function getPathForQueryParam(map queryParam, map encodingMap = {}) returns string|error { + string[] param = []; + if (queryParam.length() > 0) { + param.push("?"); + foreach var [key, value] in queryParam.entries() { + if value is () { + _ = queryParam.remove(key); + continue; + } + Encoding encodingData = encodingMap.hasKey(key) ? encodingMap.get(key) : defaultEncoding; + if (value is SimpleBasicType) { + param.push(key, "=", getEncodedUri(value.toString())); + } else if (value is SimpleBasicType[]) { + param.push(getSerializedArray(key, value, encodingData.style, encodingData.explode)); + } else if (value is record {}) { + if (encodingData.style == DEEPOBJECT) { + param.push(getDeepObjectStyleRequest(key, value)); + } else { + param.push(getFormStyleRequest(key, value, encodingData.explode)); + } + } else { + param.push(key, "=", value.toString()); + } + param.push("&"); + } + _ = param.pop(); + } + string restOfPath = string:'join("", ...param); + return restOfPath; +} diff --git a/devportal/devportal-domain-service/ballerina/modules/nonprodidp/NonProdIdpKeyManagerClient.bal b/devportal/devportal-domain-service/ballerina/modules/nonprodidp/NonProdIdpKeyManagerClient.bal new file mode 100644 index 000000000..322d011ca --- /dev/null +++ b/devportal/devportal-domain-service/ballerina/modules/nonprodidp/NonProdIdpKeyManagerClient.bal @@ -0,0 +1,161 @@ +import devportal_service.types; +import wso2/apk_common_lib as commons; +import ballerina/log; +import ballerina/http; +import ballerina/regex; +import devportal_service.kmclient; + +public isolated class NonProdIdpKeyManagerClient { + *kmclient:KeyManagerClient; + private final Client dcrClient; + private final http:Client tokenClient; + public isolated function init(types:KeyManager keyManager) returns commons:APKError? { + do { + map endpoints = keyManager.endpoints; + string dcrEndpoint = ""; + string tokenEndpoint = ""; + string username; + string password; + if endpoints.hasKey("dcr_endpoint") { + dcrEndpoint = endpoints.get("dcr_endpoint"); + } else { + return error("DCR endpoint is not defined", code = 900960, message = "DCR endpoint is not defined", description = "DCR endpoint is not defined", statusCode = 400); + } + if endpoints.hasKey("token_endpoint") { + tokenEndpoint = endpoints.get("token_endpoint"); + } else { + return error("Token endpoint is not defined", code = 900960, message = "Token endpoint is not defined", description = "Token endpoint is not defined", statusCode = 400); + } + record {}? additionalProperties = keyManager.additionalProperties; + if additionalProperties is record {} { + if additionalProperties.hasKey("username") { + username = additionalProperties.get("username"); + } else { + return error("Username is not defined", code = 900960, message = "Username is not defined", description = "Username is not defined", statusCode = 400); + } + if additionalProperties.hasKey("password") { + password = additionalProperties.get("password"); + } else { + return error("Password is not defined", code = 900960, message = "Password is not defined", description = "Password is not defined", statusCode = 400); + } + } else { + return error("Additional properties are not defined", code = 900960, message = "Additional properties are not defined", description = "Additional properties are not defined", statusCode = 400); + } + ConnectionConfig connectionConfig = {clientAuth: {username: username, password: password}, secureSocket: {enable: false}}; + self.dcrClient = check new (dcrEndpoint, connectionConfig); + self.tokenClient = check new (tokenEndpoint, secureSocket = {enable: false}); + } on fail var e { + log:printError("Error while initializing the DCR client", e); + return error("Internal Server Error", e, code = 900901, message = "Internal Server Error", description = "Internal Server Error", statusCode = 500); + } + + } + public isolated function registerOauthApplication(kmclient:ClientRegistrationRequest clientRegistrationRequst) returns kmclient:ClientRegistrationResponse|commons:APKError { + RegistrationRequest registrationRequest = { + client_name: clientRegistrationRequst.client_name, + grant_types: clientRegistrationRequst.grant_types, + redirect_uris: clientRegistrationRequst.redirect_uris + }; + Application|error applicationResult = self.dcrClient->/register.post(registrationRequest); + if applicationResult is Application { + kmclient:ClientRegistrationResponse clientRegistrationResponse = { + client_id: applicationResult.client_id, + client_secret: applicationResult.client_secret, + grant_types: applicationResult.grant_types, + redirect_uris: applicationResult.redirect_uris + }; + return clientRegistrationResponse; + } else { + commons:APKError apkError = error("Error while registering the application", applicationResult, code = 900960, message = "Error while registering the application", description = "Error while registering the application", statusCode = 500); + return apkError; + } + } + + public isolated function retrieveOauthApplicationByClientId(string clientId) returns kmclient:ClientRegistrationResponse|commons:APKError { + Application|error retrievedApplication = self.dcrClient->/register/[clientId]; + if retrievedApplication is Application { + kmclient:ClientRegistrationResponse clientRegistrationResponse = { + client_id: retrievedApplication.client_id, + client_secret: retrievedApplication.client_secret, + grant_types: retrievedApplication.grant_types, + redirect_uris: retrievedApplication.redirect_uris + }; + return clientRegistrationResponse; + } else { + commons:APKError apkError = error("Error while retrieving the application", retrievedApplication, code = 900960, message = "Error while retrieving the application", description = "Error while retrieving the application", statusCode = 500); + return apkError; + } + } + + public isolated function updateOauthApplicationByClientId(string clientId, kmclient:ClientUpdateRequest clientUpdateRequest) returns kmclient:ClientRegistrationResponse|commons:APKError { + UpdateRequest updateRequest = {client_name: clientUpdateRequest.client_name, redirect_uris: clientUpdateRequest.redirect_uris, grant_types: clientUpdateRequest.grant_types}; + Application|error updatedApplication = self.dcrClient->/register/[clientId].put(updateRequest); + if updatedApplication is Application { + return { + client_id: updatedApplication.client_id, + client_secret: updatedApplication.client_secret, + grant_types: updatedApplication.grant_types, + redirect_uris: updatedApplication.redirect_uris + }; + + } else { + commons:APKError apkError = error("Error while updating the application", updatedApplication, code = 900960, message = "Error while updating the application", description = "Error while updating the application", statusCode = 500); + return apkError; + } + } + + public isolated function deleteOauthApplication(string clientId) returns boolean|commons:APKError { + http:Response|error deletionResponse = self.dcrClient->/register/[clientId].delete; + if deletionResponse is http:Response { + if (deletionResponse.statusCode == 204) { + return true; + } else { + commons:APKError apkError = error("Error while deleting the application", code = 900960, message = "Error while deleting the application", description = "Error while deleting the application", statusCode = 500); + return apkError; + } + } else { + commons:APKError apkError = error("Error while deleting the application", deletionResponse, code = 900960, message = "Error while deleting the application", description = "Error while deleting the application", statusCode = 500); + return apkError; + } + } + + public isolated function generateAccessToken(kmclient:TokenRequest tokenRequest) returns kmclient:TokenResponse|commons:APKError { + do { + string resourcePath = string `/`; + string collonSeperatedValue = tokenRequest.client_id + ":" + tokenRequest.client_secret; + byte[] bytes = collonSeperatedValue.toBytes(); + string authorizationHeaderValue = bytes.toBase64(); + map httpHeaders = { + "Authorization": "Basic " + authorizationHeaderValue, + "Content-Type": "application/x-www-form-urlencoded" + }; + http:Request request = new; + record {} payload = {"grant_type": "client_credentials", "scope": string:'join(" ", ...tokenRequest.scopes ?: ["default"])}; + string encodedRequestBody = createFormURLEncodedRequestBody(payload); + request.setPayload(encodedRequestBody, "application/x-www-form-urlencoded"); + http:Response httpResponse = check self.tokenClient->post(resourcePath, request, httpHeaders); + if httpResponse.statusCode == http:STATUS_OK { + json jsonPayload = check httpResponse.getJsonPayload(); + kmclient:TokenResponse tokenResponse = {}; + string? accessToken = check jsonPayload?.access_token; + string? refreshToken = check jsonPayload?.refresh_token; + string? tokenType = check jsonPayload?.token_type; + int? expiresIn = check jsonPayload?.expires_in; + string? scopes = check jsonPayload?.scope; + tokenResponse.access_token = accessToken; + tokenResponse.refresh_token = refreshToken; + tokenResponse.token_type = tokenType; + tokenResponse.expires_in = expiresIn; + if scopes is string { + tokenResponse.scopes = regex:split(scopes, ","); + } + return tokenResponse; + } else { + log:printError("Error while generating the access token", statusCode = httpResponse.statusCode); + return error("Internal Server Error", code = 900901, message = "Internal Server Error", description = "Internal Server Error", statusCode = 500); + } + } on fail var e { + return error("Internal Server Error", e, code = 900901, message = "Internal Server Error", description = "Internal Server Error", statusCode = 500); + } + } +} diff --git a/devportal/devportal-domain-service/ballerina/modules/nonprodidp/client.bal b/devportal/devportal-domain-service/ballerina/modules/nonprodidp/client.bal new file mode 100644 index 000000000..581bc6f29 --- /dev/null +++ b/devportal/devportal-domain-service/ballerina/modules/nonprodidp/client.bal @@ -0,0 +1,84 @@ +import ballerina/http; + +# DCR API +public isolated client class Client { + final http:Client clientEp; + # Gets invoked to initialize the `connector`. + # + # + config - The configurations to be used when initializing the `connector` + # + serviceUrl - URL of the target service + # + return - An error if connector initialization failed + public isolated function init(string serviceUrl, ConnectionConfig config = {}) returns error? { + http:ClientConfiguration httpClientConfig = {httpVersion: config.httpVersion, timeout: config.timeout, forwarded: config.forwarded, poolConfig: config.poolConfig, compression: config.compression, circuitBreaker: config.circuitBreaker, retryConfig: config.retryConfig, validation: config.validation}; + do { + if config.http1Settings is ClientHttp1Settings { + ClientHttp1Settings settings = check config.http1Settings.ensureType(ClientHttp1Settings); + httpClientConfig.http1Settings = {...settings}; + } + if config.http2Settings is http:ClientHttp2Settings { + httpClientConfig.http2Settings = check config.http2Settings.ensureType(http:ClientHttp2Settings); + } + if config.cache is http:CacheConfig { + httpClientConfig.cache = check config.cache.ensureType(http:CacheConfig); + } + if config.responseLimits is http:ResponseLimitConfigs { + httpClientConfig.responseLimits = check config.responseLimits.ensureType(http:ResponseLimitConfigs); + } + if config.secureSocket is http:ClientSecureSocket { + httpClientConfig.secureSocket = check config.secureSocket.ensureType(http:ClientSecureSocket); + } + if config.proxy is http:ProxyConfig { + httpClientConfig.proxy = check config.proxy.ensureType(http:ProxyConfig); + } + if config.clientAuth is http:ClientAuthConfig { + httpClientConfig.auth = check config.clientAuth.ensureType(http:ClientAuthConfig); + } + } + http:Client httpEp = check new (serviceUrl, httpClientConfig); + self.clientEp = httpEp; + return; + } + # Registers an OAuth2 application + # + # + payload - Application information to register. + # + return - Created + resource isolated function post register(RegistrationRequest payload) returns Application|error { + string resourcePath = string `/register`; + http:Request request = new; + json jsonBody = payload.toJson(); + request.setPayload(jsonBody, "application/json"); + Application response = check self.clientEp->post(resourcePath, request); + return response; + } + # Get OAuth2 application information + # + # + client_id - Unique identifier of the OAuth2 client application. + # + return - Successfully Retrieved + resource isolated function get register/[string client_id]() returns Application|error { + string resourcePath = string `/register/${getEncodedUri(client_id)}`; + Application response = check self.clientEp->get(resourcePath); + return response; + } + # Updates an OAuth2 application + # + # + client_id - Unique identifier for the OAuth2 client application. + # + payload - Application information to update. + # + return - Successfully updated + resource isolated function put register/[string client_id](UpdateRequest payload) returns Application|error { + string resourcePath = string `/register/${getEncodedUri(client_id)}`; + http:Request request = new; + json jsonBody = payload.toJson(); + request.setPayload(jsonBody, "application/json"); + Application response = check self.clientEp->put(resourcePath, request); + return response; + } + # Delete OAuth2 application + # + # + client_id - Unique identifier of the OAuth2 client application. + # + return - Successfully deleted + resource isolated function delete register/[string client_id]() returns http:Response|error { + string resourcePath = string `/register/${getEncodedUri(client_id)}`; + http:Response response = check self.clientEp-> delete(resourcePath); + return response; + } +} diff --git a/devportal/devportal-domain-service/ballerina/modules/nonprodidp/types.bal b/devportal/devportal-domain-service/ballerina/modules/nonprodidp/types.bal new file mode 100644 index 000000000..cc1b9458d --- /dev/null +++ b/devportal/devportal-domain-service/ballerina/modules/nonprodidp/types.bal @@ -0,0 +1,146 @@ +import ballerina/http; + +# Provides a set of configurations for controlling the behaviours when communicating with a remote HTTP endpoint. +# +# + httpVersion - Field Description +# + http1Settings - Field Description +# + http2Settings - Field Description +# + timeout - Field Description +# + forwarded - Field Description +# + poolConfig - Field Description +# + cache - Field Description +# + compression - Field Description +# + circuitBreaker - Field Description +# + retryConfig - Field Description +# + responseLimits - Field Description +# + secureSocket - Field Description +# + proxy - Field Description +# + validation - Field Description +# + clientAuth - Field Description +@display {label: "Connection Config"} +public type ConnectionConfig record {| + # The HTTP version understood by the client + http:HttpVersion httpVersion = http:HTTP_2_0; + # Configurations related to HTTP/1.x protocol + ClientHttp1Settings http1Settings?; + # Configurations related to HTTP/2 protocol + http:ClientHttp2Settings http2Settings?; + # The maximum time to wait (in seconds) for a response before closing the connection + decimal timeout = 60; + # The choice of setting `forwarded`/`x-forwarded` header + string forwarded = "disable"; + # Configurations associated with request pooling + http:PoolConfiguration poolConfig?; + # HTTP caching related configurations + http:CacheConfig cache?; + # Specifies the way of handling compression (`accept-encoding`) header + http:Compression compression = http:COMPRESSION_AUTO; + # Configurations associated with the behaviour of the Circuit Breaker + http:CircuitBreakerConfig circuitBreaker?; + # Configurations associated with retrying + http:RetryConfig retryConfig?; + # Configurations associated with inbound response size limits + http:ResponseLimitConfigs responseLimits?; + # SSL/TLS-related options + http:ClientSecureSocket secureSocket?; + # Proxy server related options + http:ProxyConfig proxy?; + # Enables the inbound payload validation functionality which provided by the constraint package. Enabled by default + boolean validation = true; + http:ClientAuthConfig clientAuth?; +|}; + +# Provides settings related to HTTP/1.x protocol. +public type ClientHttp1Settings record {| + # Specifies whether to reuse a connection for multiple requests + http:KeepAlive keepAlive = http:KEEPALIVE_AUTO; + # The chunking behaviour of the request + http:Chunking chunking = http:CHUNKING_AUTO; + # Proxy server related options + ProxyConfig proxy?; +|}; + +# Proxy server configurations to be used with the HTTP client endpoint. +public type ProxyConfig record {| + # Host name of the proxy server + string host = ""; + # Proxy server port + int port = 0; + # Proxy server username + string userName = ""; + # Proxy server password + @display {label: "", kind: "password"} + string password = ""; +|}; + +public type TokenErrorResponse record { + # Error code classifying the type of preProcessingError. + string preProcessingError; +}; + +public type TokenResponse record { + # OAuth access tokn issues by authorization server. + string access_token; + # The type of the token issued. + string token_type; + # The lifetime in seconds of the access token. + int expires_in?; + # OPTIONAL. + # The refresh token, which can be used to obtain new access tokens. + string refresh_token?; + # The scope of the access token requested. + string scope?; +}; + +public type ClientRegistrationError record { + string 'error?; + string error_description?; +}; + +public type UpdateRequest record { + string[] redirect_uris?; + string client_name?; + string[] grant_types?; +}; + +public type JWKList_keys record { + string kid?; + string kty?; + string use?; + string[] key_ops?; + string alg?; + string x5u?; + string[] x5c?; + string x5t?; + string 'x5t\#S256?; + string e?; + string n?; + string x?; + string y?; + string d?; + string p?; + string q?; + string dp?; + string dq?; + string qi?; + string k?; +}; + +public type JWKList record { + JWKList_keys keys?; +}; + +public type RegistrationRequest record { + string[] redirect_uris?; + string client_name?; + string[] grant_types?; +}; + +public type Application record { + string client_id?; + string client_secret?; + string[] redirect_uris?; + string[] grant_types?; + string client_name?; + int client_secret_expires_at?; +}; diff --git a/devportal/devportal-domain-service/ballerina/modules/nonprodidp/utils.bal b/devportal/devportal-domain-service/ballerina/modules/nonprodidp/utils.bal new file mode 100644 index 000000000..31c60620d --- /dev/null +++ b/devportal/devportal-domain-service/ballerina/modules/nonprodidp/utils.bal @@ -0,0 +1,227 @@ +import ballerina/url; + +# Get Encoded URI for a given value. +# +# + value - Value to be encoded +# + return - Encoded string +isolated function getEncodedUri(anydata value) returns string { + string|error encoded = url:encode(value.toString(), "UTF8"); + if (encoded is string) { + return encoded; + } else { + return value.toString(); + } +} + +type SimpleBasicType string|boolean|int|float|decimal; + +# Represents encoding mechanism details. +type Encoding record { + # Defines how multiple values are delimited + string style = FORM; + # Specifies whether arrays and objects should generate as separate fields + boolean explode = true; + # Specifies the custom content type + string contentType?; + # Specifies the custom headers + map headers?; +}; + +enum EncodingStyle { + DEEPOBJECT, FORM, SPACEDELIMITED, PIPEDELIMITED +} + +final Encoding & readonly defaultEncoding = {}; + +# Generate client request when the media type is given as application/x-www-form-urlencoded. +# +# + encodingMap - Includes the information about the encoding mechanism +# + anyRecord - Record to be serialized +# + return - Serialized request body or query parameter as a string +isolated function createFormURLEncodedRequestBody(record {|anydata...;|} anyRecord, map encodingMap = {}) returns string { + string[] payload = []; + foreach [string, anydata] [key, value] in anyRecord.entries() { + Encoding encodingData = encodingMap.hasKey(key) ? encodingMap.get(key) : defaultEncoding; + if value is SimpleBasicType { + payload.push(key, "=", getEncodedUri(value.toString())); + } else if value is SimpleBasicType[] { + payload.push(getSerializedArray(key, value, encodingData.style, encodingData.explode)); + } else if (value is record {}) { + if encodingData.style == DEEPOBJECT { + payload.push(getDeepObjectStyleRequest(key, value)); + } else { + payload.push(getFormStyleRequest(key, value)); + } + } else if (value is record {}[]) { + payload.push(getSerializedRecordArray(key, value, encodingData.style, encodingData.explode)); + } + payload.push("&"); + } + _ = payload.pop(); + return string:'join("", ...payload); +} + +# Serialize the record according to the deepObject style. +# +# + parent - Parent record name +# + anyRecord - Record to be serialized +# + return - Serialized record as a string +isolated function getDeepObjectStyleRequest(string parent, record {} anyRecord) returns string { + string[] recordArray = []; + foreach [string, anydata] [key, value] in anyRecord.entries() { + if value is SimpleBasicType { + recordArray.push(parent + "[" + key + "]" + "=" + getEncodedUri(value.toString())); + } else if value is SimpleBasicType[] { + recordArray.push(getSerializedArray(parent + "[" + key + "]" + "[]", value, DEEPOBJECT, true)); + } else if value is record {} { + string nextParent = parent + "[" + key + "]"; + recordArray.push(getDeepObjectStyleRequest(nextParent, value)); + } else if value is record {}[] { + string nextParent = parent + "[" + key + "]"; + recordArray.push(getSerializedRecordArray(nextParent, value, DEEPOBJECT)); + } + recordArray.push("&"); + } + _ = recordArray.pop(); + return string:'join("", ...recordArray); +} + +# Serialize the record according to the form style. +# +# + parent - Parent record name +# + anyRecord - Record to be serialized +# + explode - Specifies whether arrays and objects should generate separate parameters +# + return - Serialized record as a string +isolated function getFormStyleRequest(string parent, record {} anyRecord, boolean explode = true) returns string { + string[] recordArray = []; + if explode { + foreach [string, anydata] [key, value] in anyRecord.entries() { + if (value is SimpleBasicType) { + recordArray.push(key, "=", getEncodedUri(value.toString())); + } else if (value is SimpleBasicType[]) { + recordArray.push(getSerializedArray(key, value, explode = explode)); + } else if (value is record {}) { + recordArray.push(getFormStyleRequest(parent, value, explode)); + } + recordArray.push("&"); + } + _ = recordArray.pop(); + } else { + foreach [string, anydata] [key, value] in anyRecord.entries() { + if (value is SimpleBasicType) { + recordArray.push(key, ",", getEncodedUri(value.toString())); + } else if (value is SimpleBasicType[]) { + recordArray.push(getSerializedArray(key, value, explode = false)); + } else if (value is record {}) { + recordArray.push(getFormStyleRequest(parent, value, explode)); + } + recordArray.push(","); + } + _ = recordArray.pop(); + } + return string:'join("", ...recordArray); +} + +# Serialize arrays. +# +# + arrayName - Name of the field with arrays +# + anyArray - Array to be serialized +# + style - Defines how multiple values are delimited +# + explode - Specifies whether arrays and objects should generate separate parameters +# + return - Serialized array as a string +isolated function getSerializedArray(string arrayName, anydata[] anyArray, string style = "form", boolean explode = true) returns string { + string key = arrayName; + string[] arrayValues = []; + if (anyArray.length() > 0) { + if (style == FORM && !explode) { + arrayValues.push(key, "="); + foreach anydata i in anyArray { + arrayValues.push(getEncodedUri(i.toString()), ","); + } + } else if (style == SPACEDELIMITED && !explode) { + arrayValues.push(key, "="); + foreach anydata i in anyArray { + arrayValues.push(getEncodedUri(i.toString()), "%20"); + } + } else if (style == PIPEDELIMITED && !explode) { + arrayValues.push(key, "="); + foreach anydata i in anyArray { + arrayValues.push(getEncodedUri(i.toString()), "|"); + } + } else if (style == DEEPOBJECT) { + foreach anydata i in anyArray { + arrayValues.push(key, "[]", "=", getEncodedUri(i.toString()), "&"); + } + } else { + foreach anydata i in anyArray { + arrayValues.push(key, "=", getEncodedUri(i.toString()), "&"); + } + } + _ = arrayValues.pop(); + } + return string:'join("", ...arrayValues); +} + +# Serialize the array of records according to the form style. +# +# + parent - Parent record name +# + value - Array of records to be serialized +# + style - Defines how multiple values are delimited +# + explode - Specifies whether arrays and objects should generate separate parameters +# + return - Serialized record as a string +isolated function getSerializedRecordArray(string parent, record {}[] value, string style = FORM, boolean explode = true) returns string { + string[] serializedArray = []; + if style == DEEPOBJECT { + int arayIndex = 0; + foreach var recordItem in value { + serializedArray.push(getDeepObjectStyleRequest(parent + "[" + arayIndex.toString() + "]", recordItem), "&"); + arayIndex = arayIndex + 1; + } + } else { + if (!explode) { + serializedArray.push(parent, "="); + } + foreach var recordItem in value { + serializedArray.push(getFormStyleRequest(parent, recordItem, explode), ","); + } + } + _ = serializedArray.pop(); + return string:'join("", ...serializedArray); +} + + +# Generate query path with query parameter. +# +# + queryParam - Query parameter map +# + encodingMap - Details on serialization mechanism +# + return - Returns generated Path or error at failure of client initialization +isolated function getPathForQueryParam(map queryParam, map encodingMap = {}) returns string|error { + string[] param = []; + if (queryParam.length() > 0) { + param.push("?"); + foreach var [key, value] in queryParam.entries() { + if value is () { + _ = queryParam.remove(key); + continue; + } + Encoding encodingData = encodingMap.hasKey(key) ? encodingMap.get(key) : defaultEncoding; + if (value is SimpleBasicType) { + param.push(key, "=", getEncodedUri(value.toString())); + } else if (value is SimpleBasicType[]) { + param.push(getSerializedArray(key, value, encodingData.style, encodingData.explode)); + } else if (value is record {}) { + if (encodingData.style == DEEPOBJECT) { + param.push(getDeepObjectStyleRequest(key, value)); + } else { + param.push(getFormStyleRequest(key, value, encodingData.explode)); + } + } else { + param.push(key, "=", value.toString()); + } + param.push("&"); + } + _ = param.pop(); + } + string restOfPath = string:'join("", ...param); + return restOfPath; +} diff --git a/devportal/devportal-domain-service/ballerina/modules/org.wso2.apk.devportal.sdk/APIClientGenerationException.bal b/devportal/devportal-domain-service/ballerina/modules/org.wso2.apk.devportal.sdk/APIClientGenerationException.bal new file mode 100644 index 000000000..8f5173e24 --- /dev/null +++ b/devportal/devportal-domain-service/ballerina/modules/org.wso2.apk.devportal.sdk/APIClientGenerationException.bal @@ -0,0 +1,10 @@ +// Ballerina error type for `org.wso2.apk.devportal.sdk.APIClientGenerationException`. + +public const APICLIENTGENERATIONEXCEPTION = "APIClientGenerationException"; + +type APIClientGenerationExceptionData record { + string message; +}; + +public type APIClientGenerationException distinct error; + diff --git a/devportal/devportal-domain-service/ballerina/modules/org.wso2.apk.devportal.sdk/APIClientGenerationManager.bal b/devportal/devportal-domain-service/ballerina/modules/org.wso2.apk.devportal.sdk/APIClientGenerationManager.bal new file mode 100644 index 000000000..c5448a444 --- /dev/null +++ b/devportal/devportal-domain-service/ballerina/modules/org.wso2.apk.devportal.sdk/APIClientGenerationManager.bal @@ -0,0 +1,215 @@ +import ballerina/jballerina.java; +import devportal_service.java.lang as javalang; +import devportal_service.java.util as javautil; + +# Ballerina class mapping for the Java `org.wso2.apk.devportal.sdk.APIClientGenerationManager` class. +@java:Binding {'class: "org.wso2.apk.devportal.sdk.APIClientGenerationManager"} +public distinct class APIClientGenerationManager { + + *java:JObject; + *javalang:Object; + + # The `handle` field that stores the reference to the `org.wso2.apk.devportal.sdk.APIClientGenerationManager` object. + public handle jObj; + + # The init function of the Ballerina class mapping the `org.wso2.apk.devportal.sdk.APIClientGenerationManager` Java class. + # + # + obj - The `handle` value containing the Java reference of the object. + public isolated function init(handle obj) { + self.jObj = obj; + } + + # The function to retrieve the string representation of the Ballerina class mapping the `org.wso2.apk.devportal.sdk.APIClientGenerationManager` Java class. + # + # + return - The `string` form of the Java object instance. + public function toString() returns string { + return java:toString(self.jObj) ?: "null"; + } + # The function that maps to the `cleanTempDirectory` method of `org.wso2.apk.devportal.sdk.APIClientGenerationManager`. + # + # + arg0 - The `string` value required to map with the Java method parameter. + public function cleanTempDirectory(string arg0) { + org_wso2_apk_devportal_sdk_APIClientGenerationManager_cleanTempDirectory(self.jObj, java:fromString(arg0)); + } + + # The function that maps to the `equals` method of `org.wso2.apk.devportal.sdk.APIClientGenerationManager`. + # + # + arg0 - The `javalang:Object` value required to map with the Java method parameter. + # + return - The `boolean` value returning from the Java mapping. + public function 'equals(javalang:Object arg0) returns boolean { + return org_wso2_apk_devportal_sdk_APIClientGenerationManager_equals(self.jObj, arg0.jObj); + } + + # The function that maps to the `generateSDK` method of `org.wso2.apk.devportal.sdk.APIClientGenerationManager`. + # + # + arg0 - The `string` value required to map with the Java method parameter. + # + arg1 - The `string` value required to map with the Java method parameter. + # + arg2 - The `string` value required to map with the Java method parameter. + # + arg3 - The `string` value required to map with the Java method parameter. + # + arg4 - The `string` value required to map with the Java method parameter. + # + arg5 - The `string` value required to map with the Java method parameter. + # + arg6 - The `string` value required to map with the Java method parameter. + # + arg7 - The `string` value required to map with the Java method parameter. + # + return - The `javautil:Map` or the `APIClientGenerationException` value returning from the Java mapping. + public isolated function generateSDK(string arg0, string arg1, string arg2, string arg3, string arg4, string arg5, string arg6, string arg7) returns javautil:Map|APIClientGenerationException { + handle|error externalObj = org_wso2_apk_devportal_sdk_APIClientGenerationManager_generateSDK(self.jObj, java:fromString(arg0), java:fromString(arg1), java:fromString(arg2), java:fromString(arg3), java:fromString(arg4), java:fromString(arg5), java:fromString(arg6), java:fromString(arg7)); + if (externalObj is error) { + APIClientGenerationException e = error APIClientGenerationException(APICLIENTGENERATIONEXCEPTION, externalObj, message = externalObj.message()); + return e; + } else { + javautil:Map newObj = new (externalObj); + return newObj; + } + } + + # The function that maps to the `getClass` method of `org.wso2.apk.devportal.sdk.APIClientGenerationManager`. + # + # + return - The `javalang:Class` value returning from the Java mapping. + public function getClass() returns javalang:Class { + handle externalObj = org_wso2_apk_devportal_sdk_APIClientGenerationManager_getClass(self.jObj); + javalang:Class newObj = new (externalObj); + return newObj; + } + + # The function that maps to the `getSupportedSDKLanguages` method of `org.wso2.apk.devportal.sdk.APIClientGenerationManager`. + # + # + return - The `string` value returning from the Java mapping. + public isolated function getSupportedSDKLanguages() returns string? { + return java:toString(org_wso2_apk_devportal_sdk_APIClientGenerationManager_getSupportedSDKLanguages(self.jObj)); + } + + # The function that maps to the `hashCode` method of `org.wso2.apk.devportal.sdk.APIClientGenerationManager`. + # + # + return - The `int` value returning from the Java mapping. + public function hashCode() returns int { + return org_wso2_apk_devportal_sdk_APIClientGenerationManager_hashCode(self.jObj); + } + + # The function that maps to the `notify` method of `org.wso2.apk.devportal.sdk.APIClientGenerationManager`. + public function notify() { + org_wso2_apk_devportal_sdk_APIClientGenerationManager_notify(self.jObj); + } + + # The function that maps to the `notifyAll` method of `org.wso2.apk.devportal.sdk.APIClientGenerationManager`. + public function notifyAll() { + org_wso2_apk_devportal_sdk_APIClientGenerationManager_notifyAll(self.jObj); + } + + # The function that maps to the `wait` method of `org.wso2.apk.devportal.sdk.APIClientGenerationManager`. + # + # + return - The `javalang:InterruptedException` value returning from the Java mapping. + public function 'wait() returns javalang:InterruptedException? { + error|() externalObj = org_wso2_apk_devportal_sdk_APIClientGenerationManager_wait(self.jObj); + if (externalObj is error) { + javalang:InterruptedException e = error javalang:InterruptedException(javalang:INTERRUPTEDEXCEPTION, externalObj, message = externalObj.message()); + return e; + } + } + + # The function that maps to the `wait` method of `org.wso2.apk.devportal.sdk.APIClientGenerationManager`. + # + # + arg0 - The `int` value required to map with the Java method parameter. + # + return - The `javalang:InterruptedException` value returning from the Java mapping. + public function wait2(int arg0) returns javalang:InterruptedException? { + error|() externalObj = org_wso2_apk_devportal_sdk_APIClientGenerationManager_wait2(self.jObj, arg0); + if (externalObj is error) { + javalang:InterruptedException e = error javalang:InterruptedException(javalang:INTERRUPTEDEXCEPTION, externalObj, message = externalObj.message()); + return e; + } + } + + # The function that maps to the `wait` method of `org.wso2.apk.devportal.sdk.APIClientGenerationManager`. + # + # + arg0 - The `int` value required to map with the Java method parameter. + # + arg1 - The `int` value required to map with the Java method parameter. + # + return - The `javalang:InterruptedException` value returning from the Java mapping. + public function wait3(int arg0, int arg1) returns javalang:InterruptedException? { + error|() externalObj = org_wso2_apk_devportal_sdk_APIClientGenerationManager_wait3(self.jObj, arg0, arg1); + if (externalObj is error) { + javalang:InterruptedException e = error javalang:InterruptedException(javalang:INTERRUPTEDEXCEPTION, externalObj, message = externalObj.message()); + return e; + } + } + +} + +# The constructor function to generate an object of `org.wso2.apk.devportal.sdk.APIClientGenerationManager`. +# +# + return - The new `APIClientGenerationManager` class generated. +public function newAPIClientGenerationManager1() returns APIClientGenerationManager { + handle externalObj = org_wso2_apk_devportal_sdk_APIClientGenerationManager_newAPIClientGenerationManager1(); + APIClientGenerationManager newObj = new (externalObj); + return newObj; +} + +function org_wso2_apk_devportal_sdk_APIClientGenerationManager_cleanTempDirectory(handle receiver, handle arg0) = @java:Method { + name: "cleanTempDirectory", + 'class: "org.wso2.apk.devportal.sdk.APIClientGenerationManager", + paramTypes: ["java.lang.String"] +} external; + +function org_wso2_apk_devportal_sdk_APIClientGenerationManager_equals(handle receiver, handle arg0) returns boolean = @java:Method { + name: "equals", + 'class: "org.wso2.apk.devportal.sdk.APIClientGenerationManager", + paramTypes: ["java.lang.Object"] +} external; + +isolated function org_wso2_apk_devportal_sdk_APIClientGenerationManager_generateSDK(handle receiver, handle arg0, handle arg1, handle arg2, handle arg3, handle arg4, handle arg5, handle arg6, handle arg7) returns handle|error = @java:Method { + name: "generateSDK", + 'class: "org.wso2.apk.devportal.sdk.APIClientGenerationManager", + paramTypes: ["java.lang.String", "java.lang.String", "java.lang.String", "java.lang.String", "java.lang.String", "java.lang.String", "java.lang.String", "java.lang.String"] +} external; + +function org_wso2_apk_devportal_sdk_APIClientGenerationManager_getClass(handle receiver) returns handle = @java:Method { + name: "getClass", + 'class: "org.wso2.apk.devportal.sdk.APIClientGenerationManager", + paramTypes: [] +} external; + +isolated function org_wso2_apk_devportal_sdk_APIClientGenerationManager_getSupportedSDKLanguages(handle receiver) returns handle = @java:Method { + name: "getSupportedSDKLanguages", + 'class: "org.wso2.apk.devportal.sdk.APIClientGenerationManager", + paramTypes: [] +} external; + +function org_wso2_apk_devportal_sdk_APIClientGenerationManager_hashCode(handle receiver) returns int = @java:Method { + name: "hashCode", + 'class: "org.wso2.apk.devportal.sdk.APIClientGenerationManager", + paramTypes: [] +} external; + +function org_wso2_apk_devportal_sdk_APIClientGenerationManager_notify(handle receiver) = @java:Method { + name: "notify", + 'class: "org.wso2.apk.devportal.sdk.APIClientGenerationManager", + paramTypes: [] +} external; + +function org_wso2_apk_devportal_sdk_APIClientGenerationManager_notifyAll(handle receiver) = @java:Method { + name: "notifyAll", + 'class: "org.wso2.apk.devportal.sdk.APIClientGenerationManager", + paramTypes: [] +} external; + +function org_wso2_apk_devportal_sdk_APIClientGenerationManager_wait(handle receiver) returns error? = @java:Method { + name: "wait", + 'class: "org.wso2.apk.devportal.sdk.APIClientGenerationManager", + paramTypes: [] +} external; + +function org_wso2_apk_devportal_sdk_APIClientGenerationManager_wait2(handle receiver, int arg0) returns error? = @java:Method { + name: "wait", + 'class: "org.wso2.apk.devportal.sdk.APIClientGenerationManager", + paramTypes: ["long"] +} external; + +function org_wso2_apk_devportal_sdk_APIClientGenerationManager_wait3(handle receiver, int arg0, int arg1) returns error? = @java:Method { + name: "wait", + 'class: "org.wso2.apk.devportal.sdk.APIClientGenerationManager", + paramTypes: ["long", "int"] +} external; + +function org_wso2_apk_devportal_sdk_APIClientGenerationManager_newAPIClientGenerationManager1() returns handle = @java:Constructor { + 'class: "org.wso2.apk.devportal.sdk.APIClientGenerationManager", + paramTypes: [] +} external; + diff --git a/devportal/devportal-domain-service/ballerina/modules/types/Keymanager.bal b/devportal/devportal-domain-service/ballerina/modules/types/Keymanager.bal new file mode 100644 index 000000000..cbcc336a0 --- /dev/null +++ b/devportal/devportal-domain-service/ballerina/modules/types/Keymanager.bal @@ -0,0 +1,40 @@ +public type KeyManager record { + string id?; + string name; + string displayName?; + string 'type; + string description?; + map endpoints = {}; + # PEM type certificate + string tlsCertficate?; + string issuer; + string[] availableGrantTypes?; + boolean enableTokenGeneration?; + boolean enableMapOAuthConsumerApps = false; + boolean enableOAuthAppCreation = true; + boolean enableOauthAppValidation = true; + string consumerKeyClaim?; + string scopesClaim?; + boolean enabled = true; + record {} additionalProperties?; +}; + +public type KeyManagerEndpoint record { + string name; + string value; +}; + +public type KeyManager_signingCertificate record { + string 'type?; + string value?; +}; + +public type KeyMappingDaoEntry record { + string uuid; + string application_uuid; + string consumer_key; + string key_type; + string create_mode; + byte[] app_info; + string key_manager_uuid; +}; diff --git a/devportal/devportal-domain-service/ballerina/modules/utils/utils.bal b/devportal/devportal-domain-service/ballerina/modules/utils/utils.bal new file mode 100644 index 000000000..989c6031a --- /dev/null +++ b/devportal/devportal-domain-service/ballerina/modules/utils/utils.bal @@ -0,0 +1,11 @@ +import ballerina/io; +import ballerina/file; +import wso2/apk_common_lib as commons; + +public isolated function storeAndRetrieveCertificate(string fileName, string base64EncodedContent) returns string|error { + string tempDir = check file:createTempDir(); + string filePath = tempDir + file:pathSeparator + fileName; + byte[] base64DecodedContent = check commons:EncoderUtil_decodeBase64(base64EncodedContent.toBytes()); + _ = check io:fileWriteBytes(filePath, base64DecodedContent); + return filePath; +} diff --git a/devportal/devportal-domain-service/ballerina/notificationTypes.bal b/devportal/devportal-domain-service/ballerina/notificationTypes.bal new file mode 100644 index 000000000..35219e4b2 --- /dev/null +++ b/devportal/devportal-domain-service/ballerina/notificationTypes.bal @@ -0,0 +1,54 @@ +// +// Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + +public type ApplicationGRPC record {| + string eventId = ""; + string name = ""; + string uuid = ""; + string owner = ""; + string policy = ""; + Application_Key[] keys = []; + string organization = ""; + string timeStamp = ""; + record {|string key; string value;|}[] attributes = []; +|}; + +public type Application_Key record {| + string key = ""; + string keyManager = ""; +|}; + +public type SubscriptionGRPC record {| + string eventId = ""; + string applicationRef = ""; + string apiRef = ""; + string policyId = ""; + string subStatus = ""; + string subscriber = ""; + string uuid = ""; + string timeStamp = ""; + string organization = ""; +|}; + +public type NotificationResponse record {| + NotificationResponse_StatusCode code = UNKNOWN; +|}; + +public enum NotificationResponse_StatusCode { + UNKNOWN, OK, FAILED +} diff --git a/devportal/devportal-domain-service/ballerina/resources/devportal-api.yaml b/devportal/devportal-domain-service/ballerina/resources/devportal-api.yaml new file mode 100644 index 000000000..6ca5a2b5f --- /dev/null +++ b/devportal/devportal-domain-service/ballerina/resources/devportal-api.yaml @@ -0,0 +1,5167 @@ +# Copyright (c) 2020, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. +# +# 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. +################################################################################ +openapi: 3.0.1 +info: + title: WSO2 API Platform for Kubernetes - Developer Portal + description: | + This document specifies a **RESTful API** for WSO2 **API Platform for Kubernetes(APK)** - **Developer Portal**. + contact: + name: WSO2 + url: https://wso2.com/api-manager/ + email: architecture@wso2.com + license: + name: Apache 2.0 + url: http://www.apache.org/licenses/LICENSE-2.0.html + version: v2.1 +servers: + - url: https://apk.wso2.com/api/devportal +###################################################### +# The "API Collection" resource APIs +###################################################### +paths: + /apis: + get: + tags: + - APIs + summary: | + Retrieve/Search APIs + description: | + This operation provides you a list of available APIs qualifying under a given search condition. + parameters: + - $ref: '#/components/parameters/limit' + - $ref: '#/components/parameters/offset' + - $ref: '#/components/parameters/requestedTenant' + - name: query + in: query + description: | + You can search in attributes by using an attribute modifier. + schema: + type: string + - $ref: '#/components/parameters/If-None-Match' + responses: + 200: + description: | + OK. List of qualifying APIs is returned. + content: + application/json: + schema: + $ref: '#/components/schemas/APIList' + 406: + $ref: '#/components/responses/NotAcceptable' + security: + - OAuth2Security: [] + x-code-samples: + - lang: Curl + source: curl -k "https://localhost:9443/api/devportal/apis" + + /apis/{apiId}: + get: + tags: + - APIs + summary: | + Get Details of an API + description: | + Using this operation, you can retrieve complete details of a single API. You need to provide the Id of the API to retrieve it. + parameters: + - $ref: '#/components/parameters/apiId' + - $ref: '#/components/parameters/requestedTenant' + - $ref: '#/components/parameters/If-None-Match' + responses: + 200: + description: | + OK. Requested API is returned + headers: + ETag: + description: | + Entity Tag of the response resource. Used by caches, or in conditional requests. + schema: + type: string + Last-Modified: + description: | + Date and time the resource has been modified the last time. Used by caches, or in conditional requests. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/API' + 304: + description: | + Not Modified. Empty body because the client has already the latest version of the requested resource. + content: {} + 404: + $ref: '#/components/responses/NotFound' + 406: + $ref: '#/components/responses/NotAcceptable' + security: + - OAuth2Security: [] + x-code-samples: + - lang: Curl + source: curl -k "https://localhost:9443/api/devportal/apis/c43a325c-260b-4302-81cb-768eafaa3aed" + + /apis/{apiId}/definition: + get: + tags: + - APIs + summary: Get the API Definition + description: | + This operation can be used to retrieve the definition of an API. + parameters: + - $ref: '#/components/parameters/apiId' + - $ref: '#/components/parameters/If-None-Match' + responses: + 200: + description: | + OK. Requested definition document of the API is returned + headers: + ETag: + description: | + Entity Tag of the response resource. Used by caches, or in conditional requests. + schema: + type: string + Last-Modified: + description: | + Date and time the resource has been modified the last time. Used by caches, or in conditional requests. + schema: + type: string + Content-Type: + description: | + The content type of the body. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/APIDefinition' + 304: + description: | + Not Modified. Empty body because the client has already the latest version of the requested resource. + content: {} + 404: + $ref: '#/components/responses/NotFound' + 406: + $ref: '#/components/responses/NotAcceptable' + security: + - OAuth2Security: [] + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://127.0.0.1:9443/api/apk/devportal/v1/apis/7a2298c4-c905-403f-8fac-38c73301631f/definition"' + operationId: getAPIDefinition + + /apis/{apiId}/sdks/{language}: + get: + tags: + - SDKs + summary: | + Generate a SDK for an API + description: | + This operation can be used to generate SDKs (System Development Kits), for the APIs available in the API Developer Portal, for a requested development language. + parameters: + - $ref: '#/components/parameters/apiId' + - name: language + in: path + description: | + Programming language of the SDK that is required. Languages supported by default are **Java**, **Javascript**, **Android** and **JMeter**. + required: true + schema: + type: string + - $ref: '#/components/parameters/requestedTenant' + responses: + 200: + description: | + OK. SDK generated successfully. + content: + application/zip: + schema: + type: string + format: byte + 400: + $ref: '#/components/responses/BadRequest' + 404: + $ref: '#/components/responses/NotFound' + 500: + $ref: '#/components/responses/InternalServerError' + security: + - OAuth2Security: + - apk:subscribe + x-code-samples: + - lang: Curl + source: curl -k -H "Authorization:Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://localhost:9443/api/devportal/apis/890a4f4d-09eb-4877-a323-57f6ce2ed79b/sdks/java" + > Petstore_java_1.0.0.zip + + ###################################################### + # The "Document Collection" resource APIs + ###################################################### + /apis/{apiId}/documents: + get: + tags: + - API Documents + summary: | + Get a List of Documents of an API + description: | + This operation can be used to retrieve a list of documents belonging to an API by providing the id of the API. + parameters: + - $ref: '#/components/parameters/apiId' + - $ref: '#/components/parameters/limit' + - $ref: '#/components/parameters/offset' + - $ref: '#/components/parameters/requestedTenant' + - $ref: '#/components/parameters/If-None-Match' + responses: + 200: + description: | + OK. Document list is returned. + headers: + ETag: + description: | + Entity Tag of the response resource. Used by caches, or in conditional requests. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/DocumentList' + 304: + description: | + Not Modified. Empty body because the client has already the latest version of the requested resource. + content: {} + 404: + $ref: '#/components/responses/NotFound' + 406: + $ref: '#/components/responses/NotAcceptable' + security: + - OAuth2Security: [] + x-code-samples: + - lang: Curl + source: curl -k "https://localhost:9443/api/devportal/apis/c43a325c-260b-4302-81cb-768eafaa3aed/documents" + + ###################################################### + # The "Individual Document" resource APIs + ###################################################### + /apis/{apiId}/documents/{documentId}: + get: + tags: + - API Documents + summary: | + Get a Document of an API + description: | + This operation can be used to retrieve a particular document's metadata associated with an API. + parameters: + - $ref: '#/components/parameters/apiId' + - $ref: '#/components/parameters/documentId' + - $ref: '#/components/parameters/requestedTenant' + - $ref: '#/components/parameters/If-None-Match' + responses: + 200: + description: | + OK. Document returned. + headers: + ETag: + description: | + Entity Tag of the response resource. Used by caches, or in conditional requests. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/Document' + 304: + description: | + Not Modified. Empty body because the client has already the latest version of the requested resource. + content: {} + 404: + $ref: '#/components/responses/NotFound' + 406: + $ref: '#/components/responses/NotAcceptable' + security: + - OAuth2Security: [] + x-code-samples: + - lang: Curl + source: curl -k "https://localhost:9443/api/devportal/apis/c43a325c-260b-4302-81cb-768eafaa3aed/documents/850a4f34-db2c-4d23-9d85-3f95fbfb082c" + + /apis/{apiId}/documents/{documentId}/content: + get: + tags: + - API Documents + summary: | + Get the Content of an API Document + description: | + This operation can be used to retrieve the content of an API's document. + parameters: + - $ref: '#/components/parameters/apiId' + - $ref: '#/components/parameters/documentId' + - $ref: '#/components/parameters/requestedTenant' + - $ref: '#/components/parameters/If-None-Match' + responses: + 200: + description: | + OK. File or inline content returned. + headers: + ETag: + description: | + Entity Tag of the response resource. Used by caches, or in conditional requests. + schema: + type: string + Last-Modified: + description: | + Date and time the resource has been modified the last time. Used by caches, or in conditional requests. + schema: + type: string + content: {} + 303: + description: | + See Other. Source can be retrieved from the URL specified at the Location header. + headers: + Location: + description: | + The Source URL of the document. + schema: + type: string + content: {} + 304: + description: | + Not Modified. Empty body because the client has already the latest version of the requested resource. + content: {} + 404: + $ref: '#/components/responses/NotFound' + 406: + $ref: '#/components/responses/NotAcceptable' + security: + - OAuth2Security: [] + x-code-samples: + - lang: Curl + source: curl -k "https://localhost:9443/api/devportal/apis/890a4f4d-09eb-4877-a323-57f6ce2ed79b/documents/0bcb7f05-599d-4e1a-adce-5cb89bfe58d5/content" + + /apis/{apiId}/thumbnail: + get: + tags: + - APIs + summary: Get Thumbnail Image + description: | + This operation can be used to download a thumbnail image of an API. + parameters: + - $ref: '#/components/parameters/apiId' + - $ref: '#/components/parameters/requestedTenant' + - $ref: '#/components/parameters/If-None-Match' + responses: + 200: + description: | + OK. Thumbnail image returned + headers: + ETag: + description: | + Entity Tag of the response resource. Used by caches, or in conditional requests. + schema: + type: string + Last-Modified: + description: | + Date and time the resource has been modified the last time. Used by caches, or in conditional requests (Will be supported in future). + schema: + type: string + Content-Type: + description: | + The content type of the body. + schema: + type: string + content: {} + 304: + description: | + Not Modified. Empty body because the client has already the latest version of the requested resource. + content: {} + 404: + $ref: '#/components/responses/NotFound' + 406: + $ref: '#/components/responses/NotAcceptable' + security: + - OAuth2Security: [] + x-code-samples: + - lang: Curl + source: 'curl -k "https://localhost:9443/api/devportal/apis/e93fb282-b456-48fc-8981-003fb89086ae/thumbnail" > image.jpeg' + + /apis/{apiId}/ratings: + get: + tags: + - Ratings + summary: Retrieve API Ratings + description: | + This operation can be used to retrieve the list of ratings of an API. + parameters: + - $ref: '#/components/parameters/apiId' + - $ref: '#/components/parameters/limit' + - $ref: '#/components/parameters/offset' + - $ref: '#/components/parameters/requestedTenant' + responses: + 200: + description: | + OK. Rating list returned. + content: + application/json: + schema: + $ref: '#/components/schemas/RatingList' + 406: + $ref: '#/components/responses/NotAcceptable' + security: + - OAuth2Security: [] + x-code-samples: + - lang: Curl + source: curl -k "https://localhost:9443/api/devportal/apis/e93fb282-b456-48fc-8981-003fb89086ae/ratings" + + /apis/{apiId}/user-rating: + get: + tags: + - Ratings + summary: Retrieve API Rating of User + description: | + This operation can be used to get the user rating of an API. + parameters: + - $ref: '#/components/parameters/apiId' + - $ref: '#/components/parameters/requestedTenant' + - $ref: '#/components/parameters/If-None-Match' + responses: + 200: + description: | + OK. Rating returned. + headers: + ETag: + description: | + Entity Tag of the response resource. Used by caches, or in conditional requests. + schema: + type: string + Last-Modified: + description: | + Date and time the resource has been modified the last time. Used by caches, or in conditional requests. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/Rating' + 304: + description: | + Not Modified. Empty body because the client already has the latest version of the requested resource. + content: {} + 404: + $ref: '#/components/responses/NotFound' + 406: + $ref: '#/components/responses/NotAcceptable' + security: + - OAuth2Security: + - apk:subscribe + x-code-samples: + - lang: Curl + source: curl -k -H "Authorization:Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://localhost:9443/api/devportal/apis/e93fb282-b456-48fc-8981-003fb89086ae/user-rating" + + put: + tags: + - Ratings + summary: Add or Update Logged in User's Rating for an API + description: | + This operation can be used to add or update an API rating. + parameters: + - $ref: '#/components/parameters/apiId' + - $ref: '#/components/parameters/requestedTenant' + requestBody: + description: | + Rating object that should to be added + content: + application/json: + schema: + $ref: '#/components/schemas/Rating' + required: true + responses: + 200: + description: | + OK. Successful response with the newly created or updated object as entity in the body. + headers: + ETag: + description: | + Entity Tag of the response resource. Used by caches, or in conditional request. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/Rating' + 400: + $ref: '#/components/responses/BadRequest' + 415: + $ref: '#/components/responses/UnsupportedMediaType' + security: + - OAuth2Security: + - apk:subscribe + x-code-samples: + - lang: Curl + source: 'curl -k -X PUT -H "Authorization:Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + -H "Content-Type: application/json" -d @data.json "https://localhost:9443/api/devportal/apis/e93fb282-b456-48fc-8981-003fb89086ae/user-rating"' + + delete: + tags: + - Ratings + summary: Delete User API Rating + description: | + This operation can be used to delete logged in user API rating. + parameters: + - $ref: '#/components/parameters/apiId' + - $ref: '#/components/parameters/requestedTenant' + - $ref: '#/components/parameters/If-Match' + responses: + 200: + description: | + OK. Resource successfully deleted. + content: {} + security: + - OAuth2Security: + - apk:subscribe + x-code-samples: + - lang: Curl + source: curl -k -X DELETE -H "Authorization:Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://localhost:9443/api/devportal/apis/e93fb282-b456-48fc-8981-003fb89086ae/user-rating" + + /apis/{apiId}/comments: + get: + tags: + - Comments + summary: Retrieve API Comments + description: | + Get a list of Comments that are already added to APIs + operationId: getAllCommentsOfAPI + parameters: + - $ref: '#/components/parameters/apiId' + - $ref: '#/components/parameters/requestedTenant' + - $ref: '#/components/parameters/limit' + - $ref: '#/components/parameters/offset' + - $ref: '#/components/parameters/includeCommenterInfo' + responses: + 200: + description: | + OK. Comments list is returned. + content: + application/json: + schema: + $ref: '#/components/schemas/CommentList' + 404: + $ref: '#/components/responses/NotFound' + 500: + $ref: '#/components/responses/InternalServerError' + security: + - OAuth2Security: [] + x-code-samples: + - lang: Curl + source: curl -k "https://localhost:9443/api/devportal/apis/e93fb282-b456-48fc-8981-003fb89086ae/comments" + + post: + tags: + - Comments + summary: Add an API Comment + operationId: addCommentToAPI + parameters: + - $ref: '#/components/parameters/apiId' + - $ref: '#/components/parameters/parentCommentID' + requestBody: + description: | + Comment object that should to be added + content: + application/json: + schema: + title: Post request body + type: object + properties: + content: + type: string + maxLength: 512 + description: | + Content of the comment + example: This is a comment + category: + type: string + description: | + Category of the comment + example: general + required: + - content + required: true + responses: + 201: + description: | + Created. Successful response with the newly created object as entity in the body. Location header contains URL of newly created entity. + headers: + ETag: + description: | + Entity Tag of the response resource. Used by caches, or in conditional request. + schema: + type: string + Location: + description: | + Location to the newly created Comment. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/Comment' + 400: + $ref: '#/components/responses/BadRequest' + 401: + $ref: '#/components/responses/Unauthorized' + 404: + $ref: '#/components/responses/NotFound' + 415: + $ref: '#/components/responses/UnsupportedMediaType' + 500: + $ref: '#/components/responses/InternalServerError' + security: + - OAuth2Security: + - apk:subscribe + x-code-samples: + - lang: Curl + source: 'curl -k -X POST -H "Authorization:Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + -H "Content-Type: application/json" -d @data.json "https://localhost:9443/api/devportal/apis/e93fb282-b456-48fc-8981-003fb89086ae/comments"' + + /apis/{apiId}/comments/{commentId}: + get: + tags: + - Comments + summary: Get Details of an API Comment + description: | + Get the individual comment given by a user for a certain API. + operationId: getCommentOfAPI + parameters: + - $ref: '#/components/parameters/commentId' + - $ref: '#/components/parameters/apiId' + - $ref: '#/components/parameters/requestedTenant' + - $ref: '#/components/parameters/If-None-Match' + - $ref: '#/components/parameters/includeCommenterInfo' + - $ref: '#/components/parameters/replyLimit' + - $ref: '#/components/parameters/replyOffset' + responses: + 200: + description: | + OK. Comment returned. + headers: + ETag: + description: | + Entity Tag of the response resource. Used by caches, or in conditional requests. + schema: + type: string + Last-Modified: + description: | + Date and time the resource has been modified the last time. Used by caches, or in conditional requests. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/Comment' + 401: + $ref: '#/components/responses/Unauthorized' + 404: + $ref: '#/components/responses/NotFound' + 406: + $ref: '#/components/responses/NotAcceptable' + 500: + $ref: '#/components/responses/InternalServerError' + security: + - OAuth2Security: [] + x-code-samples: + - lang: Curl + source: curl -k "https://localhost:9443/api/devportal/apis/e93fb282-b456-48fc-8981-003fb89086ae/comments/d4cf1704-5d09-491c-bc48-4d19ce6ea9b4" + + patch: + tags: + - Comments + summary: Edit a comment + description: | + Edit the individual comment + operationId: editCommentOfAPI + parameters: + - $ref: '#/components/parameters/commentId' + - $ref: '#/components/parameters/apiId' + requestBody: + description: | + Comment object that should to be updated + content: + application/json: + schema: + title: Patch request body + type: object + properties: + content: + type: string + maxLength: 512 + description: | + Content of the comment + example: This is a comment + category: + type: string + description: | + Category of the comment + example: general + required: true + responses: + 200: + description: | + OK. Comment updated. + headers: + ETag: + description: | + Entity Tag of the response resource. Used by caches, or in conditional request. + schema: + type: string + Location: + description: | + Location to the newly created Comment. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/Comment' + 400: + $ref: '#/components/responses/BadRequest' + 401: + $ref: '#/components/responses/Unauthorized' + 403: + description: | + Forbidden. The request must be conditional but no condition has been specified. + 404: + $ref: '#/components/responses/NotFound' + 415: + $ref: '#/components/responses/UnsupportedMediaType' + 500: + $ref: '#/components/responses/InternalServerError' + security: + - OAuth2Security: + - apk:subscribe + x-code-samples: + - lang: Curl + source: 'curl -k -X PATCH -H "Authorization:Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + -H "Content-Type: application/json" -d @data.json "https://localhost:9443/api/devportal/apis/e93fb282-b456-48fc-8981-003fb89086ae/comments/d4cf1704-5d09-491c-bc48-4d19ce6ea9b4"' + + delete: + tags: + - Comments + summary: Delete an API Comment + description: | + Remove a Comment + operationId: deleteComment + parameters: + - $ref: '#/components/parameters/commentId' + - $ref: '#/components/parameters/apiId' + - $ref: '#/components/parameters/If-Match' + responses: + 200: + description: | + OK. Resource successfully deleted. + content: {} + 401: + $ref: '#/components/responses/Unauthorized' + 403: + description: | + Forbidden. The request must be conditional but no condition has been specified. + content: {} + 404: + $ref: '#/components/responses/NotFound' + 405: + description: | + MethodNotAllowed. Request method is known by the server but is not supported by the target resource. + content: {} + 500: + $ref: '#/components/responses/InternalServerError' + security: + - OAuth2Security: + - apk:subscribe + - apk:admin # special scope added to moderate comments + x-code-samples: + - lang: Curl + source: curl -k -X DELETE -H "Authorization:Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://localhost:9443/api/devportal/apis/e93fb282-b456-48fc-8981-003fb89086ae/comments/d4cf1704-5d09-491c-bc48-4d19ce6ea9b4" + + /apis/{apiId}/comments/{commentId}/replies: + get: + tags: + - Comments + summary: Get replies of a comment + description: | + Get replies of a comment + operationId: getRepliesOfComment + parameters: + - $ref: '#/components/parameters/commentId' + - $ref: '#/components/parameters/apiId' + - $ref: '#/components/parameters/requestedTenant' + - $ref: '#/components/parameters/limit' + - $ref: '#/components/parameters/offset' + - $ref: '#/components/parameters/If-None-Match' + - $ref: '#/components/parameters/includeCommenterInfo' + responses: + 200: + description: | + OK. Comment returned. + headers: + ETag: + description: | + Entity Tag of the response resource. Used by caches, or in conditional requests. + schema: + type: string + Last-Modified: + description: | + Date and time the resource has been modified the last time. Used by caches, or in conditional requests. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/CommentList' + 401: + $ref: '#/components/responses/Unauthorized' + 404: + $ref: '#/components/responses/NotFound' + 406: + $ref: '#/components/responses/NotAcceptable' + 500: + $ref: '#/components/responses/InternalServerError' + security: + - OAuth2Security: [] + x-code-samples: + - lang: Curl + source: curl -k -H "Authorization:Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" "https://localhost:9443/api/devportal/apis/e93fb282-b456-48fc-8981-003fb89086ae/comments/d4cf1704-5d09-491c-bc48-4d19ce6ea9b4/replies" + + /apis/{apiId}/topics: + get: + tags: + - Topics + summary: | + Get a list of available topics for a given Async API + description: | + This operation will provide a list of topics available for a given Async API, based on the provided API ID. + parameters: + - $ref: '#/components/parameters/apiId' + - $ref: '#/components/parameters/requestedTenant' + responses: + 200: + description: | + OK. Topic list returned. + headers: + ETag: + description: | + Entity Tag of the response resource. Used by caches, or in conditional requests. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/TopicList' + 404: + $ref: '#/components/responses/NotFound' + 500: + $ref: '#/components/responses/InternalServerError' + security: + - OAuth2Security: [] + x-code-samples: + - lang: Curl + source: curl -k -H "Authorization:Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://localhost:9443/api/devportal/apis/5b65808c-cdf2-43e1-a695-de63e3ad0ae9/topics" + + /apis/{apiId}/subscription-policies: + get: + tags: + - APIs + summary: | + Get Details of the Subscription Throttling Policies of an API + description: | + This operation can be used to retrieve details of the subscription throttling policy of an API by specifying the API Id. + parameters: + - $ref: '#/components/parameters/apiId' + - $ref: '#/components/parameters/requestedTenant' + - $ref: '#/components/parameters/If-None-Match' + responses: + 200: + description: | + OK. Throttling Policy returned + headers: + ETag: + description: | + Entity Tag of the response resource. Used by caches, or in conditional requests. + schema: + type: string + Last-Modified: + description: | + Date and time the resource has been modified the last time. Used by caches, or in conditional requests. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/ThrottlingPolicy' + 304: + description: | + Not Modified. Empty body because the client has already the latest version of the requested resource. + content: {} + 404: + $ref: '#/components/responses/NotFound' + 406: + $ref: '#/components/responses/NotAcceptable' + security: + - OAuth2Security: [] + x-code-samples: + - lang: Curl + source: curl -k "https://localhost:9443/api/devportal/apis/268c9e55-3dc1-4f47-82e7-977e5343d077/subscription-policies" + + ###################################################### + # The "Application Collection" resource APIs + ###################################################### + /applications: + get: + tags: + - Applications + summary: | + Retrieve/Search Applications + description: | + This operation can be used to retrieve list of applications that is belonged to the user associated with the provided access token. + parameters: + - $ref: '#/components/parameters/groupId' + - name: query + in: query + description: | + You can search for an application by specifying the name as "query" attribute. + schema: + type: string + - name: sortBy + in: query + schema: + type: string + enum: + - name + - throttlingPolicy + - status + - name: sortOrder + in: query + schema: + type: string + enum: + - asc + - desc + - $ref: '#/components/parameters/limit' + - $ref: '#/components/parameters/offset' + - $ref: '#/components/parameters/If-None-Match' + responses: + 200: + description: | + OK. Application list returned. + headers: + ETag: + description: | + Entity Tag of the response resource. Used by caches, or in conditional requests. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/ApplicationList' + 304: + description: | + Not Modified. Empty body because the client has already the latest version of the requested resource. + content: {} + 400: + $ref: '#/components/responses/BadRequest' + 406: + $ref: '#/components/responses/NotAcceptable' + security: + - OAuth2Security: + - apk:subscribe + - apk:app_manage + - apk:app_import_export + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://localhost:9443/api/devportal/applications?query=CalculatorApp"' + + post: + tags: + - Applications + summary: | + Create a New Application + description: | + This operation can be used to create a new application specifying the details of the application in the payload. + requestBody: + description: | + Application object that is to be created. + content: + application/json: + schema: + $ref: '#/components/schemas/Application' + required: true + responses: + 201: + description: | + Created. Successful response with the newly created object as entity in the body. Location header contains URL of newly created entity. + headers: + ETag: + description: | + Entity Tag of the response resource. Used by caches, or in conditional request + schema: + type: string + Location: + description: | + Location of the newly created Application. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/Application' + 202: + description: | + Accepted. The request has been accepted. + headers: + Location: + description: | + Location of the newly created Application. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/WorkflowResponse' + 400: + $ref: '#/components/responses/BadRequest' + 409: + $ref: '#/components/responses/Conflict' + 415: + $ref: '#/components/responses/UnsupportedMediaType' + security: + - OAuth2Security: + - apk:subscribe + - apk:app_manage + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + -H "Content-Type: application/json" -X POST -d @data.json "https://localhost:9443/api/devportal/applications"' + + ###################################################### + # The "Individual Application" resource APIs + ###################################################### + /applications/{applicationId}: + get: + tags: + - Applications + summary: | + Get Details of an Application + description: | + This operation can be used to retrieve details of an individual application specifying the application id in the URI. + parameters: + - $ref: '#/components/parameters/applicationId' + - $ref: '#/components/parameters/If-None-Match' + - $ref: '#/components/parameters/requestedTenant' + responses: + 200: + description: | + OK. Application returned. + headers: + ETag: + description: | + Entity Tag of the response resource. Used by caches, or in conditional requests. + schema: + type: string + Last-Modified: + description: | + Date and time the resource has been modified the last time. Used by caches, or in conditional requests. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/Application' + 304: + description: | + Not Modified. Empty body because the client has already the latest version of the requested resource. + content: {} + 404: + $ref: '#/components/responses/NotFound' + 406: + $ref: '#/components/responses/NotAcceptable' + security: + - OAuth2Security: + - apk:subscribe + - apk:app_manage + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://localhost:9443/api/devportal/applications/896658a0-b4ee-4535-bbfa-806c894a4015"' + + put: + tags: + - Applications + summary: | + Update an Application + description: | + This operation can be used to update an application. Upon successful you will retrieve the updated application as the response. + parameters: + - $ref: '#/components/parameters/applicationId' + - $ref: '#/components/parameters/If-Match' + requestBody: + description: | + Application object that needs to be updated + content: + application/json: + schema: + $ref: '#/components/schemas/Application' + required: true + responses: + 200: + description: | + OK. Application updated. + headers: + ETag: + description: | + Entity Tag of the response resource. Used by caches, or in conditional request. + schema: + type: string + Last-Modified: + description: | + Date and time the resource has been modified the last time. Used by caches, or in conditional requests. + schema: + type: string + Location: + description: | + The URL of the newly created resource. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/Application' + 400: + $ref: '#/components/responses/BadRequest' + 404: + $ref: '#/components/responses/NotFound' + 412: + $ref: '#/components/responses/PreconditionFailed' + security: + - OAuth2Security: + - apk:subscribe + - apk:app_manage + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + -H "Content-Type: application/json" -X PUT -d @data.json "https://localhost:9443/api/devportal/applications/896658a0-b4ee-4535-bbfa-806c894a4015"' + + delete: + tags: + - Applications + summary: | + Remove an Application + description: | + This operation can be used to remove an application specifying its id. + parameters: + - $ref: '#/components/parameters/applicationId' + - $ref: '#/components/parameters/If-Match' + responses: + 200: + description: | + OK. Resource successfully deleted. + content: {} + 202: + description: | + Accepted. The request has been accepted. + headers: + Location: + description: | + Location of the existing Application. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/WorkflowResponse' + 404: + $ref: '#/components/responses/NotFound' + 412: + $ref: '#/components/responses/PreconditionFailed' + security: + - OAuth2Security: + - apk:subscribe + - apk:app_manage + - apk:app_import_export + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + -X DELETE "https://localhost:9443/api/devportal/applications/896658a0-b4ee-4535-bbfa-806c894a4015"' + + /applications/{applicationId}/generate-keys: + post: + tags: + - Application Keys + summary: Generate Application Keys + description: | + Generate keys (Consumer key/secret) for application + parameters: + - $ref: '#/components/parameters/applicationId' + - $ref: '#/components/parameters/requestedTenant' + requestBody: + description: | + Application key generation request object + content: + application/json: + schema: + $ref: '#/components/schemas/ApplicationKeyGenerateRequest' + required: true + responses: + 200: + description: | + OK. Keys are generated. + content: + application/json: + schema: + $ref: '#/components/schemas/ApplicationKey' + 400: + $ref: '#/components/responses/BadRequest' + 404: + $ref: '#/components/responses/NotFound' + 412: + $ref: '#/components/responses/PreconditionFailed' + security: + - OAuth2Security: + - apk:subscribe + - apk:app_manage + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + -H "Content-Type: application/json" -X POST -d @data.json "https://localhost:9443/api/devportal/applications/896658a0-b4ee-4535-bbfa-806c894a4015/generate-keys"' + + /applications/{applicationId}/map-keys: + post: + tags: + - Application Keys + summary: Map Application Keys + description: | + Map keys (Consumer key/secret) to an application + parameters: + - $ref: '#/components/parameters/applicationId' + - $ref: '#/components/parameters/requestedTenant' + requestBody: + description: | + Application key mapping request object + content: + application/json: + schema: + $ref: '#/components/schemas/ApplicationKeyMappingRequest' + required: true + responses: + 200: + description: | + OK. Keys are mapped. + content: + application/json: + schema: + $ref: '#/components/schemas/ApplicationKey' + 400: + $ref: '#/components/responses/BadRequest' + 404: + $ref: '#/components/responses/NotFound' + 412: + $ref: '#/components/responses/PreconditionFailed' + security: + - OAuth2Security: + - apk:subscribe + - apk:app_manage + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + -H "Content-Type: application/json" -X POST -d @data.json "https://localhost:9443/api/devportal/applications/896658a0-b4ee-4535-bbfa-806c894a4015/map-keys"' + + + /applications/{applicationId}/oauth-keys: + get: + tags: + - Application Keys + summary: Retrieve All Application Keys + description: | + Retrieve keys (Consumer key/secret) of application + parameters: + - $ref: '#/components/parameters/applicationId' + - $ref: '#/components/parameters/requestedTenant' + responses: + 200: + description: | + OK. Keys are returned. + content: + application/json: + schema: + $ref: '#/components/schemas/ApplicationKeyList' + 400: + $ref: '#/components/responses/BadRequest' + 404: + $ref: '#/components/responses/NotFound' + 412: + $ref: '#/components/responses/PreconditionFailed' + security: + - OAuth2Security: + - apk:subscribe + - apk:app_manage + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://localhost:9443/api/devportal/applications/16cd2684-9657-4a01-a956-4efd89e96077/oauth-keys"' + + /applications/{applicationId}/oauth-keys/{keyMappingId}: + get: + tags: + - Application Keys + summary: | + Get Key Details of a Given Type + description: | + This operation can be used to retrieve key details of an individual application specifying the key type in the URI. + parameters: + - $ref: '#/components/parameters/applicationId' + - $ref: '#/components/parameters/keyMappingId' + responses: + 200: + description: | + OK. Keys of given type are returned. + content: + application/json: + schema: + $ref: '#/components/schemas/ApplicationKey' + 400: + $ref: '#/components/responses/BadRequest' + 404: + $ref: '#/components/responses/NotFound' + 412: + $ref: '#/components/responses/PreconditionFailed' + security: + - OAuth2Security: + - apk:subscribe + - apk:app_manage + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://localhost:9443/api/devportal/applications/16cd2684-9657-4a01-a956-4efd89e96077/oauth-keys/df972173-c957-46d4-96ac-99be8e303584"' + + put: + tags: + - Application Keys + summary: | + Update Grant Types and Callback URL of an Application + description: | + This operation can be used to update grant types and callback url of an application. (Consumer Key and Consumer Secret are ignored) Upon successful you will retrieve the updated key details as the response. + parameters: + - $ref: '#/components/parameters/applicationId' + - $ref: '#/components/parameters/keyMappingId' + requestBody: + description: | + Grant types/Callback URL update request object + content: + application/json: + schema: + $ref: '#/components/schemas/ApplicationKey' + required: true + responses: + 200: + description: | + Ok. Grant types or/and callback url is/are updated. + content: + application/json: + schema: + $ref: '#/components/schemas/ApplicationKey' + 400: + $ref: '#/components/responses/BadRequest' + 404: + $ref: '#/components/responses/NotFound' + 412: + $ref: '#/components/responses/PreconditionFailed' + security: + - OAuth2Security: + - apk:subscribe + - apk:app_manage + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + -H "Content-Type: application/json" -X PUT -d @data.json "https://localhost:9443/api/devportal/applications/16cd2684-9657-4a01-a956-4efd89e96077/oauth-keys/df972173-c957-46d4-96ac-99be8e303584"' + + /applications/{applicationId}/oauth-keys/{keyMappingId}/regenerate-secret: + post: + tags: + - Application Keys + summary: | + Re-Generate Consumer Secret + description: | + This operation can be used to re generate consumer secret for an application for the give key type + parameters: + - $ref: '#/components/parameters/applicationId' + - $ref: '#/components/parameters/keyMappingId' + responses: + 200: + description: | + OK. Keys are re generated. + headers: + ETag: + description: | + Entity Tag of the response resource. Used by caches, or in conditional requests (Will be supported in future). + schema: + type: string + Last-Modified: + description: | + Date and time the resource has been modified the last time. Used by caches, or in conditional requests (Will be supported in future).‚ + schema: + type: string + Content-Type: + description: | + The content type of the body. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/ApplicationKeyReGenerateResponse' + 400: + $ref: '#/components/responses/BadRequest' + 404: + $ref: '#/components/responses/NotFound' + 412: + $ref: '#/components/responses/PreconditionFailed' + security: + - OAuth2Security: + - apk:subscribe + - apk:app_manage + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + -H "Content-Type: application/json" -X POST "https://localhost:9443/api/devportal/applications/16cd2684-9657-4a01-a956-4efd89e96077/oauth-keys/df972173-c957-46d4-96ac-99be8e303584/regenerate-secret"' + + /applications/{applicationId}/oauth-keys/{keyMappingId}/clean-up: + post: + tags: + - Application Keys + summary: Clean-Up Application Keys + description: | + Clean up keys after failed key generation of an application + parameters: + - $ref: '#/components/parameters/applicationId' + - $ref: '#/components/parameters/keyMappingId' + - $ref: '#/components/parameters/If-Match' + responses: + 200: + description: | + OK. Clean up is performed + content: {} + 400: + $ref: '#/components/responses/BadRequest' + 404: + $ref: '#/components/responses/NotFound' + 412: + $ref: '#/components/responses/PreconditionFailed' + security: + - OAuth2Security: + - apk:subscribe + - apk:app_manage + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + -H "Content-Type: application/json" -X POST "https://localhost:9443/api/devportal/applications/16cd2684-9657-4a01-a956-4efd89e96077/oauth-keys/df972173-c957-46d4-96ac-99be8e303584/clean-up"' + + /applications/{applicationId}/oauth-keys/{keyMappingId}/generate-token: + post: + tags: + - Application Tokens + summary: Generate Application Token + description: | + Generate an access token for application by client_credentials grant type + parameters: + - $ref: '#/components/parameters/applicationId' + - $ref: '#/components/parameters/keyMappingId' + - $ref: '#/components/parameters/If-Match' + requestBody: + description: | + Application token generation request object + content: + application/json: + schema: + $ref: '#/components/schemas/ApplicationTokenGenerateRequest' + required: true + responses: + 200: + description: | + OK. Token is generated. + content: + application/json: + schema: + $ref: '#/components/schemas/ApplicationToken' + 400: + $ref: '#/components/responses/BadRequest' + 404: + $ref: '#/components/responses/NotFound' + 412: + $ref: '#/components/responses/PreconditionFailed' + security: + - OAuth2Security: + - apk:subscribe + - apk:app_manage + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + -H "Content-Type: application/json" -X POST -d @data.json "https://localhost:9443/api/devportal/applications/16cd2684-9657-4a01-a956-4efd89e96077/oauth-keys/{keyMappingId}/generate-token"' + + /applications/{applicationId}/api-keys/{keyType}/generate: + post: + tags: + - API Keys + summary: Generate API Key + description: | + Generate a self contained API Key for the application + parameters: + - $ref: '#/components/parameters/applicationId' + - $ref: '#/components/parameters/keyType' + - $ref: '#/components/parameters/If-Match' + requestBody: + description: | + API Key generation request object + content: + application/json: + schema: + $ref: '#/components/schemas/APIKeyGenerateRequest' + required: false + responses: + 200: + description: | + OK. apikey generated. + content: + application/json: + schema: + $ref: '#/components/schemas/APIKey' + 400: + $ref: '#/components/responses/BadRequest' + 404: + $ref: '#/components/responses/NotFound' + 412: + $ref: '#/components/responses/PreconditionFailed' + security: + - OAuth2Security: + - apk:subscribe + - apk:app_manage + - apk:api_key + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + -H "Content-Type: application/json" -X POST -d @data.json "https://localhost:9443/api/devportal/applications/16cd2684-9657-4a01-a956-4efd89e96077/api-keys/PRODUCTION/generate"' + + /applications/{applicationId}/api-keys/{keyType}/revoke: + post: + tags: + - API Keys + summary: Revoke API Key + description: | + Revoke a self contained API Key for the application + parameters: + - $ref: '#/components/parameters/applicationId' + - $ref: '#/components/parameters/keyType' + - $ref: '#/components/parameters/If-Match' + requestBody: + description: | + API Key revoke request object + content: + application/json: + schema: + $ref: '#/components/schemas/APIKeyRevokeRequest' + required: false + responses: + 200: + description: | + OK. apikey revoked successfully. + content: {} + 400: + $ref: '#/components/responses/BadRequest' + 412: + $ref: '#/components/responses/PreconditionFailed' + security: + - OAuth2Security: + - apk:subscribe + - apk:app_manage + - apk:api_key + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + -H "Content-Type: application/json" -X POST -d @data.json "https://localhost:9443/api/devportal/applications/16cd2684-9657-4a01-a956-4efd89e96077/api-keys/PRODUCTION/revoke"' + + /applications/export: + get: + tags: + - Import Export + summary: Export an Application + description: | + This operation can be used to export the details of a particular application as a zip file. + parameters: + - name: appName + in: query + description: | + Application Name + required: true + schema: + type: string + - name: appOwner + in: query + description: | + Owner of the Application + required: true + schema: + type: string + - name: withKeys + in: query + description: | + Export application keys + schema: + type: boolean + - name: format + in: query + description: | + Format of output documents. Can be YAML or JSON. + schema: + type: string + enum: + - JSON + - YAML + responses: + 200: + description: | + OK. Export Successful. + headers: + Content-Type: + description: | + The content type of the body. + schema: + type: string + content: + application/zip: + schema: + type: string + format: binary + 400: + $ref: '#/components/responses/BadRequest' + 404: + $ref: '#/components/responses/NotFound' + 406: + $ref: '#/components/responses/NotAcceptable' + security: + - OAuth2Security: + - apk:app_import_export + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://localhost:9443/api/devportal/applications/export?appName=sampleApp&appOwner=admin&withKeys=true" + > exportedApplication.zip' + + /applications/import: + post: + tags: + - Import Export + summary: Import an Application + description: | + This operation can be used to import an application. + parameters: + - name: preserveOwner + in: query + description: | + Preserve Original Creator of the Application + schema: + type: boolean + - name: skipSubscriptions + in: query + description: | + Skip importing Subscriptions of the Application + schema: + type: boolean + - name: appOwner + in: query + description: | + Expected Owner of the Application in the Import Environment + schema: + type: string + - name: skipApplicationKeys + in: query + description: | + Skip importing Keys of the Application + schema: + type: boolean + - name: update + in: query + description: | + Update if application exists + schema: + type: boolean + requestBody: + content: + multipart/form-data: + schema: + required: + - file + properties: + file: + type: string + description: | + Zip archive consisting of exported Application Configuration. + format: binary + required: true + responses: + 200: + description: | + OK. Successful response with the updated object information as entity in the body. + headers: + Content-Type: + description: | + The content type of the body. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/ApplicationInfo' + # 207: + # description: | + # Multi Status. + # Partially successful response with skipped APIs information object as entity in the body. + # content: + # application/json: + # schema: + # $ref: '#/components/schemas/APIInfoList' + 400: + $ref: '#/components/responses/BadRequest' + 406: + $ref: '#/components/responses/NotAcceptable' + security: + - OAuth2Security: + - apk:app_import_export + x-code-samples: + - lang: Curl + source: 'curl -k -X POST -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + -F file=@exportedApplication.zip "https://127.0.0.1:9443/api/devportal/applications/import?preserveOwner=true&skipSubscriptions=false&appOwner=admin&skipApplicationKeys=false&update=true"' + + ###################################################### + # The "Subscription Collection" resource APIs + ###################################################### + /subscriptions: + get: + tags: + - Subscriptions + summary: | + Get All Subscriptions + description: | + This operation can be used to retrieve a list of subscriptions of the user associated with the provided access token. + parameters: + - $ref: '#/components/parameters/apiId-Q' + - $ref: '#/components/parameters/applicationId-Q' + - $ref: '#/components/parameters/groupId' + - $ref: '#/components/parameters/requestedTenant' + - $ref: '#/components/parameters/offset' + - $ref: '#/components/parameters/limit' + - $ref: '#/components/parameters/If-None-Match' + responses: + 200: + description: | + OK. Subscription list returned. + headers: + ETag: + description: | + Entity Tag of the response resource. Used by caches, or in conditional requests. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/SubscriptionList' + 304: + description: | + Not Modified. Empty body because the client has already the latest version of the requested resource. + content: {} + 406: + $ref: '#/components/responses/NotAcceptable' + security: + - OAuth2Security: + - apk:subscribe + - apk:sub_manage + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://localhost:9443/api/devportal/subscriptions?apiId=02e658e7-71c7-4b1d-a623-be145b789340"' + + post: + tags: + - Subscriptions + summary: | + Add a New Subscription + description: | + This operation can be used to add a new subscription providing the id of the API and the application. + parameters: + - $ref: '#/components/parameters/requestedTenant' + requestBody: + description: | + Subscription object that should to be added + content: + application/json: + schema: + $ref: '#/components/schemas/Subscription' + example: + applicationId: bbcc3be9-e29c-4ba2-a756-d922a5bd6c4d + apiId: abcff4cf-24c5-4298-a7b4-39a1fbd34693 + throttlingPolicy: Unlimited + required: true + responses: + 201: + description: | + Created. Successful response with the newly created object as entity in the body. Location header contains URL of newly created entity. + headers: + ETag: + description: | + Entity Tag of the response resource. Used by caches, or in conditional request. + schema: + type: string + Location: + description: | + Location to the newly created subscription. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/Subscription' + 202: + description: | + Accepted. The request has been accepted. + headers: + Location: + description: | + Location of the newly created subscription. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/WorkflowResponse' + 400: + $ref: '#/components/responses/BadRequest' + 415: + $ref: '#/components/responses/UnsupportedMediaType' + security: + - OAuth2Security: + - apk:subscribe + - apk:sub_manage + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + -H "Content-Type: application/json" -X POST -d @data.json "https://localhost:9443/api/devportal/subscriptions"' + + /subscriptions/multiple: + post: + tags: + - Subscriptions + summary: | + Add New Subscriptions + description: | + This operation can be used to add a new subscriptions providing the ids of the APIs and the applications. + parameters: + - $ref: '#/components/parameters/requestedTenant' + requestBody: + description: | + Subscription objects that should to be added + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Subscription' + example: + - applicationId: bbcc3be9-e29c-4ba2-a756-d922a5bd6c4d + apiId: abcff4cf-24c5-4298-a7b4-39a1fbd34693 + throttlingPolicy: Unlimited + - applicationId: 67543be9-e29c-4ba2-7856-d922a5bd6c4d + apiId: abcff4cf-24c5-4298-a7b4-39a1f7896693 + throttlingPolicy: Bronze + required: true + responses: + 200: + description: | + OK. Successful response with the newly created objects as entity in the body. + headers: + ETag: + description: | + Entity Tag of the response resource. Used by caches, or in conditional requests (Will be supported in future). + schema: + type: string + Content-Type: + description: | + The content type of the body. + schema: + type: string + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Subscription' + 400: + $ref: '#/components/responses/BadRequest' + 415: + $ref: '#/components/responses/UnsupportedMediaType' + security: + - OAuth2Security: + - apk:subscribe + - apk:sub_manage + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + -H "Content-Type: application/json" -X POST -d @data.json "https://localhost:9443/api/devportal/subscriptions/multiple"' + + ###################################################### + # The "Subscriptions related to API" resource API + ###################################################### + /subscriptions/{apiId}/additionalInfo: + get: + tags: + - Subscriptions + summary: Get Additional Information of subscriptions attached to an API. + description: | + This operation can be used to retrieve all additional Information of subscriptions attached to an API by providing the API id. + operationId: getAdditionalInfoOfAPISubscriptions + parameters: + - $ref: '#/components/parameters/apiId' + - $ref: '#/components/parameters/groupId' + - $ref: '#/components/parameters/requestedTenant' + - $ref: '#/components/parameters/offset' + - $ref: '#/components/parameters/limit' + - $ref: '#/components/parameters/If-None-Match' + responses: + 200: + description: | + OK. Types and fields returned successfully. + headers: + Content-Type: + description: | + The content of the body. + schema: + type: string + default: application/json + content: + application/json: + schema: + $ref: '#/components/schemas/AdditionalSubscriptionInfoList' + 404: + description: | + Not Found. Retrieving types and fields failed. + content: {} + security: + - OAuth2Security: [] + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" "https://localhost:9443/api/devportal/subscriptions/e93fb282-b456-48fc-8981-003fb89086ae/additionalInfo"' + + ###################################################### + # The "Individual Subscription" resource APIs + ###################################################### + /subscriptions/{subscriptionId}: + get: + tags: + - Subscriptions + summary: | + Get Details of a Subscription + description: | + This operation can be used to get details of a single subscription. + parameters: + - $ref: '#/components/parameters/subscriptionId' + - $ref: '#/components/parameters/If-None-Match' + responses: + 200: + description: | + OK. Subscription returned + headers: + ETag: + description: Entity Tag of the response resource. Used by caches, or in conditional requests. + schema: + type: string + Last-Modified: + description: Date and time the resource has been modified the last time. Used by caches, or in conditional requests. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/Subscription' + 304: + description: | + Not Modified. Empty body because the client has already the latest version of the requested resource. + content: {} + 404: + $ref: '#/components/responses/NotFound' + security: + - OAuth2Security: + - apk:subscribe + - apk:sub_manage + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://localhost:9443/api/devportal/subscriptions/5b65808c-cdf2-43e1-a695-de63e3ad0ae9"' + + put: + tags: + - Subscriptions + summary: | + Update Existing Subscription + description: | + This operation can be used to update a subscription providing the subscription id, api id, application Id, status and updated throttling policy tier. + parameters: + - $ref: '#/components/parameters/requestedTenant' + - $ref: '#/components/parameters/subscriptionId' + requestBody: + description: | + Subscription object that should to be added + content: + application/json: + schema: + $ref: '#/components/schemas/Subscription' + required: true + responses: + 200: + description: | + Subscription Updated. Successful response with the updated object as entity in the body. Location header contains URL of newly updates entity. + headers: + ETag: + description: | + Entity Tag of the response resource. Used by caches, or in conditional request. + schema: + type: string + Location: + description: | + Location to the updated subscription. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/Subscription' + 202: + description: | + Accepted. The request has been accepted. + headers: + Location: + description: | + Location of the updated subscription. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/WorkflowResponse' + 304: + description: | + Not Modified. Empty body because the client has already the latest version of the requested resource. + content: {} + 400: + $ref: '#/components/responses/BadRequest' + 404: + description: | + Not Found. Requested Subscription does not exist. + content: {} + 415: + description: | + Unsupported media type. The entity of the request was in a not supported format. + content: {} + security: + - OAuth2Security: + - apk:subscribe + - apk:sub_manage + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + -H "Content-Type: application/json" -X PUT -d @data.json "https://localhost:9443/api/devportal/subscriptions/80369180-7d90-4ee8-99a1-19fa68512aa5"' + + delete: + tags: + - Subscriptions + summary: | + Remove a Subscription + description: | + This operation can be used to remove a subscription. + parameters: + - $ref: '#/components/parameters/subscriptionId' + - $ref: '#/components/parameters/If-Match' + responses: + 200: + description: | + OK. Resource successfully deleted. + content: {} + 202: + description: | + Accepted. The request has been accepted. + headers: + Location: + description: | + Location of the existing subscription. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/WorkflowResponse' + 404: + $ref: '#/components/responses/NotFound' + 412: + $ref: '#/components/responses/PreconditionFailed' + security: + - OAuth2Security: + - apk:subscribe + - apk:sub_manage + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + -H "Content-Type: application/json" -X DELETE "https://localhost:9443/api/devportal/subscriptions/80369180-7d90-4ee8-99a1-19fa68512aa5"' + + /subscriptions/{subscriptionId}/usage: + get: + tags: + - API Monetization + summary: Get Details of a Pending Invoice for a Monetized Subscription with + Metered Billing. + description: | + This operation can be used to get details of a pending invoice for a monetized subscription with metered billing. + parameters: + - $ref: '#/components/parameters/subscriptionId' + responses: + 200: + description: | + OK. Details of a pending invoice returned. + headers: + ETag: + description: Entity Tag of the response resource. Used by caches, or in conditional requests (Will be supported in future). + schema: + type: string + Last-Modified: + description: Date and time the resource has been modified the last time. Used by caches, or in conditional requests (Will be supported in future). + schema: + type: string + Content-Type: + description: The content type of the body. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/APIMonetizationUsage' + 304: + description: | + Not Modified. Empty body because the client has already the latest version of the requested resource (Will be supported in future). + content: {} + 404: + $ref: '#/components/responses/NotFound' + security: + - OAuth2Security: + - apk:subscribe + - apk:sub_manage + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://localhost:9443/api/devportal/subscriptions/5b65808c-cdf2-43e1-a695-de63e3ad0ae9/usage"' + + ###################################################### + # The "Throttling Policy Collection" resource APIs + ###################################################### + /throttling-policies/{policyLevel}: + get: + tags: + - Throttling Policies + summary: Get All Available Throttling Policies + description: | + This operation can be used to get all available application or subscription level throttling policies + parameters: + - $ref: '#/components/parameters/limit' + - $ref: '#/components/parameters/offset' + - $ref: '#/components/parameters/policyLevel' + - $ref: '#/components/parameters/If-None-Match' + - $ref: '#/components/parameters/requestedTenant' + responses: + 200: + description: | + OK. List of throttling policies returned. + headers: + ETag: + description: | + Entity Tag of the response resource. Used by caches, or in conditional requests. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/ThrottlingPolicyList' + 304: + description: | + Not Modified. Empty body because the client has already the latest version of the requested resource. + content: {} + 406: + $ref: '#/components/responses/NotAcceptable' + security: + - OAuth2Security: [] + x-code-samples: + - lang: Curl + source: curl -k "https://localhost:9443/api/devportal/throttling-policies/application" + + ###################################################### + # The "Individual Throttling Policy" resource APIs + ###################################################### + /throttling-policies/{policyLevel}/{policyId}: + get: + tags: + - Throttling Policies + summary: | + Get Details of a Throttling Policy + description: | + This operation can be used to retrieve details of a single throttling policy by specifying the policy level and policy name. + parameters: + - $ref: '#/components/parameters/policyId' + - $ref: '#/components/parameters/policyLevel' + - $ref: '#/components/parameters/requestedTenant' + - $ref: '#/components/parameters/If-None-Match' + responses: + 200: + description: | + OK. Throttling Policy returned + headers: + ETag: + description: | + Entity Tag of the response resource. Used by caches, or in conditional requests. + schema: + type: string + Last-Modified: + description: | + Date and time the resource has been modified the last time. Used by caches, or in conditional requests. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/ThrottlingPolicy' + 304: + description: | + Not Modified. Empty body because the client has already the latest version of the requested resource. + content: {} + 404: + $ref: '#/components/responses/NotFound' + 406: + $ref: '#/components/responses/NotAcceptable' + security: + - OAuth2Security: [] + x-code-samples: + - lang: Curl + source: curl -k "https://localhost:9443/api/devportal/throttling-policies/application/10PerMin" + + ###################################################### + # The "Tag Collection" resource API + ###################################################### + /tags: + get: + tags: + - Tags + summary: | + Get All Tags + description: | + This operation can be used to retrieve a list of tags that are already added to APIs. + parameters: + - $ref: '#/components/parameters/limit' + - $ref: '#/components/parameters/offset' + - $ref: '#/components/parameters/requestedTenant' + - $ref: '#/components/parameters/If-None-Match' + responses: + 200: + description: | + OK. Tag list is returned. + headers: + ETag: + description: | + Entity Tag of the response resource. Used by caches, or in conditional requests. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/TagList' + 304: + description: | + Not Modified. Empty body because the client has already the latest version of the requested resource. + content: {} + 404: + $ref: '#/components/responses/NotFound' + 406: + $ref: '#/components/responses/NotAcceptable' + security: + - OAuth2Security: [] + x-code-samples: + - lang: Curl + source: curl -k "https://localhost:9443/api/devportal/tags" + + ###################################################### + # The "Content Search Results" resource APIs + ###################################################### + /search: + get: + tags: + - Unified Search + summary: | + Retrieve/Search APIs and API Documents by Content + description: | + This operation provides you a list of available APIs and API Documents qualifying the given keyword match. + parameters: + - $ref: '#/components/parameters/limit' + - $ref: '#/components/parameters/offset' + - $ref: '#/components/parameters/requestedTenant' + - name: query + in: query + description: | + You can search by using providing the search term in the query parameters. + schema: + type: string + - $ref: '#/components/parameters/If-None-Match' + responses: + 200: + description: | + OK. List of qualifying APIs and docs is returned. + headers: + ETag: + description: | + Entity Tag of the response resource. Used by caches, or in conditional requests (Will be supported in future). + schema: + type: string + Content-Type: + description: The content type of the body. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/SearchResultList' + 304: + description: | + Not Modified. Empty body because the client has already the latest version of the requested resource (Will be supported in future). + content: {} + 406: + $ref: '#/components/responses/NotAcceptable' + security: + - OAuth2Security: [] + x-code-samples: + - lang: Curl + source: curl -k "https://localhost:9443/api/devportal/search?query=PizzaShackAPI" + + ###################################################### + # The "SDK Generation Languages" list resource APIs + ###################################################### + /sdk-gen/languages: + get: + tags: + - SDKs + summary: | + Get a List of Supported SDK Languages + description: | + This operation will provide a list of programming languages that are supported by the swagger codegen library for generating System Development Kits (SDKs) for APIs available in the API Platform for Kubernetes (APK) Developer Portal. + responses: + 200: + description: | + OK. List of supported languages for generating SDKs. + content: + application/json: + example : ["android","java","javascript","jmeter"] + 404: + $ref: '#/components/responses/NotFound' + 500: + $ref: '#/components/responses/InternalServerError' + security: + - OAuth2Security: + - apk:subscribe + x-code-samples: + - lang: Curl + source: curl -k -H "Authorization:Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://localhost:9443/api/devportal/sdk-gen/languages" + + ###################################################### + # The Web hook API topic details + ###################################################### + /webhooks/subscriptions: + get: + tags: + - Webhooks + summary: | + Get available web hook subscriptions for a given application. + description: | + This operation will provide a list of web hook topic subscriptions for a given application. If the api id is provided results will be filtered by the api Id. + parameters: + - $ref: '#/components/parameters/applicationId-Q' + - $ref: '#/components/parameters/apiId-Q' + - $ref: '#/components/parameters/requestedTenant' + responses: + 200: + description: | + OK. Topic list returned. + headers: + ETag: + description: | + Entity Tag of the response resource. Used by caches, or in conditional requests. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/WebhookSubscriptionList' + 404: + $ref: '#/components/responses/NotFound' + 500: + $ref: '#/components/responses/InternalServerError' + security: + - OAuth2Security: [] + x-code-samples: + - lang: Curl + source: curl -k -H "Authorization:Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://localhost:9443/api/devportal/webhooks/subscriptions?applicationId=5b65808c-cdf2-43e1-a695-de63e3ad0ae9&apiId=ae4eae22-3f65-387b-a171-d37eaa366fa8" + + ###################################################### + # The Developer Portal settings List + ###################################################### + /settings: + get: + tags: + - Settings + summary: Retrieve Developer Portal settings + description: | + Retreive Developer Portal settings + parameters: + - $ref: '#/components/parameters/requestedTenant' + responses: + 200: + description: | + OK. Settings returned + content: + application/json: + schema: + $ref: '#/components/schemas/Settings' + 404: + $ref: '#/components/responses/NotFound' + security: + - OAuth2Security: + - apk:store_settings + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://localhost:9443/api/devportal/settings"' + + /settings/application-attributes: + get: + tags: + - Settings + summary: | + Get All Application Attributes from Configuration + description: | + This operation can be used to retrieve the application attributes from configuration. It will not return hidden attributes. + parameters: + - $ref: '#/components/parameters/If-None-Match' + responses: + 200: + description: | + OK. Application attributes returned. + headers: + Content-Type: + description: | + The content type of the body. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/ApplicationAttributeList' + 404: + $ref: '#/components/responses/NotFound' + 406: + $ref: '#/components/responses/NotAcceptable' + security: + - OAuth2Security: + - apk:subscribe + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://localhost:9443/api/devportal/settings/application-attributes"' + + ###################################################### + # The tenant resource APIs + ###################################################### + /tenants: + get: + tags: + - Tenants + summary: | + Get Tenants by State + description: | + This operation is used to get tenants by state + parameters: + - name: state + in: query + description: | + The state represents the current state of the tenant + schema: + type: string + default: active + enum: + - active + - inactive + - $ref: '#/components/parameters/limit' + - $ref: '#/components/parameters/offset' + responses: + 200: + description: | + OK. Tenant names returned. + headers: + Content-Type: + description: | + The content type of the body. + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/TenantList' + 404: + $ref: '#/components/responses/NotFound' + 406: + $ref: '#/components/responses/NotAcceptable' + security: + - OAuth2Security: [] + x-code-samples: + - lang: Curl + source: curl -k "https://localhost:9443/api/devportal/tenants" + + ###################################################### + # The "Recommendations" resource API + ###################################################### + /recommendations: + get: + tags: + - Recommendations + summary: Give API Recommendations for a User + description: This API can be used to get recommended APIs for a user who logs into the API Developer Portal + responses: + 200: + description: | + OK. Requested recommendations are returned + headers: + ETag: + description: | + Entity Tag of the response resource. Used by caches, or in conditional requests + schema: + type: string + content: + application/json: + schema: + $ref: '#/components/schemas/Recommendations' + 404: + $ref: '#/components/responses/NotFound' + security: + - OAuth2Security: + - apk:subscribe + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://localhost:9443/api/devportal/recommendations"' + + ###################################################### + # The "Category Collection" resource API + ###################################################### + /api-categories: + get: + tags: + - API Categories + summary: Get All API Categories + description: | + Get all API categories + parameters: + - $ref: '#/components/parameters/requestedTenant' + responses: + 200: + description: | + OK. Categories returned + content: + application/json: + schema: + $ref: '#/components/schemas/APICategoryList' + security: + - OAuth2Security: [] + x-code-samples: + - lang: Curl + source: curl -k "https://localhost:9443/api/devportal/api-categories" + + ###################################################### + # The "Key Manager Collection" resource API + ###################################################### + /key-managers: + get: + tags: + - Key Managers + summary: Get All Key Managers + description: | + Get all Key managers + parameters: + - $ref: '#/components/parameters/requestedTenant' + responses: + 200: + description: | + OK. Key Manager list returned + content: + application/json: + schema: + $ref: '#/components/schemas/KeyManagerList' + security: + - OAuth2Security: + - apk:subscribe + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://localhost:9443/api/devportal/key-managers"' + + ###################################################### + # GraphQL "Query Complexity" resource APIs + ###################################################### + /apis/{apiId}/graphql-policies/complexity: + get: + tags: + - GraphQL Policies + summary: Get the Complexity Related Details of an API + description: | + This operation can be used to retrieve complexity related details belonging to an API by providing the API id. + parameters: + - $ref: '#/components/parameters/apiId' + responses: + 200: + description: | + OK. Requested complexity details returned. + headers: + Content-Type: + description: | + The content of the body. + schema: + type: string + default: application/json + content: + application/json: + schema: + $ref: '#/components/schemas/GraphQLQueryComplexityInfo' + 404: + description: | + Not Found. Requested API does not contain any complexity details. + content: {} + security: + - OAuth2Security: [] + x-code-samples: + - lang: Curl + source: curl -k "https://localhost:9443/api/devportal/apis/e93fb282-b456-48fc-8981-003fb89086ae/graphql-policies/complexity" + + /apis/{apiId}/graphql-policies/complexity/types: + get: + tags: + - GraphQL Policies + summary: Retrieve Types and Fields of a GraphQL Schema + description: | + This operation can be used to retrieve all types and fields of the GraphQL Schema by providing the API id. + parameters: + - $ref: '#/components/parameters/apiId' + responses: + 200: + description: | + OK. Types and fields returned successfully. + headers: + Content-Type: + description: | + The content of the body. + schema: + type: string + default: application/json + content: + application/json: + schema: + $ref: '#/components/schemas/GraphQLSchemaTypeList' + 404: + description: | + Not Found. Retrieving types and fields failed. + content: {} + security: + - OAuth2Security: [] + x-code-samples: + - lang: Curl + source: curl -k "https://localhost:9443/api/devportal/apis/e93fb282-b456-48fc-8981-003fb89086ae/graphql-policies/complexity/types" + + ###################################################### + # User resource APIs + ###################################################### + /me/change-password: + post: + tags: + - Users + summary: Change the Password of the user + description: | + Using this operation, logged-in user can change their password. + operationId: changeUserPassword + requestBody: + description: | + Current and new password of the user + content: + application/json: + schema: + $ref: '#/components/schemas/CurrentAndNewPasswords' + required: true + responses: + 200: + description: OK. User password changed successfully + content: {} + 400: + $ref: '#/components/responses/BadRequest' + security: + - OAuth2Security: + - apk:subscribe + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + -H "Content-Type: application/json" -X POST -d @data.json "https://localhost:9443/api/devportal/me/change-password"' + +components: + schemas: + APIList: + title: API List + type: object + properties: + count: + type: integer + description: | + Number of APIs returned. + example: 1 + list: + type: array + items: + $ref: '#/components/schemas/APIInfo' + pagination: + $ref: '#/components/schemas/Pagination' + example: + count: 2 + list: + - id: 01234567-0123-0123-0123-012345678901 + name: CalculatorAPI + description: A calculator API that supports basic operations + context: /CalculatorAPI + version: 1.0.0 + type: HTTP + provider: admin + lifeCycleStatus: PUBLISHED + thumbnailUri: /apis/01234567-0123-0123-0123-012345678901/thumbnail + avgRating: 4.3 + throttlingPolicies: [Unlimited] + advertiseInfo: + advertised: false, + apiExternalProductionEndpoint: null, + apiExternalSandboxEndpoint: null, + originalDevPortalUrl: null, + apiOwner: null + businessInformation: + businessOwner: Jane Roe + businessOwnerEmail: businessowner@wso2.com + technicalOwner: John Doe + technicalOwnerEmail: technicalowner@wso2.com + isSubscriptionAvailable: true + monetizationLabel: null + - id: 01123567-1233-5453-0212-12353678901 + name: PizzaShackAPI + description: A Pizza ordering API + context: /PizzaShackAPI + version: 1.0.0 + type: HTTP + provider: admin + lifeCycleStatus: PUBLISHED + thumbnailUri: /apis/01123567-1233-5453-0212-12353678901/thumbnail + avgRating: 4.3 + throttlingPolicies: [ Unlimited ] + advertiseInfo: + advertised: false, + apiExternalProductionEndpoint: null, + apiExternalSandboxEndpoint: null, + originalDevPortalUrl: null, + apiOwner: null + businessInformation: + businessOwner: Jane Roe + businessOwnerEmail: businessowner@wso2.com + technicalOwner: John Doe + technicalOwnerEmail: technicalowner@wso2.com + isSubscriptionAvailable: true + monetizationLabel: null + pagination: + offset: 2 + limit: 2 + total: 10 + next: /apis?limit=2&offset=4 + previous: /apis?limit=2&offset=0 + APIInfo: + title: API Info object with basic API details. + type: object + properties: + id: + type: string + example: 01234567-0123-0123-0123-012345678901 + name: + type: string + example: CalculatorAPI + description: + type: string + example: A calculator API that supports basic operations + context: + type: string + example: CalculatorAPI + version: + type: string + example: 1.0.0 + type: + type: string + example: WS + createdTime: + type: string + example: 1614020559444 + provider: + type: string + description: | + If the provider value is not given, the user invoking the API will be used as the provider. + example: admin + lifeCycleStatus: + type: string + example: PUBLISHED + thumbnailUri: + type: string + example: /apis/01234567-0123-0123-0123-012345678901/thumbnail + avgRating: + type: string + description: Average rating of the API + example: "4.5" + throttlingPolicies: + type: array + description: List of throttling policies of the API + example: + - Unlimited + - Bronze + items: + type: string + advertiseInfo: + $ref: '#/components/schemas/AdvertiseInfo' + businessInformation: + $ref: '#/components/schemas/APIBusinessInformation' + isSubscriptionAvailable: + type: boolean + example: false + monetizationLabel: + type: string + example: Free + gatewayVendor: + type: string + example: WSO2 + additionalProperties: + type: array + items: + type: object + properties: + name: + type: string + value: + type: string + display: + type: boolean + description: | + Custom(user defined) properties of API + example: { } + APIInfoList: + title: API Info List + type: object + properties: + count: + type: integer + description: | + Number of API Info objects returned. + example: 1 + list: + type: array + items: + $ref: '#/components/schemas/APIInfo' + APIDefinition: + title: API Schema + required: + - type + type: object + properties: + type: + type: string + enum: + - swagger + - graphql + - wsdl + - async + schemaDefinition: + type: string + API: + title: API object + required: + - context + - lifeCycleStatus + - name + - version + type: object + properties: + id: + type: string + description: | + UUID of the api + example: 01234567-0123-0123-0123-012345678901 + name: + type: string + description: Name of the API + example: CalculatorAPI + description: + type: string + description: A brief description about the API + example: A calculator API that supports basic operations + context: + type: string + description: A string that represents the context of the user's request + example: CalculatorAPI + version: + type: string + description: The version of the API + example: 1.0.0 + apiDefinition: + type: string + description: | + Swagger definition of the API which contains details about URI templates and scopes + example: '{"paths":{"\/subtract":{"get":{"x-auth-type":"Application & Application + User","x-throttling-tier":"Unlimited","parameters":[{"name":"x","required":true,"type":"string","in":"query"},{"name":"y","required":true,"type":"string","in":"query"}],"responses":{"200":{}}}},"\/add":{"get":{"x-auth-type":"Application + & Application User","x-throttling-tier":"Unlimited","parameters":[{"name":"x","required":true,"type":"string","in":"query"},{"name":"y","required":true,"type":"string","in":"query"}],"responses":{"200":{}}}}},"swagger":"2.0","info":{"title":"CalculatorAPI","version":"1.0.0"}}' + wsdlUri: + type: string + description: | + WSDL URL if the API is based on a WSDL endpoint + example: http://www.webservicex.com/globalweather.asmx?wsdl + lifeCycleStatus: + type: string + description: This describes in which status of the lifecycle the API is. + example: PUBLISHED + isDefaultVersion: + type: boolean + example: false + type: + type: string + description: This describes the transport type of the API + example: HTTP + transport: + type: array + example: + - http + - https + items: + type: string + description: | + Supported transports for the API (http and/or https). + operations: + type: array + example: [] + items: + $ref: '#/components/schemas/APIOperations' + authorizationHeader: + type: string + description: | + Name of the Authorization header used for invoking the API. If it is not set, Authorization header name specified + in tenant or system level will be used. + example: Authorization + securityScheme: + type: array + description: | + Types of API security, the current API secured with. It can be either OAuth2 or mutual SSL or both. If + it is not set OAuth2 will be set as the security for the current API. + example: + - oauth2 + - oauth_basic_auth_api_key_mandatory + items: + type: string + tags: + type: array + description: Search keywords related to the API + example: + - subtract + - add + items: + type: string + tiers: + type: array + description: The subscription tiers selected for the particular API + items: + type: object + properties: + tierName: + type: string + example: Gold + tierPlan: + type: string + example: COMMERCIAL + monetizationAttributes: + type: object + properties: + fixedPrice: + type: string + example: "10" + pricePerRequest: + type: string + example: "1" + currencyType: + type: string + example: USD + billingCycle: + type: string + example: month + hasThumbnail: + type: boolean + example: true + default: false + additionalProperties: + type: array + items: + type: object + properties: + name: + type: string + value: + type: string + display: + type: boolean + description: | + Custom(user defined) properties of API + example: {} + monetization: + $ref: '#/components/schemas/APIMonetizationInfo' + endpointURLs: + type: array + items: + type: object + properties: + environmentName: + type: string + example: Default + environmentDisplayName: + type: string + example: Default + environmentType: + type: string + example: hybrid + URLs: + type: object + properties: + http: + type: string + description: HTTP environment URL + example: http://localhost:8280/phoneverify/1.0.0 + https: + type: string + description: HTTPS environment URL + example: https://localhost:8243/phoneverify/1.0.0 + ws: + type: string + description: WS environment URL + example: ws://localhost:9099/phoneverify/1.0.0 + wss: + type: string + description: WSS environment URL + example: wss://localhost:9099/phoneverify/1.0.0 + defaultVersionURLs: + type: object + properties: + http: + type: string + description: HTTP environment default URL + example: http://localhost:8280/phoneverify/ + https: + type: string + description: HTTPS environment default URL + example: https://localhost:8243/phoneverify/ + ws: + type: string + description: WS environment default URL + example: ws://localhost:9099/phoneverify/ + wss: + type: string + description: WSS environment default URL + example: wss://localhost:9099/phoneverify/ + businessInformation: + $ref: '#/components/schemas/APIBusinessInformation' + environmentList: + type: array + description: The environment list configured with non empty endpoint URLs + for the particular API. + example: + - PRODUCTION + - SANDBOX + items: + type: string + scopes: + type: array + items: + $ref: '#/components/schemas/ScopeInfo' + avgRating: + type: string + description: The average rating of the API + example: "4.5" + advertiseInfo: + $ref: '#/components/schemas/AdvertiseInfo' + isSubscriptionAvailable: + type: boolean + example: false + categories: + type: array + description: | + API categories + items: + type: string + example: "Marketing" + sdk: + type: array + description: | + Supported SDK + example: [] + items: + type: string + keyManagers: + type: object + properties: {} + description: | + API Key Managers + example: ["all"] + createdTime: + type: string + example: 2020-10-31T13:57:16.229 + lastUpdatedTime: + type: string + example: 2020-10-31T13:57:16.229 + gatewayVendor: + title: Gateway vendor of the API + type: string + example: + wso2 + asyncTransportProtocols: + type: array + description: | + Supported transports for the Async API. + example: + - http + - mqtt + items: + type: string + APIMonetizationInfo: + title: API monetization object + required: + - enabled + type: object + properties: + enabled: + type: boolean + description: Flag to indicate the monetization status + example: true + ApplicationList: + title: Application List + type: object + properties: + count: + type: integer + description: | + Number of applications returned. + example: 1 + list: + type: array + items: + $ref: '#/components/schemas/ApplicationInfo' + pagination: + $ref: '#/components/schemas/Pagination' + Application: + title: Application + required: + - name + type: object + properties: + applicationId: + type: string + readOnly: true + example: 01234567-0123-0123-0123-012345678901 + name: + maxLength: 100 + minLength: 1 + type: string + example: CalculatorApp + description: + maxLength: 512 + type: string + example: Sample calculator application + status: + type: string + readOnly: true + example: APPROVED + default: "" + groups: + type: array + example: [] + items: + type: string + subscriptionCount: + type: integer + readOnly: true + attributes: + type: object + additionalProperties: + type: string + example: {} + owner: + type: string + description: | + Application created user + readOnly: true + example: admin + createdTime: + type: string + readOnly: true + example: 1651555310208 + updatedTime: + type: string + readOnly: true + example: 1651555310208 + ApplicationInfo: + title: Application info object with basic application details + type: object + properties: + applicationId: + type: string + example: 01234567-0123-0123-0123-012345678901 + name: + type: string + example: CalculatorApp + throttlingPolicy: + type: string + example: Unlimited + description: + type: string + example: Sample calculator application + status: + type: string + example: APPROVED + default: "" + groups: + type: array + example: "" + items: + type: string + subscriptionCount: + type: integer + attributes: + type: object + properties: {} + example: External Reference ID, Billing Tier + owner: + type: string + example: admin + createdTime: + type: string + readOnly: true + example: 1651555310208 + updatedTime: + type: string + readOnly: true + example: 1651555310208 + DocumentList: + title: Document List + type: object + properties: + count: + type: integer + description: | + Number of Documents returned. + example: 1 + list: + type: array + items: + $ref: '#/components/schemas/Document' + pagination: + $ref: '#/components/schemas/Pagination' + Document: + title: Document + required: + - name + - sourceType + - type + type: object + properties: + documentId: + type: string + example: 01234567-0123-0123-0123-012345678901 + name: + type: string + example: CalculatorDoc + documentType: + type: string + example: HOWTO + enum: + - HOWTO + - SAMPLES + - PUBLIC_FORUM + - SUPPORT_FORUM + - API_MESSAGE_FORMAT + - SWAGGER_DOC + - OTHER + summary: + type: string + example: Summary of Calculator Documentation + sourceType: + type: string + example: INLINE + enum: + - INLINE + - MARKDOWN + - URL + - FILE + sourceUrl: + type: string + example: "" + otherTypeName: + type: string + example: "" + ThrottlingPolicyList: + title: Throttling Policy List + type: object + properties: + count: + type: integer + description: | + Number of Throttling Policies returned. + example: 1 + list: + type: array + items: + $ref: '#/components/schemas/ThrottlingPolicy' + pagination: + $ref: '#/components/schemas/Pagination' + ThrottlingPolicy: + title: Throttling Policy + required: + - name + - requestCount + - stopOnQuotaReach + - tierPlan + - unitTime + type: object + properties: + name: + type: string + example: Platinum + description: + type: string + example: Allows 50 request(s) per minute. + policyLevel: + type: string + example: subscription + enum: + - application + - subscription + attributes: + type: object + additionalProperties: + type: string + description: | + Custom attributes added to the throttling policy + example: {} + requestCount: + type: integer + description: | + Maximum number of requests which can be sent within a provided unit time + format: int64 + example: 50 + dataUnit: + description: | + Unit of data allowed to be transferred. Allowed values are "KB", "MB" and "GB" + type: string + example: KB + unitTime: + type: integer + format: int64 + example: 60000 + timeUnit: + type: string + example: min + rateLimitCount: + type: integer + default: 0 + description: Burst control request count + example: 10 + rateLimitTimeUnit: + type: string + description: Burst control time unit + example: min + quotaPolicyType: + type: string + description: Default quota limit type + enum: + - REQUESTCOUNT + - BANDWIDTHVOLUME + example: REQUESTCOUNT + tierPlan: + type: string + description: | + This attribute declares whether this tier is available under commercial or free + example: FREE + enum: + - FREE + - COMMERCIAL + stopOnQuotaReach: + type: boolean + description: | + If this attribute is set to false, you are capable of sending requests + even if the request count exceeded within a unit time + example: true + monetizationAttributes: + $ref: '#/components/schemas/MonetizationInfo' + throttlingPolicyPermissions: + $ref: '#/components/schemas/ThrottlingPolicyPermissionInfo' + SubscriptionList: + title: Subscription List + type: object + properties: + count: + type: integer + description: | + Number of Subscriptions returned. + example: 1 + list: + type: array + items: + $ref: '#/components/schemas/Subscription' + pagination: + $ref: '#/components/schemas/Pagination' + TopicList: + title: Topic List + type: object + properties: + count: + type: integer + description: | + Number of Topics returned. + example: 1 + list: + type: array + items: + $ref: '#/components/schemas/Topic' + pagination: + $ref: '#/components/schemas/Pagination' + Topic: + title: Topic + type: object + properties: + apiId: + type: string + example: faae5fcc-cbae-40c4-bf43-89931630d313 + name: + type: string + example: orderBooks + type: + type: string + example: publisher + WebhookSubscriptionList: + title: Subscribed Webhook List + type: object + properties: + count: + type: integer + description: | + Number of webhook subscriptions returned. + example: 1 + list: + type: array + items: + $ref: '#/components/schemas/WebhookSubscription' + pagination: + $ref: '#/components/schemas/Pagination' + WebhookSubscription: + title: Webhook Subscription + type: object + properties: + apiId: + type: string + example: faae5fcc-cbae-40c4-bf43-89931630d313 + appId: + type: string + example: faae5fcc-cbae-40c4-bf43-89931630d313 + topic: + type: string + example: orderBooks + callBackUrl: + type: string + example: www.orderbooksite.com + deliveryTime: + type: string + example: faae5fcc-cbae-40c4-bf43-89931630d313 + deliveryStatus: + type: integer + example: 1 + APIBusinessInformation: + type: object + properties: + businessOwner: + type: string + example: businessowner + businessOwnerEmail: + type: string + example: businessowner@wso2.com + technicalOwner: + type: string + example: technicalowner + technicalOwnerEmail: + type: string + example: technicalowner@wso2.com + Subscription: + title: Subscription + required: + - applicationId + - apiId + type: object + properties: + subscriptionId: + type: string + description: The UUID of the subscription + readOnly: true + example: faae5fcc-cbae-40c4-bf43-89931630d313 + applicationId: + type: string + description: The UUID of the application + example: b3ade481-30b0-4b38-9a67-498a40873a6d + apiId: + type: string + description: The unique identifier of the API. + example: 2962f3bb-8330-438e-baee-0ee1d6434ba4 + apiInfo: + $ref: '#/components/schemas/APIInfo' + applicationInfo: + $ref: '#/components/schemas/ApplicationInfo' + status: + type: string + example: UNBLOCKED + enum: + - BLOCKED + - PROD_ONLY_BLOCKED + - UNBLOCKED + - ON_HOLD + - REJECTED + - TIER_UPDATE_PENDING + - DELETE_PENDING + redirectionParams: + type: string + description: A url and other parameters the subscriber can be redirected. + readOnly: true + example: "" + Tag: + title: Tag + type: object + properties: + value: + type: string + example: tag1 + count: + type: integer + example: 5 + TagList: + title: Tag List + type: object + properties: + count: + type: integer + description: | + Number of Tags returned. + example: 1 + list: + type: array + items: + $ref: '#/components/schemas/Tag' + pagination: + $ref: '#/components/schemas/Pagination' + Rating: + title: Rating + required: + - rating + type: object + properties: + ratingId: + type: string + readOnly: true + example: 32acfa7a-77f8-4fe0-bb7f-a902f36546d0 + apiId: + type: string + readOnly: true + example: e93fb282-b456-48fc-8981-003fb89086ae + ratedBy: + maxLength: 50 + type: string + readOnly: true + example: admin + rating: + type: integer + example: 4 + RatingList: + title: Rating List + type: object + properties: + avgRating: + type: string + description: | + Average Rating of the API + example: "4" + userRating: + type: integer + description: | + Rating given by the user + example: 4 + count: + type: integer + description: | + Number of Subscriber Ratings returned. + example: 1 + list: + type: array + items: + $ref: '#/components/schemas/Rating' + pagination: + $ref: '#/components/schemas/Pagination' + Comment: + title: Comment + required: + - content + type: object + properties: + id: + type: string + readOnly: true + example: 943d3002-000c-42d3-a1b9-d6559f8a4d49 + content: + maxLength: 512 + type: string + example: This is a comment + createdTime: + type: string + readOnly: true + example: 2021-02-11-09:57:25 + createdBy: + type: string + readOnly: true + example: admin + updatedTime: + type: string + readOnly: true + example: 2021-02-12-19:57:25 + category: + type: string + readOnly: true + default: general + example : general + parentCommentId: + type: string + readOnly: true + example: 6f38aea2-f41e-4ac9-b3f2-a9493d00ba97 + entryPoint: + type: string + readOnly: true + enum: [devPortal, publisher] + commenterInfo: + $ref: '#/components/schemas/CommenterInfo' + replies: + $ref: '#/components/schemas/CommentList' + CommentList: + title: Comments List + type: object + properties: + count: + type: integer + readOnly: true + description: | + Number of Comments returned. + example: 1 + list: + type: array + readOnly: true + items: + $ref: '#/components/schemas/Comment' + pagination: + $ref: '#/components/schemas/Pagination' + Error: + title: Error object returned with 4XX HTTP status + required: + - code + - message + type: object + properties: + code: + type: integer + format: int64 + message: + type: string + description: Error message. + description: + type: string + description: | + A detail description about the error message. + moreInfo: + type: string + description: | + Preferably an url with more details about the error. + error: + type: array + description: | + If there are more than one error list them out. + For example, list out validation errors by each field. + items: + $ref: '#/components/schemas/ErrorListItem' + ErrorListItem: + title: Description of individual errors that may have occurred during a request. + required: + - code + - message + type: object + properties: + code: + type: string + message: + type: string + description: | + Description about individual errors occurred + ApplicationToken: + title: Application token details to invoke APIs + type: object + properties: + accessToken: + type: string + description: Access token + example: 1.2345678901234568E30 + tokenScopes: + type: array + description: Valid comma separated scopes for the access token + example: + - default + - read_api + - write_api + items: + type: string + validityTime: + type: integer + description: Maximum validity time for the access token + format: int64 + example: 3600 + APIKey: + title: API Key details to invoke APIs + type: object + properties: + apikey: + type: string + description: API Key + example: eyJoZWxsbyI6IndvcmxkIn0=.eyJ3c28yIjoiYXBpbSJ9.eyJ3c28yIjoic2lnbmF0dXJlIn0= + validityTime: + type: integer + format: int32 + example: 3600 + ApplicationKey: + title: Application key details + type: object + properties: + keyMappingId: + type: string + description: Key Manager Mapping UUID + readOnly: true + example: 92ab520c-8847-427a-a921-3ed19b15aad7 + keyManager: + type: string + description: Key Manager Name + example: Resident Key Manager + consumerKey: + type: string + description: Consumer key of the application + readOnly: true + example: vYDoc9s7IgAFdkSyNDaswBX7ejoa + consumerSecret: + type: string + description: Consumer secret of the application + readOnly: true + example: TIDlOFkpzB7WjufO3OJUhy1fsvAa + supportedGrantTypes: + type: array + description: The grant types that are supported by the application + example: + - client_credentials + - password + items: + type: string + callbackUrls: + type: array + description: Callback URLs of the application + items: + type: string + example: + - http://sample.com/callback/url + keyState: + type: string + description: Describes the state of the key generation. + example: APPROVED + keyType: + type: string + description: Describes to which endpoint the key belongs + example: PRODUCTION + enum: + - PRODUCTION + - SANDBOX + mode: + type: string + description: Describe the which mode Application Mapped. + example: CREATED + enum: + - MAPPED + - CREATED + token: + $ref: '#/components/schemas/ApplicationToken' + additionalProperties: + type: object + properties: {} + description: additionalProperties (if any). + ApplicationKeyReGenerateResponse: + title: Application key details after re generating consumer secret + type: object + properties: + consumerKey: + type: string + description: The consumer key associated with the application, used to identify + the client + example: vYDoc9s7IgAFdkSyNDaswBX7ejoa + consumerSecret: + type: string + description: The client secret that is used to authenticate the client with + the authentication server + example: TIDlOFkpzB7WjufO3OJUhy1fsvAa + ApplicationKeyList: + title: Application Keys List + type: object + properties: + count: + type: integer + description: | + Number of applications keys returned. + example: 1 + list: + type: array + items: + $ref: '#/components/schemas/ApplicationKey' + ApplicationKeyGenerateRequest: + title: Application key generation request object + required: + - grantTypesToBeSupported + - keyType + type: object + properties: + keyType: + type: string + enum: + - PRODUCTION + - SANDBOX + keyManager: + type: string + description: key Manager to Generate Keys + example: abcff4cf-24c5-4298-a7b4-39a1fbd34693 + grantTypesToBeSupported: + type: array + description: Grant types that should be supported by the application + example: + - password + - client_credentials + items: + type: string + callbackUrls: + type: array + items: + type: string + description: Callback URL + example: http://sample.com/callback/url + clientId: + type: string + description: Client ID for generating access token. + readOnly: true + example: sZzoeSCI_vL2cjSXZQmsmV8JEyga + clientSecret: + type: string + description: Client secret for generating access token. This is given together + with the client Id. + readOnly: true + example: nrs3YAP4htxnz_DqpvGhf9Um04oa + additionalProperties: + type: object + properties: {} + description: Additional properties needed. + example: {} + ApplicationKeyMappingRequest: + title: Application key provision request object + required: + - consumerKey + - keyType + type: object + properties: + consumerKey: + type: string + description: Consumer key of the application + example: oYhwZu4P2ThDmiDprBk6c0YfjR8a + consumerSecret: + type: string + description: Consumer secret of the application + example: ondWGtFTCOVM4sfPyOfZ7fel610a + keyManager: + type: string + description: Key Manager Name + example: Resident Key Manager + keyType: + type: string + enum: + - PRODUCTION + - SANDBOX + ApplicationTokenGenerateRequest: + title: Application access token generation request object + type: object + properties: + consumerSecret: + type: string + description: Consumer secret of the application + example: cV5pvyisxug5b5QZInq9cGZrMOMa + validityPeriod: + type: integer + description: Token validity period + format: int64 + example: 3600 + revokeToken: + type: string + description: Token to be revoked, if any + example: "" + grantType: + type: string + default: CLIENT_CREDENTIALS + enum: + - CLIENT_CREDENTIALS + - TOKEN_EXCHANGE + scopes: + type: array + description: Scopes to be assigned to the access token + items: + type: string + example: + - scope2 + additionalProperties: + type: object + properties: {} + description: Additional parameters if Authorization server needs any + APIKeyGenerateRequest: + title: API Key generation request object + type: object + properties: + validityPeriod: + type: integer + description: Token validity period + format: int32 + example: 3600 + additionalProperties: + type: object + properties: {} + description: Additional parameters if Authorization server needs any + APIKeyRevokeRequest: + title: API Key revoke request object + type: object + properties: + apikey: + type: string + description: API Key to revoke + example: eyJoZWxsbyI6IndvcmxkIn0=.eyJ3c28yIjoiYXBpbSJ9.eyJ3c28yIjoic2lnbmF0dXJlIn0= + ScopeInfo: + title: API Scope info object with scope details + type: object + properties: + key: + type: string + example: admin_scope + name: + type: string + example: admin scope + roles: + type: array + description: Allowed roles for the scope + example: + - manager + - developer + items: + type: string + description: + type: string + description: Description of the scope + ScopeList: + title: Scope list + type: object + properties: + count: + type: integer + description: | + Number of results returned. + example: 1 + list: + type: array + items: + $ref: '#/components/schemas/ScopeInfo' + pagination: + $ref: '#/components/schemas/Pagination' + ThrottlingPolicyPermissionInfo: + title: Throttling Policy Permission info object with throttling policy permission + details + type: object + properties: + type: + type: string + enum: + - allow + - deny + roles: + type: array + description: roles for this permission + example: + - manager + - developer + items: + type: string + MonetizationInfo: + title: Monetization + type: object + properties: + billingType: + type: string + example: fixedPrice + enum: + - fixedPrice + - dynamicRate + billingCycle: + type: string + example: month + fixedPrice: + type: string + example: "10" + pricePerRequest: + type: string + example: "1" + currencyType: + type: string + example: USD + APIMonetizationUsage: + title: API monetization usage object + type: object + properties: + properties: + type: object + additionalProperties: + type: string + description: Map of custom properties related to monetization usage + WorkflowResponse: + title: workflow Response + required: + - workflowStatus + type: object + properties: + workflowStatus: + type: string + description: | + This attribute declares whether this workflow task is approved or rejected. + example: APPROVED + enum: + - CREATED + - APPROVED + - REJECTED + - REGISTERED + jsonPayload: + type: string + description: | + Attributes that returned after the workflow execution + User: + title: User + required: + - email + - firstName + - lastName + - password + - username + type: object + properties: + username: + type: string + password: + type: string + firstName: + type: string + lastName: + type: string + email: + type: string + APIOperations: + title: Operation + type: object + properties: + id: + type: string + example: apioperation + target: + type: string + verb: + type: string + SearchResultList: + title: Search Result List + type: object + properties: + count: + type: integer + description: | + Number of results returned. + example: 1 + list: + type: array + items: + type: object + example: + - id: abcff4cf-24c5-4298-a7b4-39a1fbd34693 + name: PizzaShackAPI + type: API + transportType: + description: + context: "/pizzashack" + version: 1.0.0 + provider: admin + status: PUBLISHED + thumbnailUri: + businessInformation: + businessOwner: Jane Roe + businessOwnerEmail: businessowner@wso2.com + technicalOwner: John Doe + technicalOwnerEmail: technicalowner@wso2.com + avgRating: '4.0' + pagination: + $ref: '#/components/schemas/Pagination' + SearchResult: + title: Search Result + required: + - name + type: object + properties: + id: + type: string + example: 01234567-0123-0123-0123-012345678901 + name: + type: string + example: TestAPI + type: + type: string + example: API + enum: + - DOC + - API + transportType: + type: string + description: Accepted values are HTTP, WS, SOAPTOREST, GRAPHQL + discriminator: + propertyName: name + APISearchResult: + title: API Result + allOf: + - $ref: '#/components/schemas/SearchResult' + - type: object + properties: + description: + type: string + description: A brief description about the API + example: A calculator API that supports basic operations + context: + type: string + description: A string that represents the context of the user's request + example: CalculatorAPI + version: + type: string + description: The version of the API + example: 1.0.0 + provider: + type: string + description: | + If the provider value is not given, the user invoking the API will be used as the provider. + example: admin + status: + type: string + description: This describes in which status of the lifecycle the API is + example: CREATED + thumbnailUri: + type: string + example: /apis/01234567-0123-0123-0123-012345678901/thumbnail + businessInformation: + $ref: '#/components/schemas/APIBusinessInformation' + avgRating: + type: string + description: Average rating of the API + example: "4.5" + DocumentSearchResult: + title: Document Result + allOf: + - $ref: '#/components/schemas/SearchResult' + - type: object + properties: + docType: + type: string + example: HOWTO + enum: + - HOWTO + - SAMPLES + - PUBLIC_FORUM + - SUPPORT_FORUM + - API_MESSAGE_FORMAT + - SWAGGER_DOC + - OTHER + summary: + type: string + example: Summary of Calculator Documentation + sourceType: + type: string + example: INLINE + enum: + - INLINE + - URL + - FILE + - MARKDOWN + sourceUrl: + type: string + example: "" + otherTypeName: + type: string + example: "" + visibility: + type: string + example: API_LEVEL + enum: + - OWNER_ONLY + - PRIVATE + - API_LEVEL + apiName: + type: string + description: The name of the associated API + example: TestAPI + apiVersion: + type: string + description: The version of the associated API + example: 1.0.0 + apiProvider: + type: string + example: admin + apiUUID: + type: string + CommenterInfo: + type: object + properties: + firstName: + type: string + example: John + lastName: + type: string + example: David + fullName: + type: string + example: John David + Pagination: + title: Pagination + type: object + properties: + offset: + type: integer + example: 0 + limit: + type: integer + example: 10 + total: + type: integer + example: 1 + next: + type: string + description: | + Link to the next subset of resources qualified. + Empty if no more resources are to be returned. + example: "" + previous: + type: string + description: | + Link to the previous subset of resources qualified. + Empty if current subset is the first subset returned. + example: "" + Settings: + title: Settings + type: object + properties: + grantTypes: + type: array + items: + type: string + example: + - refresh_token + - urn:ietf:params:oauth:grant-type:saml2-bearer + - password + - client_credentials + - iwa:ntlm + - authorization_code + - urn:ietf:params:oauth:grant-type:jwt-bearer + applicationSharingEnabled: + type: boolean + default: false + mapExistingAuthApps: + type: boolean + default: false + apiGatewayEndpoint: + type: string + monetizationEnabled: + type: boolean + default: false + recommendationEnabled: + type: boolean + default: false + IsUnlimitedTierPaid: + type: boolean + default: false + identityProvider: + type: object + properties: + external: + type: boolean + default: false + IsAnonymousModeEnabled: + type: boolean + default: true + IsPasswordChangeEnabled: + type: boolean + default: true + userStorePasswordPattern: + type: string + description: The 'PasswordJavaRegEx' configured in the UserStoreManager + example: "^[\\S]{5,30}$" + passwordPolicyPattern: + type: string + description: The regex configured in the Password Policy property 'passwordPolicy.pattern' + example: "^[\\S]{5,30}$" + passwordPolicyMinLength: + type: integer + description: If Password Policy Feature is enabled, the property 'passwordPolicy.min.length' + is returned as the 'passwordPolicyMinLength'. If password policy is not + enabled, default value -1 will be returned. And it should be noted that + the regex pattern(s) returned in 'passwordPolicyPattern' and 'userStorePasswordPattern' + properties too will affect the minimum password length allowed and an + intersection of all conditions will be considered finally to validate + the password. + passwordPolicyMaxLength: + type: integer + description: If Password Policy Feature is enabled, the property 'passwordPolicy.max.length' + is returned as the 'passwordPolicyMaxLength'. If password policy is not + enabled, default value -1 will be returned. And it should be noted that + the regex pattern(s) returned in 'passwordPolicyPattern' and 'userStorePasswordPattern' + properties too will affect the maximum password length allowed and an + intersection of all conditions will be considered finally to validate + the password. + ApplicationAttribute: + title: Application attributes + type: object + properties: + description: + type: string + description: description of the application attribute + example: Sample description of the attribute + type: + type: string + description: type of the input element to display + example: text + tooltip: + type: string + description: tooltop to display for the input element + example: Sample tooltip + required: + type: string + description: whether this is a required attribute + example: "false" + attribute: + type: string + description: the name of the attribute + example: External Reference Id + hidden: + type: string + description: whether this is a hidden attribute + example: "false" + ApplicationAttributeList: + title: Application Attributes List + type: object + properties: + count: + type: integer + description: | + Number of application attributes returned. + example: 1 + list: + type: array + items: + $ref: '#/components/schemas/ApplicationAttribute' + Tenant: + title: Tenant + type: object + properties: + domain: + type: string + description: tenant domain + example: wso2.com + status: + type: string + description: current status of the tenant active/inactive + example: active + TenantList: + title: Tenant list + type: object + properties: + count: + type: integer + description: | + Number of tenants returned. + example: 1 + list: + type: array + items: + $ref: '#/components/schemas/Tenant' + pagination: + $ref: '#/components/schemas/Pagination' + AdvertiseInfo: + title: API Advertise info object with advertise details + type: object + properties: + advertised: + type: boolean + example: true + apiExternalProductionEndpoint: + type: string + example: https://localhost:9443/devportal + apiExternalSandboxEndpoint: + type: string + example: https://localhost:9443/devportal + originalDevPortalUrl: + type: string + example: https://localhost:9443/devportal + apiOwner: + type: string + example: admin + vendor: + type: string + default: WSO2 + enum: + - WSO2 + - AWS + APICategory: + title: API Category + required: + - name + type: object + properties: + id: + type: string + example: 01234567-0123-0123-0123-012345678901 + name: + type: string + example: Finance + description: + type: string + example: Finance related APIs + APICategoryList: + title: API Category List + type: object + properties: + count: + type: integer + description: | + Number of API categories returned. + example: 1 + list: + type: array + items: + $ref: '#/components/schemas/APICategory' + Recommendations: + title: API recommendations + type: object + properties: + count: + type: integer + description: | + Number of APIs returned. + example: 1 + list: + type: array + items: + $ref: '#/components/schemas/recommendedAPI' + recommendedAPI: + title: Recommended API + type: object + properties: + id: + type: string + example: 01234567-0123-0123-0123-012345678901 + name: + type: string + example: CalculatorAPI + avgRating: + type: string + description: Average rating of the API + example: "4.5" + KeyManagerInfo: + title: Key Manager Info + required: + - name + - type + type: object + properties: + id: + type: string + example: 01234567-0123-0123-0123-012345678901 + name: + type: string + example: Resident Key Manager + type: + type: string + example: default + displayName: + type: string + description: | + display name of Keymanager + example: Resident Key Manager + description: + type: string + example: This is Resident Key Manager + enabled: + type: boolean + example: true + availableGrantTypes: + type: array + items: + type: string + example: client_credentials + tokenEndpoint: + type: string + example: https://localhost:9443/oauth2/token + revokeEndpoint: + type: string + example: https://localhost:9443/oauth2/revoke + userInfoEndpoint: + type: string + example: "" + enableTokenGeneration: + type: boolean + example: true + enableTokenEncryption: + type: boolean + example: false + default: false + enableTokenHashing: + type: boolean + example: false + default: false + enableOAuthAppCreation: + type: boolean + example: true + default: true + enableMapOAuthConsumerApps: + type: boolean + example: false + default: false + applicationConfiguration: + type: array + items: + $ref: '#/components/schemas/KeyManagerApplicationConfiguration' + alias: + type: string + description: | + The alias of Identity Provider. + If the tokenType is EXCHANGED, the alias value should be inclusive in the audience values of the JWT token + example: https://localhost:9443/oauth2/token + additionalProperties: + type: object + properties: {} + tokenType: + type: string + description: The type of the tokens to be used (exchanged or without exchanged). + Accepted values are EXCHANGED, DIRECT and BOTH. + example: EXCHANGED + default: DIRECT + enum: + - EXCHANGED + - DIRECT + - BOTH + KeyManagerApplicationConfiguration: + title: Key Manager application Configuration + type: object + properties: + name: + type: string + example: consumer_key + label: + type: string + example: Consumer Key + type: + type: string + example: select + required: + type: boolean + example: true + mask: + type: boolean + example: true + multiple: + type: boolean + example: true + tooltip: + type: string + example: Enter username to connect to key manager + default: + type: object + properties: {} + example: admin + values: + type: array + items: + type: object + properties: {} + KeyManagerList: + title: Key Manager List + type: object + properties: + count: + type: integer + description: | + Number of Key managers returned. + example: 1 + list: + type: array + items: + $ref: '#/components/schemas/KeyManagerInfo' + GraphQLQueryComplexityInfo: + title: GraphQL Query Complexity Info + type: object + properties: + list: + type: array + items: + $ref: '#/components/schemas/GraphQLCustomComplexityInfo' + GraphQLCustomComplexityInfo: + title: GraphQL Custom Complexity Info + required: + - complexityValue + - field + - type + type: object + properties: + type: + type: string + description: | + The type found within the schema of the API + example: Country + field: + type: string + description: | + The field which is found under the type within the schema of the API + example: name + complexityValue: + type: integer + description: | + The complexity value allocated for the associated field under the specified type + example: 1 + GraphQLSchemaTypeList: + title: List of types and corresponding fields of the GraphQL Schema + type: object + properties: + typeList: + type: array + items: + $ref: '#/components/schemas/GraphQLSchemaType' + GraphQLSchemaType: + title: Single type and corresponding fields found within the GraphQL Schema + type: object + properties: + type: + type: string + description: | + Type found within the GraphQL Schema + example: Country + fieldList: + type: array + description: | + Array of fields under current type + example: + - code + - name + items: + type: string + CurrentAndNewPasswords: + title: Current and new password of the user + type: object + properties: + currentPassword: + type: string + example: password123 + newPassword: + type: string + example: newpassword1234 + AdditionalSubscriptionInfoList: + title: Additional Subscription Info List + type: object + properties: + count: + type: integer + description: | + Number of additional information sets of subscription returned. + example: 1 + list: + type: array + items: + $ref: '#/components/schemas/AdditionalSubscriptionInfo' + pagination: + $ref: '#/components/schemas/Pagination' + AdditionalSubscriptionInfo: + title: Additional Information of subscriptions related to an API + type: object + properties: + subscriptionId: + type: string + description: The UUID of the subscription + readOnly: true + example: faae5fcc-cbae-40c4-bf43-89931630d313 + applicationId: + type: string + description: The UUID of the application + example: b3ade481-30b0-4b38-9a67-498a40873a6d + applicationName: + type: string + description: The name of the application + example: Sample Application + apiId: + type: string + description: The unique identifier of the API. + example: 2962f3bb-8330-438e-baee-0ee1d6434ba4 + isSolaceAPI: + type: boolean + example: false + solaceOrganization: + type: string + example: SolaceWso2 + solaceDeployedEnvironments: + type: array + items: + type: object + properties: + environmentName: + type: string + environmentDisplayName: + type: string + organizationName: + type: string + solaceURLs: + type: array + items: + type: object + properties: + protocol: + type: string + example: Default + endpointURL: + type: string + example: Default + SolaceTopicsObject: + type: object + properties: + defaultSyntax: + $ref: '#/components/schemas/SolaceTopics' + mqttSyntax: + $ref: '#/components/schemas/SolaceTopics' + SolaceTopics: + title: SolaceTopics + type: object + properties: + publishTopics: + type: array + items: + type: string + subscribeTopics: + type: array + items: + type: string + responses: + BadRequest: + description: Bad Request. Invalid request or validation error. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + example: + code: 400 + message: Bad Request + description: Invalid request or validation error + moreInfo: "" + error: [] + Conflict: + description: Conflict. Specified resource already exists. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + example: + code: 409 + message: Conflict + description: Specified resource already exists + moreInfo: "" + error: [] + InternalServerError: + description: Internal Server Error. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + example: + code: 500 + message: Internal Server Error + description: The server encountered an internal error. Please contact + administrator. + moreInfo: "" + error: [] + NotAcceptable: + description: Not Acceptable. The requested media type is not supported. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + example: + code: 406 + message: Not Acceptable + description: The requested media type is not supported + moreInfo: "" + error: [] + NotFound: + description: Not Found. The specified resource does not exist. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + example: + code: 404 + message: Not Found + description: The specified resource does not exist + moreInfo: "" + error: [] + PreconditionFailed: + description: Precondition Failed. The request has not been performed because + one of the preconditions is not met. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + example: + code: 412 + message: Precondition Failed + description: The request has not been performed because one of the preconditions + is not met + moreInfo: "" + error: [] + Unauthorized: + description: Unauthorized. The user is not authorized. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + example: + code: 401 + message: Unauthorized + description: The user is not authorized + moreInfo: "" + error: [] + UnsupportedMediaType: + description: Unsupported Media Type. The entity of the request was not in a + supported format. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + example: + code: 415 + message: Unsupported media type + description: The entity of the request was not in a supported format + moreInfo: "" + error: [] + parameters: + parentCommentID: + name: replyTo + in: query + required: false + description: | + ID of the parent comment. + schema: + type: string + requestedTenant: + name: X-WSO2-Tenant + in: header + description: | + For cross-tenant invocations, this is used to specify the tenant/organization domain, where the resource need to be + retrieved from. + schema: + type: string + includeCommenterInfo: + name: includeCommenterInfo + in: query + required: false + description: | + Whether we need to display commenter details. + schema: + type: boolean + default : false + apiId: + name: apiId + in: path + description: | + **API ID** consisting of the **UUID** of the API. + required: true + schema: + type: string + apiProductId: + name: apiProductId + in: path + description: | + **API Product ID** consisting of the **UUID** of the API Product. + required: true + schema: + type: string + x-encoded: true + x-encoded: true + apiId-Q: + name: apiId + in: query + required: false + description: | + **API ID** consisting of the **UUID** of the API. + schema: + type: string + apiType-Q: + name: apiType + in: query + required: false + description: | + **API TYPE** Identifies the type API(API or API_PRODUCT). + schema: + type: string + language: + name: language + in: query + description: | + Programming language to generate SDK. + required: true + schema: + type: string + documentId: + name: documentId + in: path + description: | + Document Identifier + required: true + schema: + type: string + applicationId: + name: applicationId + in: path + description: | + Application Identifier consisting of the UUID of the Application. + required: true + schema: + type: string + keyMappingId: + name: keyMappingId + in: path + description: | + OAuth Key Identifier consisting of the UUID of the Oauth Key Mapping. + required: true + schema: + type: string + filterByUserRoles: + name: filterByUserRoles + in: query + required: false + description: | + Filter user by roles. + schema: + type: boolean + applicationId-Q: + name: applicationId + in: query + required: false + description: | + **Application Identifier** consisting of the UUID of the Application. + schema: + type: string + groupId: + name: groupId + in: query + required: false + description: | + Application Group Id + schema: + type: string + subscriptionId: + name: subscriptionId + in: path + description: | + Subscription Id + required: true + schema: + type: string + policyId: + name: policyId + in: path + description: | + The name of the policy + required: true + schema: + type: string + commentId: + name: commentId + in: path + description: | + Comment Id + required: true + schema: + type: string + ratingId: + name: ratingId + in: path + description: | + Rating Id + required: true + schema: + type: string + policyLevel: + name: policyLevel + in: path + description: | + List Application or Subscription type thro. + required: true + schema: + type: string + enum: + - application + - subscription + environmentName: + name: environmentName + in: query + required: false + description: | + Name of the API gateway environment. + schema: + type: string + limit: + name: limit + in: query + required: false + description: | + Maximum size of resource array to return. + schema: + type: integer + default: 25 + offset: + name: offset + in: query + required: false + description: | + Starting point within the complete list of items qualified. + schema: + type: integer + default: 0 + replyLimit: + name: replyLimit + in: query + required: false + description: | + Maximum size of replies array to return. + schema: + type: integer + default: 25 + replyOffset: + name: replyOffset + in: query + required: false + description: | + Starting point within the complete list of replies. + schema: + type: integer + default: 0 + keyType: + name: keyType + in: path + description: | + **Application Key Type** standing for the type of the keys (i.e. Production or Sandbox). + required: true + schema: + type: string + enum: + - PRODUCTION + - SANDBOX + If-None-Match: + name: If-None-Match + in: header + description: | + Validator for conditional requests; based on the ETag of the formerly retrieved + variant of the resource. + schema: + type: string + If-Match: + name: If-Match + in: header + description: | + Validator for conditional requests; based on ETag. + schema: + type: string + alertType: + name: alertType + in: path + description: | + The alert type. + required: true + schema: + type: string + configurationId: + name: configurationId + in: path + description: | + The alert configuration id. + Base64 encoded value of 'apiName#apiVersion#applicationName'. + required: true + schema: + type: string + securitySchemes: + OAuth2Security: + type: oauth2 + flows: + password: + tokenUrl: https://localhost:9443/oauth2/token + scopes: + type: array + items: test diff --git a/devportal/devportal-domain-service/ballerina/subscriptionDAO.bal b/devportal/devportal-domain-service/ballerina/subscriptionDAO.bal new file mode 100644 index 000000000..d7e37da05 --- /dev/null +++ b/devportal/devportal-domain-service/ballerina/subscriptionDAO.bal @@ -0,0 +1,316 @@ +// +// Copyright (c) 2022, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + +import ballerina/log; +import ballerinax/postgresql; +import ballerina/sql; +import wso2/apk_common_lib as commons; + +# DAO for GET Subscription plan +# +# + policyName - Policy Name +# + return - Policy ID +public isolated function getBusinessPlanByNameDAO(string policyName, string org) returns string|commons:APKError|NotFoundError { + postgresql:Client|error dbClient = getConnection(); + if dbClient is error { + string message = "Error while retrieving connection"; + return error(message, dbClient, message = message, description = message, code = 909000, statusCode = 500); + } else { + sql:ParameterizedQuery query = `SELECT UUID FROM BUSINESS_PLAN WHERE NAME =${policyName} AND ORGANIZATION =${org}`; + string|sql:Error result = dbClient->queryRow(query); + if result is sql:NoRowsError { + log:printDebug(result.toString()); + NotFoundError nfe = {body: {code: 90915, message: "Business Plan Not Found for provided Plan Name"}}; + return nfe; + } else if result is string { + log:printDebug(result.toString()); + return result; + } else { + log:printDebug(result.toString()); + string message = "Error while retrieving Business Plan"; + return error(message, result, message = message, description = message, code = 909000, statusCode = 500); + } + } +} + +isolated function addSubscriptionDAO(Subscription sub, string user, string apiId, string appId) returns Subscription|commons:APKError { + postgresql:Client|error dbClient = getConnection(); + if dbClient is error { + string message = "Error while retrieving connection"; + return error(message, dbClient, message = message, description = message, code = 909000, statusCode = 500); + } else { + // check existing subscriptions + sql:ParameterizedQuery existingCheckQuery = `SELECT SUB_STATUS, SUBS_CREATE_STATE FROM SUBSCRIPTION + WHERE API_UUID = ${apiId} AND APPLICATION_UUID = ${appId}`; + Subscription|sql:Error existingCheckResult = dbClient->queryRow(existingCheckQuery); + if existingCheckResult is sql:NoRowsError { + log:printDebug(existingCheckResult.toString()); + } else if existingCheckResult is Subscription { + log:printDebug(existingCheckResult.toString()); + string message = "Subscription Already exists"; + return error(message, message = message, description = message, code = 909000, statusCode = 500); + } else { + log:printDebug(existingCheckResult.toString()); + string message = "Error while checking exisiting subscriptions"; + return error(message, existingCheckResult, message = message, description = message, code = 909000, statusCode = 500); + } + var Tier_ID = "unlimited"; + + // Insert into SUBSCRIPTION table + sql:ParameterizedQuery query = `INSERT INTO SUBSCRIPTION (TIER_ID,API_UUID,APPLICATION_UUID, + SUB_STATUS,SUBS_CREATE_STATE,CREATED_BY,UUID, TIER_ID_PENDING) + VALUES (${Tier_ID},${apiId},${appId}, + ${sub.status},${sub.subscriptionCreateState},${user},${sub.subscriptionId},${Tier_ID})`; + sql:ExecutionResult|sql:Error result = dbClient->execute(query); + if result is sql:ExecutionResult { + log:printDebug(result.toString()); + return sub; + } else { + log:printDebug(result.toString()); + string message = "Error while inserting data into Database"; + return error(message, result, message = message, description = message, code = 909000, statusCode = 500); + } + } +} + +isolated function getSubscriptionByIdDAO(string subId, string org) returns Subscription|NotFoundError|commons:APKError { + postgresql:Client|error dbClient = getConnection(); + if dbClient is error { + string message = "Error while retrieving connection"; + return error(message, dbClient, message = message, description = message, code = 909000, statusCode = 500); + } else { + sql:ParameterizedQuery query = `SELECT + SUBS.UUID AS SUBSCRIPTION_ID, + API.API_NAME AS API_NAME, + API.API_VERSION AS API_VERSION, + API.API_TYPE AS API_TYPE, + API.ORGANIZATION AS ORGANIZATION, + APP.UUID AS APPLICATIONID, + SUBS.TIER_ID AS THROTTLINGPOLICY, + SUBS.TIER_ID_PENDING AS TIER_ID_PENDING, + SUBS.SUB_STATUS AS SUB_STATUS, + SUBS.SUBS_CREATE_STATE AS SUBS_CREATE_STATE, + SUBS.CREATED_TIME AS CREATED_TIME, + SUBS.UPDATED_TIME AS UPDATED_TIME, + API.UUID AS APIID + FROM SUBSCRIPTION SUBS, API API, APPLICATION APP + WHERE APP.UUID=SUBS.APPLICATION_UUID AND API.UUID = SUBS.API_UUID AND SUBS.UUID =${subId}`; + Subscription|sql:Error result = dbClient->queryRow(query); + if result is sql:NoRowsError { + log:printDebug(result.toString()); + NotFoundError nfe = {body: {code: 90915, message: "Subscription Not Found for provided ID"}}; + return nfe; + } else if result is Subscription { + log:printDebug(result.toString()); + return result; + } else { + log:printDebug(result.toString()); + string message = "Error while retrieving Subscription"; + return error(message, result, message = message, description = message, code = 909000, statusCode = 500); + } + } +} + +isolated function deleteSubscriptionDAO(string subId, string org) returns commons:APKError? { + postgresql:Client|error dbClient = getConnection(); + if dbClient is error { + string message = "Error while retrieving connection"; + return error(message, dbClient, message = message, description = message, code = 909000, statusCode = 500); + } else { + sql:ParameterizedQuery query = `DELETE FROM SUBSCRIPTION WHERE UUID = ${subId}`; + sql:ExecutionResult|sql:Error result = dbClient->execute(query); + if result is sql:ExecutionResult { + if (result.affectedRowCount == 0) { + string message = "Error while deleting data record in the Database"; + return error(message, message = message, description = message, code = 909000, statusCode = 500); + } + } else { + log:printDebug(result.toString()); + string message = "Error while deleting data record in the Database"; + return error(message, result, message = message, description = message, code = 909000, statusCode = 500); + } + } +} + +isolated function updateSubscriptionDAO(Subscription sub, string user, string apiId, string appId) returns Subscription|commons:APKError { + postgresql:Client|error dbClient = getConnection(); + if dbClient is error { + string message = "Error while retrieving connection"; + return error(message, dbClient, message = message, description = message, code = 909000, statusCode = 500); + } else { + var Tier_ID = "unlimited"; + // Update Policy of a subscription in SUBSCRIPTION table + sql:ParameterizedQuery query = ` UPDATE SUBSCRIPTION SET TIER_ID_PENDING = ${Tier_ID} + , TIER_ID = ${Tier_ID} , SUB_STATUS = ${sub.status} + WHERE UUID = ${sub.subscriptionId}`; + sql:ExecutionResult|sql:Error result = dbClient->execute(query); + if result is sql:ExecutionResult { + log:printDebug(result.toString()); + return sub; + } else { + log:printError(result.toString()); + string message = "Error while updating data record in Database"; + return error(message, result, message = message, description = message, code = 909000, statusCode = 500); + } + } +} + +isolated function getSubscriptionByAPIandAppIdDAO(string apiId, string appId, string org) returns Subscription|commons:APKError|NotFoundError { + postgresql:Client|error dbClient = getConnection(); + if dbClient is error { + string message = "Error while retrieving connection"; + return error(message, dbClient, message = message, description = message, code = 909000, statusCode = 500); + } else { + sql:ParameterizedQuery query = `SELECT + SUBS.UUID AS SUBSCRIPTION_ID, + API.API_NAME AS API_NAME, + API.API_VERSION AS API_VERSION, + API.API_TYPE AS API_TYPE, + API.ORGANIZATION AS ORGANIZATION, + APP.UUID AS APPLICATIONID, + SUBS.TIER_ID AS THROTTLINGPOLICY, + SUBS.TIER_ID_PENDING AS TIER_ID_PENDING, + SUBS.SUB_STATUS AS SUB_STATUS, + SUBS.SUBS_CREATE_STATE AS SUBS_CREATE_STATE, + SUBS.CREATED_TIME AS CREATED_TIME, + SUBS.UPDATED_TIME AS UPDATED_TIME, + API.UUID AS APIID + FROM SUBSCRIPTION SUBS, API API, APPLICATION APP + WHERE APP.UUID=SUBS.APPLICATION_UUID AND API.UUID = SUBS.API_UUID AND API.UUID =${apiId} AND APP.UUID=${appId}`; + Subscription|sql:Error result = dbClient->queryRow(query); + if result is sql:NoRowsError { + log:printDebug(result.toString()); + NotFoundError nfe = {body: {code: 90916, message: "Subscription not found"}}; + return nfe; + } else if result is Subscription { + log:printDebug(result.toString()); + return result; + } else { + log:printDebug(result.toString()); + string message = "Error while retrieving Subscription"; + return error(message, result, message = message, description = message, code = 909007, statusCode = 500); + } + } +} + +isolated function getSubscriptionsByAPIIdDAO(string apiId, string org) returns Subscription[]|commons:APKError { + postgresql:Client|error dbClient = getConnection(); + if dbClient is error { + string message = "Error while retrieving connection"; + return error(message, dbClient, message = message, description = message, code = 909000, statusCode = 500); + } else { + do { + sql:ParameterizedQuery query = `SELECT + SUBS.UUID AS SUBSCRIPTION_ID, + API.API_NAME AS API_NAME, + API.API_VERSION AS API_VERSION, + API.API_TYPE AS API_TYPE, + API.ORGANIZATION AS ORGANIZATION, + APP.UUID AS APPLICATIONID, + SUBS.TIER_ID AS THROTTLINGPOLICY, + SUBS.TIER_ID_PENDING AS TIER_ID_PENDING, + SUBS.SUB_STATUS AS SUB_STATUS, + SUBS.SUBS_CREATE_STATE AS SUBS_CREATE_STATE, + SUBS.CREATED_TIME AS CREATED_TIME, + SUBS.UPDATED_TIME AS UPDATED_TIME, + API.UUID AS APIID + FROM SUBSCRIPTION SUBS, API API, APPLICATION APP + WHERE APP.UUID=SUBS.APPLICATION_UUID AND API.UUID = SUBS.API_UUID AND API.UUID =${apiId}`; + stream subscriptionStream = dbClient->query(query); + Subscription[] subscriptions = check from Subscription subscription in subscriptionStream + select subscription; + check subscriptionStream.close(); + return subscriptions; + } on fail var e { + string message = "Internal Error occured while retrieving Subscription By API Id"; + return error(message, e, message = message, description = message, code = 909001, statusCode = 500); + } + } +} + +isolated function getSubscriptionsByAPPIdDAO(string appId, string org) returns Subscription[]|commons:APKError { + postgresql:Client|error dbClient = getConnection(); + if dbClient is error { + string message = "Error while retrieving connection"; + return error(message, dbClient, message = message, description = message, code = 909000, statusCode = 500); + } else { + do { + sql:ParameterizedQuery query = `SELECT + SUBS.UUID AS SUBSCRIPTION_ID, + API.API_NAME AS API_NAME, + API.API_VERSION AS API_VERSION, + API.API_TYPE AS API_TYPE, + API.ORGANIZATION AS ORGANIZATION, + APP.UUID AS APPLICATIONID, + SUBS.TIER_ID AS THROTTLINGPOLICY, + SUBS.TIER_ID_PENDING AS TIER_ID_PENDING, + SUBS.SUB_STATUS AS SUB_STATUS, + SUBS.SUBS_CREATE_STATE AS SUBS_CREATE_STATE, + SUBS.CREATED_TIME AS CREATED_TIME, + SUBS.UPDATED_TIME AS UPDATED_TIME, + API.UUID AS APIID + FROM SUBSCRIPTION SUBS, API API, APPLICATION APP + WHERE APP.UUID=SUBS.APPLICATION_UUID AND API.UUID = SUBS.API_UUID AND APP.UUID=${appId}`; + stream subscriptionStream = dbClient->query(query); + Subscription[] subscriptions = check from Subscription subscription in subscriptionStream + select subscription; + check subscriptionStream.close(); + return subscriptions; + } on fail var e { + string message = "Internal Error occured while retrieving Subscription By Application Id"; + return error(message, e, message = message, description = message, code = 909001, statusCode = 500); + } + } +} + +isolated function getSubscriptionsList(string org) returns Subscription[]|commons:APKError { + postgresql:Client|error dbClient = getConnection(); + if dbClient is error { + string message = "Error while retrieving connection"; + return error(message, dbClient, message = message, description = message, code = 909000, statusCode = 500); + } else { + do { + sql:ParameterizedQuery query = `SELECT + SUBS.UUID AS SUBSCRIPTION_ID, + API.API_NAME AS API_NAME, + API.API_VERSION AS API_VERSION, + API.API_TYPE AS API_TYPE, + API.ORGANIZATION AS ORGANIZATION, + APP.UUID AS APPLICATIONID, + SUBS.TIER_ID AS THROTTLINGPOLICY, + SUBS.TIER_ID_PENDING AS TIER_ID_PENDING, + SUBS.SUB_STATUS AS SUB_STATUS, + SUBS.SUBS_CREATE_STATE AS SUBS_CREATE_STATE, + SUBS.UUID AS UUID, + SUBS.CREATED_TIME AS CREATED_TIME, + SUBS.UPDATED_TIME AS UPDATED_TIME, + API.UUID AS APIID + FROM SUBSCRIPTION SUBS, API API, APPLICATION APP + WHERE APP.UUID=SUBS.APPLICATION_UUID AND API.UUID = SUBS.API_UUID`; + stream subscriptionStream = dbClient->query(query); + Subscription[] subscriptions = check from Subscription subscription in subscriptionStream + select subscription; + check subscriptionStream.close(); + return subscriptions; + } on fail var e { + string message = "Internal Error occured while retrieving Subscriptions"; + return error(message, e, message = message, description = message, code = 909001, statusCode = 500); + } + } +} + diff --git a/devportal/devportal-domain-service/ballerina/subscriptionImpl.bal b/devportal/devportal-domain-service/ballerina/subscriptionImpl.bal new file mode 100644 index 000000000..990a721f9 --- /dev/null +++ b/devportal/devportal-domain-service/ballerina/subscriptionImpl.bal @@ -0,0 +1,275 @@ +// +// Copyright (c) 2022, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + +import ballerina/uuid; +import ballerina/lang.value; +import wso2/notification_grpc_client; +import wso2/apk_common_lib as commons; +import ballerina/time; +import ballerina/log; + +isolated function addSubscription(Subscription payload, commons:Organization org, string user) returns Subscription|NotFoundError|commons:APKError { + do { + string apiId = ""; + string appId = ""; + string|NotFoundError subscriberId = check getSubscriberIdDAO(user, org.uuid); + if subscriberId !is string { + return subscriberId; + } + string? apiUUID = payload.apiId; + if apiUUID is string { + API|NotFoundError api = check getAPIByAPIId(apiUUID); + if api is NotFoundError { + return api; + } else if api is API { + string apiInString = api.toJsonString(); + json j = check value:fromJsonString(apiInString); + apiId = check j.id.ensureType(); + } + } + string? appUUID = payload.applicationId; + if appUUID is string { + Application|NotFoundError application = check getApplicationById(appUUID, org); + if application is NotFoundError { + return application; + } else if application is Application { + string appInString = application.toJsonString(); + json j = check value:fromJsonString(appInString); + appId = check j.applicationId.ensureType(); + } + } + // TODO: Removed Validate the policy name + // string? businessPlan = payload.throttlingPolicy; + // if businessPlan is string { + // string|commons:APKError|NotFoundError businessPlanID = getBusinessPlanByName(businessPlan, org); + // if businessPlanID is APKError|NotFoundError { + // return businessPlanID; + // } + // payload.requestedThrottlingPolicy = businessPlan; + // } + string subscriptionId = uuid:createType1AsString(); + boolean|error isSubscriptionWorkflowEnable = isSubsciptionWorkflowEnabled(org.uuid); + if isSubscriptionWorkflowEnable is error { + string message = "Error while checking subscription workflow"; + return error(message, message = message, description = message, code = 909000, statusCode = 500); + } else if (isSubscriptionWorkflowEnable) { + string|error subworkflow = addSubscriptionCreationWorkflow(subscriptionId, org.uuid); + if subworkflow is error { + string message = "Error while creating subscription workflow"; + return error(message, subworkflow, message = message, description = message, code = 909000, statusCode = 500); + } + payload.subscriptionCreateState = "CREATED"; + Subscription createdSub = check addSubscriptionDAO(payload, user, apiId, appId); + return createdSub; + } else { + payload.subscriptionCreateState = "APPROVED"; + payload.subscriptionId = subscriptionId; + payload.status = "UNBLOCKED"; + Subscription createdSub = check addSubscriptionDAO(payload, user, apiId, appId); + string[] hostList = check retrieveManagementServerHostsList(); + string eventId = uuid:createType1AsString(); + time:Utc currTime = time:utcNow(); + string date = time:utcToString(currTime); + SubscriptionGRPC createSubscriptionRequest = { + eventId: eventId, + applicationRef: createdSub.applicationId, + apiRef: createdSub.apiId, + policyId: "unlimited", + subStatus: createdSub.status, + subscriber: user, + uuid: subscriptionId, + timeStamp: date, + organization: org.uuid + }; + string devportalPubCert = keyStores.tls.certFilePath; + string devportalKeyCert = keyStores.tls.keyFilePath; + string pubCertPath = managementServerConfig.certPath; + foreach string host in hostList { + NotificationResponse|error subscriptionNotification = notification_grpc_client:createSubscription(createSubscriptionRequest, + "https://" + host + ":8766", pubCertPath, devportalPubCert, devportalKeyCert); + if subscriptionNotification is error { + string message = "Error while sending subscription create grpc event"; + log:printError(subscriptionNotification.toString()); + return error(message, subscriptionNotification, message = message, description = message, code = 909000, statusCode = 500); + } + } + return createdSub; + } + } on fail var e { + return error("Internal Error", e, code = 900900, description = "Internal Error", statusCode = 500, message = "Internal Error"); + } +} + +isolated function getBusinessPlanByName(string policyName, commons:Organization org) returns string|commons:APKError|NotFoundError { + string|commons:APKError|NotFoundError policy = getBusinessPlanByNameDAO(policyName, org.uuid); + return policy; +} + +isolated function addMultipleSubscriptions(Subscription[] subscriptions, commons:Organization org, string user) returns Subscription[]|commons:APKError|NotFoundError { + Subscription[]|commons:APKError addedSubs = []; + foreach Subscription sub in subscriptions { + Subscription|commons:APKError|NotFoundError subscriptionResponse = check addSubscription(sub, org, user); + if subscriptionResponse is Subscription { + if addedSubs is Subscription[] { + addedSubs.push(subscriptionResponse); + } + } else if subscriptionResponse is commons:APKError|NotFoundError { + return subscriptionResponse; + } + } + return addedSubs; +} + +isolated function getSubscriptionById(string subId, commons:Organization org) returns Subscription|commons:APKError|NotFoundError { + Subscription|NotFoundError subscription = check getSubscriptionByIdDAO(subId, org.uuid); + return subscription; +} + +isolated function deleteSubscription(string subId, commons:Organization organization) returns commons:APKError? { + check deleteSubscriptionDAO(subId, organization.uuid); + string[] hostList = check retrieveManagementServerHostsList(); + string eventId = uuid:createType1AsString(); + time:Utc currTime = time:utcNow(); + string date = time:utcToString(currTime); + SubscriptionGRPC deleteSubscriptionRequest = {eventId: eventId, uuid: subId, timeStamp: date, organization: organization.uuid}; + string devportalPubCert = keyStores.tls.certFilePath; + string devportalKeyCert = keyStores.tls.keyFilePath; + string pubCertPath = managementServerConfig.certPath; + foreach string host in hostList { + NotificationResponse|error subscriptionNotification = notification_grpc_client:deleteSubscription(deleteSubscriptionRequest, + "https://" + host + ":8766", pubCertPath, devportalPubCert, devportalKeyCert); + if subscriptionNotification is error { + string message = "Error while sending subscription delete grpc event"; + log:printError(subscriptionNotification.toString()); + return error(message, subscriptionNotification, message = message, description = message, code = 909000, statusCode = 500); + } + } +} + +isolated function updateSubscription(string subId, Subscription payload, commons:Organization org, string user) returns Subscription|NotFoundError|commons:APKError { + do { + Subscription|NotFoundError existingSub = check getSubscriptionByIdDAO(subId, org.uuid); + if existingSub is Subscription { + payload.subscriptionId = subId; + } else { + return existingSub; + } + string apiId = ""; + string appId = ""; + string|NotFoundError subscriberId = check getSubscriberIdDAO(user, org.uuid); + if subscriberId is NotFoundError { + return subscriberId; + } + string? apiUUID = payload.apiId; + if apiUUID is string { + API|NotFoundError api = check getAPIByAPIId(apiUUID); + if api is NotFoundError { + return api; + } else if api is API { + string apiInString = api.toJsonString(); + json j = check value:fromJsonString(apiInString); + apiId = check j.id.ensureType(); + } + } + string? appUUID = payload.applicationId; + if appUUID is string { + Application|NotFoundError application = check getApplicationById(appUUID, org); + if application is NotFoundError { + return application; + } else if application is Application { + string appInString = application.toJsonString(); + json j = check value:fromJsonString(appInString); + appId = check j.applicationId.ensureType(); + } + } + // TODO: Removed Validate the policy name + // string? businessPlan = payload.throttlingPolicy; + // if businessPlan is string { + // string|commons:APKError|NotFoundError businessPlanID = getBusinessPlanByName(businessPlan, org); + // if businessPlanID is APKError|NotFoundError { + // return businessPlanID; + // } + // payload.requestedThrottlingPolicy = businessPlan; + // } + payload.status = "UNBLOCKED"; + Subscription createdSub = check updateSubscriptionDAO(payload, user, apiId, appId); + string[] hostList = check retrieveManagementServerHostsList(); + string eventId = uuid:createType1AsString(); + time:Utc currTime = time:utcNow(); + string date = time:utcToString(currTime); + SubscriptionGRPC updateSubscriptionRequest = { + eventId: eventId, + applicationRef: createdSub.applicationId, + apiRef: createdSub.apiId, + policyId: "unlimited", + subStatus: createdSub.status, + subscriber: user, + uuid: subId, + timeStamp: date, + organization: org.uuid + }; + string devportalPubCert = keyStores.tls.certFilePath; + string devportalKeyCert = keyStores.tls.keyFilePath; + string pubCertPath = managementServerConfig.certPath; + foreach string host in hostList { + NotificationResponse|error subscriptionNotification = notification_grpc_client:updateSubscription(updateSubscriptionRequest, + "https://" + host + ":8766", pubCertPath, devportalPubCert, devportalKeyCert); + if subscriptionNotification is error { + string message = "Error while sending subscription update grpc event"; + log:printError(subscriptionNotification.toString()); + return error(message, subscriptionNotification, message = message, description = message, code = 909000, statusCode = 500); + } + } + return createdSub; + } on fail var e { + return error("Internal Error", e, code = 900900, description = "Internal Error", statusCode = 500, message = "Internal Error"); + } +} + +isolated function getSubscriptions(string? apiId, string? applicationId, string? groupId, int offset, int limitCount, commons:Organization org) returns SubscriptionList|commons:APKError|NotFoundError { + if apiId is string && applicationId is string { + // Retrieve Subscriptions per given API Id and App Id + Subscription|NotFoundError subscription = check getSubscriptionByAPIandAppIdDAO(apiId, applicationId, org.uuid); + if subscription is Subscription { + Subscription[] subs = [subscription]; + int count = subs.length(); + SubscriptionList subList = {count: count, list: subs}; + return subList; + } else { + return subscription; + } + } else if apiId is string { + // Retrieve Subscriptions per given API Id + Subscription[] subs = check getSubscriptionsByAPIIdDAO(apiId, org.uuid); + int count = subs.length(); + SubscriptionList subList = {count: count, list: subs}; + return subList; + } else if applicationId is string { + // Retrieve Subscriptions per given APP Id + Subscription[] subs = check getSubscriptionsByAPPIdDAO(applicationId, org.uuid); + int count = subs.length(); + SubscriptionList subList = {count: count, list: subs}; + return subList; + } else { + // Retrieve All Subscriptions + Subscription[] subs = check getSubscriptionsList(org.uuid); + int count = subs.length(); + SubscriptionList subList = {count: count, list: subs}; + return subList; + } +} diff --git a/devportal/devportal-domain-service/ballerina/tests/Config.toml b/devportal/devportal-domain-service/ballerina/tests/Config.toml new file mode 100644 index 000000000..3de9a60cf --- /dev/null +++ b/devportal/devportal-domain-service/ballerina/tests/Config.toml @@ -0,0 +1,45 @@ +[wso2.devportal_service] +DEVPORTAL_PORT = 9443 +keyManagerConntectorConfigurationFilePath = "tests/resources/keyManager-configs" + +[wso2.devportal_service.k8sConfig] +host = "localhost:9090" +serviceAccountPath = "tests/resources/serviceAccount" + +[wso2.devportal_service.datasourceConfiguration] +description = "Database for devportal" +url = "jdbc:postgresql://localhost:10320/WSO2AM_DB" +host = "localhost" +port = 10320 +databaseName = "WSO2AM_DB" +username = "wso2carbon" +password = "wso2carbon" +validationTimeout = 250 +testQuery = "SELECT 1" +driver = "org.postgresql.Driver" + +[wso2.devportal_service.throttleConfig.blockCondition] +enabled = true + +[wso2.devportal_service.keyStores.tls] +keyFilePath = "./tests/resources/wso2carbon.key" +certFilePath = "./tests/resources/wso2carbon.crt" +[wso2.devportal_service.keyStores.signing] +keyFilePath = "./tests/resources/wso2carbon.key" + +[wso2.devportal_service.issuerConfig] +issuer = "https://apim.wso2.com/oauth2/token" +audience = "https://apim.wso2.com/oauth2/token" +keyId = "gateway_certificate_alias" +expTime = 3600.0 + +[wso2.devportal_service.sdkConfig] +groupId = "org.wso2" +artifactId = "org.wso2.client." +modelPackage = "org.wso2.client.model." +apiPackage = "org.wso2.client.api." + +[wso2.devportal_service.managementServerConfig] +serviceName = "apk-test-wso2-apk-management-server" +namespace = "apk" +certPath = "/home/wso2apk/devportal/security/truststore/management-server.pem" diff --git a/devportal/devportal-domain-service/ballerina/tests/apiTests.bal b/devportal/devportal-domain-service/ballerina/tests/apiTests.bal new file mode 100644 index 000000000..5567540ad --- /dev/null +++ b/devportal/devportal-domain-service/ballerina/tests/apiTests.bal @@ -0,0 +1,238 @@ +// +// Copyright (c) 2022, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + +import ballerina/log; +import ballerina/test; +import devportal_service.org.wso2.apk.devportal.sdk as sdk; +import ballerina/http; +import wso2/apk_common_lib as commons; +import ballerina/io; + +commons:Organization organiztion = { + name: "org1", + displayName: "org1", + uuid: "a3b58ccf-6ecc-4557-b5bb-0a35cce38256", + organizationClaimValue: "org1", + enabled: true, + serviceListingNamespaces: ["*"], + properties: [] +}; + + +@test:BeforeSuite +function beforeFunc() { + APIBody body = { + "apiProperties":{ + "id": "01ed75e2-b30b-18c8-wwf2-25da7edd2231", + "name":"PizzaShask", + "context":"pizzssa", + "version":"1.0.0", + "provider":"admin", + "lifeCycleStatus":"PUBLISHED", + "type":"HTTP" + }, + "Definition" : { + "openapi": "3.0.0", + "info": { + "title": "Sample API", + "description": "Optional multiline or single-line description in [CommonMark](http://commonmark.org/help/) or HTML.", + "version": "0.1.9" + }, + "servers": [ + { + "url": "http://api.example.com/v1", + "description": "Optional server description, e.g. Main (production) server" + }, + { + "url": "http://staging-api.example.com", + "description": "Optional server description, e.g. Internal staging server for testing" + } + ], + "paths": { + "/users": { + "get": { + "summary": "Returns a list of users.", + "description": "Optional extended description in CommonMark or HTML.", + "responses": { + "200": { + "description": "A JSON array of user names", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + } + } + } + } + } + }; + API|commons:APKError createdAPI = createAPIDAO(body,organiztion.uuid); + if createdAPI is API { + test:assertTrue(true, "Successfully created API"); + API|commons:APKError createdAPIDefinition = addDefinitionDAO(body,organiztion.uuid); + if createdAPIDefinition is API { + test:assertTrue(true, "Successfully created API"); + } else if createdAPIDefinition is commons:APKError { + log:printError(createdAPIDefinition.toString()); + test:assertFail("Error occured while creating API"); + } + } else if createdAPI is commons:APKError { + log:printError(createdAPI.toString()); + test:assertFail("Error occured while creating API"); + } + +} + + +@test:BeforeSuite +function beforeFunc2() returns error? { + // Add thumbnail + int|commons:APKError thumbnailCategoryId = getResourceCategoryIdByCategoryTypeDAO(RESOURCE_TYPE_THUMBNAIL); + if thumbnailCategoryId is int { + Resource thumbnail = { + resourceUUID: "02ad95e2-b30b-10c8-wwf2-65da7edd2219", + apiUuid: "01ed75e2-b30b-18c8-wwf2-25da7edd2231", + resourceCategoryId: thumbnailCategoryId, + dataType: "image/png", + resourceContent: "thumbnail.png", + resourceBinaryValue: check io:fileReadBytes("./tests/resources/thumbnail.png") + + }; + Resource|commons:APKError addedThumbnail = addResourceDAO(thumbnail); + if addedThumbnail is Resource { + test:assertTrue(true, "Successfully added Thumbnail"); + } else if addedThumbnail is commons:APKError { + log:printError(addedThumbnail.toString()); + test:assertFail("Error occured while adding Thumbnail"); + } + } +} + +@test:Config {} +function getAPIByIdTest(){ + API|commons:APKError|NotFoundError apiResponse =getAPIByAPIId("01ed75e2-b30b-18c8-wwf2-25da7edd2231"); + if apiResponse is API { + test:assertTrue(true, "Successfully retrieved API"); + } else if apiResponse is commons:APKError { + test:assertFail("Error occured while retrieving API"); + } +} + +@test:Config {} +function getAPIListTest(){ + APIList | commons:APKError apiListReturned = getAPIList(25, 0, null, organiztion); + if apiListReturned is APIList { + test:assertTrue(true, "Successfully retrieved all APIs"); + } else if apiListReturned is commons:APKError { + test:assertFail("Error occured while retrieving all APIs"); + } +} + +@test:Config {} +function getAPIListContentSearchTest1(){ + APIList | commons:APKError apiListReturned = getAPIList(25, 0, "content:pizza", organiztion); + if apiListReturned is APIList { + test:assertTrue(true, "Successfully retrieved all APIs"); + } else if apiListReturned is commons:APKError { + test:assertFail("Error occured while retrieving all APIs"); + } +} + +@test:Config {} +function getAPIListContentSearchTest2(){ + //Invalid Search Query without "content:" keyword + APIList | commons:APKError apiListReturned = getAPIList(25, 0, "pizza", organiztion); + if apiListReturned is APIList { + test:assertFail("Successfully retrieved all APIs"); + } else if apiListReturned is commons:APKError { + test:assertTrue(true,"Successfully Error occured while retrieving all APIs"); + } +} + +@test:Config {} +function getAPIListContentSearchTest3(){ + //Invalid Search Query without ":" + APIList | commons:APKError apiListReturned = getAPIList(25, 0, "contentpizza", organiztion); + if apiListReturned is APIList { + test:assertFail("Successfully retrieved all APIs"); + } else if apiListReturned is commons:APKError { + test:assertTrue(true,"Successfully Error occured while retrieving all APIs"); + } +} + +@test:Config {} +function getAPIDefinitionByIdTest(){ + APIDefinition|NotFoundError|commons:APKError apiDefResponse = getAPIDefinition("01ed75e2-b30b-18c8-wwf2-25da7edd2231"); + if apiDefResponse is APIDefinition { + test:assertTrue(true, "Successfully retrieved API Definition"); + } else if apiDefResponse is commons:APKError { + log:printError(apiDefResponse.toString()); + test:assertFail("Error occured while retrieving API"); + } else if apiDefResponse is NotFoundError { + test:assertFail("Definition Not Found Error"); + } +} + +@test:Config {} +function getAPIDefinitionByIdNegativeTest(){ + APIDefinition|NotFoundError|commons:APKError apiDefResponse = getAPIDefinition("12sqwsqadasd"); + if apiDefResponse is APIDefinition { + test:assertFail("Successfully retrieved API Definition"); + } else if apiDefResponse is commons:APKError { + test:assertFail("Error occured while retrieving API"); + } else if apiDefResponse is NotFoundError { + test:assertTrue(true,"Definition Not Found Error"); + } +} + +@test:Config {} +function generateSDKImplTest(){ + http:Response|sdk:APIClientGenerationException|NotFoundError|commons:APKError sdk = generateSDKImpl("01ed75e2-b30b-18c8-wwf2-25da7edd2231","java"); + if sdk is http:Response { + test:assertTrue(true, "Successfully generated API SDK"); + } else if sdk is sdk:APIClientGenerationException|commons:APKError{ + test:assertFail("Error while generating API SDK"); + } +} + +@test:Config {} +function generateSDKImplTestNegative(){ + http:Response|sdk:APIClientGenerationException|NotFoundError|commons:APKError sdk = generateSDKImpl("12sqwsqadasd","java"); + if sdk is http:Response { + test:assertFail("Successfully generated API SDK"); + } else if sdk is sdk:APIClientGenerationException|commons:APKError { + test:assertTrue(true,"Error while generating API SDK"); + } +} + +@test:Config {} +function gethumbnailTest() { + http:Response|NotFoundError|commons:APKError thumbnail = getThumbnail("01ed75e2-b30b-18c8-wwf2-25da7edd2231"); + if thumbnail is http:Response { + test:assertTrue(true, "Successfully getting the thumbnail"); + } else { + test:assertFail("Error occured while getting the thumbnail"); + } +} diff --git a/devportal/devportal-domain-service/ballerina/tests/applicationTests.bal b/devportal/devportal-domain-service/ballerina/tests/applicationTests.bal new file mode 100644 index 000000000..efc6628d6 --- /dev/null +++ b/devportal/devportal-domain-service/ballerina/tests/applicationTests.bal @@ -0,0 +1,193 @@ +// +// Copyright (c) 2022, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + +import ballerina/test; +import ballerina/log; +import wso2/apk_common_lib as commons; +import ballerina/uuid; + +@test:Mock {functionName: "generateToken"} +test:MockFunction generateTokenMock = new (); + +@test:Mock {functionName: "updateApplication", moduleName: "wso2/notification_grpc_client"} +public isolated function updateApplicationMock(ApplicationGRPC updateApplicationRequest, string endpoint, string pubCert, string devCert, string devKey) returns error|NotificationResponse { + NotificationResponse noti = {code: "OK"}; + return noti; +} + +@test:Mock {functionName: "deleteApplication", moduleName: "wso2/notification_grpc_client"} +public isolated function deleteApplicationMock(ApplicationGRPC deleteApplicationRequest, string endpoint, string pubCert, string devCert, string devKey) returns error|NotificationResponse { + NotificationResponse noti = {code: "OK"}; + return noti; +} + +Application application = {name: "sampleApp", description: "sample application"}; + +@test:BeforeSuite +function beforeFunc1() { + ApplicationRatePlan payload = { + "planName": "25PerMin", + "displayName": "25PerMin", + "description": "25 Per Min", + "defaultLimit": { + "type": "REQUESTCOUNTLIMIT", + "requestCount": { + "requestCount": 25, + "timeUnit": "min", + "unitTime": 1 + } + } + }; + string applicationUsagePlanId = uuid:createType1AsString(); + payload.planId = applicationUsagePlanId; + ApplicationRatePlan|commons:APKError createdAppPol = addApplicationUsagePlanDAO(payload, organiztion.uuid); + if createdAppPol is ApplicationRatePlan { + test:assertTrue(true, "Application usage plan added successfully"); + BusinessPlan payloadbp = { + "planName": "MyBusinessPlan", + "displayName": "MyBusinessPlan", + "description": "test sub pol test", + "defaultLimit": { + "type": "REQUESTCOUNTLIMIT", + "requestCount": { + "requestCount": 20, + "timeUnit": "min", + "unitTime": 1 + } + }, + "rateLimitCount": 10, + "rateLimitTimeUnit": "sec", + "customAttributes": [] + }; + payloadbp.planId = uuid:createType1AsString(); + BusinessPlan|commons:APKError createdBusinessPlan = addBusinessPlanDAO(payloadbp, organiztion.uuid); + if createdBusinessPlan is BusinessPlan { + test:assertTrue(true, "Business Plan added successfully"); + } else if createdBusinessPlan is commons:APKError { + test:assertFail("Error occured while adding Business Plan"); + } + } else if createdAppPol is commons:APKError { + log:printError(createdAppPol.toString()); + test:assertFail("Error occured while adding Application Usage Plan"); + } +} + +@test:Config {} +function addApplicationTest() { + string[] testHosts = ["http://localhost:9090"]; + test:when(retrieveManagementServerHostsListMock).thenReturn(testHosts); + Application payload = {name: "sampleApp", description: "sample application"}; + NotFoundError|Application|commons:APKError createdApplication = addApplication(payload, organiztion, "apkuser"); + if createdApplication is Application { + test:assertTrue(true, "Successfully added the application"); + application.applicationId = createdApplication.applicationId; + } else if createdApplication is error { + test:assertFail("Error occured while adding application"); + } +} + +@test:Config {dependsOn: [addApplicationTest]} +function getApplicationByIdTest() { + string? appId = application.applicationId; + if appId is string { + Application|commons:APKError|NotFoundError returnedResponse = getApplicationById(appId, organiztion); + if returnedResponse is Application { + test:assertTrue(true, "Successfully retrieved application"); + } else if returnedResponse is commons:APKError|NotFoundError { + test:assertFail("Error occured while retrieving application"); + } + } else { + test:assertFail("App ID isn't a string"); + } +} + +@test:Config {dependsOn: [getApplicationByIdTest]} +function getApplicationListTest() { + ApplicationList|commons:APKError applicationList = getApplicationList("", "", "", "", 0, 0, organiztion); + if applicationList is ApplicationList { + test:assertTrue(true, "Successfully retrieved all applications"); + } else if applicationList is commons:APKError { + test:assertFail("Error occured while retrieving all applications"); + } +} + +@test:Config {dependsOn: [getApplicationListTest]} +function updateApplicationTest() { + string[] testHosts = ["http://localhost:9090"]; + test:when(retrieveManagementServerHostsListMock).thenReturn(testHosts); + Application payload = {name: "sampleApp", description: "sample application updated"}; + string? appId = application.applicationId; + if appId is string { + NotFoundError|Application|commons:APKError createdApplication = updateApplication(appId, payload, organiztion, "apkuser"); + if createdApplication is Application { + test:assertTrue(true, "Successfully added the application"); + application.applicationId = createdApplication.applicationId; + } else if createdApplication is commons:APKError { + test:assertFail("Error occured while updating application"); + } + } else { + test:assertFail("App ID isn't a string"); + } +} + +@test:Config {dependsOn: [updateApplicationTest]} +function generateAPIKeyTest() { + APIKeyGenerateRequest payload = { + validityPeriod: 3600, + additionalProperties: {} + }; + string token = "eyJhbGciOiJSUzI1NiIsICJ0eXAiOiJKV1QiLCAia2lkIjoiZ2F0ZXdheV9jZXJ0aWZpY2F0ZV9hbGlhcyJ9." + + "eyJpc3MiOiJodHRwczovL2FwaW0ud3NvMi5jb20vb2F1dGgyL3Rva2VuIiwgInN1YiI6IiIsICJhdWQiOiJodHRwczovL2FwaW0u" + + "d3NvMi5jb20vb2F1dGgyL3Rva2VuIiwgImV4cCI6MTY3MTA5MDg0NCwgIm5iZiI6MTY3MTA4NzI0NCwgImlhdCI6MTY3MTA4NzI0NCw" + + "gImp0aSI6IjAxZWQ3YzQ1LTQzMmQtMThlMC05MzBmLTUyN2I4ODM0NDM3MyIsICJrZXl0eXBlIjoiUFJPRFVDVElPTiIsICJwZXJtaXR0" + + "ZWRSZWZlcmVyIjoiIiwgInBlcm1pdHRlZElwIjoiIiwgInRva2VuX3R5cGUiOiJBUElLZXkiLCAidGllckluZm8iOiIiLCAic3Vic2" + + "NyaWJlZEFQSXMiOlt7Im5hbWUiOiJodHRwLWJpbi1hcGkiLCAiY29udGV4dCI6Ii9odHRwLWJpbi1hcGkvMS4wLjgiLCAidmVyc2lvbi" + + "I6IjEuMC44IiwgInB1Ymxpc2hlciI6ImFwa3VzZXIiLCAidXVpZCI6IjRjM2NkYTRkLTI0YTQtNDI0OC1iODI0LTliMDAwM2U5YTUxMSJ9X" + + "SwgImFwcGxpY2F0aW9uIjp7Im5hbWUiOiJTYW1wbGVBcHAxIiwgInV1aWQiOiI4Y2M1NWQ1Ny0xMmFhLTQyMzgtOGEyMS03OTMyYjZjMmJ" + + "hYjIiLCAiaWQiOiIxIiwgInRpZXIiOiI2MFBlck1pbiIsICJ0aWVyUXVvdGFUeXBlIjoiIn19.WiuN7lT7JG-66XOY-Dzam7_QpKzhZPm" + + "i3UaF1ri2950jR5ghthgYZIZ4WzUnhRvDmRLTwdgekEon_JRwe7bQYdHAgXB-_dJYdf-wGq9qmOKfB3T2c26ngO4Ca4PgU_lpl9xyHT" + + "8LFIFE_GWes43CU_SVYL4X6yoSMuu2qN9VXsOlCWnK6v5xoNZjzcqr4qZtLuck3rcR70OF-yKZ1FRc-UlmDM_4nI9LTiOYvXGvJ8V" + + "qXevZIdvWOm0qapK3hUFwK4uwxp_6qvTcwNOxGm1CoLv0JC-t2ds9EfkbI0qpWEjwJMFQqfgTLEZGT7I1m0re253Xv3Mg3I-eLtV9HcC2FA"; + test:when(generateTokenMock).thenReturn(token); + string? appId = application.applicationId; + if appId is string { + APIKey|commons:APKError|NotFoundError key = generateAPIKey(payload, appId, "PRODUCTION", "apkuser", organiztion); + if key is APIKey { + test:assertTrue(true, "API Key Successfully Generated"); + } else { + test:assertFail("Error occured while generating API Key"); + } + } else { + test:assertFail("App ID isn't a string"); + } +} + +@test:Config {dependsOn: [generateAPIKeyTest]} +function deleteApplicationTest() { + string? appId = application.applicationId; + if appId is string { + error?|boolean status = deleteApplication(appId, organiztion); + if status is boolean { + test:assertTrue(true, "Successfully deleted application"); + } else if status is error { + test:assertFail("Error occured while deleting application"); + } + } else { + test:assertFail("App ID isn't a string"); + } +} diff --git a/devportal/devportal-domain-service/ballerina/tests/resources/keyManager-configs/okta.yaml b/devportal/devportal-domain-service/ballerina/tests/resources/keyManager-configs/okta.yaml new file mode 100644 index 000000000..818f08435 --- /dev/null +++ b/devportal/devportal-domain-service/ballerina/tests/resources/keyManager-configs/okta.yaml @@ -0,0 +1,77 @@ +type: "Okta" +consumerKeyClaim: "azp" +scopesClaim: "scp" +endpoints: + - + name: "dcr_endpoint" + display_name: "DCR Endpoint" + toolTip: "Okta DCR Endpoint" + required: true + - + name: "introspection_endpoint" + display_name: "Introspection Endpoint" + toolTip: "Okta Introspection Endpoint" + required: false + - + name: "revocation_endpoint" + display_name: "Revocation Endpoint" + toolTip: "Okta Revocation Endpoint" + required: false + - + name: "token_endpoint" + display_name: "Token Endpoint" + toolTip: "Okta Token Endpoint" + required: true +endpointConfigurations: + - + name: "client_id" + display_name: "Client ID" + type: "input" + toolTip: "Okta Client ID" + required: true + - + name: "client_secret" + display_name: "Client Secret" + type : "input" + toolTip: "Okta Client Secret" + required: true + masked: true +applicationConfigurations: + - + name: "application_type" + display_name: "Application Type" + type: "select" + toolTip: "Okta Application Type" + required: true + values: + - "web" + - "native" + - "service" + default: "web" + - + name: "response_types" + display_name: "Response Types" + type: "select" + toolTip: "Okta Response Types" + required: true + values: + - "code" + - "token" + - "id_token" + - "code token" + - "code id_token" + - "token id_token" + - "code token id_token" + default: "code" + multiple: true + - name: "token_endpoint_auth_method" + display_name: "Token Endpoint Auth Method" + type: "select" + toolTip: "Okta Token Endpoint Auth Method" + required: true + values: + - "client_secret_basic" + - "client_secret_post" + - "none" + default: "client_secret_basic" + \ No newline at end of file diff --git a/devportal/devportal-domain-service/ballerina/tests/resources/serviceAccount/ca.crt b/devportal/devportal-domain-service/ballerina/tests/resources/serviceAccount/ca.crt new file mode 100644 index 000000000..caa74a133 --- /dev/null +++ b/devportal/devportal-domain-service/ballerina/tests/resources/serviceAccount/ca.crt @@ -0,0 +1,15 @@ +-----BEGIN CERTIFICATE----- +MIICTDCCAbUCFBmlzXvk8t7eLJZW7bZNZK4koJHSMA0GCSqGSIb3DQEBCwUAMGUx +CzAJBgNVBAYTAkxLMQswCQYDVQQIDAJXUDEQMA4GA1UEBwwHQ29sb21ibzENMAsG +A1UECgwEV1NPMjEUMBIGA1UECwwLRW5naW5lZXRpbmcxEjAQBgNVBAMMCWxvY2Fs +aG9zdDAeFw0yMjEyMTQwODM3MzhaFw0yMzEyMTQwODM3MzhaMGUxCzAJBgNVBAYT +AkxLMQswCQYDVQQIDAJXUDEQMA4GA1UEBwwHQ29sb21ibzENMAsGA1UECgwEV1NP +MjEUMBIGA1UECwwLRW5naW5lZXRpbmcxEjAQBgNVBAMMCWxvY2FsaG9zdDCBnzAN +BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwLPJQmKc8mWjt2ZO7b6NANIaL5cdY14+ +3wpX/rpyYG0FeMfcEU09XwApzLI0cH61HmZRAxSkOEvw5zwgLsTcgt4Z3TmbCoMq +KYtdfRVpiWK3TpmkS346mwTBsS4+tSYtqO2g3r1mcUaVqL2xaWE9Wq5sM0Vs2pjO +22IsA6BvJbcCAwEAATANBgkqhkiG9w0BAQsFAAOBgQAG9q+pkvJFuv8vdFz3XWro +aym512HJcI7pE2H+ailBR04Td63xvrq2vAINO7/0kv2CoAm8sJBLAdTxsKnhbWCh +9Pd5OSdLIgymCA/qvV24T2YTbclMyhdR95gjmYJnqJNn3YAPq2GrcjtSdEg7Lg5N +wMzx3MH2sIWDPxbYugP6EQ== +-----END CERTIFICATE----- diff --git a/devportal/devportal-domain-service/ballerina/tests/resources/serviceAccount/namespace b/devportal/devportal-domain-service/ballerina/tests/resources/serviceAccount/namespace new file mode 100644 index 000000000..909025ff4 --- /dev/null +++ b/devportal/devportal-domain-service/ballerina/tests/resources/serviceAccount/namespace @@ -0,0 +1 @@ +apk-platform \ No newline at end of file diff --git a/devportal/devportal-domain-service/ballerina/tests/resources/serviceAccount/token b/devportal/devportal-domain-service/ballerina/tests/resources/serviceAccount/token new file mode 100644 index 000000000..34bf3e982 --- /dev/null +++ b/devportal/devportal-domain-service/ballerina/tests/resources/serviceAccount/token @@ -0,0 +1 @@ +eyJhbGciOiJSUzI1NiIsImtpZCI6IkYyRnBLWThqdkFtVmlGdFRUd0RBLTh5ZXlCRFppRFVKQVAySnhQUC1LejgifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJhcGstcGxhdGZvcm0iLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlY3JldC5uYW1lIjoid3NvMmFway1wbGF0Zm9ybS10b2tlbi1kbmptbCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50Lm5hbWUiOiJ3c28yYXBrLXBsYXRmb3JtIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQudWlkIjoiYjlmYjIyMmQtNjVlMi00MGMyLWE4NGItZWY0YmFhOTdjNmQ3Iiwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50OmFway1wbGF0Zm9ybTp3c28yYXBrLXBsYXRmb3JtIn0.GzoqQGKIv7cOtgmk0qcYfRMB8f_58bmmqEVoMuHWg4jUxcCSO3KiMVhIqWZpgDYjtySrF0VNYZbmVmg4lM_jSOamAs-PZOeYVnMgRylAiRsYgPUxKmZaC8HDf_xbFeuOFCAEzhNLDiW6SCJuwIq7oxzTtEmVMxDuYGy9lRP7Uc0GktK6boW-hemTlsRT2Rv3ehO3FhTvVRzC5KES94Vy7vdJLg1r0ccxVWO_svj87SApNySFXUoZbgJe2mKIQ7trjqYludGZ7_wmw7Ba0bdGnDUqDwl41WUAP6OFMg3cN4RpPafoJoSX7zGnMt_CP5h4w46S6yOx0q6pJjRq0tO29g \ No newline at end of file diff --git a/devportal/devportal-domain-service/ballerina/tests/resources/thumbnail.png b/devportal/devportal-domain-service/ballerina/tests/resources/thumbnail.png new file mode 100644 index 000000000..035660d52 Binary files /dev/null and b/devportal/devportal-domain-service/ballerina/tests/resources/thumbnail.png differ diff --git a/devportal/devportal-domain-service/ballerina/tests/resources/wso2carbon.crt b/devportal/devportal-domain-service/ballerina/tests/resources/wso2carbon.crt new file mode 100644 index 000000000..caa74a133 --- /dev/null +++ b/devportal/devportal-domain-service/ballerina/tests/resources/wso2carbon.crt @@ -0,0 +1,15 @@ +-----BEGIN CERTIFICATE----- +MIICTDCCAbUCFBmlzXvk8t7eLJZW7bZNZK4koJHSMA0GCSqGSIb3DQEBCwUAMGUx +CzAJBgNVBAYTAkxLMQswCQYDVQQIDAJXUDEQMA4GA1UEBwwHQ29sb21ibzENMAsG +A1UECgwEV1NPMjEUMBIGA1UECwwLRW5naW5lZXRpbmcxEjAQBgNVBAMMCWxvY2Fs +aG9zdDAeFw0yMjEyMTQwODM3MzhaFw0yMzEyMTQwODM3MzhaMGUxCzAJBgNVBAYT +AkxLMQswCQYDVQQIDAJXUDEQMA4GA1UEBwwHQ29sb21ibzENMAsGA1UECgwEV1NP +MjEUMBIGA1UECwwLRW5naW5lZXRpbmcxEjAQBgNVBAMMCWxvY2FsaG9zdDCBnzAN +BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwLPJQmKc8mWjt2ZO7b6NANIaL5cdY14+ +3wpX/rpyYG0FeMfcEU09XwApzLI0cH61HmZRAxSkOEvw5zwgLsTcgt4Z3TmbCoMq +KYtdfRVpiWK3TpmkS346mwTBsS4+tSYtqO2g3r1mcUaVqL2xaWE9Wq5sM0Vs2pjO +22IsA6BvJbcCAwEAATANBgkqhkiG9w0BAQsFAAOBgQAG9q+pkvJFuv8vdFz3XWro +aym512HJcI7pE2H+ailBR04Td63xvrq2vAINO7/0kv2CoAm8sJBLAdTxsKnhbWCh +9Pd5OSdLIgymCA/qvV24T2YTbclMyhdR95gjmYJnqJNn3YAPq2GrcjtSdEg7Lg5N +wMzx3MH2sIWDPxbYugP6EQ== +-----END CERTIFICATE----- diff --git a/devportal/devportal-domain-service/ballerina/tests/resources/wso2carbon.key b/devportal/devportal-domain-service/ballerina/tests/resources/wso2carbon.key new file mode 100644 index 000000000..aa746b158 --- /dev/null +++ b/devportal/devportal-domain-service/ballerina/tests/resources/wso2carbon.key @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICWwIBAAKBgQDAs8lCYpzyZaO3Zk7tvo0A0hovlx1jXj7fClf+unJgbQV4x9wR +TT1fACnMsjRwfrUeZlEDFKQ4S/DnPCAuxNyC3hndOZsKgyopi119FWmJYrdOmaRL +fjqbBMGxLj61Ji2o7aDevWZxRpWovbFpYT1armwzRWzamM7bYiwDoG8ltwIDAQAB +AoGAPkJYBgDCYHaCPKDrY1irSdaX60RRlGdAvOMkpwIqLglLOUipS1W/PFBbMO1q +j+YAMoAwMGSc4it2+96rLzEfZQD87RFH8WxSp8NIxuCcSZBvNxLaiIhjxvU7B5LC +/S3Ao2bjM26iYalPpW8Pw/FLG6QXZEtOzmfyFAknzQR5wDECQQDsVKPFOUMNU89F ++zznViTiRj2+Z3kLfY7BmP2B/0/O9qnne98RQDRI9hu8SL4o6ll3P3wucOv7I+o6 +bqh5clq7AkEA0L2VK0vEKyR6pksJDj1wxtic9TyKEINcYnkXteOPBOHRcwXA5tBS +LTgSsQSfHe41bl3SQqQWYkY65CH4LYHHNQJAa1lS/r4w9/fO2gHyOz7FCEdRupBz +ykVhOA1PceJQFTm0GaMJw2M/nLi2BoOgZSN2OhWLSekfN/eraJllS60nCwJAch5D +UAFDBOcTmphJIhza7Ar+fGAVhwOZ3Ugge1MmHGAsdrq9hDJ9yrTuGxLQvrc9RNJM +Ihy9FAsbJR+hI5fgxQJAK+oeuE/LxSI9lVFe/wl4so0AsA98aYjK0lB+qBT6F7Zf +QEN6sCv+4Peulp4pIm160LuYt2+/iJ1G/ezRyfbctw== +-----END RSA PRIVATE KEY----- diff --git a/devportal/devportal-domain-service/ballerina/tests/subscriptionTests.bal b/devportal/devportal-domain-service/ballerina/tests/subscriptionTests.bal new file mode 100644 index 000000000..2b2a523a4 --- /dev/null +++ b/devportal/devportal-domain-service/ballerina/tests/subscriptionTests.bal @@ -0,0 +1,319 @@ +// +// Copyright (c) 2022, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + +import ballerina/test; +import ballerina/log; +import ballerina/uuid; +import wso2/apk_common_lib as commons; + +Subscription sub = {apiId: "01ed75e2-b30b-18c8-wwf2-25da7edd2231", applicationId: "21212"}; +Application applicationNew = {name: "sampleAppNew", description: "sample application"}; + +@test:Mock {functionName: "retrieveManagementServerHostsList"} +test:MockFunction retrieveManagementServerHostsListMock = new (); + +@test:Mock {functionName: "createApplication", moduleName: "wso2/notification_grpc_client"} +public isolated function createApplicationMock(ApplicationGRPC createApplicationRequest, string endpoint, string pubCert, string devCert, string devKey) returns error|NotificationResponse { + NotificationResponse noti = {code: "OK"}; + return noti; +} + +@test:Mock {functionName: "createSubscription", moduleName: "wso2/notification_grpc_client"} +public isolated function createSubscriptionMock(SubscriptionGRPC createSubscriptionRequest, string endpoint, string pubCert, string devCert, string devKey) returns error|NotificationResponse { + NotificationResponse noti = {code: "OK"}; + return noti; +} + +@test:Mock {functionName: "updateSubscription", moduleName: "wso2/notification_grpc_client"} +public isolated function updateSubscriptionMock(SubscriptionGRPC updateSubscriptionRequest, string endpoint, string pubCert, string devCert, string devKey) returns error|NotificationResponse { + NotificationResponse noti = {code: "OK"}; + return noti; +} + +@test:Mock {functionName: "deleteSubscription", moduleName: "wso2/notification_grpc_client"} +public isolated function deleteSubscriptionMock(SubscriptionGRPC deleteSubscriptionRequest, string endpoint, string pubCert, string devCert, string devKey) returns error|NotificationResponse { + NotificationResponse noti = {code: "OK"}; + return noti; +} + +@test:BeforeSuite +function beforeFunc3() { + string[] testHosts = ["http://localhost:9090"]; + test:when(retrieveManagementServerHostsListMock).thenReturn(testHosts); + Application payload = {name: "sampleAppNew", description: "sample application"}; + NotFoundError|Application|commons:APKError createdApplication = addApplication(payload, organiztion, "apkuser"); + if createdApplication is Application { + test:assertTrue(true, "Successfully added the application"); + applicationNew.applicationId = createdApplication.applicationId; + BusinessPlan payloadbp = { + "planName": "MyBusinessPlan3", + "displayName": "MyBusinessPlan3", + "description": "test sub pol test", + "defaultLimit": { + "type": "REQUESTCOUNTLIMIT", + "requestCount": { + "requestCount": 20, + "timeUnit": "min", + "unitTime": 1 + } + }, + "rateLimitCount": 10, + "rateLimitTimeUnit": "sec", + "customAttributes": [] + }; + payloadbp.planId = uuid:createType1AsString(); + BusinessPlan|commons:APKError createdBusinessPlan = addBusinessPlanDAO(payloadbp, organiztion.uuid); + if createdBusinessPlan is commons:APKError { + test:assertFail("Error occured while adding Business Plan"); + } + } else if createdApplication is error { + test:assertFail("Error occured while adding application"); + } +} + +@test:Config {} +function addSubscriptionTest() { + string? appId = applicationNew.applicationId; + if appId is string { + Subscription payload = {apiId: "01ed75e2-b30b-18c8-wwf2-25da7edd2231", applicationId: appId}; + Subscription|commons:APKError|NotFoundError subscription = addSubscription(payload, organiztion, "apkuser"); + if subscription is Subscription { + test:assertTrue(true, "Succesfully added a subscription"); + sub.subscriptionId = subscription.subscriptionId; + } else if subscription is commons:APKError { + log:printError(subscription.toString()); + test:assertFail("Error occured while adding subscription"); + } else if subscription is NotFoundError { + log:printError(subscription.toString()); + test:assertFail("Error occured while adding subscription"); + } + } else { + test:assertFail("App ID isn't a string"); + } +} + +@test:Config {dependsOn: [addSubscriptionTest]} +function addSubscriptionNegativeTest1() { + // API ID is not found or API Id is not returned + string? appId = applicationNew.applicationId; + if appId is string { + Subscription payload = {apiId: "8e3a1ca4-b649-4e57-9a57-e43b6b545af0", applicationId: appId}; + Subscription|commons:APKError|NotFoundError subscription = addSubscription(payload, organiztion, "apkuser"); + if subscription is Subscription { + test:assertFail("Succesfully added a subscription for a invalid API"); + } else { + test:assertTrue(true, "Sucessfully validated API not available while adding a subscription"); + } + } else { + test:assertFail("App ID isn't a string"); + } +} + +@test:Config {dependsOn: [addSubscriptionNegativeTest1]} +function addSubscriptionNegativeTest2() { + // APP ID is not found or APP Id is not returned + Subscription payload = {apiId: "01ed75e2-b30b-18c8-wwf2-25da7edd2231", applicationId: "01ed716f-9f85-1ade-b634-be97dee7ceb4"}; + Subscription|commons:APKError|NotFoundError subscription = addSubscription(payload, organiztion, "apkuser"); + if subscription is Subscription { + test:assertFail("Succesfully added a subscription for a invalid Application"); + } else { + test:assertTrue(true, "Sucessfully validated Application not available while adding a subscription"); + } +} + +@test:Config {dependsOn: [addSubscriptionNegativeTest2]} +function addSubscriptionNegativeTest3() { + // Policy Not Found + string? appId = applicationNew.applicationId; + if appId is string { + Subscription payload = {apiId: "01ed75e2-b30b-18c8-wwf2-25da7edd2231", applicationId: appId}; + Subscription|commons:APKError|NotFoundError subscription = addSubscription(payload, organiztion, "apkuser"); + if subscription is Subscription { + test:assertFail("Succesfully added a subscription for a invalid Policy"); + } else { + test:assertTrue(true, "Sucessfully validated Policy not available while adding a subscription"); + } + } else { + test:assertFail("App ID isn't a string"); + } +} + +@test:Config {dependsOn: [addSubscriptionNegativeTest3]} +function addMultipleSubscriptionsTest() { + // Add 2 new app + string? newappId1 = ""; + string? newappId2 = ""; + Application payload = {name: "sampleAppNew1", description: "sample application"}; + NotFoundError|Application|commons:APKError createdApplication = addApplication(payload, organiztion, "apkuser"); + if createdApplication is Application { + test:assertTrue(true, "Successfully added the application"); + newappId1 = createdApplication.applicationId; + } else if createdApplication is error { + test:assertFail("Error occured while adding application"); + } + Application payload2 = {name: "sampleAppNew2", description: "sample application"}; + NotFoundError|Application|commons:APKError createdApplication2 = addApplication(payload2, organiztion, "apkuser"); + if createdApplication2 is Application { + test:assertTrue(true, "Successfully added the application"); + newappId2 = createdApplication2.applicationId; + } else if createdApplication2 is error { + test:assertFail("Error occured while adding application"); + } + + if newappId1 is string && newappId2 is string { + Subscription[] multiSub = [ + {apiId: "01ed75e2-b30b-18c8-wwf2-25da7edd2231", applicationId: newappId1}, + {apiId: "01ed75e2-b30b-18c8-wwf2-25da7edd2231", applicationId: newappId2} + ]; + + Subscription[]|commons:APKError|NotFoundError subscriptions = addMultipleSubscriptions(multiSub, organiztion, "apkuser"); + if subscriptions is Subscription[] { + test:assertTrue(true, "Succesfully added multiple subscriptions"); + } else { + test:assertFail("Error occured while adding multiple subscriptions"); + } + } else { + test:assertFail("App ID isn't a string"); + } +} + +@test:Config {dependsOn: [addMultipleSubscriptionsTest]} +function getSubscriptionByIdTest() { + string? subId = sub.subscriptionId; + if subId is string { + Subscription|commons:APKError|NotFoundError returnedResponse = getSubscriptionById(subId, organiztion); + if returnedResponse is Subscription { + test:assertTrue(true, "Successfully retrieved subscription"); + } else { + test:assertFail("Error occured while retrieving subscription"); + } + } else { + test:assertFail("Sub ID isn't a string"); + } +} + +@test:Config {dependsOn: [getSubscriptionByIdTest]} +function updateSubscriptionTest() { + // add a new policy + BusinessPlan payloadbp = { + "planName": "MyBusinessPlan2", + "displayName": "MyBusinessPlan2", + "description": "test sub pol test", + "defaultLimit": { + "type": "REQUESTCOUNTLIMIT", + "requestCount": { + "requestCount": 20, + "timeUnit": "min", + "unitTime": 1 + } + }, + "rateLimitCount": 10, + "rateLimitTimeUnit": "sec", + "customAttributes": [] + }; + payloadbp.planId = uuid:createType1AsString(); + BusinessPlan|commons:APKError createdBusinessPlan = addBusinessPlanDAO(payloadbp, organiztion.uuid); + if createdBusinessPlan is BusinessPlan { + test:assertTrue(true, "Business Plan added successfully"); + string? appId = applicationNew.applicationId; + string? subId = sub.subscriptionId; + if appId is string && subId is string { + // Use new policy + Subscription payload = {apiId: "01ed75e2-b30b-18c8-wwf2-25da7edd2231", applicationId: appId}; + string?|Subscription|NotFoundError|error subscription = updateSubscription(subId, payload, organiztion, "apkuser"); + if subscription is Subscription { + test:assertTrue(true, "Succesfully updated the subscription"); + } else if subscription is error { + test:assertFail("Error occured while updating subscription"); + } + } else { + test:assertFail("App ID isn't a string"); + } + } else if createdBusinessPlan is commons:APKError { + test:assertFail("Error occured while adding Business Plan"); + } +} + +@test:Config {dependsOn: [updateSubscriptionTest]} +function getSubscriptionListTest1() { + // Providing both API ID and App Id + string? appId = applicationNew.applicationId; + if appId is string { + SubscriptionList|commons:APKError|NotFoundError subscriptionList = getSubscriptions("01ed75e2-b30b-18c8-wwf2-25da7edd2231", appId, "", 0, 0, organiztion); + if subscriptionList is ApplicationList { + test:assertTrue(true, "Successfully retrieved all subscriptions by API ID and App ID"); + } else { + test:assertFail("Error occured while retrieving all subscriptions"); + } + } else { + test:assertFail("App ID isn't a string"); + } +} + +@test:Config {dependsOn: [getSubscriptionListTest1]} +function getSubscriptionListTest2() { + // Providing only API ID + SubscriptionList|commons:APKError|NotFoundError subscriptionList = getSubscriptions("01ed75e2-b30b-18c8-wwf2-25da7edd2231", null, "", 0, 0, organiztion); + if subscriptionList is ApplicationList { + test:assertTrue(true, "Successfully retrieved all subscriptions by API ID and App ID"); + } else { + test:assertFail("Error occured while retrieving all subscriptions"); + } +} + +@test:Config {dependsOn: [getSubscriptionListTest2]} +function getSubscriptionListTest3() { + // Providing only App ID + string? appId = applicationNew.applicationId; + if appId is string { + SubscriptionList|commons:APKError|NotFoundError subscriptionList = getSubscriptions(null, appId, "", 0, 0, organiztion); + if subscriptionList is ApplicationList { + test:assertTrue(true, "Successfully retrieved all subscriptions by API ID and App ID"); + } else { + test:assertFail("Error occured while retrieving all subscriptions"); + } + } else { + test:assertFail("App ID isn't a string"); + } +} + +@test:Config {dependsOn: [getSubscriptionListTest3]} +function getSubscriptionListTest4() { + // Providing nothing and retrieving all subscriptions + SubscriptionList|commons:APKError|NotFoundError subscriptionList = getSubscriptions(null, null, "", 0, 0, organiztion); + if subscriptionList is ApplicationList { + test:assertTrue(true, "Successfully retrieved all subscriptions by API ID and App ID"); + } else { + test:assertFail("Error occured while retrieving all subscriptions"); + } +} + +@test:Config {dependsOn: [getSubscriptionListTest4]} +function deleteSubscriptionTest() { + string? subId = sub.subscriptionId; + if subId is string { + commons:APKError? status = deleteSubscription(subId, organiztion); + if status is () { + test:assertTrue(true, "Successfully deleted subscription"); + } else { + test:assertFail("Error occured while deleting subscription"); + } + } else { + test:assertFail("Sub ID isn't a string"); + } +} diff --git a/devportal/devportal-domain-service/ballerina/tests/testTypes.bal b/devportal/devportal-domain-service/ballerina/tests/testTypes.bal new file mode 100644 index 000000000..99161fc6a --- /dev/null +++ b/devportal/devportal-domain-service/ballerina/tests/testTypes.bal @@ -0,0 +1,127 @@ +// +// Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + +import ballerina/constraint; + +// Defines a record to create artifact. +type Artifact record {| + string? id; + string apiName; + string context; + string 'version; + string? status; +|}; + +public type APIBody record { + API apiProperties; + # Content of the definition + record {} Definition; +}; + +public type Policy record { + # Id of plan + string planId?; + # Name of plan + @constraint:String {maxLength: 60, minLength: 1} + string planName; + # Display name of the policy + @constraint:String {maxLength: 512} + string displayName?; + # Description of the policy + @constraint:String {maxLength: 1024} + string description?; + # Indicates whether the policy is deployed successfully or not. + boolean isDeployed = false; + # Indicates the type of throttle policy + string 'type?; +}; + +public type GraphQLQuery record { + # Maximum Complexity of the GraphQL query + int graphQLMaxComplexity?; + # Maximum Depth of the GraphQL query + int graphQLMaxDepth?; +}; + +public type ThrottleLimitBase record { + # Unit of the time. Allowed values are "sec", "min", "hour", "day" + string timeUnit; + # Time limit that the throttling limit applies. + int unitTime; +}; + +public type RequestCountLimit record { + *ThrottleLimitBase; + # Maximum number of requests allowed + int requestCount; +}; + +public type ThrottleLimit record { + # Type of the throttling limit. Allowed values are "REQUESTCOUNTLIMIT" and "BANDWIDTHLIMIT". + # Please see schemas of "RequestCountLimit" and "BandwidthLimit" throttling limit types in + # Definitions section. + string 'type; + RequestCountLimit requestCount?; + BandwidthLimit bandwidth?; + EventCountLimit eventCount?; +}; +public type ApplicationRatePlan record { + *Policy; + ThrottleLimit defaultLimit; +}; + +public type CustomAttribute record { + # Name of the custom attribute + string name; + # Value of the custom attribute + string value; +}; + +public type BusinessPlanPermission record { + string permissionType; + string[] roles; +}; + +public type BusinessPlan record { + *Policy; + *GraphQLQuery; + ThrottleLimit defaultLimit; + # Burst control request count + int rateLimitCount?; + # Burst control time unit + string rateLimitTimeUnit?; + # Number of subscriptions allowed + int subscriberCount?; + # Custom attributes added to the Subscription Throttling Policy + CustomAttribute[] customAttributes?; + BusinessPlanPermission permissions?; +}; + +public type BandwidthLimit record { + *ThrottleLimitBase; + # Amount of data allowed to be transfered + int dataAmount; + # Unit of data allowed to be transfered. Allowed values are "KB", "MB" and "GB" + string dataUnit; +}; + +public type EventCountLimit record { + *ThrottleLimitBase; + # Maximum number of events allowed + int eventCount; +}; \ No newline at end of file diff --git a/devportal/devportal-domain-service/ballerina/tests/testUtils.bal b/devportal/devportal-domain-service/ballerina/tests/testUtils.bal new file mode 100644 index 000000000..599c08930 --- /dev/null +++ b/devportal/devportal-domain-service/ballerina/tests/testUtils.bal @@ -0,0 +1,185 @@ +// +// Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + +import ballerina/log; +import ballerinax/postgresql; +import ballerina/sql; +import wso2/apk_common_lib as commons; +import ballerina/time; + +# Add API details to the database +# +# + apiBody - API Parameter +# + organization - organization +# + return - API | error +isolated function createAPIDAO(APIBody apiBody, string organization) returns API | commons:APKError { + postgresql:Client | error dbClient = getConnection(); + if dbClient is error { + string message = "Error while retrieving connection"; + return error(message, dbClient, message = message, description = message, code = 909000, statusCode = 500); + } else { + postgresql:JsonBinaryValue artifact = new (createArtifact(apiBody.apiProperties.id, apiBody.apiProperties)); + sql:ParameterizedQuery ADD_API_Suffix = `INSERT INTO api(uuid, api_name, api_version,context,status,organization,artifact) VALUES (`; + sql:ParameterizedQuery values = `${apiBody.apiProperties.id}, + ${apiBody.apiProperties.name}, + ${apiBody.apiProperties.'version}, + ${apiBody.apiProperties.context}, + ${apiBody.apiProperties.lifeCycleStatus}, + ${organization}, + ${artifact})`; + sql:ParameterizedQuery sqlQuery = sql:queryConcat(ADD_API_Suffix, values); + + sql:ExecutionResult | sql:Error result = dbClient->execute(sqlQuery); + + if result is sql:ExecutionResult { + return apiBody.apiProperties; + } else { + log:printDebug(result.toString()); + string message = "Error while inserting data into Database"; + return error(message, result, message = message, description = message, code = 909000, statusCode = 500); + } + } +} + +# This function used to create artifact from API +# +# + apiID - API Id parameter +# + api - api object +# + return - Return Value json +isolated function createArtifact(string? apiID, API api) returns json { + Artifact artifact = { + id: apiID, + apiName : api.name, + context : api.context, + 'version : api.'version, + status: api.lifeCycleStatus + }; + json artifactJson = artifact; + return artifactJson; +} + +# Add API definition to the database +# +# + apiBody - API Parameter +# + organization - organization +# + return - API | error +isolated function addDefinitionDAO(APIBody apiBody, string organization) returns API | commons:APKError { + postgresql:Client | error dbClient = getConnection(); + if dbClient is error { + string message = "Error while retrieving connection"; + return error(message, dbClient, message = message, description = message, code = 909000, statusCode = 500); + } else { + sql:ParameterizedQuery ADD_API_DEFINITION_Suffix = `INSERT INTO api_artifact(organization, api_uuid, api_definition,media_type) VALUES (`; + sql:ParameterizedQuery values = `${organization}, + ${apiBody.apiProperties.id}, + ${apiBody.Definition.toString().toBytes()}, + ${apiBody.apiProperties.'type} + )`; + sql:ParameterizedQuery sqlQuery = sql:queryConcat(ADD_API_DEFINITION_Suffix, values); + + sql:ExecutionResult | sql:Error result = dbClient->execute(sqlQuery); + + if result is sql:ExecutionResult { + return apiBody.apiProperties; + } else { + log:printDebug(result.toString()); + string message = "Error while inserting data into Database"; + return error(message, result, message = message, description = message, code = 909000, statusCode = 500); + } + } +} + +public isolated function addApplicationUsagePlanDAO(ApplicationRatePlan atp, string org) returns ApplicationRatePlan|commons:APKError { + postgresql:Client | error dbClient = getConnection(); + if dbClient is error { + string message = "Error while retrieving connection"; + return error(message, dbClient, message = message, description = message, code = 909000, statusCode = 500); + } else { + sql:ParameterizedQuery query = `INSERT INTO APPLICATION_USAGE_PLAN (NAME, DISPLAY_NAME, + ORGANIZATION, DESCRIPTION, QUOTA_TYPE, QUOTA, UNIT_TIME, TIME_UNIT, IS_DEPLOYED, UUID) + VALUES (${atp.planName},${atp.displayName},${org},${atp.description},${atp.defaultLimit.'type}, + ${atp.defaultLimit.requestCount?.requestCount},${atp.defaultLimit.requestCount?.unitTime}, + ${atp.defaultLimit.requestCount?.timeUnit},${atp.isDeployed},${atp.planId})`; + sql:ExecutionResult | sql:Error result = dbClient->execute(query); + if result is sql:ExecutionResult { + return atp; + } else if result is sql:Error { + log:printDebug(result.toString()); + string message = "Error while inserting data into Database"; + return error(message, result, message = message, description = message, code = 909000, statusCode = 500); + } + } +} + +public isolated function addBusinessPlanDAO(BusinessPlan stp, string org) returns BusinessPlan|commons:APKError { + postgresql:Client | error dbClient = getConnection(); + if dbClient is error { + string message = "Error while retrieving connection"; + return error(message, dbClient, message = message, description = message, code = 909000, statusCode = 500); + } else { + sql:ParameterizedQuery query = `INSERT INTO BUSINESS_PLAN (NAME, DISPLAY_NAME, ORGANIZATION, DESCRIPTION, + QUOTA_TYPE, QUOTA, UNIT_TIME, TIME_UNIT, IS_DEPLOYED, UUID, + RATE_LIMIT_COUNT,RATE_LIMIT_TIME_UNIT,MAX_DEPTH, MAX_COMPLEXITY, + BILLING_PLAN,CONNECTIONS_COUNT) VALUES (${stp.planName},${stp.displayName},${org},${stp.description},${stp.defaultLimit.'type}, + ${stp.defaultLimit.requestCount?.requestCount},${stp.defaultLimit.requestCount?.unitTime},${stp.defaultLimit.requestCount?.timeUnit}, + ${stp.isDeployed},${stp.planId},${stp.rateLimitCount},${stp.rateLimitTimeUnit},0, + 0,'FREE',0)`; + sql:ExecutionResult | sql:Error result = dbClient->execute(query); + if result is sql:ExecutionResult { + log:printDebug(result.toString()); + return stp; + } else { + log:printError(result.toString()); + string message = "Error while inserting data into Database"; + return error(message, result, message = message, description = message, code = 909000, statusCode = 500); + } + } +} + +isolated function addResourceDAO(Resource resourceItem) returns Resource|commons:APKError { + postgresql:Client | error dbClient = getConnection(); + if dbClient is error { + string message = "Error while retrieving connection"; + return error(message, dbClient, message = message, description = message, code = 909000, statusCode = 500); + } else { + time:Utc utc = time:utcNow(); + sql:ParameterizedQuery values = `${resourceItem.resourceUUID}, + ${resourceItem.apiUuid}, + ${resourceItem.resourceCategoryId}, + ${resourceItem.dataType}, + to_tsvector(${resourceItem.resourceContent}), + bytea(${resourceItem.resourceBinaryValue}), + 'apkuser', + ${utc}, + 'apkuser', + ${utc} + )`; + sql:ParameterizedQuery ADD_THUMBNAIL_Prefix = `INSERT INTO API_RESOURCES (UUID, API_UUID, RESOURCE_CATEGORY_ID, DATA_TYPE, RESOURCE_CONTENT, RESOURCE_BINARY_VALUE, CREATED_BY, CREATED_TIME, UPDATED_BY, LAST_UPDATED_TIME) VALUES (`; + sql:ParameterizedQuery sqlQuery = sql:queryConcat(ADD_THUMBNAIL_Prefix, values); + sql:ExecutionResult | sql:Error result = dbClient->execute(sqlQuery); + if result is sql:ExecutionResult { + log:printDebug("Resource added successfully"); + return resourceItem; + } else { + log:printError(result.toString()); + string message = "Error while inserting data into Database"; + return error(message, result, message = message, description = message, code = 909000, statusCode = 500); + } + } +} + diff --git a/devportal/devportal-domain-service/ballerina/types.bal b/devportal/devportal-domain-service/ballerina/types.bal new file mode 100644 index 000000000..bd6bb62c9 --- /dev/null +++ b/devportal/devportal-domain-service/ballerina/types.bal @@ -0,0 +1,924 @@ +// +// Copyright (c) 2022, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + +import ballerina/http; +import ballerina/constraint; + +public type AcceptedWorkflowResponse record {| + *http:Accepted; + WorkflowResponse body; +|}; + +public type InternalServerErrorError record {| + *http:InternalServerError; + Error body; +|}; + +public type ConflictError record {| + *http:Conflict; + Error body; +|}; + +public type NotFoundError record {| + *http:NotFound; + Error body; +|}; + +public type OkApplicationKey record {| + *http:Ok; + ApplicationKey body; +|}; + +public type BadRequestError record {| + *http:BadRequest; + Error body; +|}; + +public type UnauthorizedError record {| + *http:Unauthorized; + Error body; +|}; + +public type OkAPIKey record {| + *http:Ok; + APIKey body; +|}; + +public type OkSubscription record {| + *http:Ok; + Subscription[] body; +|}; + +public type NotAcceptableError record {| + *http:NotAcceptable; + Error body; +|}; + +public type OkApplicationToken record {| + *http:Ok; + ApplicationToken body; +|}; + +public type UnsupportedMediaTypeError record {| + *http:UnsupportedMediaType; + Error body; +|}; + +public type PreconditionFailedError record {| + *http:PreconditionFailed; + Error body; +|}; + +public type OkApplicationKeyReGenerateResponse record {| + *http:Ok; + ApplicationKeyReGenerateResponse body; +|}; + +public type OkApplicationInfo record {| + *http:Ok; + ApplicationInfo body; +|}; + +public type DocumentList record { + # Number of Documents returned. + int count?; + Document[] list?; + Pagination pagination?; +}; + +public type ApplicationKey record { + # Key Manager Mapping UUID + string keyMappingId?; + # Key Manager Name + string keyManager?; + # Consumer key of the application + string consumerKey?; + # Consumer secret of the application + string consumerSecret?; + # The grant types that are supported by the application + string[] supportedGrantTypes?; + # Callback URLs of the application + string[] callbackUrls?; + # Describes the state of the key generation. + string keyState?; + # Describes to which endpoint the key belongs + string keyType?; + # Describe the which mode Application Mapped. + string mode?; + ApplicationToken token?; + # additionalProperties (if any). + record {} additionalProperties?; +}; + +public type GraphQLSchemaTypeList record { + GraphQLSchemaType[] typeList?; +}; + +public type GraphQLSchemaType record { + # Type found within the GraphQL Schema + string 'type?; + # Array of fields under current type + string[] fieldList?; +}; + +public type APIInfo_additionalProperties record { + string name?; + string value?; + boolean display?; +}; + +public type ApplicationKeyGenerateRequest record { + string keyType; + # key Manager to Generate Keys + string keyManager?; + # Grant types that should be supported by the application + string[] grantTypesToBeSupported; + string[] callbackUrls?; + # Client ID for generating access token. + string clientId?; + # Client secret for generating access token. This is given together with the client Id. + string clientSecret?; + # Additional properties needed. + record {} additionalProperties?; +}; + +public type Document record { + string documentId?; + string name; + string documentType; + string summary?; + string sourceType; + string sourceUrl?; + string otherTypeName?; +}; + +public type APIKeyRevokeRequest record { + # API Key to revoke + string apikey?; +}; + +public type Pagination record { + int offset?; + int 'limit?; + int total?; + # Link to the next subset of resources qualified. + # Empty if no more resources are to be returned. + string next?; + # Link to the previous subset of resources qualified. + # Empty if current subset is the first subset returned. + string previous?; +}; + +public type AdditionalSubscriptionInfo_solaceURLs record { + string protocol?; + string endpointURL?; +}; + +public type RatingList record { + # Average Rating of the API + string avgRating?; + # Rating given by the user + int userRating?; + # Number of Subscriber Ratings returned. + int count?; + Rating[] list?; + Pagination pagination?; +}; + +public type APIOperations record { + string id?; + string target?; + string verb?; +}; + +public type ScopeList record { + # Number of results returned. + int count?; + ScopeInfo[] list?; + Pagination pagination?; +}; + +public type APIList record { + # Number of APIs returned. + int count?; + APIInfo[] list?; + Pagination pagination?; +}; + +public type CurrentAndNewPasswords record { + string currentPassword?; + string newPassword?; +}; + +public type ApplicationToken record { + # Access token + string accessToken?; + # Valid comma separated scopes for the access token + string[] tokenScopes?; + # Maximum validity time for the access token + int validityTime?; +}; + +public type APIMonetizationUsage record { + # Map of custom properties related to monetization usage + record {|string...;|} properties?; +}; + +public type Subscription record { + # The UUID of the subscription + string subscriptionId?; + # The UUID of the application + string applicationId; + # The unique identifier of the API. + string apiId; + APIInfo apiInfo?; + ApplicationInfo applicationInfo?; + string status?; + string subscriptionCreateState?; + # A url and other parameters the subscriber can be redirected. + string redirectionParams?; +}; + +public type Settings record { + string[] grantTypes?; + boolean applicationSharingEnabled?; + boolean mapExistingAuthApps?; + string apiGatewayEndpoint?; + boolean monetizationEnabled?; + boolean recommendationEnabled?; + boolean IsUnlimitedTierPaid?; + Settings_identityProvider identityProvider?; + boolean IsAnonymousModeEnabled?; + boolean IsPasswordChangeEnabled?; + # The 'PasswordJavaRegEx' configured in the UserStoreManager + string userStorePasswordPattern?; + # The regex configured in the Password Policy property 'passwordPolicy.pattern' + string passwordPolicyPattern?; + # If Password Policy Feature is enabled, the property 'passwordPolicy.min.length' is returned as the 'passwordPolicyMinLength'. If password policy is not enabled, default value -1 will be returned. And it should be noted that the regex pattern(s) returned in 'passwordPolicyPattern' and 'userStorePasswordPattern' properties too will affect the minimum password length allowed and an intersection of all conditions will be considered finally to validate the password. + int passwordPolicyMinLength?; + # If Password Policy Feature is enabled, the property 'passwordPolicy.max.length' is returned as the 'passwordPolicyMaxLength'. If password policy is not enabled, default value -1 will be returned. And it should be noted that the regex pattern(s) returned in 'passwordPolicyPattern' and 'userStorePasswordPattern' properties too will affect the maximum password length allowed and an intersection of all conditions will be considered finally to validate the password. + int passwordPolicyMaxLength?; +}; + +public type ThrottlingPolicyPermissionInfo record { + string 'type?; + # roles for this permission + string[] roles?; +}; + +public type AdditionalSubscriptionInfo_solaceDeployedEnvironments record { + string environmentName?; + string environmentDisplayName?; + string organizationName?; + AdditionalSubscriptionInfo_solaceURLs[] solaceURLs?; + AdditionalSubscriptionInfo_SolaceTopicsObject SolaceTopicsObject?; +}; + +public type APIMonetizationInfo record { + # Flag to indicate the monetization status + boolean enabled; +}; + +public type APIBusinessInformation record { + string businessOwner?; + string businessOwnerEmail?; + string technicalOwner?; + string technicalOwnerEmail?; +}; + +public type SolaceTopics record { + string[] publishTopics?; + string[] subscribeTopics?; +}; + +public type APISearchResult record { + *SearchResult; + # A brief description about the API + string description?; + # A string that represents the context of the user's request + string context?; + # The version of the API + string version?; + # If the provider value is not given, the user invoking the API will be used as the provider. + string provider?; + # This describes in which status of the lifecycle the API is + string status?; + string thumbnailUri?; + APIBusinessInformation businessInformation?; + # Average rating of the API + string avgRating?; +}; + +public type ApplicationAttributeList record { + # Number of application attributes returned. + int count?; + ApplicationAttribute[] list?; +}; + +public type ThrottlingPolicyList record { + # Number of Throttling Policies returned. + int count?; + ThrottlingPolicy[] list?; + Pagination pagination?; +}; + +public type Settings_identityProvider record { + boolean 'external?; +}; + +public type ApplicationKeyList record { + # Number of applications keys returned. + int count?; + ApplicationKey[] list?; +}; + +public type APIDefinition record { + string 'type; + string schemaDefinition?; +}; + +public type CommenterInfo record { + string firstName?; + string lastName?; + string fullName?; +}; + +public type Applications_import_body record { + # Zip archive consisting of exported Application Configuration. + record {byte[] fileContent; string fileName;} file; +}; + +public type AdvertiseInfo record { + boolean advertised?; + string apiExternalProductionEndpoint?; + string apiExternalSandboxEndpoint?; + string originalDevPortalUrl?; + string apiOwner?; + string vendor?; +}; + +public type CommentList record { + # Number of Comments returned. + int count?; + Comment[] list?; + Pagination pagination?; +}; + +public type API_URLs record { + # HTTP environment URL + string http?; + # HTTPS environment URL + string https?; + # WS environment URL + string ws?; + # WSS environment URL + string wss?; +}; + +public type Application record { + string applicationId?; + @constraint:String {maxLength: 100, minLength: 1} + string name; + @constraint:String {maxLength: 512} + string description?; + string status = ""; + string[] groups?; + int subscriptionCount?; + record {|string...;|} attributes?; + # Application created user + string owner?; + string createdTime?; + string updatedTime?; +}; + +public type GraphQLCustomComplexityInfo record { + # The type found within the schema of the API + string 'type; + # The field which is found under the type within the schema of the API + string 'field; + # The complexity value allocated for the associated field under the specified type + int complexityValue; +}; + +public type AdditionalSubscriptionInfoList record { + # Number of additional information sets of subscription returned. + int count?; + AdditionalSubscriptionInfo[] list?; + Pagination pagination?; +}; + +public type User record { + string username; + string password; + string firstName; + string lastName; + string email; +}; + +public type API_defaultVersionURLs record { + # HTTP environment default URL + string http?; + # HTTPS environment default URL + string https?; + # WS environment default URL + string ws?; + # WSS environment default URL + string wss?; +}; + +public type AdditionalSubscriptionInfo_SolaceTopicsObject record { + SolaceTopics defaultSyntax?; + SolaceTopics mqttSyntax?; +}; + +public type ErrorListItem record { + string code; + # Description about individual errors occurred + string message; +}; + +public type Rating record { + string ratingId?; + string apiId?; + @constraint:String {maxLength: 50} + string ratedBy?; + int rating; +}; + +public type APICategoryList record { + # Number of API categories returned. + int count?; + APICategory[] list?; +}; + +public type ApplicationInfo record { + string applicationId?; + string name?; + string throttlingPolicy?; + string description?; + string status?; + string[] groups?; + int subscriptionCount?; + record {} attributes?; + string owner?; + string createdTime?; + string updatedTime?; +}; + +public type ApplicationKeyReGenerateResponse record { + # The consumer key associated with the application, used to identify the client + string consumerKey?; + # The client secret that is used to authenticate the client with the authentication server + string consumerSecret?; +}; + +public type KeyManagerList record { + # Number of Key managers returned. + int count?; + KeyManagerInfo[] list?; +}; + +public type ApplicationAttribute record { + # description of the application attribute + string description?; + # type of the input element to display + string 'type?; + # tooltop to display for the input element + string tooltip?; + # whether this is a required attribute + string required?; + # the name of the attribute + string attribute?; + # whether this is a hidden attribute + string hidden?; +}; + +public type Recommendations record { + # Number of APIs returned. + int count?; + RecommendedAPI[] list?; +}; + +public type SearchResultList record { + # Number of results returned. + int count?; + record {}[] list?; + Pagination pagination?; +}; + +public type Tenant record { + # tenant domain + string domain?; + # current status of the tenant active/inactive + string status?; +}; + +public type KeyManagerApplicationConfiguration record { + string name?; + string label?; + string 'type?; + boolean required?; + boolean mask?; + boolean multiple?; + string tooltip?; + record {} default?; + record {}[] values?; +}; + +public type ApplicationList record { + # Number of applications returned. + int count?; + ApplicationInfo[] list?; + Pagination pagination?; +}; + +public type TopicList record { + # Number of Topics returned. + int count?; + Topic[] list?; + Pagination pagination?; +}; + +public type TagList record { + # Number of Tags returned. + int count?; + Tag[] list?; + Pagination pagination?; +}; + +public type API_tiers record { + string tierName?; + string tierPlan?; + API_monetizationAttributes monetizationAttributes?; +}; + +public type TenantList record { + # Number of tenants returned. + int count?; + Tenant[] list?; + Pagination pagination?; +}; + +public type ApplicationKeyMappingRequest record { + # Consumer key of the application + string consumerKey; + # Consumer secret of the application + string consumerSecret?; + # Key Manager Name + string keyManager?; + string keyType; +}; + +public type Topic record { + string apiId?; + string name?; + string 'type?; +}; + +public type WebhookSubscriptionList record { + # Number of webhook subscriptions returned. + int count?; + WebhookSubscription[] list?; + Pagination pagination?; +}; + +public type Comment record { + string id?; + @constraint:String {maxLength: 512} + string content; + string createdTime?; + string createdBy?; + string updatedTime?; + string category = "general"; + string parentCommentId?; + string entryPoint?; + CommenterInfo commenterInfo?; + CommentList replies?; +}; + +public type ApplicationTokenGenerateRequest record { + # Consumer secret of the application + string consumerSecret?; + # Token validity period + int validityPeriod?; + # Token to be revoked, if any + string revokeToken?; + string grantType?; + string[] scopes?; + # Additional parameters if Authorization server needs any + record {} additionalProperties?; +}; + +public type KeyManagerInfo record { + string id?; + string name; + string 'type; + # display name of Keymanager + string displayName?; + string description?; + boolean enabled?; + string[] availableGrantTypes?; + string tokenEndpoint?; + string revokeEndpoint?; + string userInfoEndpoint?; + boolean enableTokenGeneration?; + boolean enableTokenEncryption = false; + boolean enableTokenHashing = false; + boolean enableOAuthAppCreation = true; + boolean enableMapOAuthConsumerApps = false; + KeyManagerApplicationConfiguration[] applicationConfiguration?; + # The alias of Identity Provider. + # If the tokenType is EXCHANGED, the alias value should be inclusive in the audience values of the JWT token + string alias?; + record {} additionalProperties?; + # The type of the tokens to be used (exchanged or without exchanged). Accepted values are EXCHANGED, DIRECT and BOTH. + string tokenType = "DIRECT"; +}; + +public type WebhookSubscription record { + string apiId?; + string appId?; + string topic?; + string callBackUrl?; + string deliveryTime?; + int deliveryStatus?; +}; + +public type APIInfo record { + string id?; + string name?; + string description?; + string context?; + string version?; + string 'type?; + string createdTime?; + # If the provider value is not given, the user invoking the API will be used as the provider. + string provider?; + string lifeCycleStatus?; + string thumbnailUri?; + # Average rating of the API + string avgRating?; + # List of throttling policies of the API + string[] throttlingPolicies?; + AdvertiseInfo advertiseInfo?; + APIBusinessInformation businessInformation?; + boolean isSubscriptionAvailable?; + string monetizationLabel?; + string gatewayVendor?; + # Custom(user defined) properties of API + APIInfo_additionalProperties[] additionalProperties?; +}; + +public type Error record { + int code; + # Error message. + string message; + # A detail description about the error message. + string description?; + # Preferably an url with more details about the error. + string moreInfo?; + # If there are more than one error list them out. + # For example, list out validation errors by each field. + ErrorListItem[] 'error?; +}; + +public type APIKeyGenerateRequest record { + # Token validity period + int validityPeriod?; + # Additional parameters if Authorization server needs any + record {} additionalProperties?; +}; + +public type ScopeInfo record { + string 'key?; + string name?; + # Allowed roles for the scope + string[] roles?; + # Description of the scope + string description?; +}; + +public type SearchResult record { + string id?; + string name; + string 'type?; + # Accepted values are HTTP, WS, SOAPTOREST, GRAPHQL + string transportType?; +}; + +public type ThrottlingPolicy record { + string name; + string description?; + string policyLevel?; + # Custom attributes added to the throttling policy + record {|string...;|} attributes?; + # Maximum number of requests which can be sent within a provided unit time + int requestCount; + # Unit of data allowed to be transferred. Allowed values are "KB", "MB" and "GB" + string dataUnit?; + int unitTime; + string timeUnit?; + # Burst control request count + int rateLimitCount = 0; + # Burst control time unit + string rateLimitTimeUnit?; + # Default quota limit type + string quotaPolicyType?; + # This attribute declares whether this tier is available under commercial or free + string tierPlan; + # If this attribute is set to false, you are capable of sending requests + # even if the request count exceeded within a unit time + boolean stopOnQuotaReach; + MonetizationInfo monetizationAttributes?; + ThrottlingPolicyPermissionInfo throttlingPolicyPermissions?; +}; + +public type APIKey record { + # API Key + string apikey?; + int validityTime?; +}; + +public type DocumentSearchResult record { + *SearchResult; + string docType?; + string summary?; + string sourceType?; + string sourceUrl?; + string otherTypeName?; + string visibility?; + # The name of the associated API + string apiName?; + # The version of the associated API + string apiVersion?; + string apiProvider?; + string apiUUID?; +}; + +public type PatchRequestBody record { + # Content of the comment + @constraint:String {maxLength: 512} + string content?; + # Category of the comment + string category?; +}; + +public type PostRequestBody record { + # Content of the comment + @constraint:String {maxLength: 512} + string content; + # Category of the comment + string category?; +}; + +public type GraphQLQueryComplexityInfo record { + GraphQLCustomComplexityInfo[] list?; +}; + +public type RecommendedAPI record { + string id?; + string name?; + # Average rating of the API + string avgRating?; +}; + +public type SubscriptionList record { + # Number of Subscriptions returned. + int count?; + Subscription[] list?; + Pagination pagination?; +}; + +public type WorkflowResponse record { + # This attribute declares whether this workflow task is approved or rejected. + string workflowStatus; + # Attributes that returned after the workflow execution + string jsonPayload?; +}; + +public type API record { + # UUID of the api + string id?; + # Name of the API + string name; + # A brief description about the API + string description?; + # A string that represents the context of the user's request + string context; + # The version of the API + string version; + # Swagger definition of the API which contains details about URI templates and scopes + string apiDefinition?; + # WSDL URL if the API is based on a WSDL endpoint + string wsdlUri?; + # This describes in which status of the lifecycle the API is. + string lifeCycleStatus; + boolean isDefaultVersion?; + # This describes the transport type of the API + string 'type?; + string[] transport?; + APIOperations[] operations?; + # Name of the Authorization header used for invoking the API. If it is not set, Authorization header name specified + # in tenant or system level will be used. + string authorizationHeader?; + # Types of API security, the current API secured with. It can be either OAuth2 or mutual SSL or both. If + # it is not set OAuth2 will be set as the security for the current API. + string[] securityScheme?; + # Search keywords related to the API + string[] tags?; + # The subscription tiers selected for the particular API + API_tiers[] tiers?; + boolean hasThumbnail = false; + # Custom(user defined) properties of API + APIInfo_additionalProperties[] additionalProperties?; + APIMonetizationInfo monetization?; + API_endpointURLs[] endpointURLs?; + APIBusinessInformation businessInformation?; + # The environment list configured with non empty endpoint URLs for the particular API. + string[] environmentList?; + ScopeInfo[] scopes?; + # The average rating of the API + string avgRating?; + AdvertiseInfo advertiseInfo?; + boolean isSubscriptionAvailable?; + # API categories + string[] categories?; + # Supported SDK + string[] sdk?; + # API Key Managers + record {} keyManagers?; + string createdTime?; + string lastUpdatedTime?; + string gatewayVendor?; + # Supported transports for the Async API. + string[] asyncTransportProtocols?; +}; + +public type API_endpointURLs record { + string environmentName?; + string environmentDisplayName?; + string environmentType?; + API_URLs URLs?; + API_defaultVersionURLs defaultVersionURLs?; +}; + +public type Tag record { + string value?; + int count?; +}; + +public type MonetizationInfo record { + string billingType?; + string billingCycle?; + string fixedPrice?; + string pricePerRequest?; + string currencyType?; +}; + +public type AdditionalSubscriptionInfo record { + # The UUID of the subscription + string subscriptionId?; + # The UUID of the application + string applicationId?; + # The name of the application + string applicationName?; + # The unique identifier of the API. + string apiId?; + boolean isSolaceAPI?; + string solaceOrganization?; + AdditionalSubscriptionInfo_solaceDeployedEnvironments[] solaceDeployedEnvironments?; +}; + +public type APIInfoList record { + # Number of API Info objects returned. + int count?; + APIInfo[] list?; +}; + +public type APICategory record { + string id?; + string name; + string description?; +}; + +public type API_monetizationAttributes record { + string fixedPrice?; + string pricePerRequest?; + string currencyType?; + string billingCycle?; +}; diff --git a/devportal/devportal-domain-service/ballerina/workflowDAO.bal b/devportal/devportal-domain-service/ballerina/workflowDAO.bal new file mode 100644 index 000000000..e36186dfd --- /dev/null +++ b/devportal/devportal-domain-service/ballerina/workflowDAO.bal @@ -0,0 +1,142 @@ +// +// Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + +import ballerinax/postgresql; +import ballerina/sql; +import ballerina/uuid; +import ballerina/log; +import ballerina/time; + + +// This function is used to check the workflow enabled or not +isolated function isApplicationWorkflowEnabled(string organization) returns boolean|error { + boolean isWorkflowEnabled = false; + postgresql:Client | error dbClient = getConnection(); + if dbClient is error { + string message = "Error while retrieving connection"; + return error(message, dbClient, message = message, description = message, code = 909000, statusCode = 500); + } + do { + sql:ParameterizedQuery query = `SELECT encode(WORKFLOWS, 'escape')::text + FROM ORGANIZATION where ORGANIZATION.UUID = ${organization}`; + string | sql:Error result = dbClient->queryRow(query); + if(result is sql:Error) { + log:printError(result.message()); + string message = "Error while retrieving workflows"; + return error(message, result, message = message, description = message, code = 909000, statusCode = 500); + + } else { + Internal_Organization organization_workflow = { + workflows : result.length() > 0 ? check result.fromJsonStringWithType() : [] + }; + if(organization_workflow.length() > 0) { + foreach WorkflowProperties i in organization_workflow.workflows { + if(i.name == "ApplicationCreation") { + isWorkflowEnabled = i.enabled; + break; + } + } + } + } + return isWorkflowEnabled; + } +} + + +isolated function isSubsciptionWorkflowEnabled(string organization) returns boolean|error { + boolean isWorkflowEnabled = false; + postgresql:Client | error dbClient = getConnection(); + if dbClient is error { + string message = "Error while retrieving connection"; + return error(message, dbClient, message = message, description = message, code = 909000, statusCode = 500); + } + do { + sql:ParameterizedQuery query = `SELECT encode(WORKFLOWS, 'escape')::text + FROM ORGANIZATION where ORGANIZATION.UUID = ${organization}`; + string | sql:Error result = dbClient->queryRow(query); + if(result is sql:Error) { + log:printError(result.message()); + string message = "Error while retrieving workflows"; + return error(message, result, message = message, description = message, code = 909000, statusCode = 500); + + } else { + Internal_Organization organization_workflow = { + workflows : result.length() > 0 ? check result.fromJsonStringWithType() : [] + }; + if(organization_workflow.length() > 0) { + foreach WorkflowProperties i in organization_workflow.workflows { + if(i.name == "SubscriptionCreation") { + isWorkflowEnabled = i.enabled; + break; + } + } + } + } + return isWorkflowEnabled; + } +} + +isolated function addApplicationCreationWorkflow(string applicationID, string organization) returns string|error { + postgresql:Client | error dbClient = getConnection(); + string uuid = uuid:createType1AsString(); + if dbClient is error { + string message = "Error while retrieving connection"; + return error(message, dbClient, message = message, description = message, code = 909000, statusCode = 500); + } + do { + sql:ParameterizedQuery query = `INSERT INTO WORKFLOWS(uuid, wf_reference, wf_type, wf_status, + wf_created_time, wf_updated_time, organization) VALUES (${uuid}, ${applicationID}, 'APPLICATION_CREATION', + 'CREATED', ${time:utcNow()}, ${time:utcNow()} , ${organization})`; + sql:ExecutionResult|sql:Error result = dbClient->execute(query); + if(result is sql:Error) { + string message = "Error while adding application creation workflow"; + return error(message, result, message = message, description = message, code = 909000, statusCode = 500); + } + return uuid; + } +} + +isolated function addSubscriptionCreationWorkflow(string subcriptionID, string organization) returns string|error { + postgresql:Client | error dbClient = getConnection(); + string uuid = uuid:createType1AsString(); + if dbClient is error { + string message = "Error while retrieving connection"; + return error(message, dbClient, message = message, description = message, code = 909000, statusCode = 500); + } + do { + sql:ParameterizedQuery query = `INSERT INTO WORKFLOWS(uuid, wf_reference, wf_type, wf_status, + wf_created_time, wf_updated_time, organization) VALUES (${uuid}, ${subcriptionID}, 'SUBSCRIPTION_CREATION', + 'CREATED', ${time:utcNow()}, ${time:utcNow()} , ${organization})`; + sql:ExecutionResult|sql:Error result = dbClient->execute(query); + if(result is sql:Error) { + string message = "Error while adding subscription creation workflow"; + return error(message, result, message = message, description = message, code = 909000, statusCode = 500); + } + return uuid; + } +} + +public type WorkflowProperties record { + string name; + boolean enabled; + string[] properties?; +}; + +public type Internal_Organization record { + WorkflowProperties[] workflows; +}; diff --git a/devportal/devportal-domain-service/build.gradle b/devportal/devportal-domain-service/build.gradle new file mode 100644 index 000000000..4db0e8d1a --- /dev/null +++ b/devportal/devportal-domain-service/build.gradle @@ -0,0 +1,40 @@ +// +// Copyright (c) 2022, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + +plugins { + id 'net.researchgate.release' version '2.8.0' +} +allprojects { + group = project.group + version = project.version +} + +release { + tagTemplate = 'devportal-domain-service-$version' + + git { + requireBranch= "main" + pushToRemote= "origin" + } +} + +unSnapshotVersion.finalizedBy ":ballerina:commit_toml_files" +afterReleaseBuild.dependsOn ":docker:docker_push" +task build{ + dependsOn("docker:build") +} diff --git a/devportal/devportal-domain-service/docker/Dockerfile b/devportal/devportal-domain-service/docker/Dockerfile new file mode 100644 index 000000000..f5365f762 --- /dev/null +++ b/devportal/devportal-domain-service/docker/Dockerfile @@ -0,0 +1,62 @@ +FROM ubuntu:20.04 + +ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en' LC_ALL='en_US.UTF-8' + +# install JDK Dependencies +RUN apt-get update \ + && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends tzdata curl wget ca-certificates fontconfig locales \ + && echo "en_US.UTF-8 UTF-8" >> /etc/locale.gen \ + && locale-gen en_US.UTF-8 \ + && rm -rf /var/lib/apt/lists/* + +ENV JAVA_VERSION jdk-11.0.17+8 + +RUN set -eux; \ + ARCH="$(dpkg --print-architecture)"; \ + case "${ARCH}" in \ + amd64|i386:x86-64) \ + ESUM='752616097e09d7f60a3ad8bd312f90eaf50ac72577e55df229fe6e8091148f79'; \ + BINARY_URL='https://github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.17%2B8/OpenJDK11U-jre_x64_linux_hotspot_11.0.17_8.tar.gz'; \ + ;; \ + aarch64|arm64) \ + ESUM='bd6efe3290c8b5a42f695a55a26f3e3c9c284288574879d4b7089f31f5114177'; \ + BINARY_URL='https://github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.17%2B8/OpenJDK11U-jre_aarch64_linux_hotspot_11.0.17_8.tar.gz'; \ + ;; \ + *) \ + echo "Unsupported arch: ${ARCH}"; \ + exit 1; \ + ;; \ + esac; \ + curl -LfsSo /tmp/openjdk.tar.gz ${BINARY_URL}; \ + echo "${ESUM} */tmp/openjdk.tar.gz" | sha256sum -c -; \ + mkdir -p /opt/java/openjdk; \ + cd /opt/java/openjdk; \ + tar -xf /tmp/openjdk.tar.gz --strip-components=1; \ + rm -rf /tmp/openjdk.tar.gz; + +ENV JAVA_HOME=/opt/java/openjdk \ + PATH="/opt/java/openjdk/bin:$PATH" + +RUN echo Verifying install ... \ + && echo java --version && java --version \ + && echo Complete. + +ARG USER=wso2apk +ARG USER_ID=802 +ARG USER_GROUP=wso2 +ARG USER_GROUP_ID=802 +ARG USER_HOME=/home/${USER} + +RUN groupadd --system -g ${USER_GROUP_ID} ${USER_GROUP} && useradd --system --create-home --home-dir ${USER_HOME} --no-log-init -g ${USER_GROUP_ID} -u ${USER_ID} ${USER} + + +COPY docker-entrypoint.sh ${USER_HOME} +ADD devportal ${USER_HOME}/devportal +RUN chown -R ${USER} ${USER_HOME}/devportal +RUN chown ${USER} /home/${USER}/docker-entrypoint.sh + +EXPOSE 9443 +USER wso2apk +WORKDIR ${USER_HOME} + +ENTRYPOINT ["sh", "/home/wso2apk/docker-entrypoint.sh"] \ No newline at end of file diff --git a/devportal/devportal-domain-service/docker/build.gradle b/devportal/devportal-domain-service/docker/build.gradle new file mode 100644 index 000000000..c8aec273a --- /dev/null +++ b/devportal/devportal-domain-service/docker/build.gradle @@ -0,0 +1,35 @@ +// +// Copyright (c) 2022, WSO2 LLC. (http://www.wso2.com). +// +// WSO2 LLC. licenses this file to you 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. +// + +apply from: "$rootDir/../../common-gradle-scripts/docker.gradle" +apply from: "$rootDir/../../common-gradle-scripts/copy.gradle" + +tasks.named('copy_dist').configure{ + finalizedBy docker_build +} + +tasks.register('build') { + group 'build' + description 'Build docker image' + dependsOn 'copy_dist' + dependsOn 'docker_build' +} +build.configure{ + mustRunAfter(":ballerina:build") + dependsOn(":ballerina:build") + } \ No newline at end of file diff --git a/devportal/devportal-domain-service/docker/devportal/conf/Config.toml b/devportal/devportal-domain-service/docker/devportal/conf/Config.toml new file mode 100644 index 000000000..e96fd2b4a --- /dev/null +++ b/devportal/devportal-domain-service/docker/devportal/conf/Config.toml @@ -0,0 +1,40 @@ + [wso2.devportal_service.datasourceConfiguration] + description = "Database for admin" + url = "jdbc:postgresql://10.102.56.192:5432/WSO2AM_DB" + username = "wso2carbon" + password = "wso2carbon" + validationTimeout = 250 + testQuery = "SELECT 1" + driver = "org.postgresql.Driver" + host = "10.102.56.192" + port = 5432 + databaseName = "WSO2AM_DB" + + [wso2.devportal_service.throttleConfig.blockCondition] + enabled = true + + [wso2.devportal_service.keyStores.tls] + path = "/home/wso2apk/devportal/security/wso2carbon.key" + [wso2.devportal_service.keyStores.signing] + path = "/home/wso2apk/devportal/security/wso2carbon.key" + + [wso2.devportal_service.issuerConfig] + issuer = "https://apim.wso2.com/oauth2/token" + audience = "https://apim.wso2.com/oauth2/token" + keyId = "gateway_certificate_alias" + expTime = 3600.0 + + [wso2.devportal_service.sdkConfig] + groupId = "org.wso2" + artifactId = "org.wso2.client." + modelPackage = "org.wso2.client.model." + apiPackage = "org.wso2.client.api." + + [wso2.devportal_service.k8sConfig] + host = "localhost:9090" + serviceAccountPath = "tests/resources/serviceAccount" + + [wso2.devportal_service.managementServerConfig] + serviceName = "apk-test-wso2-apk-management-server" + namespace = "apk" + certPath = "/home/wso2apk/devportal/security/truststore/management-server.pem" \ No newline at end of file diff --git a/devportal/devportal-domain-service/docker/devportal/devportal.sh b/devportal/devportal-domain-service/docker/devportal/devportal.sh new file mode 100644 index 000000000..9ccf49495 --- /dev/null +++ b/devportal/devportal-domain-service/docker/devportal/devportal.sh @@ -0,0 +1,106 @@ +# resolve links - $0 may be a softlink +PRG="$0" + +while [ -h "$PRG" ]; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '.*/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`/"$link" + fi +done + +# Get standard environment variables +PRGDIR=`dirname "$PRG"` + +[ -z "$DEVPORTAL_HOME" ] && DEVPORTAL_HOME=`cd "$PRGDIR" ; pwd` + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD=java + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." + echo " Admin cannot execute $JAVACMD" + exit 1 +fi + +# if JAVA_HOME is not set we're not happy +if [ -z "$JAVA_HOME" ]; then + echo "You must set the JAVA_HOME variable before running Admin." + exit 1 +fi +# ----- Process the input command ---------------------------------------------- +args="" +for c in $* +do + if [ "$c" = "--debug" ] || [ "$c" = "-debug" ] || [ "$c" = "debug" ]; then + CMD="--debug" + continue + elif [ "$CMD" = "--debug" ]; then + if [ -z "$PORT" ]; then + PORT=$c + fi + fi +done + +if [ "$CMD" = "--debug" ]; then + if [ "$PORT" = "" ]; then + echo " Please specify the debug port after the --debug option" + exit 1 + fi + if [ -n "$JAVA_OPTS" ]; then + echo "Warning !!!. User specified JAVA_OPTS will be ignored, once you give the --debug option." + fi + CMD="RUN" + JAVA_OPTS="-Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=$PORT" + echo "Please start the remote debugging client to continue..." +fi + +CLASSPATH="" +if [ -e "$JAVA_HOME/lib/tools.jar" ]; then + CLASSPATH="$JAVA_HOME/lib/tools.jar" +fi +for t in "$DEVPORTAL_HOME"/lib/*.jar +do + CLASSPATH="$CLASSPATH":$t +done + +# ----- Execute The Requested Command ----------------------------------------- + +echo JAVA_HOME environment variable is set to $JAVA_HOME +echo DEVPORTAL_HOME environment variable is set to "$DEVPORTAL_HOME" +export BAL_CONFIG_FILES=$DEVPORTAL_HOME/conf/Config.toml +cd "$DEVPORTAL_HOME" + +TMP_DIR="$DEVPORTAL_HOME"/tmp +if [ -d "$TMP_DIR" ]; then +rm -rf "$TMP_DIR"/* +fi + +START_EXIT_STATUS=121 +status=$START_EXIT_STATUS + +if [ -z "$JVM_MEM_OPTS" ]; then + java_version=$("$JAVACMD" -version 2>&1 | awk -F '"' '/version/ {print $2}') + JVM_MEM_OPTS="-Xms256m -Xmx1024m" +fi +echo "Using Java memory options: $JVM_MEM_OPTS" + +$JAVACMD \ + $JVM_MEM_OPTS \ + $JAVA_OPTS \ + -classpath "$CLASSPATH" \ + -Djava.io.tmpdir="$DEVPORTAL_HOME/tmp" \ + -jar devportal_service.jar $* + status=$? \ No newline at end of file diff --git a/devportal/devportal-domain-service/docker/devportal/security/.gitkeep b/devportal/devportal-domain-service/docker/devportal/security/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/devportal/devportal-domain-service/docker/docker-entrypoint.sh b/devportal/devportal-domain-service/docker/docker-entrypoint.sh new file mode 100644 index 000000000..a843bed34 --- /dev/null +++ b/devportal/devportal-domain-service/docker/docker-entrypoint.sh @@ -0,0 +1,20 @@ +#!/bin/bash +# +# Copyright (c) 2022, WSO2 LLC. (http://www.wso2.com). +# +# WSO2 LLC. licenses this file to you 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. +# + +sh /home/wso2apk/devportal/devportal.sh diff --git a/devportal/devportal-domain-service/gradle.properties b/devportal/devportal-domain-service/gradle.properties new file mode 100644 index 000000000..3b8cf1003 --- /dev/null +++ b/devportal/devportal-domain-service/gradle.properties @@ -0,0 +1,5 @@ +group=org.wso2.apk +version=0.0.1-SNAPSHOT +docker_image_name = devportal-domain-service +jar_name = devportal_service.jar +dist_name = devportal \ No newline at end of file diff --git a/devportal/devportal-domain-service/gradle/wrapper/gradle-wrapper.properties b/devportal/devportal-domain-service/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..f398c33c4 --- /dev/null +++ b/devportal/devportal-domain-service/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip +networkTimeout=10000 +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/devportal/devportal-domain-service/gradlew b/devportal/devportal-domain-service/gradlew new file mode 100755 index 000000000..a69d9cb6c --- /dev/null +++ b/devportal/devportal-domain-service/gradlew @@ -0,0 +1,240 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# 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 +# +# https://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. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/devportal/devportal-domain-service/gradlew.bat b/devportal/devportal-domain-service/gradlew.bat new file mode 100644 index 000000000..f127cfd49 --- /dev/null +++ b/devportal/devportal-domain-service/gradlew.bat @@ -0,0 +1,91 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/devportal/devportal-domain-service/java/build.gradle b/devportal/devportal-domain-service/java/build.gradle new file mode 100644 index 000000000..8986869d0 --- /dev/null +++ b/devportal/devportal-domain-service/java/build.gradle @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. + * + * 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. + * + */ + +apply from: "$projectDir/../../../common-gradle-scripts/java.gradle" + +dependencies { + implementation libs.commons.logging + implementation libs.commons.validator + implementation libs.openapi.generator + implementation libs.commons.lang +} diff --git a/devportal/devportal-domain-service/java/src/main/java/org/wso2/apk/devportal/sdk/APIClientGenerationException.java b/devportal/devportal-domain-service/java/src/main/java/org/wso2/apk/devportal/sdk/APIClientGenerationException.java new file mode 100644 index 000000000..edd3f67e3 --- /dev/null +++ b/devportal/devportal-domain-service/java/src/main/java/org/wso2/apk/devportal/sdk/APIClientGenerationException.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you 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. + */ + +package org.wso2.apk.devportal.sdk; + +/** + * This is the custom exception class for API Client Generation Manager + */ +public class APIClientGenerationException extends Exception { + public APIClientGenerationException(String msg) { + super(msg); + } + + public APIClientGenerationException(String msg, Throwable e) { + super(msg, e); + } + + public APIClientGenerationException(Throwable throwable) { + super(throwable); + } + + public String getErrorMessage() { + return super.getMessage(); + } +} diff --git a/devportal/devportal-domain-service/java/src/main/java/org/wso2/apk/devportal/sdk/APIClientGenerationManager.java b/devportal/devportal-domain-service/java/src/main/java/org/wso2/apk/devportal/sdk/APIClientGenerationManager.java new file mode 100644 index 000000000..a92736278 --- /dev/null +++ b/devportal/devportal-domain-service/java/src/main/java/org/wso2/apk/devportal/sdk/APIClientGenerationManager.java @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you 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. + */ + +package org.wso2.apk.devportal.sdk; + +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.openapitools.codegen.ClientOptInput; +import org.openapitools.codegen.DefaultGenerator; +import org.openapitools.codegen.config.CodegenConfigurator; +import org.wso2.apk.devportal.sdk.SDKConstants; +import org.wso2.apk.devportal.sdk.ZIPUtils; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.zip.ZipOutputStream; + +/* + * This class is used to generate SDKs for a given API + */ +public class APIClientGenerationManager { + + private static final Log log = LogFactory.getLog(APIClientGenerationManager.class); + private static final Map langCodeGen = new HashMap(); + + public APIClientGenerationManager() { + langCodeGen.put("java", "org.openapitools.codegen.languages.JavaClientCodegen"); + langCodeGen.put("android", "org.openapitools.codegen.languages.AndroidClientCodegen"); + langCodeGen.put("csharp", "org.openapitools.codegen.languages.CSharpClientCodegen"); + langCodeGen.put("cpp", "org.openapitools.codegen.languages.CppRestClientCodegen"); + langCodeGen.put("dart", "org.openapitools.codegen.languages.DartClientCodegen"); + langCodeGen.put("flash", "org.openapitools.codegen.languages.FlashClientCodegen"); + langCodeGen.put("go", "org.openapitools.codegen.languages.GoClientCodegen"); + langCodeGen.put("groovy", "org.openapitools.codegen.languages.GroovyClientCodegen"); + langCodeGen.put("javascript", "org.openapitools.codegen.languages.JavascriptClientCodegen"); + langCodeGen.put("jmeter", "org.openapitools.codegen.languages.JMeterCodegen"); + langCodeGen.put("nodejs", "org.openapitools.codegen.languages.NodeJSServerCodegen"); + langCodeGen.put("perl", "org.openapitools.codegen.languages.PerlClientCodegen"); + langCodeGen.put("php", "org.openapitools.codegen.languages.PhpClientCodegen"); + langCodeGen.put("python", "org.openapitools.codegen.languages.PythonClientCodegen"); + langCodeGen.put("ruby", "org.openapitools.codegen.languages.RubyClientCodegen"); + langCodeGen.put("swift", "org.openapitools.codegen.languages.SwiftCodegen"); + langCodeGen.put("clojure", "org.openapitools.codegen.languages.ClojureClientCodegen"); + langCodeGen.put("aspNet5", "org.openapitools.codegen.languages.AspNet5ServerCodegen"); + langCodeGen.put("scala-akka-client", "org.openapitools.codegen.languages.ScalaAkkaClientCodegen"); + langCodeGen.put("spring", "org.openapitools.codegen.languages.SpringCodegen"); + langCodeGen.put("csharpDotNet2", "org.openapitools.codegen.languages.CsharpDotNet2ClientCodegen"); + langCodeGen.put("haskell", "org.openapitools.codegen.languages.HaskellServantCodegen"); + } + + /** + * This method generates client side SDK for a given API + * + * @param sdkLanguage preferred language to generate the SDK + * @param apiName name of the API + * @param apiVersion version of the API + * @param swaggerAPIDefinition Swagger Definition of the API + * @param groupId group id of the generated SDK + * @param artifactId artifact id of the generated SDK + * @param modelPackage model package name of the generated SDK + * @param apiPackage api package name of the generated SDK + * @return a map containing the zip file name and its' temporary location until it is downloaded + * @throws APIClientGenerationException if failed to generate the SDK + */ + public Map generateSDK(String sdkLanguage, String apiName, String apiVersion, + String swaggerAPIDefinition, String groupId, String artifactId, + String modelPackage, String apiPackage) + throws APIClientGenerationException { + + if (StringUtils.isBlank(sdkLanguage) || StringUtils.isBlank(apiName) || StringUtils.isBlank(apiVersion)) { + handleSDKGenException("SDK Language, API Name or API Version should not be null."); + } + if (StringUtils.isEmpty(swaggerAPIDefinition)) { + handleSDKGenException("Error loading the Swagger definition. Swagger file is empty."); + } + //create a temporary directory with a random name to store files created during generating the SDK + Path path = Paths.get(FileUtils.getTempDirectory().getAbsolutePath(), UUID.randomUUID().toString()); + String tempDirectoryLocation = path.toFile().getAbsolutePath(); + try { + tempDirectoryLocation = Files.createDirectories(path).toFile().getAbsolutePath(); + } catch (IOException e) { + handleSDKGenException("Unable to create temporary directory in : " + tempDirectoryLocation); + } + String specFileLocation = tempDirectoryLocation + File.separator + UUID.randomUUID() + + SDKConstants.JSON_FILE_EXTENSION; + //The below swaggerSpecFile will be deleted when cleaning the temp directory by the caller + try { + File swaggerSpecFile = new File(specFileLocation); + + boolean isSpecFileCreated = swaggerSpecFile.createNewFile(); + if (!isSpecFileCreated) { + handleSDKGenException("Unable to create the swagger spec file for API : " + apiName + " in " + + specFileLocation); + } + try (FileWriter fileWriter = new FileWriter(swaggerSpecFile.getAbsoluteFile())) { + try (BufferedWriter bufferedWriter = new BufferedWriter(fileWriter)) { + bufferedWriter.write(swaggerAPIDefinition); + } + } + } catch (IOException e) { + handleSDKGenException("Error while storing the temporary swagger file in : " + specFileLocation, e); + } + + String sdkDirectoryName = apiName + "_" + apiVersion + "_" + sdkLanguage; + String temporaryOutputPath = tempDirectoryLocation + File.separator + sdkDirectoryName; + generateClient(apiName, specFileLocation, sdkLanguage, temporaryOutputPath, + groupId, artifactId, modelPackage, apiPackage); + String temporaryZipFilePath = temporaryOutputPath + SDKConstants.ZIP_FILE_EXTENSION; + try { + ZIPUtils.zipDir(temporaryOutputPath, temporaryZipFilePath); + } catch (IOException e) { + handleSDKGenException("Error while generating .zip archive for the generated SDK.", e); + } + //The below file object is closed and deleted by the caller, so it should left open until the SDK is downloaded. + File sdkArchive = new File(temporaryZipFilePath); + Map sdkDataMap = new HashMap(); + sdkDataMap.put("zipFilePath", sdkArchive.getAbsolutePath()); + sdkDataMap.put("zipFileName", sdkDirectoryName + SDKConstants.ZIP_FILE_EXTENSION); + sdkDataMap.put("tempDirectoryPath", tempDirectoryLocation); + return sdkDataMap; + } + + public void cleanTempDirectory(String tempDirectoryPath) { + if (StringUtils.isNotBlank(tempDirectoryPath)) { + try { + FileUtils.cleanDirectory(new File(tempDirectoryPath)); + } catch (IOException e) { + // Ignore this exception since this temp directory is automatically deleted after a server + // restart. These temp files can be manually deleted if needed. Reference : APIMANAGER-4981 + log.warn("Failed to clean temporary files at : " + tempDirectoryPath + + " Delete those files manually or it will be cleared after a server restart."); + } + } + } + + /** + * This method is used to retrieve the supported languages for SDK generation + * + * @return supported languages for SDK generation + */ + public String getSupportedSDKLanguages() { + String supportedLanguages = SDKConstants.CLIENT_CODEGEN_SUPPORTED_LANGUAGES; + return supportedLanguages; + + } + + /** + * This method is used to generate SDK for a API for a given language + * + * @param apiName name of the API + * @param specLocation location of the swagger spec for the API + * @param sdkLanguage preferred SDK language + * @param temporaryOutputPath temporary location where the SDK archive is saved until downloaded + */ + private void generateClient(String apiName, String specLocation, String sdkLanguage, String temporaryOutputPath, + String groupId, String artifactId, String modelPackage, String apiPackage) { + + CodegenConfigurator codegenConfigurator = new CodegenConfigurator(); + codegenConfigurator.setGroupId(groupId); + codegenConfigurator.setArtifactId(artifactId + apiName); + codegenConfigurator + .setModelPackage(modelPackage + apiName); + codegenConfigurator.setApiPackage(apiPackage + apiName); + codegenConfigurator.setInputSpec(specLocation); + codegenConfigurator.setGeneratorName(sdkLanguage); + codegenConfigurator.setOutputDir(temporaryOutputPath); + codegenConfigurator.setValidateSpec(false); + final ClientOptInput clientOptInput = codegenConfigurator.toClientOptInput(); + new DefaultGenerator().opts(clientOptInput).generate(); + + } + + /** + * This method is to handle exceptions occurred when generating the SDK + * + * @param errorMessage error message to be printed in the log + * @throws APIClientGenerationException + */ + private void handleSDKGenException(String errorMessage) throws APIClientGenerationException { + log.error(errorMessage); + throw new APIClientGenerationException(errorMessage); + } + + /** + * This method is to handle exceptions occurred when generating the SDK (with a throwable exception) + * + * @param errorMessage error message to be printed in the log + * @param throwable throwable exception caught + * @throws APIClientGenerationException + */ + private void handleSDKGenException(String errorMessage, Throwable throwable) throws APIClientGenerationException { + log.error(errorMessage, throwable); + throw new APIClientGenerationException(errorMessage, throwable); + } +} diff --git a/devportal/devportal-domain-service/java/src/main/java/org/wso2/apk/devportal/sdk/SDKConstants.java b/devportal/devportal-domain-service/java/src/main/java/org/wso2/apk/devportal/sdk/SDKConstants.java new file mode 100644 index 000000000..cb543d05b --- /dev/null +++ b/devportal/devportal-domain-service/java/src/main/java/org/wso2/apk/devportal/sdk/SDKConstants.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you 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. + */ + +package org.wso2.apk.devportal.sdk; + +public final class SDKConstants { + //Constants for swagger-codegen client generation + public static final String CLIENT_CODEGEN_GROUPID = "org.wso2"; + public static final String CLIENT_CODEGEN_ARTIFACTID = "org.wso2.client."; + public static final String CLIENT_CODEGEN_MODAL_PACKAGE = "org.wso2.client.model."; + public static final String CLIENT_CODEGEN_API_PACKAGE = "org.wso2.client.api."; + public static final String CLIENT_CODEGEN_SUPPORTED_LANGUAGES = "android,java,javascript,jmeter"; + public static final String TEMP_DIRECTORY_NAME = "tmp"; + public static final String SWAGGER_CODEGEN_DIRECTORY = "swaggerCodegen"; + public static final String JSON_FILE_EXTENSION = ".json"; + public static final String ZIP_FILE_EXTENSION = ".zip"; + public static final String YAML_FILE_EXTENSION = ".yaml"; + public static final String YML_FILE_EXTENSION = ".yml"; +} diff --git a/devportal/devportal-domain-service/java/src/main/java/org/wso2/apk/devportal/sdk/ZIPUtils.java b/devportal/devportal-domain-service/java/src/main/java/org/wso2/apk/devportal/sdk/ZIPUtils.java new file mode 100644 index 000000000..cb3c54eee --- /dev/null +++ b/devportal/devportal-domain-service/java/src/main/java/org/wso2/apk/devportal/sdk/ZIPUtils.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you 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. + */ + +package org.wso2.apk.devportal.sdk; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +public class ZIPUtils { + + /** + * Creates a zip archive from the provided folder + * + * @param dirName folder to zip + * @param nameZipFile absolute path to the zip file which needs to be created + * @throws IOException when error occurred while creating the zip file + */ + public static void zipDir(String dirName, String nameZipFile) throws IOException { + try (FileOutputStream fW = new FileOutputStream(nameZipFile); ZipOutputStream zip = new ZipOutputStream(fW)) { + addFolderToZip("", dirName, zip); + } + + } + + private static void addFolderToZip(String path, String srcFolder, ZipOutputStream zip) throws IOException { + File folder = new File(srcFolder); + if (folder.list().length == 0) { + addFileToZip(path, srcFolder, zip, true); + } else { + for (String fileName : folder.list()) { + if (path.equals("")) { + addFileToZip(folder.getName(), srcFolder + "/" + fileName, zip, false); + } else { + addFileToZip(path + "/" + folder.getName(), srcFolder + "/" + fileName, zip, false); + } + } + } + } + + private static void addFileToZip(String path, String srcFile, ZipOutputStream zip, boolean flag) throws IOException { + File folder = new File(srcFile); + if (flag) { + zip.putNextEntry(new ZipEntry(path + "/" + folder.getName() + "/")); + } else { + if (folder.isDirectory()) { + addFolderToZip(path, srcFile, zip); + } else { + byte[] buf = new byte[1024]; + int len; + try (FileInputStream in = new FileInputStream(srcFile)) { + zip.putNextEntry(new ZipEntry(path + "/" + folder.getName())); + while ((len = in.read(buf)) > 0) { + zip.write(buf, 0, len); + } + } + } + } + } +} \ No newline at end of file diff --git a/devportal/devportal-domain-service/settings.gradle b/devportal/devportal-domain-service/settings.gradle new file mode 100644 index 000000000..aa3c78544 --- /dev/null +++ b/devportal/devportal-domain-service/settings.gradle @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2022, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. + * + * 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. + * + */ + +rootProject.name = 'devportal-domain-service' + +include ':ballerina' +include ':docker' +include ':java' +project(':ballerina').projectDir = file('ballerina') +project(':docker').projectDir = file('docker') +project(':java').projectDir = file('java') +project(':java').name = "org.wso2.apk.devportal" + +dependencyResolutionManagement { + versionCatalogs { + libs { + from(files("$rootDir/../../libs.versions.toml")) + } + } +} \ No newline at end of file diff --git a/devportal/devportal-ui/Dockerfile b/devportal/devportal-ui/Dockerfile new file mode 100644 index 000000000..e69de29bb diff --git a/devportal/devportal-ui/build.gradle b/devportal/devportal-ui/build.gradle new file mode 100644 index 000000000..e69de29bb diff --git a/devportal/devportal-ui/gradle.properties b/devportal/devportal-ui/gradle.properties new file mode 100644 index 000000000..6ab80b6c2 --- /dev/null +++ b/devportal/devportal-ui/gradle.properties @@ -0,0 +1,2 @@ +group=org.wso2.apk +version=0.0.1-SNAPSHOT diff --git a/devportal/devportal-ui/gradle/wrapper/gradle-wrapper.properties b/devportal/devportal-ui/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..ae04661ee --- /dev/null +++ b/devportal/devportal-ui/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/devportal/devportal-ui/gradlew b/devportal/devportal-ui/gradlew new file mode 100755 index 000000000..a69d9cb6c --- /dev/null +++ b/devportal/devportal-ui/gradlew @@ -0,0 +1,240 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# 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 +# +# https://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. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/devportal/devportal-ui/gradlew.bat b/devportal/devportal-ui/gradlew.bat new file mode 100644 index 000000000..f127cfd49 --- /dev/null +++ b/devportal/devportal-ui/gradlew.bat @@ -0,0 +1,91 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/helm-charts/templates/cert-manager/certificates/admin-domain-server-certificate.yaml b/helm-charts/templates/cert-manager/certificates/admin-domain-server-certificate.yaml new file mode 100644 index 000000000..9be8bfbf9 --- /dev/null +++ b/helm-charts/templates/cert-manager/certificates/admin-domain-server-certificate.yaml @@ -0,0 +1,39 @@ +# Copyright (c) 2022, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. +# +# WSO2 LLC. licenses this file to you 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. + +# The following manifests contain a self-signed issuer CR and a certificate CR. +# More document can be found at https://docs.cert-manager.io + +{{- if .Values.wso2.apk.cp.enabled }} +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-server-cert + namespace: {{ .Release.Namespace }} +spec: + commonName: admin-ds-service + privateKey: + algorithm: RSA + encoding: PKCS8 + size: 2048 + dnsNames: + - {{ template "apk-helm.resource.prefix" . }}-admin-ds-service.{{ .Release.Namespace }}.svc + - {{ template "apk-helm.resource.prefix" . }}-admin-ds-service.{{ .Release.Namespace }}.svc.cluster.local + issuerRef: + kind: ClusterIssuer + name: selfsigned-issuer + secretName: {{ template "apk-helm.resource.prefix" . }}-admin-ds-server-cert +{{- end -}} diff --git a/helm-charts/templates/cert-manager/certificates/backoffice-domain-server-certificate.yaml b/helm-charts/templates/cert-manager/certificates/backoffice-domain-server-certificate.yaml new file mode 100644 index 000000000..0bbdc81ff --- /dev/null +++ b/helm-charts/templates/cert-manager/certificates/backoffice-domain-server-certificate.yaml @@ -0,0 +1,39 @@ +# Copyright (c) 2022, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. +# +# WSO2 LLC. licenses this file to you 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. + +# The following manifests contain a self-signed issuer CR and a certificate CR. +# More document can be found at https://docs.cert-manager.io + +{{- if .Values.wso2.apk.cp.enabled }} +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: {{ template "apk-helm.resource.prefix" . }}-backoffice-ds-server-cert + namespace: {{ .Release.Namespace }} +spec: + commonName: backoffice-ds-service + privateKey: + algorithm: RSA + encoding: PKCS8 + size: 2048 + dnsNames: + - {{ template "apk-helm.resource.prefix" . }}-backoffice-ds-service.{{ .Release.Namespace }}.svc + - {{ template "apk-helm.resource.prefix" . }}-backoffice-ds-service.{{ .Release.Namespace }}.svc.cluster.local + issuerRef: + kind: ClusterIssuer + name: selfsigned-issuer + secretName: {{ template "apk-helm.resource.prefix" . }}-backoffice-ds-server-cert +{{- end -}} diff --git a/helm-charts/templates/cert-manager/certificates/devportal-domain-server-certificate.yaml b/helm-charts/templates/cert-manager/certificates/devportal-domain-server-certificate.yaml new file mode 100644 index 000000000..97a03a77d --- /dev/null +++ b/helm-charts/templates/cert-manager/certificates/devportal-domain-server-certificate.yaml @@ -0,0 +1,39 @@ +# Copyright (c) 2022, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. +# +# WSO2 LLC. licenses this file to you 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. + +# The following manifests contain a self-signed issuer CR and a certificate CR. +# More document can be found at https://docs.cert-manager.io + +{{- if .Values.wso2.apk.cp.enabled }} +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-server-cert + namespace: {{ .Release.Namespace }} +spec: + commonName: admin-ds-service + privateKey: + algorithm: RSA + encoding: PKCS8 + size: 2048 + dnsNames: + - {{ template "apk-helm.resource.prefix" . }}-devportal-ds-service.{{ .Release.Namespace }}.svc + - {{ template "apk-helm.resource.prefix" . }}-devportal-ds-service.{{ .Release.Namespace }}.svc.cluster.local + issuerRef: + kind: ClusterIssuer + name: selfsigned-issuer + secretName: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-server-cert +{{- end -}} diff --git a/helm-charts/templates/cert-manager/certificates/management-server-certificate.yaml b/helm-charts/templates/cert-manager/certificates/management-server-certificate.yaml new file mode 100644 index 000000000..2ee1a951e --- /dev/null +++ b/helm-charts/templates/cert-manager/certificates/management-server-certificate.yaml @@ -0,0 +1,39 @@ +# Copyright (c) 2022, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. +# +# WSO2 LLC. licenses this file to you 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. + +# The following manifests contain a self-signed issuer CR and a certificate CR. +# More document can be found at https://docs.cert-manager.io + +{{- if .Values.wso2.apk.cp.enabled }} +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: {{ template "apk-helm.resource.prefix" . }}-management-server-cert + namespace: {{ .Release.Namespace }} +spec: + commonName: management-server + privateKey: + algorithm: RSA + encoding: PKCS8 + size: 2048 + dnsNames: + - {{ template "apk-helm.resource.prefix" . }}-management-server.{{ .Release.Namespace }}.svc + - {{ template "apk-helm.resource.prefix" . }}-management-server.{{ .Release.Namespace }}.svc.cluster.local + issuerRef: + kind: ClusterIssuer + name: selfsigned-issuer + secretName: {{ template "apk-helm.resource.prefix" . }}-management-server-cert +{{- end -}} diff --git a/helm-charts/templates/control-plane/admin-ds/admin-domain-api-backend.yaml b/helm-charts/templates/control-plane/admin-ds/admin-domain-api-backend.yaml new file mode 100644 index 000000000..d006c7e3b --- /dev/null +++ b/helm-charts/templates/control-plane/admin-ds/admin-domain-api-backend.yaml @@ -0,0 +1,38 @@ +# Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. +# +# WSO2 LLC. licenses this file to you 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. +{{- if .Values.wso2.apk.cp.enabled }} +kind: "Backend" +apiVersion: "dp.wso2.com/v1alpha1" +metadata: + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + namespace: {{ .Release.Namespace }} +spec: + services: + - host: {{ template "apk-helm.resource.prefix" . }}-admin-ds-service.{{ .Release.Namespace }} + port: 9443 + protocol: "https" + tls: + allowedSANs: + - {{ template "apk-helm.resource.prefix" . }}-admin-ds-service.{{ .Release.Namespace }}.svc + secretRef: + {{- if and .Values.wso2.apk.cp.admin.configs .Values.wso2.apk.cp.admin.configs.tls }} + name: {{.Values.wso2.apk.cp.admin.configs.tls.secretName}} + key: {{.Values.wso2.apk.cp.admin.configs.tls.certFilename}} + {{- else }} + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-server-cert + key: tls.crt + {{- end }} +{{- end -}} diff --git a/helm-charts/templates/control-plane/admin-ds/admin-domain-api-httproute-1.yaml b/helm-charts/templates/control-plane/admin-ds/admin-domain-api-httproute-1.yaml new file mode 100644 index 000000000..aa1176eff --- /dev/null +++ b/helm-charts/templates/control-plane/admin-ds/admin-domain-api-httproute-1.yaml @@ -0,0 +1,274 @@ +# Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. +# +# WSO2 LLC. licenses this file to you 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. +{{- if .Values.wso2.apk.cp.enabled }} +apiVersion: "gateway.networking.k8s.io/v1beta1" +kind: "HTTPRoute" +metadata: + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-httproute-1 + namespace: {{ .Release.Namespace }} + labels: + api-name: "admin-domain-service" + api-version: "1.0.0" +spec: + hostnames: + - "{{ .Values.wso2.apk.listener.hostname | default "api.am.wso2.com"}}" + rules: + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/policies/search" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/policies/search" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/application-rate-plans" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/application-rate-plans" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/application-rate-plans" + method: "POST" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/application-rate-plans" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/application-rate-plans/(.*)" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/application-rate-plans/\\1" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/application-rate-plans/(.*)" + method: "PUT" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/application-rate-plans/\\1" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/application-rate-plans/(.*)" + method: "DELETE" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/application-rate-plans/\\1" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/business-plans" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/business-plans" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/business-plans" + method: "POST" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/business-plans" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/business-plans/(.*)" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/business-plans/\\1" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/business-plans/(.*)" + method: "PUT" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/business-plans/\\1" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/business-plans/(.*)" + method: "DELETE" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/business-plans/\\1" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/throttling/policies/advanced" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/throttling/policies/advanced" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/throttling/policies/advanced" + method: "POST" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/throttling/policies/advanced" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/throttling/policies/advanced/(.*)" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/throttling/policies/advanced/\\1" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/throttling/policies/advanced/(.*)" + method: "PUT" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/throttling/policies/advanced/\\1" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/throttling/policies/advanced/(.*)" + method: "DELETE" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/throttling/policies/advanced/\\1" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + parentRefs: + - group: "gateway.networking.k8s.io" + kind: "Gateway" + name: "default" + sectionName: "httpslistener" +{{- end -}} diff --git a/helm-charts/templates/control-plane/admin-ds/admin-domain-api-httproute-2.yaml b/helm-charts/templates/control-plane/admin-ds/admin-domain-api-httproute-2.yaml new file mode 100644 index 000000000..a6b1c1400 --- /dev/null +++ b/helm-charts/templates/control-plane/admin-ds/admin-domain-api-httproute-2.yaml @@ -0,0 +1,274 @@ +# Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. +# +# WSO2 LLC. licenses this file to you 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. +{{- if .Values.wso2.apk.cp.enabled }} +apiVersion: "gateway.networking.k8s.io/v1beta1" +kind: "HTTPRoute" +metadata: + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-httproute-2 + namespace: {{ .Release.Namespace }} + labels: + api-name: "admin-domain-service" + api-version: "1.0.0" +spec: + hostnames: + - "{{ .Values.wso2.apk.listener.hostname | default "api.am.wso2.com"}}" + rules: + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/throttling/policies/export" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/throttling/policies/export" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/throttling/policies/import" + method: "POST" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/throttling/policies/import" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/policies/search" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/policies/search" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/application-rate-plans" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/application-rate-plans" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/application-rate-plans" + method: "POST" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/application-rate-plans" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/application-rate-plans/(.*)" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/application-rate-plans/\\1" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/application-rate-plans/(.*)" + method: "PUT" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/application-rate-plans/\\1" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/application-rate-plans/(.*)" + method: "DELETE" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/application-rate-plans/\\1" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/business-plans" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/business-plans" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/business-plans" + method: "POST" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/business-plans" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/business-plans/(.*)" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/business-plans/\\1" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/business-plans/(.*)" + method: "PUT" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/business-plans/\\1" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/business-plans/(.*)" + method: "DELETE" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/business-plans/\\1" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/throttling/policies/advanced" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/throttling/policies/advanced" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/throttling/policies/advanced" + method: "POST" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/throttling/policies/advanced" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/throttling/policies/advanced/(.*)" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/throttling/policies/advanced/\\1" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + parentRefs: + - group: "gateway.networking.k8s.io" + kind: "Gateway" + name: "default" + sectionName: "httpslistener" +{{- end -}} diff --git a/helm-charts/templates/control-plane/admin-ds/admin-domain-api-httproute-3.yaml b/helm-charts/templates/control-plane/admin-ds/admin-domain-api-httproute-3.yaml new file mode 100644 index 000000000..f4578a112 --- /dev/null +++ b/helm-charts/templates/control-plane/admin-ds/admin-domain-api-httproute-3.yaml @@ -0,0 +1,274 @@ +# Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. +# +# WSO2 LLC. licenses this file to you 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. +{{- if .Values.wso2.apk.cp.enabled }} +apiVersion: "gateway.networking.k8s.io/v1beta1" +kind: "HTTPRoute" +metadata: + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-httproute-3 + namespace: {{ .Release.Namespace }} + labels: + api-name: "admin-domain-service" + api-version: "1.0.0" +spec: + hostnames: + - "{{ .Values.wso2.apk.listener.hostname | default "api.am.wso2.com"}}" + rules: + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/throttling/policies/advanced/(.*)" + method: "PUT" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/throttling/policies/advanced/\\1" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/throttling/policies/advanced/(.*)" + method: "DELETE" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/throttling/policies/advanced/\\1" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/throttling/policies/export" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/throttling/policies/export" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/throttling/policies/import" + method: "POST" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/throttling/policies/import" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/deny-policies" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/deny-policies" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/deny-policies" + method: "POST" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/deny-policies" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/deny-policies/(.*)" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/deny-policies/\\1" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/deny-policies/(.*)" + method: "DELETE" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/deny-policies/\\1" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/deny-policies/(.*)" + method: "PATCH" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/deny-policies/\\1" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/applications" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/applications" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/applications/(.*)" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/applications/\\1" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/applications/(.*)" + method: "DELETE" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/applications/\\1" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/applications/(.*)/change-owner" + method: "POST" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/applications/\\1/change-owner" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/environments" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/environments" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/environments" + method: "POST" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/environments" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/environments/(.*)" + method: "PUT" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/environments/\\1" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + parentRefs: + - group: "gateway.networking.k8s.io" + kind: "Gateway" + name: "default" + sectionName: "httpslistener" +{{- end -}} diff --git a/helm-charts/templates/control-plane/admin-ds/admin-domain-api-httproute-4.yaml b/helm-charts/templates/control-plane/admin-ds/admin-domain-api-httproute-4.yaml new file mode 100644 index 000000000..84d4fea43 --- /dev/null +++ b/helm-charts/templates/control-plane/admin-ds/admin-domain-api-httproute-4.yaml @@ -0,0 +1,274 @@ +# Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. +# +# WSO2 LLC. licenses this file to you 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. +{{- if .Values.wso2.apk.cp.enabled }} +apiVersion: "gateway.networking.k8s.io/v1beta1" +kind: "HTTPRoute" +metadata: + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-httproute-4 + namespace: {{ .Release.Namespace }} + labels: + api-name: "admin-domain-service" + api-version: "1.0.0" +spec: + hostnames: + - "{{ .Values.wso2.apk.listener.hostname | default "api.am.wso2.com"}}" + rules: + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/environments/(.*)" + method: "DELETE" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/environments/\\1" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/bot-detection-data" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/bot-detection-data" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/monetization/publish-usage" + method: "POST" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/monetization/publish-usage" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/monetization/publish-usage/status" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/monetization/publish-usage/status" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/workflows" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/workflows" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/workflows/(.*)" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/workflows/\\1" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/workflows/update-workflow-status" + method: "POST" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/workflows/update-workflow-status" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/tenant-info/(.*)" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/tenant-info/\\1" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/custom-urls/(.*)" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/custom-urls/\\1" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/api-categories" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/api-categories" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/api-categories" + method: "POST" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/api-categories" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/api-categories/(.*)" + method: "PUT" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/api-categories/\\1" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/api-categories/(.*)" + method: "DELETE" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/api-categories/\\1" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/settings" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/settings" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/system-scopes/(.*)" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/system-scopes/\\1" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/system-scopes" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/system-scopes" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + parentRefs: + - group: "gateway.networking.k8s.io" + kind: "Gateway" + name: "default" + sectionName: "httpslistener" +{{- end -}} diff --git a/helm-charts/templates/control-plane/admin-ds/admin-domain-api-httproute-5.yaml b/helm-charts/templates/control-plane/admin-ds/admin-domain-api-httproute-5.yaml new file mode 100644 index 000000000..c0bd4acf1 --- /dev/null +++ b/helm-charts/templates/control-plane/admin-ds/admin-domain-api-httproute-5.yaml @@ -0,0 +1,259 @@ +# Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. +# +# WSO2 LLC. licenses this file to you 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. +{{- if .Values.wso2.apk.cp.enabled }} +apiVersion: "gateway.networking.k8s.io/v1beta1" +kind: "HTTPRoute" +metadata: + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-httproute-5 + namespace: {{ .Release.Namespace }} + labels: + api-name: "admin-domain-service" + api-version: "1.0.0" +spec: + hostnames: + - "{{ .Values.wso2.apk.listener.hostname | default "api.am.wso2.com"}}" + rules: + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/system-scopes" + method: "PUT" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/system-scopes" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/system-scopes/role-aliases" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/system-scopes/role-aliases" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/system-scopes/role-aliases" + method: "PUT" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/system-scopes/role-aliases" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/roles/(.*)" + method: "HEAD" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/roles/\\1" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/tenant-theme" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/tenant-theme" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/tenant-theme" + method: "PUT" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/tenant-theme" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/tenant-config" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/tenant-config" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/tenant-config" + method: "PUT" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/tenant-config" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/tenant-config-schema" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/tenant-config-schema" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/key-managers" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/key-managers" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/key-managers" + method: "POST" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/key-managers" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/key-managers/(.*)" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/key-managers/\\1" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/key-managers/(.*)" + method: "PUT" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/key-managers/\\1" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/key-managers/(.*)" + method: "DELETE" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/key-managers/\\1" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/admin/key-managers/discover" + method: "POST" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/admin/key-managers/discover" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + parentRefs: + - group: "gateway.networking.k8s.io" + kind: "Gateway" + name: "default" + sectionName: "httpslistener" +{{- end -}} diff --git a/helm-charts/templates/control-plane/admin-ds/admin-domain-api-httproute-6.yaml b/helm-charts/templates/control-plane/admin-ds/admin-domain-api-httproute-6.yaml new file mode 100644 index 000000000..f51bdec15 --- /dev/null +++ b/helm-charts/templates/control-plane/admin-ds/admin-domain-api-httproute-6.yaml @@ -0,0 +1,50 @@ +# Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. +# +# WSO2 LLC. licenses this file to you 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. +{{- if .Values.wso2.apk.cp.enabled }} +apiVersion: "gateway.networking.k8s.io/v1beta1" +kind: "HTTPRoute" +metadata: + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-httproute-6 + namespace: {{ .Release.Namespace }} + labels: + api-name: "admin-domain-service" + api-version: "1.0.0" +spec: + hostnames: + - "{{ .Values.wso2.apk.listener.hostname | default "api.am.wso2.com"}}" + rules: + - matches: + - path: + type: "PathPrefix" + value: "/api/admin/organizations" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + - matches: + - path: + type: "Exact" + value: "/api/admin/organization-info" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-backend + parentRefs: + - group: "gateway.networking.k8s.io" + kind: "Gateway" + name: "default" + sectionName: "httpslistener" +{{- end -}} diff --git a/helm-charts/templates/control-plane/admin-ds/admin-domain-api-policy.yaml b/helm-charts/templates/control-plane/admin-ds/admin-domain-api-policy.yaml new file mode 100644 index 000000000..9c7f096f4 --- /dev/null +++ b/helm-charts/templates/control-plane/admin-ds/admin-domain-api-policy.yaml @@ -0,0 +1,37 @@ +# Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. +# +# WSO2 LLC. licenses this file to you 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. +{{- if .Values.wso2.apk.dp.enabled }} +kind: "APIPolicy" +apiVersion: "dp.wso2.com/v1alpha1" +metadata: + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-api-policy + namespace: {{ .Release.Namespace }} +spec: + override: + backendJwtToken: + enabled: true + encoding: "base64" + signingAlgorithm: "SHA256withRSA" + header: "X-JWT-Assertion" + tokenTTL: 3600 + customClaims: + - claim: "admin" + value: "http://wso2.org/claims/enduser" + targetRef: + group: "gateway.networking.k8s.io" + kind: "API" + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-api +{{- end -}} diff --git a/helm-charts/templates/control-plane/admin-ds/admin-domain-api.yaml b/helm-charts/templates/control-plane/admin-ds/admin-domain-api.yaml new file mode 100644 index 000000000..b0bc273a1 --- /dev/null +++ b/helm-charts/templates/control-plane/admin-ds/admin-domain-api.yaml @@ -0,0 +1,40 @@ +# Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. +# +# WSO2 LLC. licenses this file to you 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. +{{- if .Values.wso2.apk.cp.enabled }} +kind: "API" +apiVersion: "dp.wso2.com/v1alpha1" +metadata: + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-api + namespace: {{ .Release.Namespace }} + labels: + api-name: "admin-domain-service" + api-version: "1.0.0" +spec: + apiName: "admin-domain-service" + apiType: "REST" + apiVersion: "1.0.0" + basePath: "/api/admin/1.0.0" + organization: "carbon.super" + production: + - httpRouteRefs: + - {{ template "apk-helm.resource.prefix" . }}-admin-ds-httproute-1 + - {{ template "apk-helm.resource.prefix" . }}-admin-ds-httproute-2 + - {{ template "apk-helm.resource.prefix" . }}-admin-ds-httproute-3 + - {{ template "apk-helm.resource.prefix" . }}-admin-ds-httproute-4 + - {{ template "apk-helm.resource.prefix" . }}-admin-ds-httproute-5 + - {{ template "apk-helm.resource.prefix" . }}-admin-ds-httproute-6 + systemAPI: true +{{- end -}} diff --git a/helm-charts/templates/control-plane/admin-ds/admin-ds-configmap.yaml b/helm-charts/templates/control-plane/admin-ds/admin-ds-configmap.yaml new file mode 100644 index 000000000..4fa5262e4 --- /dev/null +++ b/helm-charts/templates/control-plane/admin-ds/admin-ds-configmap.yaml @@ -0,0 +1,51 @@ +# Copyright (c) 2022, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. +# +# WSO2 LLC. licenses this file to you 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. + +{{- if .Values.wso2.apk.cp.enabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-configmap + namespace: {{ .Release.Namespace }} +data: + Config.toml: | + [ballerina.log] + level = "DEBUG" + [ballerina.http] + traceLogConsole = true + # Sample configurations + [wso2.admin_service.datasourceConfiguration] + description = "Database for admin" + url = "{{ .Values.wso2.apk.cp.database.url }}" + host = "{{ .Values.wso2.apk.cp.database.host }}" + port = {{ .Values.wso2.apk.cp.database.port }} + databaseName = "{{ .Values.wso2.apk.cp.database.databaseName }}" + username = "{{ .Values.wso2.apk.cp.database.username }}" + validationTimeout = {{ .Values.wso2.apk.cp.database.validationTimeout }} + testQuery = "{{ .Values.wso2.apk.cp.database.validationQuery }}" + driver = "{{ .Values.wso2.apk.cp.database.driver }}" + [wso2.admin_service.throttleConfig.blockCondition] + enabled = true + [wso2.admin_service.idpConfiguration] + organizationClaim = "{{ .Values.wso2.apk.idp.organizationClaim }}" + userClaim = "{{ .Values.wso2.apk.idp.usernameClaim }}" + [wso2.admin_service.idpConfiguration.publicKey] + certFilePath = "/home/wso2apk/admin/security/mg.pem" + [wso2.admin_service.keyStores.tls] + keyFilePath = "/home/wso2apk/admin/security/admin.key" + certFilePath = "/home/wso2apk/admin/security/admin.pem" + +{{- end -}} diff --git a/helm-charts/templates/control-plane/admin-ds/admin-ds-deployment.yaml b/helm-charts/templates/control-plane/admin-ds/admin-ds-deployment.yaml new file mode 100644 index 000000000..57b574700 --- /dev/null +++ b/helm-charts/templates/control-plane/admin-ds/admin-ds-deployment.yaml @@ -0,0 +1,132 @@ +# Copyright (c) 2022, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. +# +# WSO2 LLC. licenses this file to you 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. + +{{- if .Values.wso2.apk.cp.enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-deployment + namespace: {{ .Release.Namespace }} +spec: + replicas: {{ .Values.wso2.apk.cp.admin.deployment.replicas }} + strategy: + type: {{ .Values.wso2.apk.cp.admin.deployment.strategy }} + selector: + matchLabels: +{{ include "apk-helm.pod.selectorLabels" (dict "root" . "app" "admin-ds" ) | indent 6}} + template: + metadata: + labels: +{{ include "apk-helm.pod.selectorLabels" (dict "root" . "app" "admin-ds" ) | indent 8}} + spec: + initContainers: + - name: init-db + image: busybox:1.32 + command: ['sh', '-c', 'echo -e "Checking for the availability of DB Server deployment"; while ! nc -z "{{ .Values.wso2.apk.cp.database.host }}" {{.Values.wso2.apk.cp.database.port }}; do sleep 1; printf "-"; done; echo -e " >> DB Server has started";'] + containers: + - name: admin-ds + image: {{ .Values.wso2.apk.cp.admin.deployment.image }} + imagePullPolicy: {{ .Values.wso2.apk.cp.admin.deployment.imagePullPolicy }} + ports: + - containerPort: 9443 + protocol: "TCP" + - containerPort: 9444 + protocol: "TCP" + readinessProbe: + httpGet: + path: /health + port: 9443 + scheme: HTTPS + initialDelaySeconds: {{ .Values.wso2.apk.cp.admin.deployment.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.wso2.apk.cp.admin.deployment.readinessProbe.periodSeconds }} + livenessProbe: + httpGet: + path: /health + port: 9443 + scheme: HTTPS + initialDelaySeconds: {{ .Values.wso2.apk.cp.admin.deployment.livenessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.wso2.apk.cp.admin.deployment.livenessProbe.periodSeconds }} +{{ include "apk-helm.deployment.resources" .Values.wso2.apk.cp.admin.deployment.resources | indent 10 }} + volumeMounts: + - mountPath: /home/wso2apk/admin/conf/Config.toml + name: config-toml-volume + subPath: Config.toml + - mountPath: /home/wso2apk/admin/security/mg.pem + name: admin-ds-jwt-validation-key-volume + subPath: mg.pem + - name: admin-ds-tls-volume + mountPath: /home/wso2apk/admin/security/admin.key + {{- if and .Values.wso2.apk.cp.admin.configs .Values.wso2.apk.cp.admin.configs.tls }} + subPath: {{ .Values.wso2.apk.cp.admin.configs.tls.certKeyFilename | default "tls.key" }} + {{- else }} + subPath: tls.key + {{- end }} + - name: admin-ds-tls-volume + mountPath: /home/wso2apk/admin/security/admin.pem + {{- if and .Values.wso2.apk.cp.admin.configs .Values.wso2.apk.cp.admin.configs.tls }} + subPath: {{ .Values.wso2.apk.cp.admin.configs.tls.certFilename | default "tls.crt" }} + {{- else }} + subPath: tls.crt + {{- end }} + - name: keymanager-connetor--nonprodidp + mountPath: /home/wso2apk/admin/keymanager/nonprodidp.yaml + subPath: nonprodidp.yaml + {{- range .Values.wso2.apk.cp.keyManagerConnectors}} + - name: key-manager-connectors-{{ .type}} + mountPath: /home/wso2apk/admin/keymanager/{{ .fileName}} + subPath: {{ .fileName}} + {{- end }} + env: + - name: DB_PASSWORD + valueFrom: + secretKeyRef: + {{ if and .Values.wso2.apk.cp.database .Values.wso2.apk.cp.database.secretName }} + name: "{{ .Values.wso2.apk.cp.database.secretName}}" + key: "{{ .Values.wso2.apk.cp.database.secretKey}}" + {{ else }} + name: "apk-db-secret" + key: "DB_PASSWORD" + {{ end }} + {{- if and .Values.wso2.subscription .Values.wso2.subscription.imagePullSecrets}} + imagePullSecrets: + - name: {{ .Values.wso2.subscription.imagePullSecrets }} + {{ end }} + + volumes: + - name: admin-ds-jwt-validation-key-volume + secret: + secretName: {{ template "apk-helm.resource.prefix" . }}-admin-ds-jwt-validaion-secret + - name: config-toml-volume + configMap: + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-configmap + - name: admin-ds-tls-volume + secret: + {{ if and .Values.wso2.apk.cp.admin.configs .Values.wso2.apk.cp.admin.configs.tls }} + secretName: {{ .Values.wso2.apk.cp.admin.configs.tls.secretName | default (printf "%s-admin-ds-server-cert" (include "apk-helm.resource.prefix" .)) }} + {{ else }} + secretName: {{ template "apk-helm.resource.prefix" . }}-admin-ds-server-cert + {{ end }} + - name: keymanager-connetor--nonprodidp + configMap: + name: {{ template "apk-helm.resource.prefix" . }}-nonprodidp-config + {{if .Values.wso2.apk.cp.keyManagerConnectors }} + {{- range .Values.wso2.apk.cp.keyManagerConnectors}} + - name: key-manager-connectors-{{ .type}} + configMap: + name: {{ .name}} + {{- end }} + {{end}} +{{- end -}} diff --git a/helm-charts/templates/control-plane/admin-ds/admin-ds-jwt-validation-secret.yaml b/helm-charts/templates/control-plane/admin-ds/admin-ds-jwt-validation-secret.yaml new file mode 100644 index 000000000..4da3524af --- /dev/null +++ b/helm-charts/templates/control-plane/admin-ds/admin-ds-jwt-validation-secret.yaml @@ -0,0 +1,10 @@ +{{- if .Values.wso2.apk.cp.enabled }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-jwt-validaion-secret + namespace: {{ .Release.Namespace }} +type: Opaque +data: + mg.pem: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURrekNDQW51Z0F3SUJBZ0lKQVBEOGVTM2VtY3JRTUEwR0NTcUdTSWIzRFFFQkN3VUFNR1F4Q3pBSkJnTlYKQkFZVEFsVlRNUXN3Q1FZRFZRUUlEQUpEUVRFV01CUUdBMVVFQnd3TlRXOTFiblJoYVc0Z1ZtbGxkekVOTUFzRwpBMVVFQ2d3RVYxTlBNakVOTUFzR0ExVUVDd3dFVjFOUE1qRVNNQkFHQTFVRUF3d0piRzlqWVd4b2IzTjBNQ0FYCkRUSXlNVEV4TnpFNE1EWXpPRm9ZRHpJd05USXhNVEE1TVRnd05qTTRXakJrTVFzd0NRWURWUVFHRXdKVlV6RUwKTUFrR0ExVUVDQXdDUTBFeEZqQVVCZ05WQkFjTURVMXZkVzUwWVdsdUlGWnBaWGN4RFRBTEJnTlZCQW9NQkZkVApUekl4RFRBTEJnTlZCQXNNQkZkVFR6SXhFakFRQmdOVkJBTU1DV3h2WTJGc2FHOXpkRENDQVNJd0RRWUpLb1pJCmh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTjlaRUQyb1JDbTljZjF2RUV2UjFKL1R3TGFrSmNQeVN2UDIKT1p1Y3hiVlBDeVhvbnlsZEtJbUVoSjZMZnVNcnV4NW9wQmVYRnpJZWhjOElJalkvSlUyR2xpaG5ybFBFbE1EUQoyUXVjelpqUTZuYWlrWVRrcU5zTk5NRitXdml0N0lIVVljejM2cEliK21KbSt4ZlNubFRaWVA2MGtsY2xDK3g2CmloVzVJUG5EcUxqS1F0OTFYWFVCRkczRFYrbHVoT1NzQXJuRHBWZzBreGdqd2MvRkxJMXNpY0JoWVMxWXpPWU0Kd08zWFh4ZFlUMlNJS3VaM0ZxMk5TSGQzSEUwamNIU2FIbXBjMWpONDRrTzRPRWJsdzhjMlJDT21WRkN6YXY3SApQQVVveG1JQUEyRHNNRTN2OHdwSGM2L0lFZkZTVVU3blFNbFVhTjN1QUpVeFpBVmh5YzhDQXdFQUFhTkdNRVF3ClFnWURWUjBSQkRzd09ZSUhZV1JoY0hSbGNvSUlaVzVtYjNKalpYS0NCbkp2ZFhSbGNvSUpiRzlqWVd4b2IzTjAKZ2hGdFlXNWhaMlZ0Wlc1MExYTmxjblpsY2pBTkJna3Foa2lHOXcwQkFRc0ZBQU9DQVFFQWNsY0NqWGppS3J1UwpyWUhNRjNDeDBPSmEwS2tlWkoxVkxFY0xseXAvTXp4VEdvdnk5MXR3NlhNVVFFbndqVkxLWUc5T3Q1MU9wc3pyCmdqQXBGSnE1QlZyblJsNHp0ajFsdHVMUmpyVzBlSnIrckNpbUFKdVI0ZUhMRTUrRU5uc2t1cGVNUXdyUG50dFMKdkVMUkZmMm1Zd3JqY2sxZFdNUGhsOGUyQmh4bDN3QXgwb1o0Z0k4d2dSSThndlVNYW0xd0hzeWR1NEpCYVRuWgpSM2FpOFpIU1Q2QlZHTUhBMFdUVTFpVWJyK0dDUkFjRE5kSkJpNHpCY0JzejREN09RdTBVK1dPbTBXWlNWNGZjCmNXdTE5K0pydk1KN0llWDNaaHFSdkdiblQzWVVSSFpoUGZsbGFoYWZTNlhMYzBzeExYMFV5RGJybkk2enZoRWMKb1NySFI0WGcwUT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K +{{- end -}} diff --git a/helm-charts/templates/control-plane/admin-ds/admin-ds-service.yaml b/helm-charts/templates/control-plane/admin-ds/admin-ds-service.yaml new file mode 100644 index 000000000..06cd106fa --- /dev/null +++ b/helm-charts/templates/control-plane/admin-ds/admin-ds-service.yaml @@ -0,0 +1,34 @@ +# Copyright (c) 2022, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. +# +# WSO2 LLC. licenses this file to you 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. + +{{- if .Values.wso2.apk.cp.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-service + namespace : {{ .Release.Namespace }} +spec: + # label keys and values that must match in order to receive traffic for this service + selector: +{{ include "apk-helm.pod.selectorLabels" (dict "root" . "app" "admin-ds" ) | indent 4}} + ports: + - name: servlet-https + protocol: TCP + port: 9443 + - name: internal-api-https + protocol: TCP + port: 9444 +{{- end -}} diff --git a/helm-charts/templates/control-plane/admin-ds/internal-domain-api-backend.yaml b/helm-charts/templates/control-plane/admin-ds/internal-domain-api-backend.yaml new file mode 100644 index 000000000..9ba0386ee --- /dev/null +++ b/helm-charts/templates/control-plane/admin-ds/internal-domain-api-backend.yaml @@ -0,0 +1,38 @@ +# Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. +# +# WSO2 LLC. licenses this file to you 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. +{{- if .Values.wso2.apk.cp.enabled }} +kind: "Backend" +apiVersion: "dp.wso2.com/v1alpha1" +metadata: + name: {{ template "apk-helm.resource.prefix" . }}-internal-admin-ds-backend + namespace: {{ .Release.Namespace }} +spec: + services: + - host: {{ template "apk-helm.resource.prefix" . }}-admin-ds-service.{{ .Release.Namespace }} + port: 9444 + protocol: "https" + tls: + allowedSANs: + - {{ template "apk-helm.resource.prefix" . }}-admin-ds-service.{{ .Release.Namespace }}.svc + secretRef: + {{- if and .Values.wso2.apk.cp.admin.configs .Values.wso2.apk.cp.admin.configs.tls }} + name: {{.Values.wso2.apk.cp.admin.configs.tls.secretName}} + key: {{.Values.wso2.apk.cp.admin.configs.tls.certFilename}} + {{- else }} + name: {{ template "apk-helm.resource.prefix" . }}-admin-ds-server-cert + key: tls.crt + {{- end }} +{{- end -}} diff --git a/helm-charts/templates/control-plane/admin-ds/internal-domain-api-httproute.yaml b/helm-charts/templates/control-plane/admin-ds/internal-domain-api-httproute.yaml new file mode 100644 index 000000000..a9f9f9b46 --- /dev/null +++ b/helm-charts/templates/control-plane/admin-ds/internal-domain-api-httproute.yaml @@ -0,0 +1,43 @@ +# Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. +# +# WSO2 LLC. licenses this file to you 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. +{{- if .Values.wso2.apk.cp.enabled }} +apiVersion: "gateway.networking.k8s.io/v1beta1" +kind: "HTTPRoute" +metadata: + name: {{ template "apk-helm.resource.prefix" . }}-internal-ds-httproute + namespace: {{ .Release.Namespace }} + labels: + api-name: "internal-domain-service" + api-version: "v1" +spec: + hostnames: + - "{{ .Values.wso2.apk.listener.hostname | default "api.am.wso2.com"}}" + rules: + - matches: + - path: + type: "PathPrefix" + value: "/api/internal/v1" + method: "GET" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-internal-admin-ds-backend + parentRefs: + - group: "gateway.networking.k8s.io" + kind: "Gateway" + name: "default" + sectionName: "httpslistener" +{{- end -}} diff --git a/helm-charts/templates/control-plane/admin-ds/internal-domain-api.yaml b/helm-charts/templates/control-plane/admin-ds/internal-domain-api.yaml new file mode 100644 index 000000000..9dd376585 --- /dev/null +++ b/helm-charts/templates/control-plane/admin-ds/internal-domain-api.yaml @@ -0,0 +1,35 @@ +# Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. +# +# WSO2 LLC. licenses this file to you 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. +{{- if .Values.wso2.apk.cp.enabled }} +kind: "API" +apiVersion: "dp.wso2.com/v1alpha1" +metadata: + name: {{ template "apk-helm.resource.prefix" . }}-internal-admin-ds-api + namespace: {{ .Release.Namespace }} + labels: + api-name: "internal-domain-service" + api-version: "v1" +spec: + apiName: "admin-domain-service" + apiType: "REST" + apiVersion: "v1" + basePath: "/api/internal/v1" + organization: "carbon.super" + production: + - httpRouteRefs: + - {{ template "apk-helm.resource.prefix" . }}-internal-ds-httproute + systemAPI: true +{{- end -}} diff --git a/helm-charts/templates/control-plane/backoffice-ds/backoffice-domain-api-backend.yaml b/helm-charts/templates/control-plane/backoffice-ds/backoffice-domain-api-backend.yaml new file mode 100644 index 000000000..553a45313 --- /dev/null +++ b/helm-charts/templates/control-plane/backoffice-ds/backoffice-domain-api-backend.yaml @@ -0,0 +1,38 @@ +# Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. +# +# WSO2 LLC. licenses this file to you 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. +{{- if .Values.wso2.apk.cp.enabled }} +kind: "Backend" +apiVersion: "dp.wso2.com/v1alpha1" +metadata: + name: {{ template "apk-helm.resource.prefix" . }}-backoffice-ds-backend + namespace: {{ .Release.Namespace }} +spec: + services: + - host: {{ template "apk-helm.resource.prefix" . }}-backoffice-ds-service.{{ .Release.Namespace }} + port: 9443 + protocol: "https" + tls: + allowedSANs: + - {{ template "apk-helm.resource.prefix" . }}-backoffice-ds-service.{{ .Release.Namespace }}.svc + secretRef: + {{- if and .Values.wso2.apk.cp.backoffice.configs .Values.wso2.apk.cp.backoffice.configs.tls }} + name: {{.Values.wso2.apk.cp.backoffice.configs.tls.secretName}} + key: {{.Values.wso2.apk.cp.backoffice.configs.tls.certFilename}} + {{- else }} + name: {{ template "apk-helm.resource.prefix" . }}-backoffice-ds-server-cert + key: tls.crt + {{- end }} +{{- end -}} diff --git a/helm-charts/templates/control-plane/backoffice-ds/backoffice-domain-api-httproute-1.yaml b/helm-charts/templates/control-plane/backoffice-ds/backoffice-domain-api-httproute-1.yaml new file mode 100644 index 000000000..80fad600a --- /dev/null +++ b/helm-charts/templates/control-plane/backoffice-ds/backoffice-domain-api-httproute-1.yaml @@ -0,0 +1,244 @@ +# Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. +# +# WSO2 LLC. licenses this file to you 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. +{{- if .Values.wso2.apk.cp.enabled }} +apiVersion: "gateway.networking.k8s.io/v1beta1" +kind: "HTTPRoute" +metadata: + name: {{ template "apk-helm.resource.prefix" . }}-backoffice-ds-httproute-1 + namespace: {{ .Release.Namespace }} + labels: + api-name: "backoffice-domain-service" + api-version: "1.0.0" +spec: + hostnames: + - "{{ .Values.wso2.apk.listener.hostname | default "api.am.wso2.com"}}" + rules: + - matches: + - path: + type: "RegularExpression" + value: "/api/backoffice/apis" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/backoffice/apis" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-backoffice-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/backoffice/apis/(.*)" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/backoffice/apis/\\1" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-backoffice-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/backoffice/apis/(.*)" + method: "PUT" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/backoffice/apis/\\1" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-backoffice-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/backoffice/apis/(.*)/definition" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/backoffice/apis/\\1/definition" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-backoffice-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/backoffice/apis/(.*)/resource-paths" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/backoffice/apis/\\1/resource-paths" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-backoffice-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/backoffice/apis/(.*)/thumbnail" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/backoffice/apis/\\1/thumbnail" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-backoffice-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/backoffice/apis/(.*)/thumbnail" + method: "PUT" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/backoffice/apis/\\1/thumbnail" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-backoffice-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/backoffice/apis/(.*)/documents" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/backoffice/apis/\\1/documents" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-backoffice-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/backoffice/apis/(.*)/documents" + method: "POST" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/backoffice/apis/\\1/documents" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-backoffice-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/backoffice/apis/(.*)/documents/(.*)" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/backoffice/apis/\\1/documents/\\2" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-backoffice-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/backoffice/apis/(.*)/documents/(.*)" + method: "PUT" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/backoffice/apis/\\1/documents/\\2" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-backoffice-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/backoffice/apis/(.*)/documents/(.*)" + method: "DELETE" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/backoffice/apis/\\1/documents/\\2" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-backoffice-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/backoffice/apis/(.*)/documents/(.*)/content" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/backoffice/apis/\\1/documents/\\2/content" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-backoffice-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/backoffice/apis/(.*)/documents/(.*)/content" + method: "POST" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/backoffice/apis/\\1/documents/\\2/content" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-backoffice-ds-backend + parentRefs: + - group: "gateway.networking.k8s.io" + kind: "Gateway" + name: "default" + sectionName: "httpslistener" +{{- end -}} diff --git a/helm-charts/templates/control-plane/backoffice-ds/backoffice-domain-api-httproute-2.yaml b/helm-charts/templates/control-plane/backoffice-ds/backoffice-domain-api-httproute-2.yaml new file mode 100644 index 000000000..6e15e4203 --- /dev/null +++ b/helm-charts/templates/control-plane/backoffice-ds/backoffice-domain-api-httproute-2.yaml @@ -0,0 +1,124 @@ +# Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. +# +# WSO2 LLC. licenses this file to you 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. +{{- if .Values.wso2.apk.cp.enabled }} +apiVersion: "gateway.networking.k8s.io/v1beta1" +kind: "HTTPRoute" +metadata: + name: {{ template "apk-helm.resource.prefix" . }}-backoffice-ds-httproute-2 + namespace: {{ .Release.Namespace }} + labels: + api-name: "backoffice-domain-service" + api-version: "1.0.0" +spec: + hostnames: + - "{{ .Values.wso2.apk.listener.hostname | default "api.am.wso2.com"}}" + rules: + - matches: + - path: + type: "RegularExpression" + value: "/api/backoffice/apis/(.*)/comments" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/backoffice/apis/\\1/comments" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-backoffice-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/backoffice/apis/(.*)/comments" + method: "POST" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/backoffice/apis/\\1/comments" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-backoffice-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/backoffice/apis/(.*)/comments/(.*)" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/backoffice/apis/\\1/comments/\\2" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-backoffice-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/backoffice/apis/(.*)/comments/(.*)" + method: "DELETE" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/backoffice/apis/\\1/comments/\\2" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-backoffice-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/backoffice/apis/(.*)/comments/(.*)" + method: "PATCH" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/backoffice/apis/\\1/comments/\\2" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-backoffice-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/backoffice/apis/(.*)/comments/(.*)/replies" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/backoffice/apis/\\1/comments/\\2/replies" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-backoffice-ds-backend + parentRefs: + - group: "gateway.networking.k8s.io" + kind: "Gateway" + name: "default" + sectionName: "httpslistener" +{{- end -}} diff --git a/helm-charts/templates/control-plane/backoffice-ds/backoffice-domain-api-httproute-3.yaml b/helm-charts/templates/control-plane/backoffice-ds/backoffice-domain-api-httproute-3.yaml new file mode 100644 index 000000000..27b1e8974 --- /dev/null +++ b/helm-charts/templates/control-plane/backoffice-ds/backoffice-domain-api-httproute-3.yaml @@ -0,0 +1,199 @@ +# Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. +# +# WSO2 LLC. licenses this file to you 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. +{{- if .Values.wso2.apk.cp.enabled }} +apiVersion: "gateway.networking.k8s.io/v1beta1" +kind: "HTTPRoute" +metadata: + name: {{ template "apk-helm.resource.prefix" . }}-backoffice-ds-httproute-3 + namespace: {{ .Release.Namespace }} + labels: + api-name: "backoffice-domain-service" + api-version: "1.0.0" +spec: + hostnames: + - "{{ .Values.wso2.apk.listener.hostname | default "api.am.wso2.com"}}" + rules: + - matches: + - path: + type: "RegularExpression" + value: "/api/backoffice/subscriptions" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/backoffice/subscriptions" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-backoffice-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/backoffice/subscriptions/(.*)/subscriber-info" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/backoffice/subscriptions/\\1/subscriber-info" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-backoffice-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/backoffice/subscriptions/block-subscription" + method: "POST" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/backoffice/subscriptions/block-subscription" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-backoffice-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/backoffice/subscriptions/unblock-subscription" + method: "POST" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/backoffice/subscriptions/unblock-subscription" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-backoffice-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/backoffice/usage-plans" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/backoffice/usage-plans" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-backoffice-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/backoffice/search" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/backoffice/search" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-backoffice-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/backoffice/settings" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/backoffice/settings" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-backoffice-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/backoffice/api-categories" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/backoffice/api-categories" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-backoffice-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/backoffice/apis/change-lifecycle" + method: "POST" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/backoffice/apis/change-lifecycle" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-backoffice-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/backoffice/apis/(.*)/lifecycle-history" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/backoffice/apis/\\1/lifecycle-history" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-backoffice-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/backoffice/apis/(.*)/lifecycle-state" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/backoffice/apis/\\1/lifecycle-state" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-backoffice-ds-backend + parentRefs: + - group: "gateway.networking.k8s.io" + kind: "Gateway" + name: "default" + sectionName: "httpslistener" +{{- end -}} diff --git a/helm-charts/templates/control-plane/backoffice-ds/backoffice-domain-api-policy.yaml b/helm-charts/templates/control-plane/backoffice-ds/backoffice-domain-api-policy.yaml new file mode 100644 index 000000000..c9c09fff5 --- /dev/null +++ b/helm-charts/templates/control-plane/backoffice-ds/backoffice-domain-api-policy.yaml @@ -0,0 +1,37 @@ +# Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. +# +# WSO2 LLC. licenses this file to you 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. +{{- if .Values.wso2.apk.dp.enabled }} +kind: "APIPolicy" +apiVersion: "dp.wso2.com/v1alpha1" +metadata: + name: {{ template "apk-helm.resource.prefix" . }}-backoffice-ds-api-policy + namespace: {{ .Release.Namespace }} +spec: + override: + backendJwtToken: + enabled: true + encoding: "base64" + signingAlgorithm: "SHA256withRSA" + header: "X-JWT-Assertion" + tokenTTL: 3600 + customClaims: + - claim: "admin" + value: "http://wso2.org/claims/enduser" + targetRef: + group: "gateway.networking.k8s.io" + kind: "API" + name: {{ template "apk-helm.resource.prefix" . }}-backoffice-ds-api +{{- end -}} diff --git a/helm-charts/templates/control-plane/backoffice-ds/backoffice-domain-api.yaml b/helm-charts/templates/control-plane/backoffice-ds/backoffice-domain-api.yaml new file mode 100644 index 000000000..431aae707 --- /dev/null +++ b/helm-charts/templates/control-plane/backoffice-ds/backoffice-domain-api.yaml @@ -0,0 +1,38 @@ +# Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. +# +# WSO2 LLC. licenses this file to you 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. + +{{- if .Values.wso2.apk.cp.enabled }} +kind: "API" +apiVersion: "dp.wso2.com/v1alpha1" +metadata: + name: {{ template "apk-helm.resource.prefix" . }}-backoffice-ds-api + namespace: {{ .Release.Namespace }} + labels: + api-name: "backoffice-domain-service" + api-version: "1.0.0" +spec: + apiName: "Backoffice Domain API" + apiType: "REST" + apiVersion: "1.0.0" + basePath: "/api/backoffice/1.0.0" + organization: "carbon.super" + production: + - httpRouteRefs: + - {{ template "apk-helm.resource.prefix" . }}-backoffice-ds-httproute-1 + - {{ template "apk-helm.resource.prefix" . }}-backoffice-ds-httproute-2 + - {{ template "apk-helm.resource.prefix" . }}-backoffice-ds-httproute-3 + systemAPI: true +{{- end -}} diff --git a/helm-charts/templates/control-plane/backoffice-ds/backoffice-ds-configmap.yaml b/helm-charts/templates/control-plane/backoffice-ds/backoffice-ds-configmap.yaml new file mode 100644 index 000000000..c61eba7c5 --- /dev/null +++ b/helm-charts/templates/control-plane/backoffice-ds/backoffice-ds-configmap.yaml @@ -0,0 +1,51 @@ +# Copyright (c) 2022, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. +# +# WSO2 LLC. licenses this file to you 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. + +{{- if .Values.wso2.apk.cp.enabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "apk-helm.resource.prefix" . }}-backoffice-ds-configmap + namespace: {{ .Release.Namespace }} +data: + Config.toml: | + # Sample configurations + [wso2.backoffice_service.datasourceConfiguration] + description = "Database for backoffice" + url = "{{ .Values.wso2.apk.cp.database.url }}" + host = "{{ .Values.wso2.apk.cp.database.host }}" + port = {{ .Values.wso2.apk.cp.database.port }} + databaseName = "{{ .Values.wso2.apk.cp.database.databaseName }}" + username = "{{ .Values.wso2.apk.cp.database.username }}" + validationTimeout = {{ .Values.wso2.apk.cp.database.validationTimeout }} + testQuery = "{{ .Values.wso2.apk.cp.database.validationQuery }}" + driver = "{{ .Values.wso2.apk.cp.database.driver }}" + [wso2.backoffice_service.idpConfiguration] + organizationClaim = "{{ .Values.wso2.apk.idp.organizationClaim }}" + userClaim = "{{ .Values.wso2.apk.idp.usernameClaim }}" + [wso2.backoffice_service.idpConfiguration.publicKey] + certFilePath = "/home/wso2apk/backoffice/security/mg.pem" + [wso2.backoffice_service.keyStores.tls] + keyFilePath = "/home/wso2apk/backoffice/security/backoffice.key" + certFilePath = "/home/wso2apk/backoffice/security/backoffice.pem" + [wso2.backoffice_service.k8sConfig] + host = "kubernetes.default" + serviceAccountPath = "/var/run/secrets/kubernetes.io/serviceaccount" + [wso2.backoffice_service.managementServerConfig] + serviceName = "{{ template "apk-helm.resource.prefix" . }}-management-server" + namespace = "{{ .Release.Namespace }}" + certPath = "/home/wso2apk/backoffice/security/truststore/management-server.pem" +{{- end -}} diff --git a/helm-charts/templates/control-plane/backoffice-ds/backoffice-ds-deployment.yaml b/helm-charts/templates/control-plane/backoffice-ds/backoffice-ds-deployment.yaml new file mode 100644 index 000000000..c9e08e1f2 --- /dev/null +++ b/helm-charts/templates/control-plane/backoffice-ds/backoffice-ds-deployment.yaml @@ -0,0 +1,129 @@ +# Copyright (c) 2022, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. +# +# WSO2 LLC. licenses this file to you 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. + +{{- if .Values.wso2.apk.cp.enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "apk-helm.resource.prefix" . }}-backoffice-ds-deployment + namespace: {{ .Release.Namespace }} +spec: + replicas: {{ .Values.wso2.apk.cp.backoffice.deployment.replicas }} + strategy: + type: {{ .Values.wso2.apk.cp.backoffice.deployment.strategy }} + selector: + matchLabels: +{{ include "apk-helm.pod.selectorLabels" (dict "root" . "app" "backoffice-ds" ) | indent 6}} + template: + metadata: + labels: +{{ include "apk-helm.pod.selectorLabels" (dict "root" . "app" "backoffice-ds" ) | indent 8}} + spec: + serviceAccountName: {{ .Values.wso2.apk.auth.serviceAccountName }} + initContainers: + - name: init-db + image: busybox:1.32 + command: ['sh', '-c', 'echo -e "Checking for the availability of DB Server deployment"; while ! nc -z "{{ .Values.wso2.apk.cp.database.host }}" {{.Values.wso2.apk.cp.database.port }}; do sleep 1; printf "-"; done; echo -e " >> DB Server has started";'] + containers: + - name: backoffice-ds + image: {{ .Values.wso2.apk.cp.backoffice.deployment.image }} + imagePullPolicy: {{ .Values.wso2.apk.cp.backoffice.deployment.imagePullPolicy }} + ports: + - containerPort: 9443 + protocol: "TCP" + - containerPort: 9444 + protocol: "TCP" + readinessProbe: + httpGet: + path: /health + port: 9443 + scheme: HTTPS + initialDelaySeconds: {{ .Values.wso2.apk.cp.backoffice.deployment.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.wso2.apk.cp.backoffice.deployment.readinessProbe.periodSeconds }} + livenessProbe: + httpGet: + path: /health + port: 9443 + scheme: HTTPS + initialDelaySeconds: {{ .Values.wso2.apk.cp.backoffice.deployment.livenessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.wso2.apk.cp.backoffice.deployment.livenessProbe.periodSeconds }} +{{ include "apk-helm.deployment.resources" .Values.wso2.apk.cp.backoffice.deployment.resources | indent 10 }} + volumeMounts: + - mountPath: /home/wso2apk/backoffice/conf/Config.toml + name: config-toml-volume + subPath: Config.toml + - mountPath: /home/wso2apk/backoffice/security/mg.pem + name: backoffice-ds-jwt-validation-key-volume + subPath: mg.pem + - name: backoffice-ds-tls-volume + mountPath: /home/wso2apk/backoffice/security/backoffice.key + {{- if and .Values.wso2.apk.cp.backoffice.configs .Values.wso2.apk.cp.backoffice.configs.tls }} + subPath: {{ .Values.wso2.apk.cp.backoffice.configs.tls.certKeyFilename | default "tls.key" }} + {{- else }} + subPath: tls.key + {{- end }} + - name: backoffice-ds-tls-volume + mountPath: /home/wso2apk/backoffice/security/backoffice.pem + {{- if and .Values.wso2.apk.cp.backoffice.configs .Values.wso2.apk.cp.backoffice.configs.tls }} + subPath: {{ .Values.wso2.apk.cp.backoffice.configs.tls.certFilename | default "tls.crt" }} + {{- else }} + subPath: tls.crt + {{- end }} + - name: management-server-tls-volume + mountPath: /home/wso2apk/backoffice/security/truststore/management-server.pem + {{- if and .Values.wso2.apk.cp.managementServer.configs .Values.wso2.apk.cp.managementServer.configs.tls }} + subPath: {{ .Values.wso2.apk.cp.managementServer.configs.tls.certFilename | default "tls.crt" }} + {{- else }} + subPath: tls.crt + {{- end }} + env: + - name: DB_PASSWORD + valueFrom: + secretKeyRef: + {{ if and .Values.wso2.apk.cp.database .Values.wso2.apk.cp.database.secretName }} + name: "{{ .Values.wso2.apk.cp.database.secretName}}" + key: "{{ .Values.wso2.apk.cp.database.secretKey}}" + {{ else }} + name: "apk-db-secret" + key: "DB_PASSWORD" + {{ end }} + {{- if and .Values.wso2.subscription .Values.wso2.subscription.imagePullSecrets}} + imagePullSecrets: + - name: {{ .Values.wso2.subscription.imagePullSecrets }} + {{ end }} + + volumes: + - name: backoffice-ds-jwt-validation-key-volume + secret: + secretName: {{ template "apk-helm.resource.prefix" . }}-backoffice-ds-jwt-validaion-secret + - name: config-toml-volume + configMap: + name: {{ template "apk-helm.resource.prefix" . }}-backoffice-ds-configmap + - name: backoffice-ds-tls-volume + secret: + {{ if and .Values.wso2.apk.cp.backoffice.configs .Values.wso2.apk.cp.backoffice.configs.tls }} + secretName: {{ .Values.wso2.apk.cp.backoffice.configs.tls.secretName | default (printf "%s-backoffice-ds-server-cert" (include "apk-helm.resource.prefix" .)) }} + {{ else }} + secretName: {{ template "apk-helm.resource.prefix" . }}-backoffice-ds-server-cert + {{ end }} + - name: management-server-tls-volume + secret: + {{- if and .Values.wso2.apk.cp.managementServer.configs .Values.wso2.apk.cp.managementServer.configs.tls }} + secretName: {{ .Values.wso2.apk.cp.managementServer.configs.tls.secretName | default (printf "%s-management-server-cert" (include "apk-helm.resource.prefix" .)) }} + {{- else }} + secretName: {{ template "apk-helm.resource.prefix" . }}-management-server-cert + {{- end }} +{{- end -}} diff --git a/helm-charts/templates/control-plane/backoffice-ds/backoffice-ds-jwt-validation-secret.yaml b/helm-charts/templates/control-plane/backoffice-ds/backoffice-ds-jwt-validation-secret.yaml new file mode 100644 index 000000000..edb367105 --- /dev/null +++ b/helm-charts/templates/control-plane/backoffice-ds/backoffice-ds-jwt-validation-secret.yaml @@ -0,0 +1,10 @@ +{{- if .Values.wso2.apk.cp.enabled }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ template "apk-helm.resource.prefix" . }}-backoffice-ds-jwt-validaion-secret + namespace: {{ .Release.Namespace }} +type: Opaque +data: + mg.pem: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURrekNDQW51Z0F3SUJBZ0lKQVBEOGVTM2VtY3JRTUEwR0NTcUdTSWIzRFFFQkN3VUFNR1F4Q3pBSkJnTlYKQkFZVEFsVlRNUXN3Q1FZRFZRUUlEQUpEUVRFV01CUUdBMVVFQnd3TlRXOTFiblJoYVc0Z1ZtbGxkekVOTUFzRwpBMVVFQ2d3RVYxTlBNakVOTUFzR0ExVUVDd3dFVjFOUE1qRVNNQkFHQTFVRUF3d0piRzlqWVd4b2IzTjBNQ0FYCkRUSXlNVEV4TnpFNE1EWXpPRm9ZRHpJd05USXhNVEE1TVRnd05qTTRXakJrTVFzd0NRWURWUVFHRXdKVlV6RUwKTUFrR0ExVUVDQXdDUTBFeEZqQVVCZ05WQkFjTURVMXZkVzUwWVdsdUlGWnBaWGN4RFRBTEJnTlZCQW9NQkZkVApUekl4RFRBTEJnTlZCQXNNQkZkVFR6SXhFakFRQmdOVkJBTU1DV3h2WTJGc2FHOXpkRENDQVNJd0RRWUpLb1pJCmh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTjlaRUQyb1JDbTljZjF2RUV2UjFKL1R3TGFrSmNQeVN2UDIKT1p1Y3hiVlBDeVhvbnlsZEtJbUVoSjZMZnVNcnV4NW9wQmVYRnpJZWhjOElJalkvSlUyR2xpaG5ybFBFbE1EUQoyUXVjelpqUTZuYWlrWVRrcU5zTk5NRitXdml0N0lIVVljejM2cEliK21KbSt4ZlNubFRaWVA2MGtsY2xDK3g2CmloVzVJUG5EcUxqS1F0OTFYWFVCRkczRFYrbHVoT1NzQXJuRHBWZzBreGdqd2MvRkxJMXNpY0JoWVMxWXpPWU0Kd08zWFh4ZFlUMlNJS3VaM0ZxMk5TSGQzSEUwamNIU2FIbXBjMWpONDRrTzRPRWJsdzhjMlJDT21WRkN6YXY3SApQQVVveG1JQUEyRHNNRTN2OHdwSGM2L0lFZkZTVVU3blFNbFVhTjN1QUpVeFpBVmh5YzhDQXdFQUFhTkdNRVF3ClFnWURWUjBSQkRzd09ZSUhZV1JoY0hSbGNvSUlaVzVtYjNKalpYS0NCbkp2ZFhSbGNvSUpiRzlqWVd4b2IzTjAKZ2hGdFlXNWhaMlZ0Wlc1MExYTmxjblpsY2pBTkJna3Foa2lHOXcwQkFRc0ZBQU9DQVFFQWNsY0NqWGppS3J1UwpyWUhNRjNDeDBPSmEwS2tlWkoxVkxFY0xseXAvTXp4VEdvdnk5MXR3NlhNVVFFbndqVkxLWUc5T3Q1MU9wc3pyCmdqQXBGSnE1QlZyblJsNHp0ajFsdHVMUmpyVzBlSnIrckNpbUFKdVI0ZUhMRTUrRU5uc2t1cGVNUXdyUG50dFMKdkVMUkZmMm1Zd3JqY2sxZFdNUGhsOGUyQmh4bDN3QXgwb1o0Z0k4d2dSSThndlVNYW0xd0hzeWR1NEpCYVRuWgpSM2FpOFpIU1Q2QlZHTUhBMFdUVTFpVWJyK0dDUkFjRE5kSkJpNHpCY0JzejREN09RdTBVK1dPbTBXWlNWNGZjCmNXdTE5K0pydk1KN0llWDNaaHFSdkdiblQzWVVSSFpoUGZsbGFoYWZTNlhMYzBzeExYMFV5RGJybkk2enZoRWMKb1NySFI0WGcwUT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K +{{- end -}} diff --git a/helm-charts/templates/control-plane/backoffice-ds/backoffice-ds-service.yaml b/helm-charts/templates/control-plane/backoffice-ds/backoffice-ds-service.yaml new file mode 100644 index 000000000..501f8d917 --- /dev/null +++ b/helm-charts/templates/control-plane/backoffice-ds/backoffice-ds-service.yaml @@ -0,0 +1,35 @@ +# Copyright (c) 2022, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. +# +# WSO2 LLC. licenses this file to you 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. + +{{- if .Values.wso2.apk.cp.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "apk-helm.resource.prefix" . }}-backoffice-ds-service + namespace : {{ .Release.Namespace }} +spec: + # label keys and values that must match in order to receive traffic for this service + selector: +{{ include "apk-helm.pod.selectorLabels" (dict "root" . "app" "backoffice-ds" ) | indent 4}} + ports: + # ports that this service should serve on + - name: backoffice-https + protocol: TCP + port: 9443 + - name: backoffice-internal-https + protocol: TCP + port: 9444 +{{- end -}} diff --git a/helm-charts/templates/control-plane/devportal-ds/apikey-signing-keystore-secret.yaml b/helm-charts/templates/control-plane/devportal-ds/apikey-signing-keystore-secret.yaml new file mode 100644 index 000000000..e758138ce --- /dev/null +++ b/helm-charts/templates/control-plane/devportal-ds/apikey-signing-keystore-secret.yaml @@ -0,0 +1,10 @@ +{{- if .Values.wso2.apk.cp.enabled }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ template "apk-helm.resource.prefix" . }}-apikey-signing-keystore-secret + namespace: {{ .Release.Namespace }} +type: Opaque +data: + wso2carbon.key: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFb2dJQkFBS0NBUUVBa2RnbmNvQ3J6NjU1THE4cFRkWDA3ZW9WQmpkWkRDVUU2dWVCZDBEMWhwSjAvekUzCngzQXo2dGx2enM5OFBzUHVHemFRT01tdUxhNHF4TkorT0t4Sm11dERVbENscHV2eHVmK2p5cTRnQ1Y1dEVJSUwKV1JNQmpsQkVwSmZXbTYzK1ZLS1U0bnZCV05KN0tmaFdqbDgrRFVkTlNoMnBDRExwVU9ibWI5S3F1cWMxeDRCZwp0dGpONHJ4L1ArMy92KzFqRVRYeklQMUw0NHlIdHBRTnYwa2hZZjRqL2FIamNFcmk5eWt2cHoxbXRkYWNicktLCjI1TjRWMUhIUndEcVppSnpPQ0NJU1hEdXFCNndndVkvdjRuMGwxWHRyRXM3aUN5ZlJGd05TS05yTHFyMjN0UjEKQ3NjbUxmYkg2WkxnNUNZSlREKzF1UFN4MEhNT0I0V3Y1MVBiV3dJREFRQUJBb0lCQUFlRnd3QnpSZWxsWjJ5OQpXTlVNbkhYZnVyYU5DUFBKRTdMYmFXQnhvazI1cE5LUTJGUUV6bzRRMUdVeUZkelZsYVRPVzFhdExic1V5UWRKCk90SWVMaXhtY1hJcWVoRGRDZnA5QnNGcWhTUFdrZ0RscEVPSTZSaWlaKzFSYmtsWXRTTS93T0dFWHBtcWxFaGwKa3hsWmdrV0VaYWFBQWRCTUhVcXdvNHdsclVGZXBlN0xGSHdIV3paOGRjUlpuaUhwVURiSVd0VkVwKzJMZzFhOQpBdS9reEZTUklJK0Z6WU1RRExIVDh0WWRiajVXbjN4Sms0Tk01c09JRm5iZ2FNbHhwRXFlNWVjYzY0NHZ4NHRrCkVEYVdFOExidmNCZ2NSb2thR2daS05TVmRHM1JQdWFjWDhGUG9IeGdrbHEvMldENzlxUGRZdUdmRFQxWEhCUXEKeFRqb2R0a0NnWUVBeDhCcDJpOGh4Zmc3ekQxZDAzTmFZekFad3loZnVMNmhvQXhHUGdMVzQvVktNOEtHSnU3UQo2QnZrZUpkVkY4UzlvZlQ5RHRRUUFMS3FTN3NValBDdFdxK3FSeUR0S2VTM3lzRmxvUlRHZ1VnU3ZmNFpKMDByCkQyU28xTjhwUWtNcmNud2lPTnpzaWZtVE9ZWHpQQ0oyeXlnVk1kZGxQb3BCL21EN2ZLMmhUTGNDZ1lFQXV1bXoKODZCdzRuYzg1bGgyL2xDYTBORXdRcUU3Nm5rekNUaUhGdTU2SmswUUMxZ2pBUWRBc2J2WFloeHUrOGUxR2R4Twp1eVlhYkFYN042c0NJQzFuVlNZL2lVZWFnMnh2b0lZVkZiZ2xaWFNjWUxpQmZGNVZtOEF0aUlGdi9Fc0ZZZW03CkswT2l5U09GZ1NtRmlCRVRrTnFUNExwcGNYbzM2OGgwTzhnL3luMENnWUFwRjVJdkNrY2VYTVNnYlhkaHluY3IKdEhkNFNGUDR3MjZvYUI0REg3NXBRc3F5L3k5dHp1ODI4Slg5b05RbWdaaXBPcWJjYUErcXRSYUhZY01HZzNTRwpGV0VvSk1QbFBHSDYyZkk0UXZmYkhLS09aemx4ZGxTSFpDTy9OdkZiNmttRDBibVFqUkkwQ0IyYlZjMEY3K2tVClBmaXVPaXRmeEQxelFTdzdKOVRvM1FLQmdGbTR3MFBvT1NmTWV2UkxkTnRCRC8rNjJzS3hLTlMxMXhUUENMR3UKU2Y1R3NiUHdXK1VyZVJlWUJweTI3Mk4zQ3V6ZC93RUJHbC9PUXpnR281K1VpK3lvem9qMFVTeFRDZ1p4Tm4vVgpoRVgrUXU1K3d0RlRheDYza21QYlZra3lMZVJCVVRKRVprak0vMUh2LzRSQVJqY2JaUzdUN0xlbkpsN05PMVpUCkdxUDFBb0dBWUF3cmk0NEN1YzZieTFiRTY1TFpVZm4rZytTRCtib2M5N1doL0NCMzZlMm5zZ1pSVzBMTVluNysKenlRcU1kS1lUQ1kxVW1wZVRMSW4zQmp6Y1d0d0lVS0ZGc1NoSHVNNHNIL1kycWcwNGN0SHgyU2ZNMEpFRDg3Mgp3c1FGbXZKNkxwZGNwSElLTjU1SzdGTVdYQlZoN0FpNnI0SnB4Rkdlb3dJN3E5clJrbk09Ci0tLS0tRU5EIFJTQSBQUklWQVRFIEtFWS0tLS0tCg== +{{- end -}} diff --git a/helm-charts/templates/control-plane/devportal-ds/devportal-domain-api-backend.yaml b/helm-charts/templates/control-plane/devportal-ds/devportal-domain-api-backend.yaml new file mode 100644 index 000000000..ee1cc538f --- /dev/null +++ b/helm-charts/templates/control-plane/devportal-ds/devportal-domain-api-backend.yaml @@ -0,0 +1,38 @@ +# Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. +# +# WSO2 LLC. licenses this file to you 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. +{{- if .Values.wso2.apk.cp.enabled }} +kind: "Backend" +apiVersion: "dp.wso2.com/v1alpha1" +metadata: + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + namespace: {{ .Release.Namespace }} +spec: + services: + - host: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-service.{{ .Release.Namespace }} + port: 9443 + protocol: "https" + tls: + allowedSANs: + - {{ template "apk-helm.resource.prefix" . }}-devportal-ds-service.{{ .Release.Namespace }}.svc + secretRef: + {{- if and .Values.wso2.apk.cp.devportal.configs .Values.wso2.apk.cp.devportal.configs.tls }} + name: {{.Values.wso2.apk.cp.devportal.configs.tls.secretName}} + key: {{.Values.wso2.apk.cp.devportal.configs.tls.certFilename}} + {{- else }} + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-server-cert + key: tls.crt + {{- end }} +{{- end -}} diff --git a/helm-charts/templates/control-plane/devportal-ds/devportal-domain-api-httproute-1.yaml b/helm-charts/templates/control-plane/devportal-ds/devportal-domain-api-httproute-1.yaml new file mode 100644 index 000000000..b6df5ced3 --- /dev/null +++ b/helm-charts/templates/control-plane/devportal-ds/devportal-domain-api-httproute-1.yaml @@ -0,0 +1,214 @@ +# Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. +# +# WSO2 LLC. licenses this file to you 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. +{{- if .Values.wso2.apk.cp.enabled }} +apiVersion: "gateway.networking.k8s.io/v1beta1" +kind: "HTTPRoute" +metadata: + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-httproute-1 + namespace: {{ .Release.Namespace }} + labels: + api-name: "devportal-domain-service" + api-version: "1.0.0" +spec: + hostnames: + - "{{ .Values.wso2.apk.listener.hostname | default "api.am.wso2.com"}}" + rules: + - matches: + - path: + type: "RegularExpression" + value: "/api/devportal/apis" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/devportal/apis" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/devportal/apis/(.*)" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/devportal/apis/\\1" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/devportal/apis/(.*)/definition" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/devportal/apis/\\1/definition" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/devportal/apis/(.*)/sdks/(.*)" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/devportal/apis/\\1/sdks/\\2" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/devportal/apis/(.*)/documents" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/devportal/apis/\\1/documents" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/devportal/apis/(.*)/documents/(.*)" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/devportal/apis/\\1/documents/\\2" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/devportal/apis/(.*)/documents/(.*)/content" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/devportal/apis/\\1/documents/\\2/content" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/devportal/apis/(.*)/thumbnail" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/devportal/apis/\\1/thumbnail" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/devportal/apis/(.*)/ratings" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/devportal/apis/\\1/ratings" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/devportal/apis/(.*)/user-rating" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/devportal/apis/\\1/user-rating" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/devportal/apis/(.*)/user-rating" + method: "PUT" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/devportal/apis/\\1/user-rating" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/devportal/apis/(.*)/user-rating" + method: "DELETE" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/devportal/apis/\\1/user-rating" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + parentRefs: + - group: "gateway.networking.k8s.io" + kind: "Gateway" + name: "default" + sectionName: "httpslistener" +{{- end -}} diff --git a/helm-charts/templates/control-plane/devportal-ds/devportal-domain-api-httproute-2.yaml b/helm-charts/templates/control-plane/devportal-ds/devportal-domain-api-httproute-2.yaml new file mode 100644 index 000000000..6c2b054cf --- /dev/null +++ b/helm-charts/templates/control-plane/devportal-ds/devportal-domain-api-httproute-2.yaml @@ -0,0 +1,259 @@ +# Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. +# +# WSO2 LLC. licenses this file to you 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. +{{- if .Values.wso2.apk.cp.enabled }} +apiVersion: "gateway.networking.k8s.io/v1beta1" +kind: "HTTPRoute" +metadata: + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-httproute-2 + namespace: {{ .Release.Namespace }} + labels: + api-name: "devportal-domain-service" + api-version: "1.0.0" +spec: + hostnames: + - "{{ .Values.wso2.apk.listener.hostname | default "api.am.wso2.com"}}" + rules: + - matches: + - path: + type: "RegularExpression" + value: "/api/devportal/apis/(.*)/comments" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/devportal/apis/\\1/comments" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/devportal/apis/(.*)/comments" + method: "POST" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/devportal/apis/\\1/comments" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/devportal/apis/(.*)/comments/(.*)" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/devportal/apis/\\1/comments/\\2" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/devportal/apis/(.*)/comments/(.*)" + method: "DELETE" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/devportal/apis/\\1/comments/\\2" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/devportal/apis/(.*)/comments/(.*)" + method: "PATCH" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/devportal/apis/\\1/comments/\\2" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/devportal/apis/(.*)/comments/(.*)/replies" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/devportal/apis/\\1/comments/\\2/replies" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/devportal/apis/(.*)/topics" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/devportal/apis/\\1/topics" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/devportal/apis/(.*)/subscription-policies" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/devportal/apis/\\1/subscription-policies" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/devportal/tenants" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/devportal/tenants" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/devportal/recommendations" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/devportal/recommendations" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/devportal/api-categories" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/devportal/api-categories" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/devportal/key-managers" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/devportal/key-managers" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/devportal/apis/(.*)/graphql-policies/complexity" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/devportal/apis/\\1/graphql-policies/complexity" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/devportal/apis/(.*)/graphql-policies/complexity/types" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/devportal/apis/\\1/graphql-policies/complexity/types" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/devportal/me/change-password" + method: "POST" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/devportal/me/change-password" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + parentRefs: + - group: "gateway.networking.k8s.io" + kind: "Gateway" + name: "default" + sectionName: "httpslistener" +{{- end -}} diff --git a/helm-charts/templates/control-plane/devportal-ds/devportal-domain-api-httproute-3.yaml b/helm-charts/templates/control-plane/devportal-ds/devportal-domain-api-httproute-3.yaml new file mode 100644 index 000000000..b3c6520a9 --- /dev/null +++ b/helm-charts/templates/control-plane/devportal-ds/devportal-domain-api-httproute-3.yaml @@ -0,0 +1,229 @@ +# Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. +# +# WSO2 LLC. licenses this file to you 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. +{{- if .Values.wso2.apk.cp.enabled }} +apiVersion: "gateway.networking.k8s.io/v1beta1" +kind: "HTTPRoute" +metadata: + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-httproute-3 + namespace: {{ .Release.Namespace }} + labels: + api-name: "devportal-domain-service" + api-version: "1.0.0" +spec: + hostnames: + - "{{ .Values.wso2.apk.listener.hostname | default "api.am.wso2.com"}}" + rules: + - matches: + - path: + type: "RegularExpression" + value: "/api/devportal/applications" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/devportal/applications" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/devportal/applications" + method: "POST" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/devportal/applications" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/devportal/applications/(.*)" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/devportal/applications/\\1" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/devportal/applications/(.*)" + method: "PUT" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/devportal/applications/\\1" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/devportal/applications/(.*)" + method: "DELETE" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/devportal/applications/\\1" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/devportal/applications/(.*)/generate-keys" + method: "POST" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/devportal/applications/\\1/generate-keys" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/devportal/applications/(.*)/map-keys" + method: "POST" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/devportal/applications/\\1/map-keys" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/devportal/applications/(.*)/keys" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/devportal/applications/\\1/keys" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/devportal/applications/(.*)/keys/(.*)" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/devportal/applications/\\1/keys/\\2" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/devportal/applications/(.*)/keys/(.*)" + method: "PUT" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/devportal/applications/\\1/keys/\\2" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/devportal/applications/(.*)/keys/(.*)/regenerate-secret" + method: "POST" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/devportal/applications/\\1/keys/\\2/regenerate-secret" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/devportal/applications/(.*)/keys/(.*)/clean-up" + method: "POST" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/devportal/applications/\\1/keys/\\2/clean-up" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/devportal/applications/(.*)/keys/(.*)/generate-token" + method: "POST" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/devportal/applications/\\1/keys/\\2/generate-token" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + parentRefs: + - group: "gateway.networking.k8s.io" + kind: "Gateway" + name: "default" + sectionName: "httpslistener" +{{- end -}} diff --git a/helm-charts/templates/control-plane/devportal-ds/devportal-domain-api-httproute-4.yaml b/helm-charts/templates/control-plane/devportal-ds/devportal-domain-api-httproute-4.yaml new file mode 100644 index 000000000..581e50e63 --- /dev/null +++ b/helm-charts/templates/control-plane/devportal-ds/devportal-domain-api-httproute-4.yaml @@ -0,0 +1,184 @@ +# Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. +# +# WSO2 LLC. licenses this file to you 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. +{{- if .Values.wso2.apk.cp.enabled }} +apiVersion: "gateway.networking.k8s.io/v1beta1" +kind: "HTTPRoute" +metadata: + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-httproute-4 + namespace: {{ .Release.Namespace }} + labels: + api-name: "devportal-domain-service" + api-version: "1.0.0" +spec: + hostnames: + - "{{ .Values.wso2.apk.listener.hostname | default "api.am.wso2.com"}}" + rules: + - matches: + - path: + type: "RegularExpression" + value: "/api/devportal/applications/(.*)/oauth-keys" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/devportal/applications/\\1/oauth-keys" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/devportal/applications/(.*)/oauth-keys/(.*)" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/devportal/applications/\\1/oauth-keys/\\2" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/devportal/applications/(.*)/oauth-keys/(.*)" + method: "PUT" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/devportal/applications/\\1/oauth-keys/\\2" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/devportal/applications/(.*)/oauth-keys/(.*)/regenerate-secret" + method: "POST" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/devportal/applications/\\1/oauth-keys/\\2/regenerate-secret" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/devportal/applications/(.*)/oauth-keys/(.*)/clean-up" + method: "POST" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/devportal/applications/\\1/oauth-keys/\\2/clean-up" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/devportal/applications/(.*)/oauth-keys/(.*)/generate-token" + method: "POST" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/devportal/applications/\\1/oauth-keys/\\2/generate-token" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/devportal/applications/(.*)/api-keys/(.*)/generate" + method: "POST" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/devportal/applications/\\1/api-keys/\\2/generate" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/devportal/applications/(.*)/api-keys/(.*)/revoke" + method: "POST" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/devportal/applications/\\1/api-keys/\\2/revoke" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/devportal/applications/export" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/devportal/applications/export" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/devportal/applications/import" + method: "POST" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/devportal/applications/import" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + parentRefs: + - group: "gateway.networking.k8s.io" + kind: "Gateway" + name: "default" + sectionName: "httpslistener" +{{- end -}} diff --git a/helm-charts/templates/control-plane/devportal-ds/devportal-domain-api-httproute-5.yaml b/helm-charts/templates/control-plane/devportal-ds/devportal-domain-api-httproute-5.yaml new file mode 100644 index 000000000..c644bdfe8 --- /dev/null +++ b/helm-charts/templates/control-plane/devportal-ds/devportal-domain-api-httproute-5.yaml @@ -0,0 +1,274 @@ +# Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. +# +# WSO2 LLC. licenses this file to you 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. +{{- if .Values.wso2.apk.cp.enabled }} +apiVersion: "gateway.networking.k8s.io/v1beta1" +kind: "HTTPRoute" +metadata: + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-httproute-5 + namespace: {{ .Release.Namespace }} + labels: + api-name: "devportal-domain-service" + api-version: "1.0.0" +spec: + hostnames: + - "{{ .Values.wso2.apk.listener.hostname | default "api.am.wso2.com"}}" + rules: + - matches: + - path: + type: "RegularExpression" + value: "/api/devportal/subscriptions" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/devportal/subscriptions" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/devportal/subscriptions" + method: "POST" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/devportal/subscriptions" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/devportal/subscriptions/multiple" + method: "POST" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/devportal/subscriptions/multiple" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/devportal/subscriptions/(.*)/additionalInfo" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/devportal/subscriptions/\\1/additionalInfo" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/devportal/subscriptions/(.*)" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/devportal/subscriptions/\\1" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/devportal/subscriptions/(.*)" + method: "PUT" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/devportal/subscriptions/\\1" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/devportal/subscriptions/(.*)" + method: "DELETE" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/devportal/subscriptions/\\1" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/devportal/subscriptions/(.*)/usage" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/devportal/subscriptions/\\1/usage" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/devportal/throttling-policies/(.*)" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/devportal/throttling-policies/\\1" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/devportal/throttling-policies/(.*)/(.*)" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/devportal/throttling-policies/\\1/\\2" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/devportal/tags" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/devportal/tags" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/devportal/search" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/devportal/search" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/devportal/sdk-gen/languages" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/devportal/sdk-gen/languages" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/devportal/webhooks/subscriptions" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/devportal/webhooks/subscriptions" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/devportal/settings" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/devportal/settings" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + - matches: + - path: + type: "RegularExpression" + value: "/api/devportal/settings/application-attributes" + method: "GET" + filters: + - type: "URLRewrite" + urlRewrite: + path: + type: "ReplaceFullPath" + replaceFullPath: "/api/devportal/settings/application-attributes" + backendRefs: + - group: dp.wso2.com + kind: Backend + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-backend + parentRefs: + - group: "gateway.networking.k8s.io" + kind: "Gateway" + name: "default" + sectionName: "httpslistener" +{{- end -}} diff --git a/helm-charts/templates/control-plane/devportal-ds/devportal-domain-api-policy.yaml b/helm-charts/templates/control-plane/devportal-ds/devportal-domain-api-policy.yaml new file mode 100644 index 000000000..b73236bd0 --- /dev/null +++ b/helm-charts/templates/control-plane/devportal-ds/devportal-domain-api-policy.yaml @@ -0,0 +1,37 @@ +# Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. +# +# WSO2 LLC. licenses this file to you 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. +{{- if .Values.wso2.apk.dp.enabled }} +kind: "APIPolicy" +apiVersion: "dp.wso2.com/v1alpha1" +metadata: + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-api-policy + namespace: {{ .Release.Namespace }} +spec: + override: + backendJwtToken: + enabled: true + encoding: "base64" + signingAlgorithm: "SHA256withRSA" + header: "X-JWT-Assertion" + tokenTTL: 3600 + customClaims: + - claim: "admin" + value: "http://wso2.org/claims/enduser" + targetRef: + group: "gateway.networking.k8s.io" + kind: "API" + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-api +{{- end -}} diff --git a/helm-charts/templates/control-plane/devportal-ds/devportal-domain-api.yaml b/helm-charts/templates/control-plane/devportal-ds/devportal-domain-api.yaml new file mode 100644 index 000000000..afd2e2615 --- /dev/null +++ b/helm-charts/templates/control-plane/devportal-ds/devportal-domain-api.yaml @@ -0,0 +1,39 @@ +# Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. +# +# WSO2 LLC. licenses this file to you 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. +{{- if .Values.wso2.apk.cp.enabled }} +kind: "API" +apiVersion: "dp.wso2.com/v1alpha1" +metadata: + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-api + namespace: {{ .Release.Namespace }} + labels: + api-name: "devportal-domain-service" + api-version: "1.0.0" +spec: + apiName: "Devportal Domain API" + apiType: "REST" + apiVersion: "1.0.0" + basePath: "/api/devportal/1.0.0" + organization: "carbon.super" + production: + - httpRouteRefs: + - {{ template "apk-helm.resource.prefix" . }}-devportal-ds-httproute-1 + - {{ template "apk-helm.resource.prefix" . }}-devportal-ds-httproute-2 + - {{ template "apk-helm.resource.prefix" . }}-devportal-ds-httproute-3 + - {{ template "apk-helm.resource.prefix" . }}-devportal-ds-httproute-4 + - {{ template "apk-helm.resource.prefix" . }}-devportal-ds-httproute-5 + systemAPI: true +{{- end -}} diff --git a/helm-charts/templates/control-plane/devportal-ds/devportal-ds-configmap.yaml b/helm-charts/templates/control-plane/devportal-ds/devportal-ds-configmap.yaml new file mode 100644 index 000000000..fc2f4e4d9 --- /dev/null +++ b/helm-charts/templates/control-plane/devportal-ds/devportal-ds-configmap.yaml @@ -0,0 +1,69 @@ +# Copyright (c) 2022, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. +# +# WSO2 LLC. licenses this file to you 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. + +{{- if .Values.wso2.apk.cp.enabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-configmap + namespace: {{ .Release.Namespace }} +data: + Config.toml: | + [ballerina.log] + level = "DEBUG" + [ballerina.http] + traceLogConsole = true + # Sample configurations + [wso2.devportal_service.datasourceConfiguration] + description = "Database for admin" + url = "{{ .Values.wso2.apk.cp.database.url }}" + host = "{{ .Values.wso2.apk.cp.database.host }}" + port = {{ .Values.wso2.apk.cp.database.port }} + databaseName = "{{ .Values.wso2.apk.cp.database.databaseName }}" + username = "{{ .Values.wso2.apk.cp.database.username }}" + validationTimeout = {{ .Values.wso2.apk.cp.database.validationTimeout }} + testQuery = "{{ .Values.wso2.apk.cp.database.validationQuery }}" + driver = "{{ .Values.wso2.apk.cp.database.driver }}" + [wso2.devportal_service.idpConfiguration] + organizationClaim = "{{ .Values.wso2.apk.idp.organizationClaim }}" + userClaim = "{{ .Values.wso2.apk.idp.usernameClaim }}" + [wso2.devportal_service.idpConfiguration.publicKey] + certFilePath = "/home/wso2apk/devportal/security/mg.pem" + [wso2.devportal_service.throttleConfig.blockCondition] + enabled = true + [wso2.devportal_service.keyStores.tls] + keyFilePath = "/home/wso2apk/devportal/security/devportal.key" + certFilePath = "/home/wso2apk/devportal/security/devportal.pem" + [wso2.devportal_service.keyStores.signing] + keyFilePath = "/home/wso2apk/devportal/security/wso2carbon.key" + [wso2.devportal_service.issuerConfig] + issuer = "https://apim.wso2.com/oauth2/token" + audience = "https://apim.wso2.com/oauth2/token" + keyId = "gateway_certificate_alias" + expTime = 3600.0 + [wso2.devportal_service.sdkConfig] + groupId = "org.wso2" + artifactId = "org.wso2.client." + modelPackage = "org.wso2.client.model." + apiPackage = "org.wso2.client.api." + [wso2.devportal_service.k8sConfig] + host = "kubernetes.default" + serviceAccountPath = "/var/run/secrets/kubernetes.io/serviceaccount" + [wso2.devportal_service.managementServerConfig] + serviceName = "{{ template "apk-helm.resource.prefix" . }}-management-server" + namespace = "{{ .Release.Namespace }}" + certPath = "/home/wso2apk/devportal/security/truststore/management-server.pem" +{{- end -}} diff --git a/helm-charts/templates/control-plane/devportal-ds/devportal-ds-deployment.yaml b/helm-charts/templates/control-plane/devportal-ds/devportal-ds-deployment.yaml new file mode 100644 index 000000000..74048f950 --- /dev/null +++ b/helm-charts/templates/control-plane/devportal-ds/devportal-ds-deployment.yaml @@ -0,0 +1,155 @@ +# Copyright (c) 2022, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. +# +# WSO2 LLC. licenses this file to you 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. + +{{- if .Values.wso2.apk.cp.enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-deployment + namespace: {{ .Release.Namespace }} +spec: + replicas: {{ .Values.wso2.apk.cp.devportal.deployment.replicas }} + strategy: + type: {{ .Values.wso2.apk.cp.devportal.deployment.strategy }} + selector: + matchLabels: + +{{ include "apk-helm.pod.selectorLabels" (dict "root" . "app" "devportal-ds" ) | indent 6}} + template: + metadata: + labels: +{{ include "apk-helm.pod.selectorLabels" (dict "root" . "app" "devportal-ds" ) | indent 8}} + spec: + serviceAccountName: {{ .Values.wso2.apk.auth.serviceAccountName }} + initContainers: + - name: init-db + image: busybox:1.32 + command: ['sh', '-c', 'echo -e "Checking for the availability of DB Server deployment"; while ! nc -z "{{ .Values.wso2.apk.cp.database.host }}" {{.Values.wso2.apk.cp.database.port }}; do sleep 1; printf "-"; done; echo -e " >> DB Server has started";'] + containers: + - name: devportal-ds + image: {{ .Values.wso2.apk.cp.devportal.deployment.image }} + imagePullPolicy: {{ .Values.wso2.apk.cp.devportal.deployment.imagePullPolicy }} + ports: + - containerPort: 9443 + protocol: "TCP" + readinessProbe: + httpGet: + path: /health + port: 9443 + scheme: HTTPS + initialDelaySeconds: {{ .Values.wso2.apk.cp.devportal.deployment.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.wso2.apk.cp.devportal.deployment.readinessProbe.periodSeconds }} + livenessProbe: + httpGet: + path: /health + port: 9443 + scheme: HTTPS + initialDelaySeconds: {{ .Values.wso2.apk.cp.devportal.deployment.livenessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.wso2.apk.cp.devportal.deployment.livenessProbe.periodSeconds }} + +{{ include "apk-helm.deployment.resources" .Values.wso2.apk.cp.devportal.deployment.resources | indent 10 }} + volumeMounts: + - mountPath: /home/wso2apk/devportal/security/wso2carbon.key + name: devportal-signing-keystore-volume + subPath: wso2carbon.key + - mountPath: /home/wso2apk/devportal/conf/Config.toml + name: config-toml-volume + subPath: Config.toml + - mountPath: /home/wso2apk/devportal/security/mg.pem + name: devportal-ds-jwt-validation-key-volume + subPath: mg.pem + - name: devportal-ds-tls-volume + mountPath: /home/wso2apk/devportal/security/devportal.key + {{- if and .Values.wso2.apk.cp.devportal.configs .Values.wso2.apk.cp.devportal.configs.tls }} + subPath: {{ .Values.wso2.apk.cp.devportal.configs.tls.certKeyFilename | default "tls.key" }} + {{- else }} + subPath: tls.key + {{- end }} + - name: devportal-ds-tls-volume + mountPath: /home/wso2apk/devportal/security/devportal.pem + {{- if and .Values.wso2.apk.cp.devportal.configs .Values.wso2.apk.cp.devportal.configs.tls }} + subPath: {{ .Values.wso2.apk.cp.devportal.configs.tls.certFilename | default "tls.crt" }} + {{- else }} + subPath: tls.crt + {{- end }} + - name: management-server-tls-volume + mountPath: /home/wso2apk/devportal/security/truststore/management-server.pem + {{- if and .Values.wso2.apk.cp.managementServer.configs .Values.wso2.apk.cp.managementServer.configs.tls }} + subPath: {{ .Values.wso2.apk.cp.managementServer.configs.tls.certFilename | default "tls.crt" }} + {{- else }} + subPath: tls.crt + {{- end }} + - name: keymanager-connetor--nonprodidp + mountPath: /home/wso2apk/devportal/keymanager/nonprodidp.yaml + subPath: nonprodidp.yaml + {{if .Values.wso2.apk.cp.keyManagerConnectors }} + {{- range $index, $val := $.Values.wso2.apk.cp.keyManagerConnectors}} + - name: key-manager-connectors-{{ .type}} + mountPath: /home/wso2apk/admin/keymanager/{{ .fileName}} + subPath: {{ .fileName}} + {{- end }} + {{end}} + env: + - name: DB_PASSWORD + valueFrom: + secretKeyRef: + {{ if and .Values.wso2.apk.cp.database .Values.wso2.apk.cp.database.secretName }} + name: "{{ .Values.wso2.apk.cp.database.secretName}}" + key: "{{ .Values.wso2.apk.cp.database.secretKey}}" + {{ else }} + name: "apk-db-secret" + key: "DB_PASSWORD" + {{ end }} + {{- if and .Values.wso2.subscription .Values.wso2.subscription.imagePullSecrets}} + imagePullSecrets: + - name: {{ .Values.wso2.subscription.imagePullSecrets }} + {{ end }} + + volumes: + - name: devportal-ds-jwt-validation-key-volume + secret: + secretName: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-jwt-validaion-secret + - name: config-toml-volume + configMap: + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-configmap + - name: devportal-ds-tls-volume + secret: + {{ if and .Values.wso2.apk.cp.devportal.configs .Values.wso2.apk.cp.devportal.configs.tls }} + secretName: {{ .Values.wso2.apk.cp.devportal.configs.tls.secretName | default (printf "%s-devportal-ds-server-cert" (include "apk-helm.resource.prefix" .)) }} + {{ else }} + secretName: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-server-cert + {{ end }} + - name: devportal-signing-keystore-volume + secret: + secretName: {{ template "apk-helm.resource.prefix" . }}-apikey-signing-keystore-secret + - name: management-server-tls-volume + secret: + {{- if and .Values.wso2.apk.cp.managementServer.configs .Values.wso2.apk.cp.managementServer.configs.tls }} + secretName: {{ .Values.wso2.apk.cp.managementServer.configs.tls.secretName | default (printf "%s-management-server-cert" (include "apk-helm.resource.prefix" .)) }} + {{- else }} + secretName: {{ template "apk-helm.resource.prefix" . }}-management-server-cert + {{- end }} + - name: keymanager-connetor--nonprodidp + configMap: + name: {{ template "apk-helm.resource.prefix" . }}-nonprodidp-config + {{if .Values.wso2.apk.cp.keyManagerConnectors }} + {{- range $index, $val := $.Values.wso2.apk.cp.keyManagerConnectors}} + - name: key-manager-connectors-{{ .type}} + configMap: + name: {{ .name}} + {{- end }} + {{end}} +{{- end -}} diff --git a/helm-charts/templates/control-plane/devportal-ds/devportal-ds-jwt-validation-secret.yaml b/helm-charts/templates/control-plane/devportal-ds/devportal-ds-jwt-validation-secret.yaml new file mode 100644 index 000000000..a6612e98a --- /dev/null +++ b/helm-charts/templates/control-plane/devportal-ds/devportal-ds-jwt-validation-secret.yaml @@ -0,0 +1,10 @@ +{{- if .Values.wso2.apk.cp.enabled }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-jwt-validaion-secret + namespace: {{ .Release.Namespace }} +type: Opaque +data: + mg.pem: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURrekNDQW51Z0F3SUJBZ0lKQVBEOGVTM2VtY3JRTUEwR0NTcUdTSWIzRFFFQkN3VUFNR1F4Q3pBSkJnTlYKQkFZVEFsVlRNUXN3Q1FZRFZRUUlEQUpEUVRFV01CUUdBMVVFQnd3TlRXOTFiblJoYVc0Z1ZtbGxkekVOTUFzRwpBMVVFQ2d3RVYxTlBNakVOTUFzR0ExVUVDd3dFVjFOUE1qRVNNQkFHQTFVRUF3d0piRzlqWVd4b2IzTjBNQ0FYCkRUSXlNVEV4TnpFNE1EWXpPRm9ZRHpJd05USXhNVEE1TVRnd05qTTRXakJrTVFzd0NRWURWUVFHRXdKVlV6RUwKTUFrR0ExVUVDQXdDUTBFeEZqQVVCZ05WQkFjTURVMXZkVzUwWVdsdUlGWnBaWGN4RFRBTEJnTlZCQW9NQkZkVApUekl4RFRBTEJnTlZCQXNNQkZkVFR6SXhFakFRQmdOVkJBTU1DV3h2WTJGc2FHOXpkRENDQVNJd0RRWUpLb1pJCmh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTjlaRUQyb1JDbTljZjF2RUV2UjFKL1R3TGFrSmNQeVN2UDIKT1p1Y3hiVlBDeVhvbnlsZEtJbUVoSjZMZnVNcnV4NW9wQmVYRnpJZWhjOElJalkvSlUyR2xpaG5ybFBFbE1EUQoyUXVjelpqUTZuYWlrWVRrcU5zTk5NRitXdml0N0lIVVljejM2cEliK21KbSt4ZlNubFRaWVA2MGtsY2xDK3g2CmloVzVJUG5EcUxqS1F0OTFYWFVCRkczRFYrbHVoT1NzQXJuRHBWZzBreGdqd2MvRkxJMXNpY0JoWVMxWXpPWU0Kd08zWFh4ZFlUMlNJS3VaM0ZxMk5TSGQzSEUwamNIU2FIbXBjMWpONDRrTzRPRWJsdzhjMlJDT21WRkN6YXY3SApQQVVveG1JQUEyRHNNRTN2OHdwSGM2L0lFZkZTVVU3blFNbFVhTjN1QUpVeFpBVmh5YzhDQXdFQUFhTkdNRVF3ClFnWURWUjBSQkRzd09ZSUhZV1JoY0hSbGNvSUlaVzVtYjNKalpYS0NCbkp2ZFhSbGNvSUpiRzlqWVd4b2IzTjAKZ2hGdFlXNWhaMlZ0Wlc1MExYTmxjblpsY2pBTkJna3Foa2lHOXcwQkFRc0ZBQU9DQVFFQWNsY0NqWGppS3J1UwpyWUhNRjNDeDBPSmEwS2tlWkoxVkxFY0xseXAvTXp4VEdvdnk5MXR3NlhNVVFFbndqVkxLWUc5T3Q1MU9wc3pyCmdqQXBGSnE1QlZyblJsNHp0ajFsdHVMUmpyVzBlSnIrckNpbUFKdVI0ZUhMRTUrRU5uc2t1cGVNUXdyUG50dFMKdkVMUkZmMm1Zd3JqY2sxZFdNUGhsOGUyQmh4bDN3QXgwb1o0Z0k4d2dSSThndlVNYW0xd0hzeWR1NEpCYVRuWgpSM2FpOFpIU1Q2QlZHTUhBMFdUVTFpVWJyK0dDUkFjRE5kSkJpNHpCY0JzejREN09RdTBVK1dPbTBXWlNWNGZjCmNXdTE5K0pydk1KN0llWDNaaHFSdkdiblQzWVVSSFpoUGZsbGFoYWZTNlhMYzBzeExYMFV5RGJybkk2enZoRWMKb1NySFI0WGcwUT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K +{{- end -}} diff --git a/helm-charts/templates/control-plane/devportal-ds/devportal-ds-service.yaml b/helm-charts/templates/control-plane/devportal-ds/devportal-ds-service.yaml new file mode 100644 index 000000000..fc4f5fd64 --- /dev/null +++ b/helm-charts/templates/control-plane/devportal-ds/devportal-ds-service.yaml @@ -0,0 +1,47 @@ +# Copyright (c) 2022, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. +# +# WSO2 LLC. licenses this file to you 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. + +{{- if .Values.wso2.apk.cp.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-service + namespace : {{ .Release.Namespace }} +spec: + # label keys and values that must match in order to receive traffic for this service + selector: +{{ include "apk-helm.pod.selectorLabels" (dict "root" . "app" "devportal-ds" ) | indent 4}} + ports: + # ports that this service should serve on + - name: pass-through-http + protocol: TCP + port: 8280 + - name: pass-through-https + protocol: TCP + port: 8243 + - name: servlet-http + protocol: TCP + port: 9763 + - name: servlet-https + protocol: TCP + port: 9443 + - name: websub-http + protocol: TCP + port: 9021 + - name: websub-https + protocol: TCP + port: 8021 +{{- end -}} diff --git a/helm-charts/templates/control-plane/keymanager-connectors/nonprodidp.yaml b/helm-charts/templates/control-plane/keymanager-connectors/nonprodidp.yaml new file mode 100644 index 000000000..e3caa3b51 --- /dev/null +++ b/helm-charts/templates/control-plane/keymanager-connectors/nonprodidp.yaml @@ -0,0 +1,59 @@ +# Copyright (c) 2022, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. +# +# WSO2 LLC. licenses this file to you 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. + +{{- if .Values.wso2.apk.dp.enabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "apk-helm.resource.prefix" . }}-nonprodidp-config + namespace: {{ .Release.Namespace }} +data: + nonprodidp.yaml: | + type: "nonProdIdp" + display_name: "Non-Prod IdP" + consumerKeyClaim: "azp" + scopesClaim: "scope" + endpoints: + - + name: "dcr_endpoint" + display_name: "DCR Endpoint" + toolTip: "DCR Endpoint" + required: true + - + name: "revocation_endpoint" + display_name: "Revocation Endpoint" + toolTip: "Revocation Endpoint" + required: false + - + name: "token_endpoint" + display_name: "Token Endpoint" + toolTip: "Token Endpoint" + required: true + endpointConfigurations: + - + name: "username" + display_name: "Username" + type: "input" + toolTip: "DCR Username" + required: true + - + name: "password" + display_name: "Password" + type : "input" + toolTip: "Password" + required: true + masked: true +{{- end}} \ No newline at end of file diff --git a/helm-charts/templates/control-plane/management-server/management-server-config-toml.yaml b/helm-charts/templates/control-plane/management-server/management-server-config-toml.yaml new file mode 100644 index 000000000..63824f66c --- /dev/null +++ b/helm-charts/templates/control-plane/management-server/management-server-config-toml.yaml @@ -0,0 +1,19 @@ +{{- if .Values.wso2.apk.cp.enabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "apk-helm.resource.prefix" . }}-management-server-config-toml + namespace: {{ .Release.Namespace }} +data: + config.toml: | + [backOffice] + host = "{{ template "apk-helm.resource.prefix" . }}-backoffice-ds-service.{{ .Release.Namespace }}.svc" + port = 9444 + serviceBasePath = "/api/backoffice/internal/apis" + [managementServer.keystore] + certPath = "/home/wso2/security/keystore/management-server.pem" + keyPath = "/home/wso2/security/keystore/management-server.key" + [managementServer.truststore] + location = "/home/wso2/security/truststore" + +{{- end -}} diff --git a/helm-charts/templates/control-plane/management-server/management-server-deployment.yaml b/helm-charts/templates/control-plane/management-server/management-server-deployment.yaml new file mode 100644 index 000000000..817cf769d --- /dev/null +++ b/helm-charts/templates/control-plane/management-server/management-server-deployment.yaml @@ -0,0 +1,153 @@ +# -------------------------------------------------------------------- +# Copyright (c) 2022, WSO2 LLC. (http://wso2.com) All Rights Reserved. +# +# 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. +# ----------------------------------------------------------------------- + +{{- if .Values.wso2.apk.cp.enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "apk-helm.resource.prefix" . }}-management-server-deployment + namespace: {{ .Release.Namespace }} +spec: + replicas: {{ .Values.wso2.apk.cp.managementServer.deployment.replicas }} + strategy: + type: {{ .Values.wso2.apk.cp.managementServer.deployment.strategy }} + selector: + matchLabels: +{{ include "apk-helm.pod.selectorLabels" (dict "root" . "app" "management-server" ) | indent 6}} + template: + metadata: + labels: +{{ include "apk-helm.pod.selectorLabels" (dict "root" . "app" "management-server" ) | indent 8}} + spec: + containers: + - name: management-server + image: {{ .Values.wso2.apk.cp.managementServer.deployment.image }} + imagePullPolicy: {{ .Values.wso2.apk.cp.managementServer.deployment.imagePullPolicy }} + ports: + - containerPort: 18000 + - containerPort: 8765 + - containerPort: 8766 +{{ include "apk-helm.deployment.env" .Values.wso2.apk.cp.managementServer.deployment.env | indent 10 }} + - name: MGT_SERVER_PRIVATE_KEY_PATH + value: /home/wso2/security/keystore/management-server.key + - name: MGT_SERVER_PUBLIC_CERT_PATH + value: /home/wso2/security/keystore/management-server.pem + - name: MGT_SERVER_NAME + value: {{ template "apk-helm.resource.prefix" . }}-management-server.{{ .Release.Namespace }}.svc +{{ include "apk-helm.deployment.resources" .Values.wso2.apk.cp.managementServer.deployment.resources | indent 10 }} + volumeMounts: + - name: management-server-keystore-secret-volume + mountPath: /home/wso2/security/keystore/management-server.key + {{- if and .Values.wso2.apk.cp.managementServer.configs .Values.wso2.apk.cp.managementServer.configs.tls }} + subPath: {{ .Values.wso2.apk.cp.managementServer.configs.tls.certKeyFilename | default "tls.key" }} + {{- else }} + subPath: tls.key + {{- end }} + - name: management-server-keystore-secret-volume + mountPath: /home/wso2/security/keystore/management-server.pem + {{- if and .Values.wso2.apk.cp.managementServer.configs .Values.wso2.apk.cp.managementServer.configs.tls }} + subPath: {{ .Values.wso2.apk.cp.managementServer.configs.tls.certFilename | default "tls.crt" }} + {{- else }} + subPath: tls.crt + {{- end }} + - name: adapter-truststore-secret-volume + mountPath: /home/wso2/security/truststore/adapter.crt + {{ if and .Values.wso2.apk.dp.adapter.configs .Values.wso2.apk.dp.adapter.configs.tls }} + subPath: {{ .Values.wso2.apk.dp.adapter.configs.tls.certFilename | default "tls.crt" }} + {{ else }} + subPath: tls.crt + {{ end }} + - name: backoffice-ds-tls-volume + mountPath: /home/wso2/security/truststore/backoffice.pem + {{- if and .Values.wso2.apk.cp.backoffice.configs .Values.wso2.apk.cp.backoffice.configs.tls }} + subPath: {{ .Values.wso2.apk.cp.backoffice.configs.tls.certFilename | default "tls.crt" }} + {{- else }} + subPath: tls.crt + {{- end }} + - name: devportal-ds-tls-volume + mountPath: /home/wso2/security/truststore/devportal.pem + {{- if and .Values.wso2.apk.cp.devportal.configs .Values.wso2.apk.cp.devportal.configs.tls }} + subPath: {{ .Values.wso2.apk.cp.devportal.configs.tls.certFilename | default "tls.crt" }} + {{- else }} + subPath: tls.crt + {{- end }} + - name: admin-ds-tls-volume + mountPath: /home/wso2/security/truststore/admin.pem + {{- if and .Values.wso2.apk.cp.admin.configs .Values.wso2.apk.cp.admin.configs.tls }} + subPath: {{ .Values.wso2.apk.cp.admin.configs.tls.certFilename | default "tls.crt" }} + {{- else }} + subPath: tls.crt + {{- end }} + - name: management-server-config-toml-volume + mountPath: /home/wso2/conf/ + readinessProbe: + exec: + command: [ "sh", "check_health.sh" ] + initialDelaySeconds: {{ .Values.wso2.apk.cp.managementServer.deployment.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.wso2.apk.cp.managementServer.deployment.readinessProbe.periodSeconds }} + failureThreshold: {{ .Values.wso2.apk.cp.managementServer.deployment.readinessProbe.failureThreshold }} + livenessProbe: + exec: + command: [ "sh", "check_health.sh" ] + initialDelaySeconds: {{ .Values.wso2.apk.cp.managementServer.deployment.livenessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.wso2.apk.cp.managementServer.deployment.livenessProbe.periodSeconds }} + failureThreshold: {{ .Values.wso2.apk.cp.managementServer.deployment.livenessProbe.failureThreshold }} + {{- if and .Values.wso2.subscription .Values.wso2.subscription.imagePullSecrets}} + imagePullSecrets: + - name: {{ .Values.wso2.subscription.imagePullSecrets }} + {{ end }} + + volumes: + - name: management-server-keystore-secret-volume + secret: + {{- if and .Values.wso2.apk.cp.managementServer.configs .Values.wso2.apk.cp.managementServer.configs.tls }} + secretName: {{ .Values.wso2.apk.cp.managementServer.configs.tls.secretName | default (printf "%s-management-server-cert" (include "apk-helm.resource.prefix" .)) }} + {{- else }} + secretName: {{ template "apk-helm.resource.prefix" . }}-management-server-cert + {{- end }} + - name: adapter-truststore-secret-volume + secret: + {{ if and .Values.wso2.apk.dp.adapter.configs .Values.wso2.apk.dp.adapter.configs.tls }} + secretName: {{ .Values.wso2.apk.dp.adapter.configs.tls.secretName | default "apk-root-certificate"}} + {{ else }} + secretName: apk-root-certificate + {{ end }} + - name: management-server-config-toml-volume + configMap: + name: {{ template "apk-helm.resource.prefix" . }}-management-server-config-toml + - name: backoffice-ds-tls-volume + secret: + {{ if and .Values.wso2.apk.cp.backoffice.configs .Values.wso2.apk.cp.backoffice.configs.tls }} + secretName: {{ .Values.wso2.apk.cp.backoffice.configs.tls.secretName | default (printf "%s-backoffice-ds-server-cert" (include "apk-helm.resource.prefix" .)) }} + {{ else }} + secretName: {{ template "apk-helm.resource.prefix" . }}-backoffice-ds-server-cert + {{ end }} + - name: devportal-ds-tls-volume + secret: + {{ if and .Values.wso2.apk.cp.devportal.configs .Values.wso2.apk.cp.devportal.configs.tls }} + secretName: {{ .Values.wso2.apk.cp.devportal.configs.tls.secretName | default (printf "%s-devportal-ds-server-cert" (include "apk-helm.resource.prefix" .)) }} + {{ else }} + secretName: {{ template "apk-helm.resource.prefix" . }}-devportal-ds-server-cert + {{ end }} + - name: admin-ds-tls-volume + secret: + {{ if and .Values.wso2.apk.cp.admin.configs .Values.wso2.apk.cp.admin.configs.tls }} + secretName: {{ .Values.wso2.apk.cp.admin.configs.tls.secretName | default (printf "%s-admin-ds-server-cert" (include "apk-helm.resource.prefix" .)) }} + {{ else }} + secretName: {{ template "apk-helm.resource.prefix" . }}-admin-ds-server-cert + {{ end }} + +{{- end -}} diff --git a/helm-charts/templates/control-plane/management-server/management-server-service.yaml b/helm-charts/templates/control-plane/management-server/management-server-service.yaml new file mode 100644 index 000000000..c476d0c10 --- /dev/null +++ b/helm-charts/templates/control-plane/management-server/management-server-service.yaml @@ -0,0 +1,40 @@ +# -------------------------------------------------------------------- +# Copyright (c) 2022, WSO2 LLC. (http://wso2.com) All Rights Reserved. +# +# 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. +# ----------------------------------------------------------------------- + +{{- if .Values.wso2.apk.cp.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "apk-helm.resource.prefix" . }}-management-server + namespace : {{ .Release.Namespace }} +spec: + type: ClusterIP + selector: +{{ include "apk-helm.pod.selectorLabels" (dict "root" . "app" "management-server" ) | indent 4}} + ports: + - name: "xds-management-server" + port: 18000 + targetPort: 18000 + protocol: TCP + - name: "grpc-management-server" + port: 8765 + targetPort: 8765 + protocol: TCP + - name: "notification-management-server" + port: 8766 + targetPort: 8766 + protocol: TCP +{{- end -}} diff --git a/helm-charts/templates/idp/idp-ds/idp-ds-deployment.yaml b/helm-charts/templates/idp/idp-ds/idp-ds-deployment.yaml index d246dd99d..8031938ca 100644 --- a/helm-charts/templates/idp/idp-ds/idp-ds-deployment.yaml +++ b/helm-charts/templates/idp/idp-ds/idp-ds-deployment.yaml @@ -38,7 +38,7 @@ spec: initContainers: - name: init-db image: busybox:1.32 - command: ['sh', '-c', 'echo -e "Checking for the availability of DB Server deployment"; while ! nc -z "{{ .Values.idp.database.host }}" {{.Values.idp.database.port }}; do sleep 1; printf "-"; done; echo -e " >> DB Server has started";'] + command: ['sh', '-c', 'echo -e "Checking for the availability of DB Server deployment"; while ! nc -z "{{ .Values.wso2.apk.cp.database.host }}" {{.Values.wso2.apk.cp.database.port }}; do sleep 1; printf "-"; done; echo -e " >> DB Server has started";'] securityContext: allowPrivilegeEscalation: false capabilities: diff --git a/helm-charts/templates/postgres/initdb-conf.yaml b/helm-charts/templates/postgres/initdb-conf.yaml index cc293bf95..e94313fc7 100644 --- a/helm-charts/templates/postgres/initdb-conf.yaml +++ b/helm-charts/templates/postgres/initdb-conf.yaml @@ -26,6 +26,372 @@ data: GRANT ALL PRIVILEGES ON DATABASE "WSO2AM_DB" TO wso2carbon; \c "WSO2AM_DB" BEGIN TRANSACTION; + + CREATE TABLE IF NOT EXISTS INTERNAL_USER ( + UUID VARCHAR(100) NOT NULL, + IDP_USER_NAME VARCHAR(255) NOT NULL, + PRIMARY KEY (UUID), + UNIQUE (IDP_USER_NAME) + ); + + CREATE TABLE IF NOT EXISTS APPLICATION ( + NAME VARCHAR(100), + USER_UUID VARCHAR(100), + APPLICATION_TIER VARCHAR(50) DEFAULT 'Unlimited', + CALLBACK_URL VARCHAR(512), + DESCRIPTION VARCHAR(512), + APPLICATION_STATUS VARCHAR(50) DEFAULT 'APPROVED', + GROUP_ID VARCHAR(100), + CREATED_BY VARCHAR(100), + CREATED_TIME TIMESTAMP, + UPDATED_BY VARCHAR(100), + UPDATED_TIME TIMESTAMP, + UUID VARCHAR(256), + TOKEN_TYPE VARCHAR(10), + ORGANIZATION VARCHAR(100), + FOREIGN KEY(USER_UUID) REFERENCES INTERNAL_USER(UUID) ON UPDATE CASCADE ON DELETE RESTRICT, + PRIMARY KEY(UUID), + UNIQUE(NAME,USER_UUID,ORGANIZATION) + ); + + CREATE TABLE IF NOT EXISTS API ( + UUID VARCHAR(256), + API_NAME VARCHAR(256), + API_VERSION VARCHAR(30), + CONTEXT VARCHAR(256), + CONTEXT_TEMPLATE VARCHAR(256), + API_TIER VARCHAR(256), + API_TYPE VARCHAR(10), + ORGANIZATION VARCHAR(100), + GATEWAY_VENDOR VARCHAR(100) DEFAULT 'wso2', + CREATED_BY VARCHAR(100), + CREATED_TIME TIMESTAMP, + UPDATED_BY VARCHAR(100), + UPDATED_TIME TIMESTAMP, + STATUS VARCHAR(30), + VERSION_COMPARABLE VARCHAR(15), + LOG_LEVEL VARCHAR(255) DEFAULT 'OFF', + REVISIONS_CREATED INTEGER DEFAULT 0, + SDK JSONB, + CATEGORIES JSONB, + ARTIFACT JSONB NOT NULL, + DEFAULT_API_VERSION VARCHAR(30), + PRIMARY KEY(UUID), + UNIQUE(API_NAME,API_VERSION,ORGANIZATION) + ); + + CREATE TABLE API_ARTIFACT ( + ORGANIZATION VARCHAR(100) NOT NULL, + API_UUID VARCHAR(256) NOT NULL, + API_DEFINITION BYTEA, + MEDIA_TYPE VARCHAR(100), + FOREIGN KEY(API_UUID) REFERENCES API(UUID) ON UPDATE CASCADE ON DELETE CASCADE + ); + + CREATE SEQUENCE RESOURCE_CATEGORIES_seq; + CREATE TABLE RESOURCE_CATEGORIES ( + RESOURCE_CATEGORY_ID INTEGER DEFAULT NEXTVAL ('RESOURCE_CATEGORIES_seq'), + RESOURCE_CATEGORY VARCHAR(255), + PRIMARY KEY (RESOURCE_CATEGORY_ID), + UNIQUE (RESOURCE_CATEGORY) + ); + + CREATE TABLE API_RESOURCES ( + UUID VARCHAR(255), + API_UUID VARCHAR(256), + RESOURCE_CATEGORY_ID INTEGER, + DATA_TYPE VARCHAR(255), + RESOURCE_CONTENT TSVECTOR, + RESOURCE_BINARY_VALUE BYTEA, + CREATED_BY VARCHAR(100), + CREATED_TIME TIMESTAMP(6) DEFAULT CURRENT_TIMESTAMP, + UPDATED_BY VARCHAR(100), + LAST_UPDATED_TIME TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY(UUID), + FOREIGN KEY(API_UUID) REFERENCES API(UUID) ON + UPDATE CASCADE ON DELETE CASCADE, + FOREIGN KEY (RESOURCE_CATEGORY_ID) REFERENCES RESOURCE_CATEGORIES(RESOURCE_CATEGORY_ID) + ); + + CREATE TABLE API_DOC_META_DATA( + UUID VARCHAR(255), + RESOURCE_UUID VARCHAR(255), + API_UUID VARCHAR(256), + NAME VARCHAR(255), + SUMMARY VARCHAR(1024), + TYPE VARCHAR(255), + OTHER_TYPE_NAME VARCHAR(255), + SOURCE_URL VARCHAR(255), + FILE_NAME VARCHAR(255), + SOURCE_TYPE VARCHAR(255), + VISIBILITY VARCHAR(30), + CREATED_BY VARCHAR(100), + CREATED_TIME TIMESTAMP(6) DEFAULT CURRENT_TIMESTAMP, + UPDATED_BY VARCHAR(100), + LAST_UPDATED_TIME TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY(UUID), + FOREIGN KEY(API_UUID) REFERENCES API(UUID) ON + UPDATE CASCADE ON DELETE CASCADE, + FOREIGN KEY(RESOURCE_UUID) REFERENCES API_RESOURCES(UUID) ON + UPDATE CASCADE ON DELETE CASCADE + ); + + CREATE SEQUENCE API_URL_MAPPING_SEQUENCE START WITH 1 INCREMENT BY 1; + CREATE TABLE IF NOT EXISTS API_URL_MAPPING ( + URL_MAPPING_ID INTEGER DEFAULT nextval('api_url_mapping_sequence'), + API_UUID VARCHAR(256) NOT NULL, + HTTP_METHOD VARCHAR(20) NULL, + AUTH_SCHEME VARCHAR(50) NULL, + URL_PATTERN VARCHAR(512) NULL, + THROTTLING_TIER_UNIT_TIME VARCHAR(255) DEFAULT NULL, + THROTTLING_TIER_UNIT_VALUE VARCHAR(255) DEFAULT NULL, + PRIMARY KEY(URL_MAPPING_ID), + FOREIGN KEY(API_UUID) REFERENCES API(UUID) ON UPDATE CASCADE ON DELETE CASCADE + ); + + CREATE TABLE IF NOT EXISTS API_RESOURCE_SCOPE_MAPPING ( + SCOPE_NAME VARCHAR(256) NOT NULL, + URL_MAPPING_ID INTEGER NOT NULL, + FOREIGN KEY(URL_MAPPING_ID) REFERENCES API_URL_MAPPING(URL_MAPPING_ID) ON DELETE CASCADE, + PRIMARY KEY(SCOPE_NAME, URL_MAPPING_ID) + ); + + CREATE TABLE IF NOT EXISTS SUBSCRIPTION ( + UUID VARCHAR(256), + TIER_ID VARCHAR(50), + TIER_ID_PENDING VARCHAR(50), + API_UUID VARCHAR(256), + LAST_ACCESSED TIMESTAMP NULL, + APPLICATION_UUID VARCHAR(256), + SUB_STATUS VARCHAR(50), + SUBS_CREATE_STATE VARCHAR(50) DEFAULT 'SUBSCRIBE', + CREATED_BY VARCHAR(100), + CREATED_TIME TIMESTAMP, + UPDATED_BY VARCHAR(100), + UPDATED_TIME TIMESTAMP, + FOREIGN KEY(APPLICATION_UUID) REFERENCES APPLICATION(UUID) ON UPDATE CASCADE ON DELETE CASCADE, + FOREIGN KEY(API_UUID) REFERENCES API(UUID) ON + UPDATE CASCADE ON DELETE CASCADE, + PRIMARY KEY (UUID) + ); + + CREATE TABLE APPLICATION_KEY_MAPPING ( + UUID VARCHAR(100), + APPLICATION_UUID VARCHAR(256), + CONSUMER_KEY VARCHAR(512), + KEY_TYPE VARCHAR(512) NOT NULL, + CREATE_MODE VARCHAR(30) DEFAULT 'CREATED', + APP_INFO BYTEA DEFAULT NULL, + KEY_MANAGER_UUID VARCHAR(100), + FOREIGN KEY(APPLICATION_UUID) REFERENCES APPLICATION(UUID) ON UPDATE CASCADE ON DELETE CASCADE, + -- FOREIGN KEY(KEY_MANAGER_UUID) REFERENCES KEY_MANAGER(UUID) ON UPDATE CASCADE ON DELETE CASCADE, -- + PRIMARY KEY(APPLICATION_UUID,KEY_TYPE,KEY_MANAGER_UUID) + ); + + CREATE SEQUENCE API_LC_EVENT_SEQUENCE START WITH 1 INCREMENT BY 1; + CREATE TABLE IF NOT EXISTS API_LC_EVENT ( + EVENT_ID INTEGER DEFAULT nextval('api_lc_event_sequence'), + API_UUID VARCHAR(256) NOT NULL, + PREVIOUS_STATE VARCHAR(50), + NEW_STATE VARCHAR(50) NOT NULL, + USER_UUID VARCHAR(100) NOT NULL, + ORGANIZATION VARCHAR(100) NOT NULL, + EVENT_DATE TIMESTAMP NOT NULL, + FOREIGN KEY(API_UUID) REFERENCES API(UUID) ON + UPDATE CASCADE ON DELETE CASCADE, + FOREIGN KEY(USER_UUID) REFERENCES INTERNAL_USER(UUID) ON UPDATE CASCADE ON DELETE CASCADE, + PRIMARY KEY (EVENT_ID) + ); + + CREATE TABLE IF NOT EXISTS API_COMMENTS ( + COMMENT_ID VARCHAR(64) NOT NULL, + COMMENT_TEXT VARCHAR(512), + CREATED_BY VARCHAR(255), + CREATED_TIME TIMESTAMP NOT NULL, + UPDATED_TIME TIMESTAMP, + API_UUID VARCHAR(256), + PARENT_COMMENT_ID VARCHAR(64) DEFAULT NULL, + ENTRY_POINT VARCHAR(20), + CATEGORY VARCHAR(20) DEFAULT 'general', + FOREIGN KEY(API_UUID) REFERENCES API(UUID) ON DELETE CASCADE, + FOREIGN KEY(PARENT_COMMENT_ID) REFERENCES API_COMMENTS(COMMENT_ID), + PRIMARY KEY(COMMENT_ID) + ); + + CREATE TABLE IF NOT EXISTS API_RATINGS ( + RATING_UUID VARCHAR(255) NOT NULL, + API_UUID VARCHAR(256), + RATING INTEGER, + USER_UUID VARCHAR(100), + FOREIGN KEY(API_UUID) REFERENCES API(UUID) ON UPDATE CASCADE ON DELETE CASCADE, + FOREIGN KEY(USER_UUID) REFERENCES INTERNAL_USER(UUID) ON + UPDATE CASCADE ON DELETE RESTRICT, + PRIMARY KEY (RATING_UUID) + ); + + CREATE TABLE IF NOT EXISTS BUSINESS_PLAN ( + UUID VARCHAR(256), + NAME VARCHAR(512) NOT NULL, + DISPLAY_NAME VARCHAR(512) NULL DEFAULT NULL, + ORGANIZATION VARCHAR(100) NOT NULL, + DESCRIPTION VARCHAR(1024) NULL DEFAULT NULL, + QUOTA_TYPE VARCHAR(25) NOT NULL, + QUOTA INTEGER NOT NULL, + QUOTA_UNIT VARCHAR(10) NULL, + UNIT_TIME INTEGER NOT NULL, + TIME_UNIT VARCHAR(25) NOT NULL, + RATE_LIMIT_COUNT INTEGER NULL DEFAULT NULL, + RATE_LIMIT_TIME_UNIT VARCHAR(25) NULL DEFAULT NULL, + IS_DEPLOYED BOOLEAN NOT NULL DEFAULT '0', + CUSTOM_ATTRIBUTES BYTEA DEFAULT NULL, + STOP_ON_QUOTA_REACH BOOLEAN NOT NULL DEFAULT '0', + BILLING_PLAN VARCHAR(20) NOT NULL, + MONETIZATION_PLAN VARCHAR(25) NULL DEFAULT NULL, + FIXED_RATE VARCHAR(15) NULL DEFAULT NULL, + BILLING_CYCLE VARCHAR(15) NULL DEFAULT NULL, + PRICE_PER_REQUEST VARCHAR(15) NULL DEFAULT NULL, + CURRENCY VARCHAR(15) NULL DEFAULT NULL, + MAX_COMPLEXITY INTEGER NOT NULL DEFAULT 0, + MAX_DEPTH INTEGER NOT NULL DEFAULT 0, + CONNECTIONS_COUNT INTEGER NOT NULL DEFAULT 0, + PRIMARY KEY(UUID), + UNIQUE(NAME, ORGANIZATION) + ); + + CREATE TABLE IF NOT EXISTS APPLICATION_USAGE_PLAN ( + NAME VARCHAR(512) NOT NULL, + DISPLAY_NAME VARCHAR(512) NULL DEFAULT NULL, + ORGANIZATION VARCHAR(100) NOT NULL, + DESCRIPTION VARCHAR(1024) NULL DEFAULT NULL, + QUOTA_TYPE VARCHAR(25) NOT NULL, + QUOTA INTEGER NOT NULL, + QUOTA_UNIT VARCHAR(10) NULL DEFAULT NULL, + UNIT_TIME INTEGER NOT NULL, + TIME_UNIT VARCHAR(25) NOT NULL, + IS_DEPLOYED BOOLEAN NOT NULL DEFAULT '0', + CUSTOM_ATTRIBUTES BYTEA DEFAULT NULL, + UUID VARCHAR(256), + PRIMARY KEY(UUID), + UNIQUE(NAME, ORGANIZATION) + ); + + CREATE TABLE BLOCK_CONDITION ( + TYPE varchar(45) DEFAULT NULL, + BLOCK_CONDITION varchar(512) DEFAULT NULL, + ENABLED varchar(45) DEFAULT NULL, + ORGANIZATION varchar(100) DEFAULT NULL, + UUID VARCHAR(256), + PRIMARY KEY (UUID) + ); + + CREATE TABLE APPLICATION_GROUP_MAPPING ( + APPLICATION_UUID VARCHAR(256) NOT NULL, + GROUP_ID VARCHAR(512) NOT NULL, + ORGANIZATION VARCHAR(100) DEFAULT NULL, + PRIMARY KEY (APPLICATION_UUID,GROUP_ID,ORGANIZATION), + FOREIGN KEY (APPLICATION_UUID) REFERENCES APPLICATION(UUID) ON DELETE CASCADE ON UPDATE CASCADE + ); + + CREATE TABLE IF NOT EXISTS APPLICATION_ATTRIBUTES ( + APPLICATION_UUID VARCHAR(256) NOT NULL, + NAME VARCHAR(255) NOT NULL, + APP_ATTRIBUTE VARCHAR(1024) NOT NULL, + ORGANIZATION VARCHAR(100) NOT NULL, + PRIMARY KEY(APPLICATION_UUID,NAME), + FOREIGN KEY(APPLICATION_UUID) REFERENCES APPLICATION(UUID) ON + DELETE CASCADE ON UPDATE CASCADE + ); + + CREATE TABLE IF NOT EXISTS API_CATEGORIES ( + UUID VARCHAR(50), + NAME VARCHAR(255), + DESCRIPTION VARCHAR(1024), + ORGANIZATION VARCHAR(100), + UNIQUE(NAME,ORGANIZATION), + PRIMARY KEY(UUID) + ); + + CREATE TABLE IF NOT EXISTS ORGANIZATION ( + UUID VARCHAR(50), + NAME VARCHAR(255), + DISPLAY_NAME VARCHAR(255), + STATUS BOOLEAN NOT NULL DEFAULT 'TRUE', + NAMESPACE JSONB, + WORKFLOWS BYTEA, + UNIQUE(NAME), + PRIMARY KEY(UUID) + ); + + CREATE TABLE IF NOT EXISTS ORGANIZATION_CLAIM_MAPPING ( + UUID VARCHAR(50), + CLAIM_KEY VARCHAR(255), + CLAIM_VALUE VARCHAR(255), + FOREIGN KEY(UUID) REFERENCES ORGANIZATION(UUID) ON UPDATE CASCADE ON DELETE CASCADE, + UNIQUE(UUID,CLAIM_KEY) + ); + + CREATE TABLE IF NOT EXISTS ORGANIZATION_VHOST ( + UUID VARCHAR(50), + VHOST VARCHAR(255), + TYPE VARCHAR(50), + FOREIGN KEY(UUID) REFERENCES ORGANIZATION(UUID) ON UPDATE CASCADE ON DELETE CASCADE, + UNIQUE(UUID, VHOST, TYPE) + ); + + CREATE TABLE IF NOT EXISTS WORKFLOWS( + UUID VARCHAR(255) NOT NULL , + WF_REFERENCE VARCHAR(255) NOT NULL, + WF_TYPE VARCHAR(255) NOT NULL, + WF_STATUS VARCHAR(255) NOT NULL, + WF_CREATED_TIME TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + WF_UPDATED_TIME TIMESTAMP DEFAULT CURRENT_TIMESTAMP , + ORGANIZATION VARCHAR(255), + PRIMARY KEY (UUID) + ); + + CREATE TABLE IF NOT EXISTS KEY_MANAGER ( + UUID VARCHAR(100) NOT NULL, + NAME VARCHAR(100) NULL, + DISPLAY_NAME VARCHAR(100) NULL, + ISSUER VARCHAR(100) NOT NULL, + DESCRIPTION VARCHAR(256) NULL, + TYPE VARCHAR(45) NULL, + CONFIGURATION BYTEA NULL, + ENABLED BOOLEAN DEFAULT '1', + ORGANIZATION VARCHAR(100) NULL, + PRIMARY KEY(UUID), + UNIQUE(NAME,ORGANIZATION) + ); + + -- End of APK Tables -- + + -- Performance indexes start-- + + create index IDX_AI_CTX on API (CONTEXT); + create index IDX_AI_ORG on API (ORGANIZATION); + create index IDX_AKM_CK on APPLICATION_KEY_MAPPING (CONSUMER_KEY); + create index IDX_AUM_AI on API_URL_MAPPING (API_UUID); + -- create index IDX_AUM_TT on API_URL_MAPPING (THROTTLING_TIER); -- + create index IDX_BP_QT on BUSINESS_PLAN (QUOTA_TYPE); + create index IDX_S_AITIAI on SUBSCRIPTION (API_UUID,TIER_ID,APPLICATION_UUID); + create index IDX_AUP_QT on APPLICATION_USAGE_PLAN (QUOTA_TYPE); + create index IDX_A_AT_CB on APPLICATION (APPLICATION_TIER,CREATED_BY); + create index IDX_SUB_APP_ID on SUBSCRIPTION (APPLICATION_UUID, UUID); + + GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO wso2carbon; + GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO wso2carbon; + GRANT ALL PRIVILEGES ON ALL FUNCTIONS IN SCHEMA public TO wso2carbon; + + -- Insert Initial APK data --- + INSERT INTO RESOURCE_CATEGORIES (RESOURCE_CATEGORY) VALUES ('Thumbnail'); + INSERT INTO RESOURCE_CATEGORIES (RESOURCE_CATEGORY) VALUES ('Document'); + -- End Insert Initial APK data + + -- Insert Demo APK data --- + INSERT INTO INTERNAL_USER(uuid, IDP_USER_NAME) VALUES ( 'apkuser', 'apkuser'); + INSERT INTO organization(uuid, name, display_name, status, workflows) VALUES ( 'a3b58ccf-6ecc-4557-b5bb-0a35cce38256', 'default', 'default', true, ''); + INSERT INTO organization_claim_mapping(uuid, claim_key, claim_value) VALUES ( 'a3b58ccf-6ecc-4557-b5bb-0a35cce38256', 'organizationClaimValue', 'default'); + -- End Insert Demo APK data -- Insert Non Prod IDP table -- CREATE TABLE CONSUMER_APPS ( CONSUMER_KEY VARCHAR(255), diff --git a/helm-charts/values.yaml b/helm-charts/values.yaml index e71839d3e..82a70ec00 100644 --- a/helm-charts/values.yaml +++ b/helm-charts/values.yaml @@ -44,6 +44,108 @@ wso2: # jwksEndpoint: "https://idp.am.wso2.com:9095/oauth2/jwks" # secretName: "wso2apk-idp-signing" # fileName: "idp.crt" + cp: + enabled: true + database: + driver: "org.postgresql.Driver" + url: "jdbc:postgresql://wso2apk-db-service:5432/WSO2AM_DB" + host: "wso2apk-db-service" + port: 5432 + databaseName: "WSO2AM_DB" + username: "wso2carbon" + secretName: "apk-db-secret" + secretKey: "DB_PASSWORD" + validationQuery: "SELECT 1" + validationTimeout: 250 + devportal: + deployment: + resources: + requests: + memory: "128Mi" + cpu: "100m" + limits: + memory: "1028Mi" + cpu: "1000m" + readinessProbe: + initialDelaySeconds: 20 + periodSeconds: 20 + failureThreshold: 5 + livenessProbe: + initialDelaySeconds: 20 + periodSeconds: 20 + failureThreshold: 5 + strategy: Recreate + replicas: 1 + imagePullPolicy: Always + image: wso2/devportal-domain-service:0.0.1-m11 + admin: + deployment: + resources: + requests: + memory: "128Mi" + cpu: "100m" + limits: + memory: "1028Mi" + cpu: "1000m" + readinessProbe: + initialDelaySeconds: 20 + periodSeconds: 20 + failureThreshold: 5 + livenessProbe: + initialDelaySeconds: 20 + periodSeconds: 20 + failureThreshold: 5 + strategy: Recreate + replicas: 1 + imagePullPolicy: Always + image: wso2/admin-domain-service:0.0.1-m11 + backoffice: + deployment: + resources: + requests: + memory: "128Mi" + cpu: "100m" + limits: + memory: "1028Mi" + cpu: "1000m" + readinessProbe: + initialDelaySeconds: 20 + periodSeconds: 20 + failureThreshold: 5 + livenessProbe: + initialDelaySeconds: 20 + periodSeconds: 20 + failureThreshold: 5 + strategy: Recreate + replicas: 1 + imagePullPolicy: Always + image: wso2/backoffice-domain-service:0.0.1-m11 + managementServer: + deployment: + resources: + requests: + memory: "128Mi" + cpu: "100m" + limits: + memory: "1028Mi" + cpu: "1000m" + strategy: Recreate + replicas: 1 + imagePullPolicy: Always + image: wso2/management-server:0.0.1-m11 + readinessProbe: + initialDelaySeconds: 20 + periodSeconds: 20 + failureThreshold: 5 + livenessProbe: + initialDelaySeconds: 20 + periodSeconds: 20 + failureThreshold: 5 + # configs: + # tls: + # secretName: "management-server-cert" + # certKeyFilename: "tls.key" + # certFilename: "certchain.crt" dp: enabled: true gateway: diff --git a/helm-charts/values.yaml.template b/helm-charts/values.yaml.template index da4001486..ce3189828 100644 --- a/helm-charts/values.yaml.template +++ b/helm-charts/values.yaml.template @@ -68,6 +68,178 @@ wso2: secretName: "" # -- IDP jwt signing certificate file name fileName: "" + cp: + # -- Enabled control plane. + enabled: true + database: + # -- Database Driver class. + driver: "org.postgresql.Driver" + # -- Database URL. + url: "jdbc:postgresql://wso2apk-db-service:5432/WSO2AM_DB" + # -- Database Host. + host: "wso2apk-db-service" + # -- Database Port. + port: 5432 + # -- Database Name. + databaseName: "WSO2AM_DB" + # -- Database Username. + username: "wso2carbon" + # -- Database Password secret name. + secretName: "apk-db-secret" + # -- Database Password secret key. + secretKey: "DB_PASSWORD" + # -- Database validation query. + validationQuery: "SELECT 1" + # -- Database validation timeout in ms. + validationTimeout: 250 + devportal: + deployment: + resources: + requests: + # -- CPU request for the container + memory: "128Mi" + # -- Memory request for the container + cpu: "100m" + limits: + # -- CPU limit for the container + memory: "1028Mi" + # -- Memory limit for the container + cpu: "1000m" + readinessProbe: + # -- Number of seconds after the container has started before liveness probes are initiated. + initialDelaySeconds: 20 + # -- How often (in seconds) to perform the probe. + periodSeconds: 20 + # -- Minimum consecutive failures for the probe to be considered failed after having succeeded. + failureThreshold: 5 + livenessProbe: + # -- Number of seconds after the container has started before liveness probes are initiated. + initialDelaySeconds: 20 + # -- How often (in seconds) to perform the probe. + periodSeconds: 20 + # -- Minimum consecutive failures for the probe to be considered failed after having succeeded. + failureThreshold: 5 + # -- Deployment strategy + strategy: Recreate + # -- Number of replicas + replicas: 1 + # -- Image pull policy + imagePullPolicy: Always + # -- Image + image: wso2/devportal-domain-service:latest + admin: + deployment: + resources: + requests: + # -- CPU request for the container + memory: "128Mi" + # -- Memory request for the container + cpu: "100m" + limits: + # -- CPU limit for the container + memory: "1028Mi" + # -- Memory limit for the container + cpu: "1000m" + readinessProbe: + # -- Number of seconds after the container has started before liveness probes are initiated. + initialDelaySeconds: 20 + # -- How often (in seconds) to perform the probe. + periodSeconds: 20 + # -- Minimum consecutive failures for the probe to be considered failed after having succeeded. + failureThreshold: 5 + livenessProbe: + # -- Number of seconds after the container has started before liveness probes are initiated. + initialDelaySeconds: 20 + # -- How often (in seconds) to perform the probe. + periodSeconds: 20 + # -- Minimum consecutive failures for the probe to be considered failed after having succeeded. + failureThreshold: 5 + # -- Deployment strategy + strategy: Recreate + # -- Number of replicas + replicas: 1 + # -- Image pull policy + imagePullPolicy: Always + # -- Image + image: wso2/admin-domain-service:latest + backoffice: + deployment: + resources: + requests: + # -- CPU request for the container + memory: "128Mi" + # -- Memory request for the container + cpu: "100m" + limits: + # -- CPU limit for the container + memory: "1028Mi" + # -- Memory limit for the container + cpu: "1000m" + readinessProbe: + # -- Number of seconds after the container has started before liveness probes are initiated. + initialDelaySeconds: 20 + # -- How often (in seconds) to perform the probe. + periodSeconds: 20 + # -- Minimum consecutive failures for the probe to be considered failed after having succeeded. + failureThreshold: 5 + livenessProbe: + # -- Number of seconds after the container has started before liveness probes are initiated. + initialDelaySeconds: 20 + # -- How often (in seconds) to perform the probe. + periodSeconds: 20 + # -- Minimum consecutive failures for the probe to be considered failed after having succeeded. + failureThreshold: 5 + # -- Deployment strategy + strategy: Recreate + # -- Number of replicas + replicas: 1 + # -- Image pull policy + imagePullPolicy: Always + # -- Image + image: wso2/backoffice-domain-service:latest + managementServer: + deployment: + resources: + requests: + # -- CPU request for the container + memory: "128Mi" + # -- Memory request for the container + cpu: "100m" + limits: + # -- CPU limit for the container + memory: "1028Mi" + # -- Memory limit for the container + cpu: "1000m" + # -- Deployment strategy + strategy: Recreate + # -- Number of replicas + replicas: 1 + # -- Image pull policy + imagePullPolicy: Always + # -- Image + image: wso2/management-server:0.0.1-m8 + readinessProbe: + # -- Number of seconds after the container has started before liveness probes are initiated. + initialDelaySeconds: 20 + # -- How often (in seconds) to perform the probe. + periodSeconds: 20 + # -- Minimum consecutive failures for the probe to be considered failed after having succeeded. + failureThreshold: 5 + livenessProbe: + # -- Number of seconds after the container has started before liveness probes are initiated. + initialDelaySeconds: 20 + # -- How often (in seconds) to perform the probe. + periodSeconds: 20 + # -- Minimum consecutive failures for the probe to be considered failed after having succeeded. + failureThreshold: 5 + configs: + tls: + # -- TLS secret name + secretName: "management-server-cert" + # -- TLS key file name + certKeyFilename: "tls.key" + # -- TLS certificate file name + certFilename: "certchain.crt" dp: # -- Enable the deployment of the Data Plane enabled: true diff --git a/management-server/Dockerfile b/management-server/Dockerfile new file mode 100644 index 000000000..abed2c66a --- /dev/null +++ b/management-server/Dockerfile @@ -0,0 +1,68 @@ +# -------------------------------------------------------------------- +# Copyright (c) 2022, WSO2 LLC. (http://wso2.com) All Rights Reserved. +# +# 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. +# ----------------------------------------------------------------------- + +FROM alpine:3.17.2 +LABEL maintainer="WSO2 Docker Maintainers " + +RUN apk update && apk upgrade --no-cache +RUN apk add --no-cache tzdata + +ENV LANG=C.UTF-8 + +ARG APK_USER=wso2 +ARG APK_USER_ID=802 +ARG APK_USER_GROUP=wso2 +ARG APK_USER_GROUP_ID=802 +ARG APK_USER_HOME=/home/${APK_USER} +ARG GRPC_HEALTH_PROBE_PATH=/bin/grpc_health_probe +ARG TARGETARCH +ENV MGT_SERVER_PRIVATE_KEY_PATH=/home/wso2/security/keystore/mg.key +ENV MGT_SERVER_PUBLIC_CERT_PATH=/home/wso2/security/keystore/mg.pem +ARG CHECKSUM_AMD64="c72704c9cd49fb18f8df28de26e29c2563b6515e38efee65a6c3a29ec7368a91" +ARG CHECKSUM_ARM64="a7b42093b702ea83f4dcbd1dd74e4085c118fe93b9cfd3f205e48506a9ac94a0" + +ARG MOTD="\n\ + Welcome to WSO2 Docker Resources \n\ + --------------------------------- \n\ + This Docker container comprises of a WSO2 product, running with its latest GA release \n\ + which is under the Apache License, Version 2.0. \n\ + Read more about Apache License, Version 2.0 here @ http://www.apache.org/licenses/LICENSE-2.0.\n" + +RUN \ + addgroup -S -g ${APK_USER_GROUP_ID} ${APK_USER_GROUP} \ + && adduser -S -u ${APK_USER_ID} -h ${APK_USER_HOME} -G ${APK_USER_GROUP} ${APK_USER} \ + && mkdir ${APK_USER_HOME}/logs && mkdir -p ${APK_USER_HOME}/artifacts/apis \ + && chown -R ${APK_USER}:${APK_USER_GROUP} ${APK_USER_HOME} \ + && echo '[ ! -z "${TERM}" -a -r /etc/motd ] && cat /etc/motd' >> /etc/bash.bashrc; echo "${MOTD}" > /etc/motd + +RUN \ + wget -q https://github.com/grpc-ecosystem/grpc-health-probe/releases/download/v0.4.16/grpc_health_probe-linux-${TARGETARCH} \ + && mv grpc_health_probe-linux-${TARGETARCH} ${GRPC_HEALTH_PROBE_PATH}\ + && if [ "${TARGETARCH}" = "amd64" ]; then echo "${CHECKSUM_AMD64} ${GRPC_HEALTH_PROBE_PATH}" | sha256sum -c -; fi + +RUN \ + chmod +x ${GRPC_HEALTH_PROBE_PATH} \ + && chown ${APK_USER}:${APK_USER_GROUP} ${GRPC_HEALTH_PROBE_PATH} + +WORKDIR ${APK_USER_HOME} +USER ${APK_USER} + +COPY resources/conf/config.toml conf/ +COPY resources/conf/log_config.toml conf/ +COPY ./${TARGETARCH}/main mgt_server +COPY resources/check_health.sh . + +CMD ./mgt_server diff --git a/management-server/README.md b/management-server/README.md new file mode 100644 index 000000000..49a17f6a9 --- /dev/null +++ b/management-server/README.md @@ -0,0 +1 @@ +## Management Server \ No newline at end of file diff --git a/management-server/build.gradle b/management-server/build.gradle new file mode 100644 index 000000000..d312288b3 --- /dev/null +++ b/management-server/build.gradle @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2022, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. + * + * 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. + * + */ + +plugins { + id 'net.researchgate.release' version '2.8.0' +} + +apply from: "$rootDir/../common-gradle-scripts/docker.gradle" +apply from: "$rootDir/../common-gradle-scripts/go.gradle" + +release { + tagTemplate = 'management-server-$version' + + git { + requireBranch= "main" + pushToRemote= "origin" + } +} + +allprojects { + group = project.group + version = project.version +} + +tasks.named('go_revive_run').configure { + finalizedBy go_tidy +} + +tasks.named('go_build').configure { + dependsOn go_revive_run + dependsOn go_vet + finalizedBy docker_build +} + +task build{ + dependsOn go_build + dependsOn docker_build +} + +afterReleaseBuild.dependsOn "docker_push" \ No newline at end of file diff --git a/management-server/cmd/main.go b/management-server/cmd/main.go new file mode 100644 index 000000000..9b10a9e5b --- /dev/null +++ b/management-server/cmd/main.go @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2022, WSO2 LLC. (http://www.wso2.org). + * + * 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. + * + */ + +package main + +import ( + "os" + "os/signal" + + "github.com/wso2/apk/management-server/internal/database" + server "github.com/wso2/apk/management-server/internal/grpc-server" + "github.com/wso2/apk/management-server/internal/logger" + "github.com/wso2/apk/management-server/internal/notification" + "github.com/wso2/apk/management-server/internal/synchronizer" + "github.com/wso2/apk/management-server/internal/xds" +) + +func main() { + logger.LoggerServer.Info("Starting Management server ...") + sig := make(chan os.Signal, 1) + signal.Notify(sig, os.Interrupt) + // connect to the postgres database + database.ConnectToDB() + defer database.CloseDBConn() + go xds.InitAPKMgtServer() + + go synchronizer.ProcessApplicationEvents() + go synchronizer.ProcessSubscriptionEvents() + go server.StartGRPCServer() + go notification.StartGRPCServer() + +OUTER: + for { + select { + case s := <-sig: + switch s { + case os.Interrupt: + break OUTER + } + } + } +} diff --git a/management-server/go.mod b/management-server/go.mod new file mode 100644 index 000000000..ad5e3208a --- /dev/null +++ b/management-server/go.mod @@ -0,0 +1,32 @@ +module github.com/wso2/apk/management-server + +go 1.19 + +require ( + github.com/envoyproxy/go-control-plane v0.11.0 + github.com/jackc/pgx/v5 v5.3.1 + github.com/pelletier/go-toml v1.9.5 + github.com/sirupsen/logrus v1.9.0 + github.com/wso2/apk/adapter v0.0.0-20230313062104-25216c8acbc5 + google.golang.org/grpc v1.53.0 + google.golang.org/protobuf v1.29.0 +) + +replace github.com/wso2/apk/adapter => ../adapter + +require ( + github.com/census-instrumentation/opencensus-proto v0.4.1 // indirect + github.com/cncf/xds/go v0.0.0-20230310173818-32f1caf87195 // indirect + github.com/envoyproxy/protoc-gen-validate v0.9.1 // indirect + github.com/golang/protobuf v1.5.3 // indirect + github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect + github.com/jackc/puddle/v2 v2.2.0 // indirect + golang.org/x/crypto v0.7.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sync v0.1.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect + gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect +) diff --git a/management-server/go.sum b/management-server/go.sum new file mode 100644 index 000000000..57cf04313 --- /dev/null +++ b/management-server/go.sum @@ -0,0 +1,100 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/census-instrumentation/opencensus-proto v0.4.1 h1:iKLQ0xPNFxR/2hzXZMrBo8f1j86j5WHzznCCQxV/b8g= +github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/xds/go v0.0.0-20230310173818-32f1caf87195 h1:58f1tJ1ra+zFINPlwLWvQsR9CzAKt2e+EWV2yX9oXQ4= +github.com/cncf/xds/go v0.0.0-20230310173818-32f1caf87195/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +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/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.11.0 h1:jtLewhRR2vMRNnq2ZZUoCjUlgut+Y0+sDDWPOfwOi1o= +github.com/envoyproxy/go-control-plane v0.11.0/go.mod h1:VnHyVMpzcLvCFt9yUz1UnCwHLhwx1WguiVDV7pTG/tI= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/envoyproxy/protoc-gen-validate v0.9.1 h1:PS7VIOgmSVhWUEeZwTe7z7zouA22Cr590PzXKbZHOVY= +github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= +github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.3.1 h1:Fcr8QJ1ZeLi5zsPZqQeUZhNhxfkkKBOgJuYkJHoBOtU= +github.com/jackc/pgx/v5 v5.3.1/go.mod h1:t3JDKnCBlYIc0ewLF0Q7B8MXmoIaBOZj/ic7iHozM/8= +github.com/jackc/puddle/v2 v2.2.0 h1:RdcDk92EJBuBS55nQMMYFXTxwstHug4jkhT5pq8VxPk= +github.com/jackc/puddle/v2 v2.2.0/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= +github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= +github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +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/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= +golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.29.0 h1:44S3JjaKmLEE4YIkjzexaP+NzZsudE3Zin5Njn/pYX0= +google.golang.org/protobuf v1.29.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= +gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/management-server/gradle.properties b/management-server/gradle.properties new file mode 100644 index 000000000..ecfbd3b37 --- /dev/null +++ b/management-server/gradle.properties @@ -0,0 +1,4 @@ +group=org.wso2.apk +version=0.0.1-SNAPSHOT +file=cmd/main.go +docker_image_name=management-server diff --git a/management-server/gradle/wrapper/gradle-wrapper.properties b/management-server/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..ae04661ee --- /dev/null +++ b/management-server/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/management-server/gradlew b/management-server/gradlew new file mode 100755 index 000000000..a69d9cb6c --- /dev/null +++ b/management-server/gradlew @@ -0,0 +1,240 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# 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 +# +# https://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. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/management-server/gradlew.bat b/management-server/gradlew.bat new file mode 100644 index 000000000..f127cfd49 --- /dev/null +++ b/management-server/gradlew.bat @@ -0,0 +1,91 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/management-server/internal/backoffice/api_crud.go b/management-server/internal/backoffice/api_crud.go new file mode 100644 index 000000000..0bd87b074 --- /dev/null +++ b/management-server/internal/backoffice/api_crud.go @@ -0,0 +1,109 @@ +package backoffice + +import ( + "bytes" + "crypto/tls" + "encoding/json" + "fmt" + "net/http" + "time" + + apiProtos "github.com/wso2/apk/adapter/pkg/discovery/api/wso2/discovery/service/apkmgt" + "github.com/wso2/apk/adapter/pkg/utils/tlsutils" + "github.com/wso2/apk/management-server/internal/config" + "github.com/wso2/apk/management-server/internal/logger" +) + +// Back Office client connetion +var backOfficeClient *http.Client + +type api struct { + ID string `json:"id"` + Name string `json:"name"` + Context string `json:"context"` + Version string `json:"version"` + Provider string `json:"provider"` + OrganizationID string `json:"organization"` + LifeCycleStatus string `json:"LifeCycleStatus"` +} + +type definition interface{} + +type requestData struct { + APIProperties api `json:"apiProperties"` + Definition definition `json:"Definition"` +} + +func init() { + _, _, truststoreLocation := tlsutils.GetKeyLocations() + caCertPool := tlsutils.GetTrustedCertPool(truststoreLocation) + transport := &http.Transport{ + MaxIdleConns: 2, + IdleConnTimeout: 30 * time.Second, + TLSClientConfig: &tls.Config{RootCAs: caCertPool}, + } + backOfficeClient = &http.Client{Transport: transport} +} + +func getBackOfficeURL() string { + conf := config.ReadConfigs() + logger.LoggerMGTServer.Infof("backoffice service: https://%s:%d%s", conf.BackOffice.Host, conf.BackOffice.Port, conf.BackOffice.ServiceBasePath) + return fmt.Sprintf("https://%s:%d%s", conf.BackOffice.Host, conf.BackOffice.Port, conf.BackOffice.ServiceBasePath) +} + +func composeRequestBody(api *apiProtos.API) requestData { + request := new(requestData) + request.APIProperties.ID = api.Uuid + request.APIProperties.Name = api.Name + request.APIProperties.Context = api.Context + request.APIProperties.Version = api.Version + request.APIProperties.Provider = api.Provider + request.APIProperties.OrganizationID = api.OrganizationId + json.Unmarshal([]byte(api.Definition), &request.Definition) + return *request +} + +// CreateAPI creates an API by invoking backoffice service +func CreateAPI(api *apiProtos.API) error { + postBody, _ := json.Marshal(composeRequestBody(api)) + requestBody := bytes.NewBuffer(postBody) + _, err := backOfficeClient.Post(getBackOfficeURL(), "application/json", requestBody) + if err != nil { + return err + } + return nil +} + +// UpdateAPI updates an API by invoking backoffice service +func UpdateAPI(api *apiProtos.API) error { + putBody, _ := json.Marshal(composeRequestBody(api)) + requestBody := bytes.NewBuffer(putBody) + putRequest, err := http.NewRequest(http.MethodPut, fmt.Sprintf("%s/%s", getBackOfficeURL(), api.Uuid), requestBody) + if err != nil { + return err + } + + // Perform the HTTP request and check the response status code + response, err := backOfficeClient.Do(putRequest) + if err != nil { + return err + } + defer response.Body.Close() + + if response.StatusCode == http.StatusNotFound { + // If the status code indicates an 404, call the create API to create the API in database. + // This is done to handle the case where the API is not in the database due to managemnt server failure. + CreateAPI(api) + } + return nil +} + +// DeleteAPI deletes an API by invoking backoffice service +func DeleteAPI(api *apiProtos.API) error { + deleteRequest, err := http.NewRequest(http.MethodDelete, fmt.Sprintf("%s/%s", getBackOfficeURL(), api.Uuid), nil) + _, err = backOfficeClient.Do(deleteRequest) + if err != nil { + return err + } + return nil +} diff --git a/management-server/internal/config/default_config.go b/management-server/internal/config/default_config.go new file mode 100644 index 000000000..9e740ad25 --- /dev/null +++ b/management-server/internal/config/default_config.go @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2022, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * + * 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. + * + */ + +package config + +// Configuration object which is populated with default values. +var defaultConfig = &Config{ + ManagementServer: managementServer{ + XDSPort: 18000, + NodeLabels: []string{"default"}, + GRPCPort: 8765, + NotificationPort: 8766, + }, + Database: database{ + Name: "WSO2AM_DB", + Username: "wso2carbon", + Password: "wso2carbon", + Host: "wso2apk-db-service", + Port: 5432, + PoolOptions: dbPool{ + PoolMaxConns: 4, + PoolMinConns: 0, + PoolMaxConnLifetime: "1h", + PoolMaxConnIdleTime: "1h", + PoolHealthCheckPeriod: "1m", + PoolMaxConnLifetimeJitter: "1s", + }, + DbCache: dbCache{ + CleanupInterval: "1h", + TTL: "1h", + }, + }, + BackOffice: backOffice{ + Host: "localhost", + Port: 9443, + ServiceBasePath: "/api/backoffice/internal/apis", + }, +} diff --git a/management-server/internal/config/parser.go b/management-server/internal/config/parser.go new file mode 100644 index 000000000..453e458ae --- /dev/null +++ b/management-server/internal/config/parser.go @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2022, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * + * 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. + * + */ + +package config + +import ( + "fmt" + "io/ioutil" + "os" + "reflect" + "sync" + + toml "github.com/pelletier/go-toml" + "github.com/wso2/apk/adapter/pkg/config" + "github.com/wso2/apk/adapter/pkg/logging" + "github.com/wso2/apk/management-server/internal/logger" +) + +var ( + onceConfigRead sync.Once + mgwHome string + managementServerConfig *Config +) + +// constants related to utility functions +const ( + // RelativeConfigPath is the relative file path where the configuration file is. + relativeConfigPath = "/conf/config.toml" +) + +// ReadConfigs implements adapter configuration read operation. The read operation will happen only once, hence +// the consistancy is ensured. +// +// If the "APK_HOME" variable is set, the configuration file location would be picked relative to the +// variable's value ("/conf/config.toml"). otherwise, the "APK_HOME" variable would be set to the directory +// from where the executable is called from. +// +// Returns the configuration object mapped from the configuration file during the startup. +func ReadConfigs() *Config { + managementServerConfig := defaultConfig + onceConfigRead.Do(func() { + mgwHome = config.GetApkHome() + _, err := os.Stat(mgwHome + relativeConfigPath) + if err != nil { + logger.LoggerMGTServer.ErrorC(logging.ErrorDetails{ + Message: fmt.Sprintf("Configuration file not found. Error: %v", err), + Severity: logging.BLOCKER, + ErrorCode: 1202, + }) + } + content, readErr := ioutil.ReadFile(mgwHome + relativeConfigPath) + if readErr != nil { + logger.LoggerMGTServer.ErrorC(logging.ErrorDetails{ + Message: fmt.Sprintf("Error reading configurations. Error: %v", readErr), + Severity: logging.BLOCKER, + ErrorCode: 1203, + }) + } + parseErr := toml.Unmarshal(content, managementServerConfig) + if parseErr != nil { + logger.LoggerMGTServer.ErrorC(logging.ErrorDetails{ + Message: fmt.Sprintf("Error parsing the configuration. Error: %v ", parseErr), + Severity: logging.BLOCKER, + ErrorCode: 1204, + }) + } + // Resolve environment variables. + config.ResolveConfigEnvValues(reflect.ValueOf(&(managementServerConfig.ManagementServer)).Elem(), "ManagementServer", true) + config.ResolveConfigEnvValues(reflect.ValueOf(&(managementServerConfig.Database)).Elem(), "Database", true) + }) + return managementServerConfig +} diff --git a/management-server/internal/config/types.go b/management-server/internal/config/types.go new file mode 100644 index 000000000..beb05e8b6 --- /dev/null +++ b/management-server/internal/config/types.go @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2022, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * + * 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. + * + */ + +package config + +// Config represents the adapter configuration. +// It is created directly from the configuration toml file. +type Config struct { + ManagementServer managementServer + Database database + BackOffice backOffice +} + +type managementServer struct { + XDSPort int32 `toml:"xdsPort"` + NodeLabels []string `toml:"nodeLabels"` + GRPCPort uint `toml:"gRPCPort"` + NotificationPort uint `toml:"notificationPort"` + Keystore keystore `toml:"keystore"` + Truststore truststore `toml:"truststore"` +} + +type keystore struct { + KeyPath string + CertPath string +} +type truststore struct { + Location string +} + +type backOffice struct { + Host string + Port int + ServiceBasePath string +} + +type database struct { + Name string + Username string + Password string + Host string + Port int + PoolOptions dbPool + DbCache dbCache +} + +type dbCache struct { + CleanupInterval string + TTL string +} + +type dbPool struct { + // PoolMaxConns is the maximum size of the pool. The default is the greater of 4 or runtime.NumCPU() + PoolMaxConns int + + // PoolMinConns is the minimum size of the pool. After connection closes, the pool might dip below MinConns. A low + // number of MinConns might mean the pool is empty after MaxConnLifetime until the health check has a chance + // to create new connections. + PoolMinConns int + + // PoolMaxConnLifetime is the duration since creation after which a connection will be automatically closed. + PoolMaxConnLifetime string + + // PoolMaxConnIdleTime is the duration after which an idle connection will be automatically closed by the health check. + PoolMaxConnIdleTime string + + // HealthCheckPeriod is the duration between checks of the health of idle connections. + PoolHealthCheckPeriod string + + // PoolMaxConnLifetimeJitter is the duration after MaxConnLifetime to randomly decide to close a connection. + // This helps prevent all connections from being closed at the exact same time, starving the pool. + PoolMaxConnLifetimeJitter string +} diff --git a/management-server/internal/database/app_cache.go b/management-server/internal/database/app_cache.go new file mode 100644 index 000000000..43c13d4f6 --- /dev/null +++ b/management-server/internal/database/app_cache.go @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2022, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 LLC. licenses this file to you 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. + */ + +package database + +import ( + "errors" + "sync" + "time" + + apkmgt "github.com/wso2/apk/adapter/pkg/discovery/api/wso2/discovery/apkmgt" + "github.com/wso2/apk/management-server/internal/config" + "github.com/wso2/apk/management-server/internal/logger" +) + +// CachedApplication is an application with an expiry timestamp +type CachedApplication struct { + application *apkmgt.Application + expireAtTimestamp int64 +} + +// ApplicationLocalCache is data holder for cached applications +type ApplicationLocalCache struct { + stop chan struct{} + + wg sync.WaitGroup + mu sync.RWMutex + apps map[string]CachedApplication +} + +var cleanupInterval time.Duration +var ttl time.Duration + +func init() { + conf := config.ReadConfigs() + cleanupInterval, _ = time.ParseDuration(conf.Database.DbCache.CleanupInterval) + ttl, _ = time.ParseDuration(conf.Database.DbCache.TTL) + DbCache = NewApplicationLocalCache(cleanupInterval) +} + +// NewApplicationLocalCache creates an application local cache +func NewApplicationLocalCache(cleanupInterval time.Duration) *ApplicationLocalCache { + lc := &ApplicationLocalCache{ + apps: make(map[string]CachedApplication), + stop: make(chan struct{}), + } + + lc.wg.Add(1) + go func(cleanupInterval time.Duration) { + defer lc.wg.Done() + lc.cleanupLoop(cleanupInterval) + }(cleanupInterval) + return lc +} + +func (lc *ApplicationLocalCache) cleanupLoop(interval time.Duration) { + t := time.NewTicker(interval) + defer t.Stop() + + for { + select { + case <-lc.stop: + return + case <-t.C: + lc.mu.Lock() + for uid, cu := range lc.apps { + if cu.expireAtTimestamp <= time.Now().Unix() { + delete(lc.apps, uid) + } + } + lc.mu.Unlock() + } + } +} + +func (lc *ApplicationLocalCache) stopCleanup() { + close(lc.stop) + lc.wg.Wait() +} + +// Update updates the expiry timestamp of an existing application in the cache +func (lc *ApplicationLocalCache) Update(u *apkmgt.Application, expireAtTimestamp int64) { + lc.mu.Lock() + defer lc.mu.Unlock() + + lc.apps[u.Uuid] = CachedApplication{ + application: u, + expireAtTimestamp: expireAtTimestamp, + } + logger.LoggerDatabase.Infof("Cache updated successfully.. cache: %v", lc.apps) +} + +// UpdateSubscriptionInApplication updates the subscription of an application in the cache +func (lc *ApplicationLocalCache) UpdateSubscriptionInApplication(appUUID string, s *apkmgt.Subscription) error { + if app, ok := lc.apps[appUUID]; ok { + for i, sub := range app.application.Subscriptions { + if sub.Uuid == s.Uuid { + lc.apps[appUUID].application.Subscriptions[i] = s + return nil + } + } + app.expireAtTimestamp = time.Now().Unix() + ttl.Microseconds() + } else { + return ErrApplicationNotInCache + } + return ErrSubscriptionNotInAppCache +} + +// AddSubscriptionForApplication adds a subscription to an application in the cache +func (lc *ApplicationLocalCache) AddSubscriptionForApplication(appUUID string, s *apkmgt.Subscription) error { + if app, ok := lc.apps[appUUID]; ok { + app.application.Subscriptions = append(app.application.Subscriptions, s) + app.expireAtTimestamp = time.Now().Unix() + ttl.Microseconds() + return nil + } + return ErrApplicationNotInCache +} + +// DeleteSubscriptionFromApplication deletes a subscription from an application in the cache +func (lc *ApplicationLocalCache) DeleteSubscriptionFromApplication(appUUID, subUUID string) error { + if app, ok := lc.apps[appUUID]; ok { + for i, sub := range app.application.Subscriptions { + if sub.Uuid == subUUID { + app.application.Subscriptions[i] = app.application.Subscriptions[len(app.application.Subscriptions)-1] + app.application.Subscriptions = app.application.Subscriptions[:len(app.application.Subscriptions)-1] + return nil + } + } + app.expireAtTimestamp = time.Now().Unix() + ttl.Microseconds() + } else { + return ErrApplicationNotInCache + } + return ErrSubscriptionNotInAppCache +} + +var ( + // ErrApplicationNotInCache is the error returned when application is not present in the cache + ErrApplicationNotInCache = errors.New("unable to find application in cache") + // ErrSubscriptionNotInAppCache is the error returned when subscription is not present in the cache + ErrSubscriptionNotInAppCache = errors.New("unable to find subscription in application cache") +) + +// Read returns an applicaiton found in the in the cache with the given application id +func (lc *ApplicationLocalCache) Read(id string) (*apkmgt.Application, error) { + lc.mu.RLock() + defer lc.mu.RUnlock() + + cu, ok := lc.apps[id] + if !ok { + return &apkmgt.Application{}, ErrApplicationNotInCache + } + + return cu.application, nil +} + +// ReadAll returns all the applications in the cache +func (lc *ApplicationLocalCache) ReadAll() ([]*apkmgt.Application, error) { + var apps []*apkmgt.Application + + for _, app := range lc.apps { + apps = append(apps, app.application) + } + return apps, nil +} + +// Delete deletes an applicaton in the cache using the given id +func (lc *ApplicationLocalCache) Delete(id string) { + lc.mu.Lock() + defer lc.mu.Unlock() + + delete(lc.apps, id) +} diff --git a/management-server/internal/database/dao.go b/management-server/internal/database/dao.go new file mode 100644 index 000000000..4f28602fb --- /dev/null +++ b/management-server/internal/database/dao.go @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2022, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * + * 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. + * + */ + +package database + +import ( + "encoding/json" + "fmt" + "time" + + apkmgt "github.com/wso2/apk/adapter/pkg/discovery/api/wso2/discovery/apkmgt" + apiProtos "github.com/wso2/apk/adapter/pkg/discovery/api/wso2/discovery/service/apkmgt" + "github.com/wso2/apk/adapter/pkg/logging" + "github.com/wso2/apk/management-server/internal/logger" +) + +// DbCache is a pointer to an ApplicationLocalCache +var DbCache *ApplicationLocalCache + +func init() { + DbCache = NewApplicationLocalCache(cleanupInterval) +} + +type artifact struct { + APIName string `json:"apiName"` + ID string `json:"id"` + Context string `json:"context"` + Version string `json:"version"` + ProviderName string `json:"providerName"` + Status string `json:"status"` +} + +// GetApplicationByUUID retrives an application using uuid and returns it +func GetApplicationByUUID(uuid string) (*apkmgt.Application, error) { + rows, _ := ExecDBQuery(queryGetApplicationByUUID, uuid) + rows.Next() + values, err := rows.Values() + if err != nil { + return nil, err + } + subs, _ := getSubscriptionsForApplication(uuid) + keys, _ := getConsumerKeysForApplication(uuid) + application := &apkmgt.Application{ + Uuid: values[0].(string), + Name: values[1].(string), + Owner: "", //ToDo : Check how to get Owner from db + Attributes: nil, //ToDo : check the values for Attributes + Subscriber: "", + Organization: values[3].(string), + Subscriptions: subs, + ConsumerKeys: keys, + } + DbCache.Update(application, time.Now().Unix()+ttl.Microseconds()) + return application, nil +} + +// GetCachedApplicationByUUID returns the Application details from the cache. +// If the application is not available in the cache, it will fetch the application from DB. +func GetCachedApplicationByUUID(uuid string) (*apkmgt.Application, error) { + if app, ok := DbCache.Read(uuid); ok == nil { + return app, nil + } + return GetApplicationByUUID(uuid) +} + +// getSubscriptionsForApplication returns all subscriptions from DB, for a given application. +func getSubscriptionsForApplication(appUUID string) ([]*apkmgt.Subscription, error) { + rows, _ := ExecDBQuery(queryGetAllSubscriptionsForApplication, appUUID) + var subs []*apkmgt.Subscription + for rows.Next() { + values, err := rows.Values() + if err != nil { + return nil, err + } + subs = append(subs, &apkmgt.Subscription{ + Uuid: values[0].(string), + ApiUuid: values[1].(string), + PolicyId: "", + SubscriptionStatus: values[3].(string), + Organization: values[4].(string), + CreatedBy: values[5].(string), + }) + } + return subs, nil +} + +// getConsumerKeysForApplication returns all Consumer Keys from DB, for a given application. +func getConsumerKeysForApplication(appUUID string) ([]*apkmgt.ConsumerKey, error) { + rows, _ := ExecDBQuery(queryConsumerKeysForApplication, appUUID) + var keys []*apkmgt.ConsumerKey + for rows.Next() { + values, err := rows.Values() + if err != nil { + return nil, err + } + keys = append(keys, &apkmgt.ConsumerKey{ + Key: values[0].(string), + KeyManager: values[1].(string), + }) + } + return keys, nil +} + +// GetSubscriptionByUUID returns the Application details from the DB for a given subscription UUID. +func GetSubscriptionByUUID(subUUID string) (*apkmgt.Subscription, error) { + rows, _ := ExecDBQuery(querySubscriptionByUUID, subUUID) + rows.Next() + values, err := rows.Values() + if err != nil { + return nil, err + } + return &apkmgt.Subscription{ + Uuid: values[0].(string), + ApiUuid: values[1].(string), + PolicyId: "", + SubscriptionStatus: values[2].(string), + Organization: values[3].(string), + CreatedBy: values[4].(string), + }, nil +} + +// CreateAPI creates an API in the DB +func CreateAPI(api *apiProtos.API) error { + _, err := ExecDBQuery(queryCreateAPI, &api.Uuid, &api.Name, &api.Provider, + &api.Version, &api.Context, &api.OrganizationId, &api.CreatedBy, time.Now(), &api.Type, marshalArtifact(api), "PUBLISHED") + + if err != nil { + logger.LoggerDatabase.ErrorC(logging.ErrorDetails{ + Message: fmt.Sprintf("Error creating API %q, Error: %v", api.Uuid, err.Error()), + Severity: logging.CRITICAL, + ErrorCode: 1201, + }) + return err + } + return nil +} + +// UpdateAPI updates the given API in the DB +func UpdateAPI(api *apiProtos.API) error { + _, err := ExecDBQuery(queryUpdateAPI, &api.Uuid, &api.Name, &api.Provider, + &api.Version, &api.Context, &api.OrganizationId, &api.UpdatedBy, time.Now(), &api.Type, marshalArtifact(api), "PUBLISHED") + if err != nil { + logger.LoggerDatabase.ErrorC(logging.ErrorDetails{ + Message: fmt.Sprintf("Error updating API %q, Error: %v", api.Uuid, err.Error()), + Severity: logging.CRITICAL, + ErrorCode: 1202, + }) + return err + } + return nil +} + +// DeleteAPI deletes the given API in the DB +func DeleteAPI(api *apiProtos.API) error { + _, err := ExecDBQuery(queryDeleteAPI, api.Uuid) + if err != nil { + logger.LoggerDatabase.ErrorC(logging.ErrorDetails{ + Message: fmt.Sprintf("Error deleting API %q, Error: %v", api.Uuid, err.Error()), + Severity: logging.CRITICAL, + ErrorCode: 1203, + }) + return err + } + return nil +} + +func marshalArtifact(api *apiProtos.API) string { + artifact := &artifact{APIName: api.Name, + ID: api.Uuid, + Context: api.Context, + Version: api.Version, + ProviderName: api.Provider, + Status: "PUBLISHED", + } + jsonString, err := json.Marshal(artifact) + if err != nil { + return "{}" + } + return string(jsonString) +} diff --git a/management-server/internal/database/database.go b/management-server/internal/database/database.go new file mode 100644 index 000000000..af4a1c98c --- /dev/null +++ b/management-server/internal/database/database.go @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2022, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * + * 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. + * + */ + +package database + +import ( + "context" + "fmt" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgxpool" + "github.com/wso2/apk/adapter/pkg/logging" + "github.com/wso2/apk/management-server/internal/config" + "github.com/wso2/apk/management-server/internal/logger" +) + +var dbPool *pgxpool.Pool + +// ConnectToDB creates the DB connection +func ConnectToDB() { + conf := config.ReadConfigs() + var err error + connString := fmt.Sprintf("postgresql://%s:%s@%s:%d/%s?pool_max_conns=%d&pool_min_conns=%d&"+ + "pool_max_conn_lifetime=%s&pool_max_conn_idle_time=%s&pool_health_check_period=%s&pool_max_conn_lifetime_jitter=%s", + conf.Database.Username, + conf.Database.Password, + conf.Database.Host, + conf.Database.Port, + conf.Database.Name, + conf.Database.PoolOptions.PoolMaxConns, + conf.Database.PoolOptions.PoolMinConns, + conf.Database.PoolOptions.PoolMaxConnLifetime, + conf.Database.PoolOptions.PoolMaxConnIdleTime, + conf.Database.PoolOptions.PoolHealthCheckPeriod, + conf.Database.PoolOptions.PoolMaxConnLifetimeJitter) + dbPool, err = pgxpool.New(context.Background(), connString) + if err != nil { + logger.LoggerDatabase.ErrorC(logging.ErrorDetails{ + Message: fmt.Sprintf("Unable to connect to database: %v", err.Error()), + Severity: logging.CRITICAL, + ErrorCode: 1100, + }) + } +} + +// ExecDBQuery executes a given database query with the arguments provided +func ExecDBQuery(query string, args ...interface{}) (pgx.Rows, error) { + rows, err := dbPool.Query(context.Background(), query, args...) + if err != nil { + return nil, err + } + return rows, nil +} + +// IsAliveConn checks whether the DB connections pool is alive +func IsAliveConn(ctx context.Context) (isAlive bool) { + if err := dbPool.Ping(ctx); err != nil { + return true + } + return isAlive +} + +// CloseDBConn closes the DB connections pool +func CloseDBConn() { + dbPool.Close() +} diff --git a/management-server/internal/database/queries.go b/management-server/internal/database/queries.go new file mode 100644 index 000000000..3c2b4cbed --- /dev/null +++ b/management-server/internal/database/queries.go @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2022, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * + * 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. + * + */ + +package database + +const ( + queryGetApplicationByUUID string = " SELECT " + + " APP.UUID," + + " APP.NAME," + + " APP.SUBSCRIBER_ID," + + " APP.ORGANIZATION ORGANIZATION," + + " SUB.USER_ID " + + " FROM " + + " SUBSCRIBER SUB," + + " APPLICATION APP " + + " WHERE " + + " APP.UUID = $1 " + + " AND APP.SUBSCRIBER_ID = SUB.SUBSCRIBER_ID" + + queryGetAllSubscriptionsForApplication string = "select " + + " SUB.uuid as UUID, " + + " API.api_uuid as API_UUID, " + + " API.api_version as API_VERSION, " + + " SUB.sub_status as SUB_STATUS, " + + " APP.organization as ORGANIZATION, " + + " SUB.created_by as CREATED_BY " + + " FROM " + + " APPLICATION APP, SUBSCRIPTION SUB, API API " + + " where 1 = 1 " + + " AND APP.application_id = SUB.application_id " + + " AND SUB.api_id = API.api_id " + + " AND APP.uuid = $1" + + queryConsumerKeysForApplication string = "select " + + " APPKEY.consumer_key, " + + " APPKEY.key_manager " + + " from " + + " application_key_mapping APPKEY, " + + " application APP " + + " where 1=1 " + + " AND APP.application_id = APPKEY.application_id " + + " AND APP.UUID = $1" + + querySubscriptionByUUID string = "select " + + " SUB.uuid, " + + " API.api_uuid, " + + " SUB.sub_status, " + + " API.organization, " + + " SUB.created_by " + + " from " + + " subscription SUB, " + + " api API " + + " where 1=1 " + + " AND SUB.api_id = API.api_id " + + " AND SUB.uuid = $1" + + queryCreateAPI string = "INSERT INTO API " + + "(API_UUID, API_NAME, API_PROVIDER, API_VERSION," + + "CONTEXT, ORGANIZATION, CREATED_BY, CREATED_TIME, API_TYPE, ARTIFACT, STATUS)" + + " VALUES " + "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)" + + queryDeleteAPI string = "DELETE FROM API" + + " WHERE " + + "API_UUID = $1" + + queryUpdateAPI string = "UPDATE API SET " + + "API_NAME = $2, " + + "API_PROVIDER = $3, " + + "API_VERSION = $4, " + + "CONTEXT = $5, " + + "ORGANIZATION = $6, " + + "UPDATED_BY = $7, " + + "UPDATED_TIME = $8, " + + "API_TYPE = $9, " + + "ARTIFACT = $10, " + + "STATUS = $11" + + " WHERE " + + "API_UUID = $1" +) diff --git a/management-server/internal/grpc-server/server.go b/management-server/internal/grpc-server/server.go new file mode 100644 index 000000000..df277b5a8 --- /dev/null +++ b/management-server/internal/grpc-server/server.go @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2022, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * + * 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. + * + */ + +package server + +import ( + "context" + "crypto/tls" + "fmt" + "net" + "time" + + apiProtos "github.com/wso2/apk/adapter/pkg/discovery/api/wso2/discovery/service/apkmgt" + "github.com/wso2/apk/adapter/pkg/health" + healthservice "github.com/wso2/apk/adapter/pkg/health/api/wso2/health/service" + "github.com/wso2/apk/adapter/pkg/logging" + "github.com/wso2/apk/adapter/pkg/utils/tlsutils" + "github.com/wso2/apk/management-server/internal/backoffice" + "github.com/wso2/apk/management-server/internal/config" + "github.com/wso2/apk/management-server/internal/logger" + "github.com/wso2/apk/management-server/internal/utils" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/keepalive" +) + +type apiService struct { + apiProtos.UnimplementedAPIServiceServer +} + +func newAPIService() *apiService { + return &apiService{} +} + +// CreateAPI creates an API +func (s *apiService) CreateAPI(ctx context.Context, api *apiProtos.API) (*apiProtos.Response, error) { + logger.LoggerMGTServer.Infof("Create Message received : %q", api) + err := backoffice.CreateAPI(api) + if err != nil { + logger.LoggerMGTServer.Errorf("Error Creating API : %v", err.Error()) + return &apiProtos.Response{Result: false}, err + } + return &apiProtos.Response{Result: true}, nil +} + +// UpdateAPI updates an API +func (s *apiService) UpdateAPI(ctx context.Context, api *apiProtos.API) (*apiProtos.Response, error) { + logger.LoggerMGTServer.Infof("Update Message received : %q", api) + err := backoffice.UpdateAPI(api) + if err != nil { + logger.LoggerMGTServer.Errorf("Error Updating API : %v", err.Error()) + return &apiProtos.Response{Result: false}, err + } + return &apiProtos.Response{Result: true}, nil +} + +// DeleteAPI deletes an API +func (s *apiService) DeleteAPI(ctx context.Context, api *apiProtos.API) (*apiProtos.Response, error) { + logger.LoggerMGTServer.Infof("Delete Message received : %q", api) + err := backoffice.DeleteAPI(api) + if err != nil { + logger.LoggerMGTServer.Errorf("Error Deleting API : %v", err.Error()) + return &apiProtos.Response{Result: false}, err + } + return &apiProtos.Response{Result: true}, nil +} + +// StartGRPCServer start the GRPC server +func StartGRPCServer() { + var grpcOptions []grpc.ServerOption + publicKeyLocation, privateKeyLocation, truststoreLocation := utils.GetKeyLocations() + cert, err := tlsutils.GetServerCertificate(publicKeyLocation, privateKeyLocation) + caCertPool := tlsutils.GetTrustedCertPool(truststoreLocation) + if err == nil { + grpcOptions = append(grpcOptions, grpc.Creds( + credentials.NewTLS(&tls.Config{ + Certificates: []tls.Certificate{cert}, + ClientAuth: tls.RequireAndVerifyClientCert, + ClientCAs: caCertPool, + }), + )) + } else { + logger.LoggerMGTServer.ErrorC(logging.ErrorDetails{ + Message: fmt.Sprintf("Failed to initiate the ssl context, error: %v", err.Error()), + Severity: logging.BLOCKER, + ErrorCode: 1200, + }) + } + grpcOptions = append(grpcOptions, grpc.KeepaliveParams( + keepalive.ServerParameters{ + Time: time.Duration(5 * time.Minute), + Timeout: time.Duration(20 * time.Second), + }), + ) + grpcServer := grpc.NewServer(grpcOptions...) + conf := config.ReadConfigs() + port := conf.ManagementServer.GRPCPort + lis, err := net.Listen("tcp", fmt.Sprintf(":%d", port)) + if err != nil { + logger.LoggerMGTServer.ErrorC(logging.ErrorDetails{ + Message: fmt.Sprintf("Failed to listen on port: %v, error: %v", port, err.Error()), + Severity: logging.BLOCKER, + ErrorCode: 1201, + }) + } + // register services + apiService := newAPIService() + apiProtos.RegisterAPIServiceServer(grpcServer, apiService) + healthservice.RegisterHealthServer(grpcServer, &health.Server{}) + logger.LoggerMGTServer.Infof("Management server is listening for GRPC connections on port: %v.", port) + grpcServer.Serve(lis) +} diff --git a/management-server/internal/logger/logging.go b/management-server/internal/logger/logging.go new file mode 100644 index 000000000..681110474 --- /dev/null +++ b/management-server/internal/logger/logging.go @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2022, WSO2 LLC. (http://www.wso2.org) + * + * 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. + * + */ + +// Package logger contains the package references for log messages +// If a new package is introduced, the corresponding logger reference is need to be created as well. +package logger + +import ( + "github.com/sirupsen/logrus" + "github.com/wso2/apk/adapter/pkg/logging" +) + +/* loggers should be initiated only for the main packages + ********** Don't initiate loggers for sub packages **************** + +When you add a new logger instance add the related package name as a constant +*/ + +// package name constants +const ( + pkgServer = "github.com/wso2/apk/management-server" + pkgXds = "github.com/wso2/apk/management-server/xds" + pkgXdsServer = "github.com/wso2/apk/management-server/xds/server" + pkgMGTServer = "github.com/wso2/apk/management-server/internal/grpc-server" + pkgNotificationServer = "github.com/wso2/apk/management-server/internal/notification" + pkgDatabase = "github.com/wso2/apk/management-server/internal/database" +) + +// logger package references +var ( + LoggerServer logging.Log + LoggerXds logging.Log + LoggerXdsServer logging.Log + LoggerMGTServer logging.Log + LoggerNotificationServer logging.Log + LoggerDatabase logging.Log +) + +func init() { + UpdateLoggers() +} + +// UpdateLoggers initializes the logger package references +func UpdateLoggers() { + LoggerServer = logging.InitPackageLogger(pkgServer) + LoggerXds = logging.InitPackageLogger(pkgXds) + LoggerXdsServer = logging.InitPackageLogger(pkgXdsServer) + LoggerMGTServer = logging.InitPackageLogger(pkgMGTServer) + LoggerNotificationServer = logging.InitPackageLogger(pkgNotificationServer) + LoggerDatabase = logging.InitPackageLogger(pkgDatabase) + logrus.Info("Updated loggers") +} diff --git a/management-server/internal/notification/notificationds.pb.go b/management-server/internal/notification/notificationds.pb.go new file mode 100644 index 000000000..d6db0c011 --- /dev/null +++ b/management-server/internal/notification/notificationds.pb.go @@ -0,0 +1,915 @@ +// +// Copyright (c) 2022, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. +// +// 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. +// + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.25.0-devel +// protoc v3.13.0 +// source: wso2/discovery/subscription/notificationds.proto + +package notification + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type NotificationResponse_StatusCode int32 + +const ( + // The response code is not known. + NotificationResponse_UNKNOWN NotificationResponse_StatusCode = 0 + // The response code to notify that the number of requests are under limit. + NotificationResponse_OK NotificationResponse_StatusCode = 1 + // The response code to notify that the number of requests are over limit. + NotificationResponse_FAILED NotificationResponse_StatusCode = 2 +) + +// Enum value maps for NotificationResponse_StatusCode. +var ( + NotificationResponse_StatusCode_name = map[int32]string{ + 0: "UNKNOWN", + 1: "OK", + 2: "FAILED", + } + NotificationResponse_StatusCode_value = map[string]int32{ + "UNKNOWN": 0, + "OK": 1, + "FAILED": 2, + } +) + +func (x NotificationResponse_StatusCode) Enum() *NotificationResponse_StatusCode { + p := new(NotificationResponse_StatusCode) + *p = x + return p +} + +func (x NotificationResponse_StatusCode) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (NotificationResponse_StatusCode) Descriptor() protoreflect.EnumDescriptor { + return file_wso2_discovery_subscription_notificationds_proto_enumTypes[0].Descriptor() +} + +func (NotificationResponse_StatusCode) Type() protoreflect.EnumType { + return &file_wso2_discovery_subscription_notificationds_proto_enumTypes[0] +} + +func (x NotificationResponse_StatusCode) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use NotificationResponse_StatusCode.Descriptor instead. +func (NotificationResponse_StatusCode) EnumDescriptor() ([]byte, []int) { + return file_wso2_discovery_subscription_notificationds_proto_rawDescGZIP(), []int{2, 0} +} + +type Application struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + EventId string `protobuf:"bytes,1,opt,name=eventId,proto3" json:"eventId,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + Uuid string `protobuf:"bytes,3,opt,name=uuid,proto3" json:"uuid,omitempty"` + Owner string `protobuf:"bytes,4,opt,name=owner,proto3" json:"owner,omitempty"` + Policy string `protobuf:"bytes,5,opt,name=policy,proto3" json:"policy,omitempty"` + Attributes map[string]string `protobuf:"bytes,6,rep,name=attributes,proto3" json:"attributes,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Keys []*Application_Key `protobuf:"bytes,7,rep,name=keys,proto3" json:"keys,omitempty"` + Organization string `protobuf:"bytes,8,opt,name=organization,proto3" json:"organization,omitempty"` + TimeStamp string `protobuf:"bytes,9,opt,name=timeStamp,proto3" json:"timeStamp,omitempty"` +} + +func (x *Application) Reset() { + *x = Application{} + if protoimpl.UnsafeEnabled { + mi := &file_wso2_discovery_subscription_notificationds_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Application) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Application) ProtoMessage() {} + +func (x *Application) ProtoReflect() protoreflect.Message { + mi := &file_wso2_discovery_subscription_notificationds_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Application.ProtoReflect.Descriptor instead. +func (*Application) Descriptor() ([]byte, []int) { + return file_wso2_discovery_subscription_notificationds_proto_rawDescGZIP(), []int{0} +} + +func (x *Application) GetEventId() string { + if x != nil { + return x.EventId + } + return "" +} + +func (x *Application) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *Application) GetUuid() string { + if x != nil { + return x.Uuid + } + return "" +} + +func (x *Application) GetOwner() string { + if x != nil { + return x.Owner + } + return "" +} + +func (x *Application) GetPolicy() string { + if x != nil { + return x.Policy + } + return "" +} + +func (x *Application) GetAttributes() map[string]string { + if x != nil { + return x.Attributes + } + return nil +} + +func (x *Application) GetKeys() []*Application_Key { + if x != nil { + return x.Keys + } + return nil +} + +func (x *Application) GetOrganization() string { + if x != nil { + return x.Organization + } + return "" +} + +func (x *Application) GetTimeStamp() string { + if x != nil { + return x.TimeStamp + } + return "" +} + +type Subscription struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + EventId string `protobuf:"bytes,1,opt,name=eventId,proto3" json:"eventId,omitempty"` + ApplicationRef string `protobuf:"bytes,2,opt,name=applicationRef,proto3" json:"applicationRef,omitempty"` + ApiRef string `protobuf:"bytes,3,opt,name=apiRef,proto3" json:"apiRef,omitempty"` + PolicyId string `protobuf:"bytes,4,opt,name=policyId,proto3" json:"policyId,omitempty"` + SubStatus string `protobuf:"bytes,5,opt,name=subStatus,proto3" json:"subStatus,omitempty"` + Subscriber string `protobuf:"bytes,6,opt,name=subscriber,proto3" json:"subscriber,omitempty"` + Uuid string `protobuf:"bytes,7,opt,name=uuid,proto3" json:"uuid,omitempty"` + TimeStamp string `protobuf:"bytes,8,opt,name=timeStamp,proto3" json:"timeStamp,omitempty"` + Organization string `protobuf:"bytes,9,opt,name=organization,proto3" json:"organization,omitempty"` +} + +func (x *Subscription) Reset() { + *x = Subscription{} + if protoimpl.UnsafeEnabled { + mi := &file_wso2_discovery_subscription_notificationds_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Subscription) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Subscription) ProtoMessage() {} + +func (x *Subscription) ProtoReflect() protoreflect.Message { + mi := &file_wso2_discovery_subscription_notificationds_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Subscription.ProtoReflect.Descriptor instead. +func (*Subscription) Descriptor() ([]byte, []int) { + return file_wso2_discovery_subscription_notificationds_proto_rawDescGZIP(), []int{1} +} + +func (x *Subscription) GetEventId() string { + if x != nil { + return x.EventId + } + return "" +} + +func (x *Subscription) GetApplicationRef() string { + if x != nil { + return x.ApplicationRef + } + return "" +} + +func (x *Subscription) GetApiRef() string { + if x != nil { + return x.ApiRef + } + return "" +} + +func (x *Subscription) GetPolicyId() string { + if x != nil { + return x.PolicyId + } + return "" +} + +func (x *Subscription) GetSubStatus() string { + if x != nil { + return x.SubStatus + } + return "" +} + +func (x *Subscription) GetSubscriber() string { + if x != nil { + return x.Subscriber + } + return "" +} + +func (x *Subscription) GetUuid() string { + if x != nil { + return x.Uuid + } + return "" +} + +func (x *Subscription) GetTimeStamp() string { + if x != nil { + return x.TimeStamp + } + return "" +} + +func (x *Subscription) GetOrganization() string { + if x != nil { + return x.Organization + } + return "" +} + +type NotificationResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Code NotificationResponse_StatusCode `protobuf:"varint,1,opt,name=code,proto3,enum=discovery.service.apkmgt.NotificationResponse_StatusCode" json:"code,omitempty"` +} + +func (x *NotificationResponse) Reset() { + *x = NotificationResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_wso2_discovery_subscription_notificationds_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *NotificationResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NotificationResponse) ProtoMessage() {} + +func (x *NotificationResponse) ProtoReflect() protoreflect.Message { + mi := &file_wso2_discovery_subscription_notificationds_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use NotificationResponse.ProtoReflect.Descriptor instead. +func (*NotificationResponse) Descriptor() ([]byte, []int) { + return file_wso2_discovery_subscription_notificationds_proto_rawDescGZIP(), []int{2} +} + +func (x *NotificationResponse) GetCode() NotificationResponse_StatusCode { + if x != nil { + return x.Code + } + return NotificationResponse_UNKNOWN +} + +type Application_Key struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + KeyManager string `protobuf:"bytes,2,opt,name=keyManager,proto3" json:"keyManager,omitempty"` +} + +func (x *Application_Key) Reset() { + *x = Application_Key{} + if protoimpl.UnsafeEnabled { + mi := &file_wso2_discovery_subscription_notificationds_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Application_Key) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Application_Key) ProtoMessage() {} + +func (x *Application_Key) ProtoReflect() protoreflect.Message { + mi := &file_wso2_discovery_subscription_notificationds_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Application_Key.ProtoReflect.Descriptor instead. +func (*Application_Key) Descriptor() ([]byte, []int) { + return file_wso2_discovery_subscription_notificationds_proto_rawDescGZIP(), []int{0, 1} +} + +func (x *Application_Key) GetKey() string { + if x != nil { + return x.Key + } + return "" +} + +func (x *Application_Key) GetKeyManager() string { + if x != nil { + return x.KeyManager + } + return "" +} + +var File_wso2_discovery_subscription_notificationds_proto protoreflect.FileDescriptor + +var file_wso2_discovery_subscription_notificationds_proto_rawDesc = []byte{ + 0x0a, 0x30, 0x77, 0x73, 0x6f, 0x32, 0x2f, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, + 0x2f, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6e, 0x6f, + 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x64, 0x73, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x12, 0x18, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x2e, 0x73, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x61, 0x70, 0x6b, 0x6d, 0x67, 0x74, 0x22, 0xcd, 0x03, 0x0a, + 0x0b, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, + 0x65, 0x76, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x65, + 0x76, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x75, + 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x75, 0x69, 0x64, 0x12, 0x14, + 0x0a, 0x05, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6f, + 0x77, 0x6e, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x55, 0x0a, 0x0a, + 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x35, 0x2e, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x2e, 0x73, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x2e, 0x61, 0x70, 0x6b, 0x6d, 0x67, 0x74, 0x2e, 0x41, 0x70, 0x70, 0x6c, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, + 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, + 0x74, 0x65, 0x73, 0x12, 0x3d, 0x0a, 0x04, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x29, 0x2e, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x2e, 0x73, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x61, 0x70, 0x6b, 0x6d, 0x67, 0x74, 0x2e, 0x41, 0x70, 0x70, + 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x4b, 0x65, 0x79, 0x52, 0x04, 0x6b, 0x65, + 0x79, 0x73, 0x12, 0x22, 0x0a, 0x0c, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, + 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x53, 0x74, + 0x61, 0x6d, 0x70, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x53, + 0x74, 0x61, 0x6d, 0x70, 0x1a, 0x3d, 0x0a, 0x0f, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, + 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, + 0x02, 0x38, 0x01, 0x1a, 0x37, 0x0a, 0x03, 0x4b, 0x65, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, + 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x1e, 0x0a, 0x0a, + 0x6b, 0x65, 0x79, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0a, 0x6b, 0x65, 0x79, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x22, 0x98, 0x02, 0x0a, + 0x0c, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, + 0x07, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, + 0x65, 0x76, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x26, 0x0a, 0x0e, 0x61, 0x70, 0x70, 0x6c, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x66, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0e, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x66, 0x12, + 0x16, 0x0a, 0x06, 0x61, 0x70, 0x69, 0x52, 0x65, 0x66, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x06, 0x61, 0x70, 0x69, 0x52, 0x65, 0x66, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, + 0x79, 0x49, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, + 0x79, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x75, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x75, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x72, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, + 0x72, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x75, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x75, 0x75, 0x69, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x53, 0x74, 0x61, + 0x6d, 0x70, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x53, 0x74, + 0x61, 0x6d, 0x70, 0x12, 0x22, 0x0a, 0x0c, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6f, 0x72, 0x67, 0x61, 0x6e, + 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x94, 0x01, 0x0a, 0x14, 0x4e, 0x6f, 0x74, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x4d, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x39, + 0x2e, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x2e, 0x61, 0x70, 0x6b, 0x6d, 0x67, 0x74, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x53, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x22, + 0x2d, 0x0a, 0x0a, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x0b, 0x0a, + 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x06, 0x0a, 0x02, 0x4f, 0x4b, + 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x02, 0x32, 0xa3, + 0x05, 0x0a, 0x13, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x6a, 0x0a, 0x11, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x2e, 0x64, 0x69, + 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, + 0x61, 0x70, 0x6b, 0x6d, 0x67, 0x74, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x1a, 0x2e, 0x2e, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x2e, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x61, 0x70, 0x6b, 0x6d, 0x67, 0x74, 0x2e, 0x4e, 0x6f, + 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x6a, 0x0a, 0x11, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x70, 0x70, 0x6c, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x2e, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, + 0x65, 0x72, 0x79, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x61, 0x70, 0x6b, 0x6d, + 0x67, 0x74, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x2e, + 0x2e, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x2e, 0x61, 0x70, 0x6b, 0x6d, 0x67, 0x74, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6a, + 0x0a, 0x11, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x2e, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x2e, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x61, 0x70, 0x6b, 0x6d, 0x67, 0x74, 0x2e, 0x41, + 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x2e, 0x2e, 0x64, 0x69, 0x73, + 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x61, + 0x70, 0x6b, 0x6d, 0x67, 0x74, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, 0x0a, 0x12, 0x43, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x26, 0x2e, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x2e, 0x73, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x2e, 0x61, 0x70, 0x6b, 0x6d, 0x67, 0x74, 0x2e, 0x53, 0x75, 0x62, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x2e, 0x2e, 0x64, 0x69, 0x73, 0x63, 0x6f, + 0x76, 0x65, 0x72, 0x79, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x61, 0x70, 0x6b, + 0x6d, 0x67, 0x74, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, 0x0a, 0x12, 0x55, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x26, + 0x2e, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x2e, 0x61, 0x70, 0x6b, 0x6d, 0x67, 0x74, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x2e, 0x2e, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, + 0x72, 0x79, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x61, 0x70, 0x6b, 0x6d, 0x67, + 0x74, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, 0x0a, 0x12, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x26, 0x2e, 0x64, + 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x2e, 0x61, 0x70, 0x6b, 0x6d, 0x67, 0x74, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x2e, 0x2e, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, + 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x61, 0x70, 0x6b, 0x6d, 0x67, 0x74, 0x2e, + 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x80, 0x01, 0x0a, 0x2e, 0x6f, 0x72, 0x67, 0x2e, 0x77, 0x73, 0x6f, + 0x32, 0x2e, 0x61, 0x70, 0x6b, 0x2e, 0x65, 0x6e, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x72, 0x2e, 0x64, + 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x2e, 0x61, 0x70, 0x6b, 0x6d, 0x67, 0x74, 0x42, 0x13, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x00, 0x5a, 0x34, + 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x77, 0x73, 0x6f, 0x32, 0x2f, + 0x61, 0x70, 0x6b, 0x2f, 0x61, 0x64, 0x61, 0x70, 0x74, 0x65, 0x72, 0x2f, 0x64, 0x69, 0x73, 0x63, + 0x6f, 0x76, 0x65, 0x72, 0x79, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2f, 0x61, 0x70, + 0x6b, 0x6d, 0x67, 0x74, 0x88, 0x01, 0x01, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_wso2_discovery_subscription_notificationds_proto_rawDescOnce sync.Once + file_wso2_discovery_subscription_notificationds_proto_rawDescData = file_wso2_discovery_subscription_notificationds_proto_rawDesc +) + +func file_wso2_discovery_subscription_notificationds_proto_rawDescGZIP() []byte { + file_wso2_discovery_subscription_notificationds_proto_rawDescOnce.Do(func() { + file_wso2_discovery_subscription_notificationds_proto_rawDescData = protoimpl.X.CompressGZIP(file_wso2_discovery_subscription_notificationds_proto_rawDescData) + }) + return file_wso2_discovery_subscription_notificationds_proto_rawDescData +} + +var file_wso2_discovery_subscription_notificationds_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_wso2_discovery_subscription_notificationds_proto_msgTypes = make([]protoimpl.MessageInfo, 5) +var file_wso2_discovery_subscription_notificationds_proto_goTypes = []interface{}{ + (NotificationResponse_StatusCode)(0), // 0: discovery.service.apkmgt.NotificationResponse.StatusCode + (*Application)(nil), // 1: discovery.service.apkmgt.Application + (*Subscription)(nil), // 2: discovery.service.apkmgt.Subscription + (*NotificationResponse)(nil), // 3: discovery.service.apkmgt.NotificationResponse + nil, // 4: discovery.service.apkmgt.Application.AttributesEntry + (*Application_Key)(nil), // 5: discovery.service.apkmgt.Application.Key +} +var file_wso2_discovery_subscription_notificationds_proto_depIdxs = []int32{ + 4, // 0: discovery.service.apkmgt.Application.attributes:type_name -> discovery.service.apkmgt.Application.AttributesEntry + 5, // 1: discovery.service.apkmgt.Application.keys:type_name -> discovery.service.apkmgt.Application.Key + 0, // 2: discovery.service.apkmgt.NotificationResponse.code:type_name -> discovery.service.apkmgt.NotificationResponse.StatusCode + 1, // 3: discovery.service.apkmgt.NotificationService.CreateApplication:input_type -> discovery.service.apkmgt.Application + 1, // 4: discovery.service.apkmgt.NotificationService.UpdateApplication:input_type -> discovery.service.apkmgt.Application + 1, // 5: discovery.service.apkmgt.NotificationService.DeleteApplication:input_type -> discovery.service.apkmgt.Application + 2, // 6: discovery.service.apkmgt.NotificationService.CreateSubscription:input_type -> discovery.service.apkmgt.Subscription + 2, // 7: discovery.service.apkmgt.NotificationService.UpdateSubscription:input_type -> discovery.service.apkmgt.Subscription + 2, // 8: discovery.service.apkmgt.NotificationService.DeleteSubscription:input_type -> discovery.service.apkmgt.Subscription + 3, // 9: discovery.service.apkmgt.NotificationService.CreateApplication:output_type -> discovery.service.apkmgt.NotificationResponse + 3, // 10: discovery.service.apkmgt.NotificationService.UpdateApplication:output_type -> discovery.service.apkmgt.NotificationResponse + 3, // 11: discovery.service.apkmgt.NotificationService.DeleteApplication:output_type -> discovery.service.apkmgt.NotificationResponse + 3, // 12: discovery.service.apkmgt.NotificationService.CreateSubscription:output_type -> discovery.service.apkmgt.NotificationResponse + 3, // 13: discovery.service.apkmgt.NotificationService.UpdateSubscription:output_type -> discovery.service.apkmgt.NotificationResponse + 3, // 14: discovery.service.apkmgt.NotificationService.DeleteSubscription:output_type -> discovery.service.apkmgt.NotificationResponse + 9, // [9:15] is the sub-list for method output_type + 3, // [3:9] is the sub-list for method input_type + 3, // [3:3] is the sub-list for extension type_name + 3, // [3:3] is the sub-list for extension extendee + 0, // [0:3] is the sub-list for field type_name +} + +func init() { file_wso2_discovery_subscription_notificationds_proto_init() } +func file_wso2_discovery_subscription_notificationds_proto_init() { + if File_wso2_discovery_subscription_notificationds_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_wso2_discovery_subscription_notificationds_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Application); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_wso2_discovery_subscription_notificationds_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Subscription); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_wso2_discovery_subscription_notificationds_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*NotificationResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_wso2_discovery_subscription_notificationds_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Application_Key); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_wso2_discovery_subscription_notificationds_proto_rawDesc, + NumEnums: 1, + NumMessages: 5, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_wso2_discovery_subscription_notificationds_proto_goTypes, + DependencyIndexes: file_wso2_discovery_subscription_notificationds_proto_depIdxs, + EnumInfos: file_wso2_discovery_subscription_notificationds_proto_enumTypes, + MessageInfos: file_wso2_discovery_subscription_notificationds_proto_msgTypes, + }.Build() + File_wso2_discovery_subscription_notificationds_proto = out.File + file_wso2_discovery_subscription_notificationds_proto_rawDesc = nil + file_wso2_discovery_subscription_notificationds_proto_goTypes = nil + file_wso2_discovery_subscription_notificationds_proto_depIdxs = nil +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConnInterface + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion6 + +// NotificationServiceClient is the client API for NotificationService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type NotificationServiceClient interface { + CreateApplication(ctx context.Context, in *Application, opts ...grpc.CallOption) (*NotificationResponse, error) + UpdateApplication(ctx context.Context, in *Application, opts ...grpc.CallOption) (*NotificationResponse, error) + DeleteApplication(ctx context.Context, in *Application, opts ...grpc.CallOption) (*NotificationResponse, error) + CreateSubscription(ctx context.Context, in *Subscription, opts ...grpc.CallOption) (*NotificationResponse, error) + UpdateSubscription(ctx context.Context, in *Subscription, opts ...grpc.CallOption) (*NotificationResponse, error) + DeleteSubscription(ctx context.Context, in *Subscription, opts ...grpc.CallOption) (*NotificationResponse, error) +} + +type notificationServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewNotificationServiceClient(cc grpc.ClientConnInterface) NotificationServiceClient { + return ¬ificationServiceClient{cc} +} + +func (c *notificationServiceClient) CreateApplication(ctx context.Context, in *Application, opts ...grpc.CallOption) (*NotificationResponse, error) { + out := new(NotificationResponse) + err := c.cc.Invoke(ctx, "/discovery.service.apkmgt.NotificationService/CreateApplication", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *notificationServiceClient) UpdateApplication(ctx context.Context, in *Application, opts ...grpc.CallOption) (*NotificationResponse, error) { + out := new(NotificationResponse) + err := c.cc.Invoke(ctx, "/discovery.service.apkmgt.NotificationService/UpdateApplication", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *notificationServiceClient) DeleteApplication(ctx context.Context, in *Application, opts ...grpc.CallOption) (*NotificationResponse, error) { + out := new(NotificationResponse) + err := c.cc.Invoke(ctx, "/discovery.service.apkmgt.NotificationService/DeleteApplication", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *notificationServiceClient) CreateSubscription(ctx context.Context, in *Subscription, opts ...grpc.CallOption) (*NotificationResponse, error) { + out := new(NotificationResponse) + err := c.cc.Invoke(ctx, "/discovery.service.apkmgt.NotificationService/CreateSubscription", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *notificationServiceClient) UpdateSubscription(ctx context.Context, in *Subscription, opts ...grpc.CallOption) (*NotificationResponse, error) { + out := new(NotificationResponse) + err := c.cc.Invoke(ctx, "/discovery.service.apkmgt.NotificationService/UpdateSubscription", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *notificationServiceClient) DeleteSubscription(ctx context.Context, in *Subscription, opts ...grpc.CallOption) (*NotificationResponse, error) { + out := new(NotificationResponse) + err := c.cc.Invoke(ctx, "/discovery.service.apkmgt.NotificationService/DeleteSubscription", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// NotificationServiceServer is the server API for NotificationService service. +type NotificationServiceServer interface { + CreateApplication(context.Context, *Application) (*NotificationResponse, error) + UpdateApplication(context.Context, *Application) (*NotificationResponse, error) + DeleteApplication(context.Context, *Application) (*NotificationResponse, error) + CreateSubscription(context.Context, *Subscription) (*NotificationResponse, error) + UpdateSubscription(context.Context, *Subscription) (*NotificationResponse, error) + DeleteSubscription(context.Context, *Subscription) (*NotificationResponse, error) +} + +// UnimplementedNotificationServiceServer can be embedded to have forward compatible implementations. +type UnimplementedNotificationServiceServer struct { +} + +func (*UnimplementedNotificationServiceServer) CreateApplication(context.Context, *Application) (*NotificationResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method CreateApplication not implemented") +} +func (*UnimplementedNotificationServiceServer) UpdateApplication(context.Context, *Application) (*NotificationResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateApplication not implemented") +} +func (*UnimplementedNotificationServiceServer) DeleteApplication(context.Context, *Application) (*NotificationResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method DeleteApplication not implemented") +} +func (*UnimplementedNotificationServiceServer) CreateSubscription(context.Context, *Subscription) (*NotificationResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method CreateSubscription not implemented") +} +func (*UnimplementedNotificationServiceServer) UpdateSubscription(context.Context, *Subscription) (*NotificationResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateSubscription not implemented") +} +func (*UnimplementedNotificationServiceServer) DeleteSubscription(context.Context, *Subscription) (*NotificationResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method DeleteSubscription not implemented") +} + +func RegisterNotificationServiceServer(s *grpc.Server, srv NotificationServiceServer) { + s.RegisterService(&_NotificationService_serviceDesc, srv) +} + +func _NotificationService_CreateApplication_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Application) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(NotificationServiceServer).CreateApplication(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/discovery.service.apkmgt.NotificationService/CreateApplication", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(NotificationServiceServer).CreateApplication(ctx, req.(*Application)) + } + return interceptor(ctx, in, info, handler) +} + +func _NotificationService_UpdateApplication_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Application) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(NotificationServiceServer).UpdateApplication(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/discovery.service.apkmgt.NotificationService/UpdateApplication", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(NotificationServiceServer).UpdateApplication(ctx, req.(*Application)) + } + return interceptor(ctx, in, info, handler) +} + +func _NotificationService_DeleteApplication_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Application) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(NotificationServiceServer).DeleteApplication(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/discovery.service.apkmgt.NotificationService/DeleteApplication", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(NotificationServiceServer).DeleteApplication(ctx, req.(*Application)) + } + return interceptor(ctx, in, info, handler) +} + +func _NotificationService_CreateSubscription_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Subscription) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(NotificationServiceServer).CreateSubscription(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/discovery.service.apkmgt.NotificationService/CreateSubscription", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(NotificationServiceServer).CreateSubscription(ctx, req.(*Subscription)) + } + return interceptor(ctx, in, info, handler) +} + +func _NotificationService_UpdateSubscription_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Subscription) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(NotificationServiceServer).UpdateSubscription(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/discovery.service.apkmgt.NotificationService/UpdateSubscription", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(NotificationServiceServer).UpdateSubscription(ctx, req.(*Subscription)) + } + return interceptor(ctx, in, info, handler) +} + +func _NotificationService_DeleteSubscription_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Subscription) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(NotificationServiceServer).DeleteSubscription(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/discovery.service.apkmgt.NotificationService/DeleteSubscription", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(NotificationServiceServer).DeleteSubscription(ctx, req.(*Subscription)) + } + return interceptor(ctx, in, info, handler) +} + +var _NotificationService_serviceDesc = grpc.ServiceDesc{ + ServiceName: "discovery.service.apkmgt.NotificationService", + HandlerType: (*NotificationServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "CreateApplication", + Handler: _NotificationService_CreateApplication_Handler, + }, + { + MethodName: "UpdateApplication", + Handler: _NotificationService_UpdateApplication_Handler, + }, + { + MethodName: "DeleteApplication", + Handler: _NotificationService_DeleteApplication_Handler, + }, + { + MethodName: "CreateSubscription", + Handler: _NotificationService_CreateSubscription_Handler, + }, + { + MethodName: "UpdateSubscription", + Handler: _NotificationService_UpdateSubscription_Handler, + }, + { + MethodName: "DeleteSubscription", + Handler: _NotificationService_DeleteSubscription_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "wso2/discovery/subscription/notificationds.proto", +} diff --git a/management-server/internal/notification/notificationds.proto b/management-server/internal/notification/notificationds.proto new file mode 100644 index 000000000..e3be2558f --- /dev/null +++ b/management-server/internal/notification/notificationds.proto @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2022, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * + * 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. + * + */ + +syntax = "proto3"; + +package discovery.service.apkmgt; + +option go_package = "github.com/wso2/apk/adapter/discovery/service/apkmgt"; +option java_package = "org.wso2.apk.enforcer.discovery.service.apkmgt"; +option java_outer_classname = "notificationDsProto"; +option java_multiple_files = false; +option java_generic_services = true; + +service NotificationService { + rpc CreateApplication(Application) returns (NotificationResponse); + rpc UpdateApplication(Application) returns (NotificationResponse); + rpc DeleteApplication(Application) returns (NotificationResponse); + rpc CreateSubscription(Subscription) returns (NotificationResponse); + rpc UpdateSubscription(Subscription) returns (NotificationResponse); + rpc DeleteSubscription(Subscription) returns (NotificationResponse); +} + +message Application { + string eventId = 1; + string name = 2; + string uuid = 3; + string owner = 4; + string policy = 5; + map attributes = 6; + message Key { + string key = 1; + string keyManager = 2; + } + repeated Key keys = 7; + string organization = 8; + string timeStamp = 9; +} + +message Subscription { + string eventId = 1; + string applicationRef = 2; + string apiRef = 3; + string policyId = 4; + string subStatus = 5; + string subscriber = 6; + string uuid = 7; + string timeStamp = 8; + string organization = 9; +} + +message NotificationResponse { + enum StatusCode { + // The response code is not known. + UNKNOWN = 0; + // The response code to notify that the number of requests are under limit. + OK = 1; + // The response code to notify that the number of requests are over limit. + FAILED = 2; + } + StatusCode code = 1; +} diff --git a/management-server/internal/notification/server.go b/management-server/internal/notification/server.go new file mode 100644 index 000000000..8cbeed994 --- /dev/null +++ b/management-server/internal/notification/server.go @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2022, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * + * 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. + * + */ + +package notification + +import ( + "context" + "crypto/tls" + "fmt" + "net" + "time" + + "github.com/wso2/apk/adapter/pkg/logging" + "github.com/wso2/apk/adapter/pkg/utils/tlsutils" + "github.com/wso2/apk/management-server/internal/config" + "github.com/wso2/apk/management-server/internal/logger" + "github.com/wso2/apk/management-server/internal/synchronizer" + internal_types "github.com/wso2/apk/management-server/internal/types" + "github.com/wso2/apk/management-server/internal/utils" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/keepalive" +) + +type notificationService struct { + notificationService UnimplementedNotificationServiceServer +} + +func newnotificationService() *notificationService { + return ¬ificationService{} +} + +// CreateApplication sends an application create event +func (s *notificationService) CreateApplication(ctx context.Context, application *Application) (*NotificationResponse, error) { + logger.LoggerNotificationServer.Infof("Message received : %q", &application) + var event = internal_types.ApplicationEvent{ + Label: config.ReadConfigs().ManagementServer.NodeLabels[0], + UUID: application.Uuid, + Name: application.Name, + Owner: application.Owner, + Policy: application.Policy, + Attributes: application.Attributes, + //Keys: application.Keys, + Organization: application.Organization, + TimeStamp: application.TimeStamp, + IsRemoveEvent: false, + } + synchronizer.AddApplicationEventsToChannel(event) + return &NotificationResponse{Code: NotificationResponse_OK}, nil +} + +// UpdateApplication sends an application update event +func (s *notificationService) UpdateApplication(ctx context.Context, application *Application) (*NotificationResponse, error) { + logger.LoggerNotificationServer.Infof("Message received : %q", &application) + var event = internal_types.ApplicationEvent{ + Label: config.ReadConfigs().ManagementServer.NodeLabels[0], + UUID: application.Uuid, + Name: application.Name, + Owner: application.Owner, + Policy: application.Policy, + Attributes: application.Attributes, + //Keys: application.Keys, + Organization: application.Organization, + TimeStamp: application.TimeStamp, + IsRemoveEvent: false, + } + synchronizer.AddApplicationEventsToChannel(event) + return &NotificationResponse{Code: NotificationResponse_OK}, nil +} + +// DeleteApplication sends an application delete event +func (s *notificationService) DeleteApplication(ctx context.Context, application *Application) (*NotificationResponse, error) { + logger.LoggerNotificationServer.Infof("Message received : %q", &application) + var event = internal_types.ApplicationEvent{ + Label: config.ReadConfigs().ManagementServer.NodeLabels[0], + UUID: application.Uuid, + Organization: application.Organization, + IsRemoveEvent: true, + } + synchronizer.AddApplicationEventsToChannel(event) + return &NotificationResponse{Code: NotificationResponse_OK}, nil +} + +// CreateSubscription sends a subscription create event +func (s *notificationService) CreateSubscription(ctx context.Context, subscription *Subscription) (*NotificationResponse, error) { + logger.LoggerNotificationServer.Infof("Message received : %q", &subscription) + var event = internal_types.SubscriptionEvent{ + Label: config.ReadConfigs().ManagementServer.NodeLabels[0], + UUID: subscription.Uuid, + ApplicationRef: subscription.ApplicationRef, + APIRef: subscription.ApiRef, + PolicyID: subscription.PolicyId, + SubStatus: subscription.SubStatus, + Subscriber: subscription.Subscriber, + Organization: subscription.Organization, + TimeStamp: subscription.TimeStamp, + IsRemoveEvent: false, + } + synchronizer.AddSubscriptionEventsToChannel(event) + return &NotificationResponse{Code: NotificationResponse_OK}, nil +} + +// UpdateSubscription sends a subscription update event +func (s *notificationService) UpdateSubscription(ctx context.Context, subscription *Subscription) (*NotificationResponse, error) { + logger.LoggerNotificationServer.Infof("Message received : %q", &subscription) + var event = internal_types.SubscriptionEvent{ + Label: config.ReadConfigs().ManagementServer.NodeLabels[0], + UUID: subscription.Uuid, + ApplicationRef: subscription.ApplicationRef, + APIRef: subscription.ApiRef, + PolicyID: subscription.PolicyId, + SubStatus: subscription.SubStatus, + Subscriber: subscription.Subscriber, + Organization: subscription.Organization, + TimeStamp: subscription.TimeStamp, + IsRemoveEvent: false, + } + synchronizer.AddSubscriptionEventsToChannel(event) + return &NotificationResponse{Code: NotificationResponse_OK}, nil +} + +// DeleteSubscription sends a subscription delete event +func (s *notificationService) DeleteSubscription(ctx context.Context, subscription *Subscription) (*NotificationResponse, error) { + logger.LoggerNotificationServer.Infof("Message received : %q", &subscription) + var event = internal_types.SubscriptionEvent{ + Label: config.ReadConfigs().ManagementServer.NodeLabels[0], + UUID: subscription.Uuid, + Organization: subscription.Organization, + IsRemoveEvent: true, + } + synchronizer.AddSubscriptionEventsToChannel(event) + return &NotificationResponse{Code: NotificationResponse_OK}, nil +} + +// StartGRPCServer starts the GRPC server for notifications +func StartGRPCServer() { + var grpcOptions []grpc.ServerOption + publicKeyLocation, privateKeyLocation, truststoreLocation := utils.GetKeyLocations() + cert, err := tlsutils.GetServerCertificate(publicKeyLocation, privateKeyLocation) + caCertPool := tlsutils.GetTrustedCertPool(truststoreLocation) + if err == nil { + grpcOptions = append(grpcOptions, grpc.Creds( + credentials.NewTLS(&tls.Config{ + Certificates: []tls.Certificate{cert}, + ClientAuth: tls.RequireAndVerifyClientCert, + ClientCAs: caCertPool, + }), + )) + } else { + logger.LoggerNotificationServer.ErrorC(logging.ErrorDetails{ + Message: fmt.Sprintf("Failed to initiate the ssl context, error: %v", err.Error()), + Severity: logging.BLOCKER, + ErrorCode: 1200, + }) + } + grpcOptions = append(grpcOptions, grpc.KeepaliveParams( + keepalive.ServerParameters{ + Time: time.Duration(5 * time.Minute), + Timeout: time.Duration(20 * time.Second), + }), + ) + grpcServer := grpc.NewServer(grpcOptions...) + conf := config.ReadConfigs() + port := conf.ManagementServer.NotificationPort + lis, err := net.Listen("tcp", fmt.Sprintf(":%d", port)) + if err != nil { + logger.LoggerNotificationServer.ErrorC(logging.ErrorDetails{ + Message: fmt.Sprintf("Failed to listen for Notifications on port: %v, error: %v", port, err.Error()), + Severity: logging.BLOCKER, + ErrorCode: 1201, + }) + } + // register services + notificationService := newnotificationService() + RegisterNotificationServiceServer(grpcServer, notificationService) + logger.LoggerNotificationServer.Infof("Management server is listening for GRPC connections on port: %v.", port) + grpcServer.Serve(lis) +} diff --git a/management-server/internal/resources/log_config.toml b/management-server/internal/resources/log_config.toml new file mode 100644 index 000000000..9589b8602 --- /dev/null +++ b/management-server/internal/resources/log_config.toml @@ -0,0 +1,17 @@ +# The logging configuration file for APK Agent +######### root Level ######## +logfile = "logs/adapter.log" +logLevel = "INFO" + +[rotation] +MaxSize = 10 #megabytes +MaxBackups = 3 +MaxAge = 2 #days +Compress = true + +######### package Level ############ +# LogLevels = "DEBG", "FATL", "ERRO", "WARN", "INFO", "PANC" + +[[pkg]] +name = "github.com/wso2/apk/APKAgent/xds" +logLevel = "INFO" \ No newline at end of file diff --git a/management-server/internal/synchronizer/application_fetcher.go b/management-server/internal/synchronizer/application_fetcher.go new file mode 100644 index 000000000..e818e01ea --- /dev/null +++ b/management-server/internal/synchronizer/application_fetcher.go @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2022, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 LLC. licenses this file to you 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. + */ + +package synchronizer + +import ( + "github.com/wso2/apk/management-server/internal/types" + "github.com/wso2/apk/management-server/internal/xds" +) + +// ApplicationCreateAndDeleteEventChannel represents the channel to send/receive Application events +var ApplicationCreateAndDeleteEventChannel chan types.ApplicationEvent + +// SubscriptionCreateAndDeleteEventChannel represents the channel to send/receive Subscription events +var SubscriptionCreateAndDeleteEventChannel chan types.SubscriptionEvent + +func init() { + // Channel to handle application create and delete events + ApplicationCreateAndDeleteEventChannel = make(chan types.ApplicationEvent) + // Channel to handle subscription create and delete events + SubscriptionCreateAndDeleteEventChannel = make(chan types.SubscriptionEvent) +} + +// AddApplicationEventsToChannel adds the application event to the channel +func AddApplicationEventsToChannel(event types.ApplicationEvent) { + ApplicationCreateAndDeleteEventChannel <- event +} + +// AddSubscriptionEventsToChannel adds the subscription event to the channel +func AddSubscriptionEventsToChannel(event types.SubscriptionEvent) { + SubscriptionCreateAndDeleteEventChannel <- event +} + +// ProcessApplicationEvents processes the application event +func ProcessApplicationEvents() { + for e := range ApplicationCreateAndDeleteEventChannel { + if e.IsRemoveEvent { + xds.RemoveApplication(e.Label, e.UUID) + } else { + xds.AddSingleApplication(e.Label, e) + } + } +} + +// ProcessSubscriptionEvents processes the subscription event +func ProcessSubscriptionEvents() { + for e := range SubscriptionCreateAndDeleteEventChannel { + if e.IsRemoveEvent { + xds.RemoveSubscription(e.Label, e.UUID) + } else { + xds.AddSingleSubscription(e.Label, e) + } + } +} diff --git a/management-server/internal/types/types.go b/management-server/internal/types/types.go new file mode 100644 index 000000000..56bb452ac --- /dev/null +++ b/management-server/internal/types/types.go @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2022, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * + * 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. + * + */ + +package types + +// ApplicationEvent is a data holder for an application event +type ApplicationEvent struct { + Label string + UUID string + Name string + Owner string + Policy string + Attributes map[string]string + Keys []*ApplicationKey + Organization string + TimeStamp string + IsRemoveEvent bool +} + +// ApplicationKey is a data holder for an application key +type ApplicationKey struct { + Key string + KeyManager string +} + +// SubscriptionEvent is a data holder for a subscription event +type SubscriptionEvent struct { + Label string + UUID string + ApplicationRef string + APIRef string + PolicyID string + SubStatus string + Subscriber string + Organization string + TimeStamp string + IsRemoveEvent bool + IsUpdateEvent bool +} diff --git a/management-server/internal/utils/utils.go b/management-server/internal/utils/utils.go new file mode 100644 index 000000000..6a85c19d2 --- /dev/null +++ b/management-server/internal/utils/utils.go @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org). + * + * 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. + * + */ +package utils + +import "github.com/wso2/apk/management-server/internal/config" + +// GetKeyLocations function returns the public key path and private key path +func GetKeyLocations() (string, string, string) { + conf := config.ReadConfigs() + publicKeyLocation := conf.ManagementServer.Keystore.CertPath + privateKeyLocation := conf.ManagementServer.Keystore.KeyPath + truststoreLocation := conf.ManagementServer.Truststore.Location + return publicKeyLocation, privateKeyLocation, truststoreLocation +} diff --git a/management-server/internal/xds/callbacks/callbacks.go b/management-server/internal/xds/callbacks/callbacks.go new file mode 100644 index 000000000..00e7c0530 --- /dev/null +++ b/management-server/internal/xds/callbacks/callbacks.go @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2022, WSO2 LLC. (http://www.wso2.org). + * + * 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. + * + */ + +// Package callbacks is used to intercept the XDS requests/responses +package callbacks + +import ( + "context" + "fmt" + + corev3 "github.com/envoyproxy/go-control-plane/envoy/config/core/v3" + discovery "github.com/envoyproxy/go-control-plane/envoy/service/discovery/v3" + "github.com/wso2/apk/adapter/pkg/logging" + "github.com/wso2/apk/management-server/internal/logger" +) + +// Callbacks is used to debug the xds server related communication. +type Callbacks struct { +} + +// Report logs the fetches and requests. +func (cb *Callbacks) Report() {} + +// OnStreamOpen prints debug logs +func (cb *Callbacks) OnStreamOpen(_ context.Context, id int64, typ string) error { + logger.LoggerXds.Infof("stream %d open for %s\n", id, typ) + return nil +} + +// OnStreamClosed prints debug logs +func (cb *Callbacks) OnStreamClosed(id int64, node *corev3.Node) { + logger.LoggerXds.Infof("stream %d closed\n", id) +} + +// OnStreamRequest prints debug logs +func (cb *Callbacks) OnStreamRequest(id int64, request *discovery.DiscoveryRequest) error { + logger.LoggerXds.Infof("stream request on stream id: %d, from node: %s, version: %s, for type: %s", + id, request.GetNode(), request.GetVersionInfo(), request.GetTypeUrl()) + if request.ErrorDetail != nil { + logger.LoggerXds.ErrorC(logging.ErrorDetails{ + Message: fmt.Sprintf("Stream request for type %s on stream id: %d Error: %s", request.GetTypeUrl(), id, request.ErrorDetail.Message), + Severity: logging.MINOR, + ErrorCode: 1001, + }) + } + return nil +} + +// OnStreamResponse prints debug logs +func (cb *Callbacks) OnStreamResponse(context context.Context, id int64, request *discovery.DiscoveryRequest, response *discovery.DiscoveryResponse) { + logger.LoggerXds.Infof("stream response on stream id: %d node: %s for type: %s version: %s", + id, request.GetNode(), request.GetTypeUrl(), response.GetVersionInfo()) +} + +// OnFetchRequest prints debug logs +func (cb *Callbacks) OnFetchRequest(_ context.Context, req *discovery.DiscoveryRequest) error { + logger.LoggerXds.Infof("fetch request from node: %s, version: %s, for type: %s", req.Node.Id, req.VersionInfo, req.TypeUrl) + return nil +} + +// OnFetchResponse prints debug logs +func (cb *Callbacks) OnFetchResponse(req *discovery.DiscoveryRequest, res *discovery.DiscoveryResponse) { + logger.LoggerXds.Infof("fetch response to node: %s, version: %s, for type: %s", req.Node.Id, req.VersionInfo, res.TypeUrl) +} + +// OnDeltaStreamOpen is unused. +func (cb *Callbacks) OnDeltaStreamOpen(_ context.Context, id int64, typ string) error { + return nil +} + +// OnDeltaStreamClosed is unused. +func (cb *Callbacks) OnDeltaStreamClosed(id int64, node *corev3.Node) { +} + +// OnStreamDeltaResponse is unused. +func (cb *Callbacks) OnStreamDeltaResponse(id int64, req *discovery.DeltaDiscoveryRequest, res *discovery.DeltaDiscoveryResponse) { +} + +// OnStreamDeltaRequest is unused. +func (cb *Callbacks) OnStreamDeltaRequest(id int64, req *discovery.DeltaDiscoveryRequest) error { + return nil +} diff --git a/management-server/internal/xds/server.go b/management-server/internal/xds/server.go new file mode 100644 index 000000000..1d2cf6e76 --- /dev/null +++ b/management-server/internal/xds/server.go @@ -0,0 +1,400 @@ +/* + * Copyright (c) 2022, WSO2 LLC. (http://www.wso2.org). + * + * 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. + * + */ + +package xds + +import ( + "context" + "crypto/tls" + "fmt" + "math/rand" + "net" + "strings" + "sync" + "time" + + "github.com/wso2/apk/management-server/internal/database" + + corev3 "github.com/envoyproxy/go-control-plane/envoy/config/core/v3" + "github.com/envoyproxy/go-control-plane/pkg/cache/types" + sub_service "github.com/wso2/apk/adapter/pkg/discovery/api/wso2/discovery/service/subscription" + internal_application "github.com/wso2/apk/adapter/pkg/discovery/api/wso2/discovery/subscription" + wso2_cache "github.com/wso2/apk/adapter/pkg/discovery/protocol/cache/v3" + wso2_resource "github.com/wso2/apk/adapter/pkg/discovery/protocol/resource/v3" + wso2_server "github.com/wso2/apk/adapter/pkg/discovery/protocol/server/v3" + "github.com/wso2/apk/adapter/pkg/logging" + "github.com/wso2/apk/adapter/pkg/utils/tlsutils" + "github.com/wso2/apk/management-server/internal/config" + "github.com/wso2/apk/management-server/internal/logger" + internal_types "github.com/wso2/apk/management-server/internal/types" + "github.com/wso2/apk/management-server/internal/utils" + "github.com/wso2/apk/management-server/internal/xds/callbacks" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials" +) + +var ( + applicationCache wso2_cache.SnapshotCache + applicationCacheMutex sync.Mutex + subscriptionCache wso2_cache.SnapshotCache + subscriptionCacheMutex sync.Mutex + introducedLabels map[string]bool +) + +const ( + maxRandomInt int = 999999999 + grpcMaxConcurrentStreams = 1000000 +) + +// IDHash uses ID field as the node hash. +type IDHash struct{} + +// ID uses the node ID field +func (IDHash) ID(node *corev3.Node) string { + if node == nil { + return "unknown" + } + return node.Id +} + +var _ wso2_cache.NodeHash = IDHash{} + +func init() { + applicationCache = wso2_cache.NewSnapshotCache(false, IDHash{}, nil) + subscriptionCache = wso2_cache.NewSnapshotCache(false, IDHash{}, nil) + rand.Seed(time.Now().UnixNano()) + introducedLabels = make(map[string]bool, 1) +} + +// FeedData mock data +func FeedData() { + config := config.ReadConfigs() + logger.LoggerXdsServer.Debug("adding mock data") + version := rand.Intn(maxRandomInt) + applications := internal_application.Application{ + Uuid: "apiUUID1", + Name: "name1", + } + newSnapshot, _ := wso2_cache.NewSnapshot(fmt.Sprint(version), map[wso2_resource.Type][]types.Resource{ + wso2_resource.ApplicationType: {&applications}, + }) + applicationCacheMutex.Lock() + defer applicationCacheMutex.Unlock() + applicationCache.SetSnapshot(context.Background(), config.ManagementServer.NodeLabels[0], newSnapshot) +} + +// AddSingleApplication will update the Application specified by the UUID to the xds cache +func AddSingleApplication(label string, application internal_types.ApplicationEvent) { + appKeys := make([]*internal_application.Application_Key, len(application.Keys)) + for i, key := range application.Keys { + appKeys[i] = &internal_application.Application_Key{ + Key: key.Key, + KeyManager: key.KeyManager, + } + } + convertedApplication := &internal_application.Application{ + Uuid: application.UUID, + Name: application.Name, + Policy: application.Policy, + Owner: application.Owner, + Organization: application.Organization, + Keys: appKeys, + Attributes: application.Attributes, + } + logger.LoggerXds.Debugf("Converted Application: %v", convertedApplication) + + var newSnapshot wso2_cache.Snapshot + version := rand.Intn(maxRandomInt) + currentSnapshot, err := applicationCache.GetSnapshot(label) + + // error occurs if no snapshot is under the provided label + if err != nil { + newSnapshot, _ = wso2_cache.NewSnapshot(fmt.Sprint(version), map[wso2_resource.Type][]types.Resource{ + wso2_resource.ApplicationType: {convertedApplication}, + }) + } else { + resourceMap := currentSnapshot.GetResourcesAndTTL(wso2_resource.ApplicationType) + resourceMap[convertedApplication.Uuid] = types.ResourceWithTTL{ + Resource: convertedApplication, + } + applicationResources := convertResourceMapToArray(resourceMap) + newSnapshot, _ = wso2_cache.NewSnapshot(fmt.Sprint(version), map[wso2_resource.Type][]types.Resource{ + wso2_resource.ApplicationType: applicationResources, + }) + } + applicationCacheMutex.Lock() + defer applicationCacheMutex.Unlock() + applicationCache.SetSnapshot(context.Background(), label, newSnapshot) + introducedLabels[label] = true + logger.LoggerXds.Infof("Application Snapshot is updated for label %s with the version %d. New snapshot "+ + "size is %d.", label, version, len(newSnapshot.GetResourcesAndTTL(wso2_resource.ApplicationType))) + +} + +// RemoveApplication removes the Application entry from XDS cache +func RemoveApplication(label, appUUID string) { + var newSnapshot wso2_cache.Snapshot + version := rand.Intn(maxRandomInt) + for l := range introducedLabels { + // If the label does not match with any introduced labels, don't need to delete the application from cache. + if !strings.EqualFold(label, l) { + continue + } + currentSnapshot, err := applicationCache.GetSnapshot(label) + if err != nil { + continue + } + + resourceMap := currentSnapshot.GetResourcesAndTTL(wso2_resource.ApplicationType) + _, apiFound := resourceMap[appUUID] + // If the Application is found, then the xds cache is updated and returned. + if apiFound { + logger.LoggerXds.Debugf("Application : %s is found within snapshot for label %s", appUUID, label) + delete(resourceMap, appUUID) + apiResources := convertResourceMapToArray(resourceMap) + newSnapshot, _ = wso2_cache.NewSnapshot(fmt.Sprint(version), map[wso2_resource.Type][]types.Resource{ + wso2_resource.ApplicationType: apiResources, + }) + applicationCacheMutex.Lock() + defer applicationCacheMutex.Unlock() + applicationCache.SetSnapshot(context.Background(), label, newSnapshot) + logger.LoggerXds.Infof("API Snaphsot is updated for label %s with the version %d. New snapshot "+ + "size is %d.", label, version, len(newSnapshot.GetResourcesAndTTL(wso2_resource.ApplicationType))) + return + } + } + logger.LoggerXds.Errorf("Application : %s is not found within snapshot for label %s", appUUID, label) +} + +// AddMultipleApplications adds the applications specified in applicationEventArray to the xds cache +// This will ideally be used to populate all applications in the startup of the mgt server. +func AddMultipleApplications(applicationEventArray []*internal_types.ApplicationEvent) { + snapshotMap := make(map[string]*wso2_cache.Snapshot) + version := rand.Intn(maxRandomInt) + + for _, event := range applicationEventArray { + label := event.Label + appUUID := event.UUID + + application, err := database.GetApplicationByUUID(appUUID) + if err != nil { + logger.LoggerDatabase.ErrorC(logging.ErrorDetails{ + Message: fmt.Sprintf("Error retrieving application for uuid : %s from database error: %v, "+ + "hence skipping add to xdx cache", appUUID, err), + Severity: logging.MINOR, + ErrorCode: 1101, + }) + continue + } + + snapshotEntry, snapshotFound := snapshotMap[label] + var newSnapshot wso2_cache.Snapshot + + if !snapshotFound { + newSnapshot, _ = wso2_cache.NewSnapshot(fmt.Sprint(version), map[wso2_resource.Type][]types.Resource{ + wso2_resource.ApplicationType: {application}, + }) + snapshotEntry = &newSnapshot + snapshotMap[label] = &newSnapshot + } else { + // error occurs if no snapshot is under the provided label + resourceMap := snapshotEntry.GetResourcesAndTTL(wso2_resource.ApplicationType) + resourceMap[appUUID] = types.ResourceWithTTL{ + Resource: application, + } + appResources := convertResourceMapToArray(resourceMap) + newSnapshot, _ = wso2_cache.NewSnapshot(fmt.Sprint(version), map[wso2_resource.Type][]types.Resource{ + wso2_resource.ApplicationType: appResources, + }) + snapshotMap[label] = &newSnapshot + } + } + applicationCacheMutex.Lock() + defer applicationCacheMutex.Unlock() + for label, snapshotEntry := range snapshotMap { + applicationCache.SetSnapshot(context.Background(), label, *snapshotEntry) + introducedLabels[label] = true + logger.LoggerXds.Infof("Application Snaphsot is updated for label %s with the version %d.", label, version) + } +} + +func convertResourceMapToArray(resourceMap map[string]types.ResourceWithTTL) []types.Resource { + var appResources []types.Resource + for _, res := range resourceMap { + appResources = append(appResources, res.Resource) + } + return appResources +} + +// SetEmptySnapshot sets an empty snapshot into the applicationCache for the given label +// this is used to set empty snapshot when there are no Applications available for a label +func SetEmptySnapshot(label string) error { + version := rand.Intn(maxRandomInt) + newSnapshot, err := wso2_cache.NewSnapshot(fmt.Sprint(version), map[wso2_resource.Type][]types.Resource{ + wso2_resource.ApplicationType: {}, + }) + if err != nil { + logger.LoggerXds.ErrorC(logging.ErrorDetails{ + Message: fmt.Sprintf("Error creating empty snapshot. error: %v", err.Error()), + Severity: logging.CRITICAL, + ErrorCode: 1003, + }) + return err + } + applicationCacheMutex.Lock() + defer applicationCacheMutex.Unlock() + //performing null check again to avoid race conditions + _, errSnap := applicationCache.GetSnapshot(label) + if errSnap != nil && strings.Contains(errSnap.Error(), "no snapshot found for node") { + errSetSnap := applicationCache.SetSnapshot(context.Background(), label, newSnapshot) + if errSetSnap != nil { + logger.LoggerXds.ErrorC(logging.ErrorDetails{ + Message: fmt.Sprintf("Error setting empty snapshot to applicationCache. error : %v", errSetSnap.Error()), + Severity: logging.CRITICAL, + ErrorCode: 1004, + }) + return errSetSnap + } + } + return nil +} + +// InitAPKMgtServer initializes the APK management server +func InitAPKMgtServer() { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + apkMgtAPIDsSrv := wso2_server.NewServer(ctx, applicationCache, &callbacks.Callbacks{}) + subSrv := wso2_server.NewServer(ctx, subscriptionCache, &callbacks.Callbacks{}) + publicKeyLocation, privateKeyLocation, truststoreLocation := utils.GetKeyLocations() + cert, err := tlsutils.GetServerCertificate(publicKeyLocation, privateKeyLocation) + if err != nil { + logger.LoggerMGTServer.ErrorC(logging.ErrorDetails{ + Message: fmt.Sprintf("Failed to initiate the ssl context, error: %v", err.Error()), + Severity: logging.BLOCKER, + ErrorCode: 1200, + }) + } + caCertPool := tlsutils.GetTrustedCertPool(truststoreLocation) + var grpcOptions []grpc.ServerOption + grpcOptions = append(grpcOptions, grpc.MaxConcurrentStreams(grpcMaxConcurrentStreams), grpc.Creds( + credentials.NewTLS(&tls.Config{ + Certificates: []tls.Certificate{cert}, + ClientAuth: tls.RequireAndVerifyClientCert, + ClientCAs: caCertPool, + }), + )) + grpcServer := grpc.NewServer(grpcOptions...) + sub_service.RegisterApplicationDiscoveryServiceServer(grpcServer, apkMgtAPIDsSrv) + sub_service.RegisterSubscriptionDiscoveryServiceServer(grpcServer, subSrv) + config := config.ReadConfigs() + port := config.ManagementServer.XDSPort + + //todo (amaliMatharaarachchi) handle error gracefully + listener, err := net.Listen("tcp", fmt.Sprintf(":%d", port)) + if err != nil { + logger.LoggerServer.ErrorC(logging.ErrorDetails{ + Message: fmt.Sprintf("Error while listening on port: %v. Error: %v", port, err.Error()), + Severity: logging.BLOCKER, + ErrorCode: 1000, + }) + } + + logger.LoggerServer.Infof("APK Management server XDS is starting on port %v.", port) + if err = grpcServer.Serve(listener); err != nil { + logger.LoggerServer.ErrorC(logging.ErrorDetails{ + Message: fmt.Sprint("Error while starting APK Management server XDS server."), + Severity: logging.BLOCKER, + ErrorCode: 1001, + }) + } +} + +// AddSingleSubscription will update the Subscription specified by the UUID to the xds cache +func AddSingleSubscription(label string, subscription internal_types.SubscriptionEvent) { + convertedSubscription := &internal_application.Subscription{ + Uuid: subscription.UUID, + ApplicationRef: subscription.ApplicationRef, + ApiRef: subscription.APIRef, + SubStatus: subscription.SubStatus, + PolicyId: subscription.PolicyID, + Organization: subscription.Organization, + Subscriber: subscription.Subscriber, + TimeStamp: subscription.TimeStamp, + } + logger.LoggerXds.Debugf("Converted Subscription: %v", convertedSubscription) + var newSnapshot wso2_cache.Snapshot + version := rand.Intn(maxRandomInt) + currentSnapshot, err := subscriptionCache.GetSnapshot(label) + + // error occurs if no snapshot is under the provided label + if err != nil { + newSnapshot, _ = wso2_cache.NewSnapshot(fmt.Sprint(version), map[wso2_resource.Type][]types.Resource{ + wso2_resource.SubscriptionType: {convertedSubscription}, + }) + } else { + resourceMap := currentSnapshot.GetResourcesAndTTL(wso2_resource.SubscriptionType) + resourceMap[convertedSubscription.Uuid] = types.ResourceWithTTL{ + Resource: convertedSubscription, + } + subscriptionResources := convertResourceMapToArray(resourceMap) + newSnapshot, _ = wso2_cache.NewSnapshot(fmt.Sprint(version), map[wso2_resource.Type][]types.Resource{ + wso2_resource.SubscriptionType: subscriptionResources, + }) + } + subscriptionCacheMutex.Lock() + defer subscriptionCacheMutex.Unlock() + subscriptionCache.SetSnapshot(context.Background(), label, newSnapshot) + introducedLabels[label] = true + logger.LoggerXds.Infof("Subscription Snapshot is updated for label %s with the version %d. New snapshot "+ + "size is %d.", label, version, len(newSnapshot.GetResourcesAndTTL(wso2_resource.SubscriptionType))) + +} + +// RemoveSubscription removes the Subscription entry from XDS cache +func RemoveSubscription(label, subUUID string) { + var newSnapshot wso2_cache.Snapshot + version := rand.Intn(maxRandomInt) + for l := range introducedLabels { + // If the label does not match with any introduced labels, don't need to delete the subscription from cache. + if !strings.EqualFold(label, l) { + continue + } + currentSnapshot, err := subscriptionCache.GetSnapshot(label) + if err != nil { + continue + } + + resourceMap := currentSnapshot.GetResourcesAndTTL(wso2_resource.SubscriptionType) + _, subFound := resourceMap[subUUID] + // If the Subscription is found, then the xds cache is updated and returned. + if subFound { + logger.LoggerXds.Debugf("Subscription : %s is found within snapshot for label %s", subUUID, label) + delete(resourceMap, subUUID) + subResources := convertResourceMapToArray(resourceMap) + newSnapshot, _ = wso2_cache.NewSnapshot(fmt.Sprint(version), map[wso2_resource.Type][]types.Resource{ + wso2_resource.SubscriptionType: subResources, + }) + subscriptionCacheMutex.Lock() + defer subscriptionCacheMutex.Unlock() + subscriptionCache.SetSnapshot(context.Background(), label, newSnapshot) + logger.LoggerXds.Infof("Subscription Snaphsot is updated for label %s with the version %d. New snapshot "+ + "size is %d.", label, version, len(newSnapshot.GetResourcesAndTTL(wso2_resource.SubscriptionType))) + return + } + } + logger.LoggerXds.Errorf("Subscription : %s is not found within snapshot for label %s", subUUID, label) +} diff --git a/management-server/resources/check_health.sh b/management-server/resources/check_health.sh new file mode 100755 index 000000000..e963bc5a3 --- /dev/null +++ b/management-server/resources/check_health.sh @@ -0,0 +1,26 @@ +#!/bin/bash +# -------------------------------------------------------------------- +# Copyright (c) 2023, WSO2 LLC. (http://wso2.com) All Rights Reserved. +# +# 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. +# ----------------------------------------------------------------------- + +MGT_SERVER_XDS_PORT="${MGT_SERVER_XDS_PORT:-8765}" +MGT_SERVER_NAME="${MGT_SERVER_NAME:-management-server}" +grpc_health_probe -addr "127.0.0.1:${MGT_SERVER_XDS_PORT}" \ + -tls \ + -tls-ca-cert "${MGT_SERVER_PUBLIC_CERT_PATH}" \ + -tls-client-cert "${MGT_SERVER_PUBLIC_CERT_PATH}" \ + -tls-client-key "${MGT_SERVER_PRIVATE_KEY_PATH}" \ + -tls-server-name ${MGT_SERVER_NAME} \ + -connect-timeout=3s \ No newline at end of file diff --git a/management-server/resources/conf/config.toml b/management-server/resources/conf/config.toml new file mode 100644 index 000000000..e69de29bb diff --git a/management-server/resources/conf/log_config.toml b/management-server/resources/conf/log_config.toml new file mode 100644 index 000000000..bb60c5b1c --- /dev/null +++ b/management-server/resources/conf/log_config.toml @@ -0,0 +1,17 @@ +# The logging configuration file for APK Agent +######### root Level ######## +logfile = "logs/adapter.log" +logLevel = "INFO" + +[rotation] +MaxSize = 10 #megabytes +MaxBackups = 3 +MaxAge = 2 #days +Compress = true + +######### package Level ############ +# LogLevels = "DEBG", "FATL", "ERRO", "WARN", "INFO", "PANC" + +# [[pkg]] +# name = "github.com/wso2/apk/management-server/xds" +# logLevel = "INFO" diff --git a/management-server/revive.toml b/management-server/revive.toml new file mode 100644 index 000000000..731949181 --- /dev/null +++ b/management-server/revive.toml @@ -0,0 +1,28 @@ +ignoreGeneratedHeader = false +severity = "warning" +confidence = 0.8 +errorCode = 0 +warningCode = 0 + +[rule.blank-imports] +[rule.context-as-argument] +[rule.context-keys-type] +[rule.dot-imports] +[rule.error-return] +[rule.error-strings] +[rule.error-naming] +[rule.exported] +[rule.if-return] +[rule.increment-decrement] +[rule.var-naming] +[rule.var-declaration] +[rule.range] +[rule.receiver-naming] +[rule.time-naming] +[rule.unexported-return] +[rule.indent-error-flow] +[rule.errorf] +[rule.empty-block] +[rule.superfluous-else] +[rule.unreachable-code] +[rule.redefines-builtin-id]