diff --git a/.cz-config.js b/.cz-config.js index cb2e19d3a5..36200eaba7 100644 --- a/.cz-config.js +++ b/.cz-config.js @@ -53,5 +53,5 @@ module.exports = { breaklineChar: '|', // It is supported for fields body and footer. footerPrefix: 'Closes ', - breakingPrefix: 'BREAKING CHANGES: ', + breakingPrefix: 'BREAKING CHANGE: ', }; diff --git a/.eslintrc.json b/.eslintrc.json index e7d83277a4..2f6c7aa831 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -182,7 +182,14 @@ "dot-notation": "off", // disabled in favor of @typescript-eslint/dot-notation "eqeqeq": ["error", "always"], "etc/no-commented-out-code": "warn", - "etc/no-deprecated": "warn", + "etc/no-deprecated": [ + "warn", + { + "ignored": { + "templateOptions|to|FormlyTemplateOptions|expressionProperties": "name" // deprecated formly methods are temporarily ignored + } + } + ], "id-blacklist": [ "error", "any", diff --git a/.github/workflows/automated-upgrade.yml b/.github/workflows/automated-upgrade.yml index b511c6b8be..03a5eaa369 100644 --- a/.github/workflows/automated-upgrade.yml +++ b/.github/workflows/automated-upgrade.yml @@ -29,18 +29,18 @@ jobs: continue-on-error: true steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 if: github.ref != 'refs/heads/develop' with: ref: ${{ github.event.pull_request.head.sha }} - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 if: github.ref == 'refs/heads/develop' with: ref: develop - name: Use Node.js 16 - uses: actions/setup-node@v2 + uses: actions/setup-node@v3 with: node-version: ${{ env.NODE_VERSION }} cache: npm diff --git a/.github/workflows/dead-code.yml b/.github/workflows/dead-code.yml index 759c54b2f0..82408414f7 100644 --- a/.github/workflows/dead-code.yml +++ b/.github/workflows/dead-code.yml @@ -14,12 +14,12 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: fetch-depth: 0 - name: Use Node.js 16 - uses: actions/setup-node@v2 + uses: actions/setup-node@v3 with: node-version: ${{ env.NODE_VERSION }} cache: npm diff --git a/.github/workflows/demo-server-up.yml b/.github/workflows/demo-server-up.yml index 850b0e7edb..fac154b503 100644 --- a/.github/workflows/demo-server-up.yml +++ b/.github/workflows/demo-server-up.yml @@ -28,7 +28,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Publish SSR image to Registry id: ssr uses: elgohr/Publish-Docker-Github-Action@v4 diff --git a/.github/workflows/development.yml b/.github/workflows/development.yml index 624b4e9cde..8b3b3d4539 100644 --- a/.github/workflows/development.yml +++ b/.github/workflows/development.yml @@ -32,9 +32,9 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Use Node.js 16 - uses: actions/setup-node@v2 + uses: actions/setup-node@v3 with: node-version: ${{ env.NODE_VERSION }} cache: npm @@ -79,9 +79,9 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Use Node.js 16 - uses: actions/setup-node@v2 + uses: actions/setup-node@v3 with: node-version: ${{ env.NODE_VERSION }} cache: npm @@ -106,12 +106,12 @@ jobs: if: "!startsWith(github.ref, 'refs/tags/') && github.ref != 'refs/heads/master' && github.ref != 'refs/heads/develop'" steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: fetch-depth: 0 - name: Use Node.js 16 - uses: actions/setup-node@v2 + uses: actions/setup-node@v3 with: node-version: ${{ env.NODE_VERSION }} cache: npm @@ -137,9 +137,9 @@ jobs: test: ['normal', 'customization'] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Use Node.js 16 - uses: actions/setup-node@v2 + uses: actions/setup-node@v3 with: node-version: ${{ env.NODE_VERSION }} cache: npm @@ -157,7 +157,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Production Build PWA Image run: docker-compose build pwa @@ -167,7 +167,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Build Nginx Image run: docker-compose build nginx diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index cea065a526..7d1af906a5 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -15,12 +15,12 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: fetch-depth: 0 - name: Use Node.js 16 - uses: actions/setup-node@v2 + uses: actions/setup-node@v3 with: node-version: ${{ env.NODE_VERSION }} cache: npm diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index d56d58c9d0..c297aa4571 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -35,9 +35,9 @@ jobs: TESTING: true steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Use Node.js 16 - uses: actions/setup-node@v2 + uses: actions/setup-node@v3 with: node-version: ${{ env.NODE_VERSION }} cache: npm @@ -52,7 +52,7 @@ jobs: run: npm run build:multi - name: Upload Build Output - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: dist path: dist @@ -66,15 +66,15 @@ jobs: test: ['b2c', 'b2b'] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Use Node.js 16 - uses: actions/setup-node@v2 + uses: actions/setup-node@v3 with: node-version: ${{ env.NODE_VERSION }} cache: npm - name: Download Build Output - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v3 with: name: dist path: dist @@ -109,13 +109,13 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Install e2e dependencies run: cd e2e && npm i - name: Download Build Output - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v3 with: name: dist path: dist @@ -141,7 +141,7 @@ jobs: node dist/$THEME/run-standalone & - name: Cypress - uses: cypress-io/github-action@v2 + uses: cypress-io/github-action@v4 with: install: false wait-on: 'http://localhost:4200' @@ -150,14 +150,14 @@ jobs: command: npx ts-node cypress-ci-e2e **/*${{ matrix.test }}*.e2e-spec.ts - name: Upload Screenshots - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 if: failure() with: name: screenshots path: e2e/cypress/screenshots - name: Upload Videos - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 if: failure() with: name: videos @@ -169,7 +169,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Execute shellspec tests run: | docker run --rm -v "${{ github.workspace }}/nginx/docker-entrypoint.d:/src" shellspec/shellspec diff --git a/.github/workflows/reports.yml b/.github/workflows/reports.yml index 34941c0de1..aab1ec0f5c 100644 --- a/.github/workflows/reports.yml +++ b/.github/workflows/reports.yml @@ -24,7 +24,7 @@ jobs: url: https://pwa-gh-review-reports.azurewebsites.net steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Reset .dockerignore run: echo node_modules > .dockerignore diff --git a/.github/workflows/updates.yml b/.github/workflows/updates.yml index 9a9d33ab87..980928c6ff 100644 --- a/.github/workflows/updates.yml +++ b/.github/workflows/updates.yml @@ -18,9 +18,9 @@ jobs: continue-on-error: true steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Use Node.js 16 - uses: actions/setup-node@v2 + uses: actions/setup-node@v3 with: node-version: ${{ env.NODE_VERSION }} cache: npm diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 37e23b7e04..546eb64cef 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -41,9 +41,9 @@ jobs: runs-on: windows-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Use Node.js 16 - uses: actions/setup-node@v2 + uses: actions/setup-node@v3 with: node-version: ${{ env.NODE_VERSION }} cache: npm @@ -61,9 +61,9 @@ jobs: runs-on: windows-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Use Node.js 16 - uses: actions/setup-node@v2 + uses: actions/setup-node@v3 with: node-version: ${{ env.NODE_VERSION }} cache: npm @@ -91,9 +91,9 @@ jobs: runs-on: windows-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Use Node.js 16 - uses: actions/setup-node@v2 + uses: actions/setup-node@v3 with: node-version: ${{ env.NODE_VERSION }} cache: npm @@ -107,9 +107,9 @@ jobs: runs-on: windows-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Use Node.js 16 - uses: actions/setup-node@v2 + uses: actions/setup-node@v3 with: node-version: ${{ env.NODE_VERSION }} cache: npm diff --git a/.husky/commit-msg b/.husky/commit-msg index 0bd658f496..5a8500090b 100755 --- a/.husky/commit-msg +++ b/.husky/commit-msg @@ -1,4 +1,4 @@ #!/bin/sh . "$(dirname "$0")/_/husky.sh" -npx --no-install commitlint --edit "$1" +npx --no -- commitlint --edit $1 diff --git a/.stylelintrc.json b/.stylelintrc.json index c975e9e9fe..4056063acd 100644 --- a/.stylelintrc.json +++ b/.stylelintrc.json @@ -14,6 +14,7 @@ "font-family-name-quotes": "always-unless-keyword", "function-url-no-scheme-relative": true, "function-url-quotes": "always", + "import-notation": "string", "media-feature-name-no-vendor-prefix": true, "media-feature-name-no-unknown": true, "no-descending-specificity": null, diff --git a/3rd-party-licenses.txt b/3rd-party-licenses.txt index cf5dfd7912..c7285aaf42 100644 --- a/3rd-party-licenses.txt +++ b/3rd-party-licenses.txt @@ -2,36 +2,36 @@ "@adobe/css-tools@4.0.1","MIT","Copyright (c) 2012 TJ Holowaychuk . Copyright (c) 2022 Jean-Philippe Zolesio ","https://github.com/adobe/css-tools" "@aduh95/viz.js@3.7.0","MIT","Copyright (c) 2014-2018 Michael Daines","https://github.com/aduh95/viz.js" "@ampproject/remapping@2.2.0","Apache-2.0","","https://github.com/ampproject/remapping" -"@angular-builders/custom-webpack@14.0.1","MIT","Copyright (c) 2018 Evgeny Barabanov","https://github.com/just-jeb/angular-builders" -"@angular-devkit/architect@0.1402.5","MIT","Copyright (c) 2017 Google, Inc.","https://github.com/angular/angular-cli" -"@angular-devkit/build-angular@14.2.5","MIT","Copyright (c) 2017 Google, Inc.","https://github.com/angular/angular-cli" -"@angular-devkit/build-webpack@0.1402.5","MIT","Copyright (c) 2017 Google, Inc.","https://github.com/angular/angular-cli" +"@angular-builders/custom-webpack@14.1.0","MIT","Copyright (c) 2018 Evgeny Barabanov","https://github.com/just-jeb/angular-builders" +"@angular-devkit/architect@0.1402.10","MIT","Copyright (c) 2017 Google, Inc.","https://github.com/angular/angular-cli" +"@angular-devkit/build-angular@14.2.10","MIT","Copyright (c) 2017 Google, Inc.","https://github.com/angular/angular-cli" +"@angular-devkit/build-webpack@0.1402.10","MIT","Copyright (c) 2017 Google, Inc.","https://github.com/angular/angular-cli" "@angular-devkit/core@13.3.9","MIT","Copyright (c) 2017 Google, Inc.","https://github.com/angular/angular-cli" -"@angular-devkit/core@14.2.5","MIT","Copyright (c) 2017 Google, Inc.","https://github.com/angular/angular-cli" +"@angular-devkit/core@14.2.10","MIT","Copyright (c) 2017 Google, Inc.","https://github.com/angular/angular-cli" "@angular-devkit/schematics@13.3.9","MIT","Copyright (c) 2017 Google, Inc.","https://github.com/angular/angular-cli" -"@angular-devkit/schematics@14.2.5","MIT","Copyright (c) 2017 Google, Inc.","https://github.com/angular/angular-cli" -"@angular-eslint/builder@14.1.2","MIT","Copyright (c) 2020 James Henry","https://github.com/angular-eslint/angular-eslint" -"@angular-eslint/bundled-angular-compiler@14.1.2","MIT","Copyright (c) 2020 James Henry","https://github.com/angular-eslint/angular-eslint" -"@angular-eslint/eslint-plugin-template@14.1.2","MIT","Copyright (c) 2020 James Henry","https://github.com/angular-eslint/angular-eslint" -"@angular-eslint/eslint-plugin@14.1.2","MIT","Copyright (c) 2020 James Henry","https://github.com/angular-eslint/angular-eslint" -"@angular-eslint/schematics@14.1.2","MIT","Copyright (c) 2020 James Henry","https://github.com/angular-eslint/angular-eslint" -"@angular-eslint/template-parser@14.1.2","MIT","Copyright (c) 2020 James Henry","https://github.com/angular-eslint/angular-eslint" -"@angular-eslint/utils@14.1.2","MIT","Copyright (c) 2020 James Henry","" -"@angular/animations@14.2.5","MIT","","https://github.com/angular/angular" -"@angular/cdk@14.2.4","MIT","Copyright (c) 2022 Google LLC.","https://github.com/angular/components" -"@angular/cli@14.2.5","MIT","Copyright (c) 2017 Google, Inc.","https://github.com/angular/angular-cli" -"@angular/common@14.2.5","MIT","","https://github.com/angular/angular" -"@angular/compiler-cli@14.2.5","MIT","","https://github.com/angular/angular" -"@angular/compiler@14.2.5","MIT","","https://github.com/angular/angular" -"@angular/core@14.2.5","MIT","","https://github.com/angular/angular" -"@angular/forms@14.2.5","MIT","","https://github.com/angular/angular" -"@angular/language-service@14.2.5","MIT","","https://github.com/angular/angular" -"@angular/localize@14.2.5","MIT","","https://github.com/angular/angular" -"@angular/platform-browser-dynamic@14.2.5","MIT","","https://github.com/angular/angular" -"@angular/platform-browser@14.2.5","MIT","","https://github.com/angular/angular" -"@angular/platform-server@14.2.5","MIT","","https://github.com/angular/angular" -"@angular/router@14.2.5","MIT","","https://github.com/angular/angular" -"@angular/service-worker@14.2.5","MIT","","https://github.com/angular/angular" +"@angular-devkit/schematics@14.2.10","MIT","Copyright (c) 2017 Google, Inc.","https://github.com/angular/angular-cli" +"@angular-eslint/builder@14.4.0","MIT","Copyright (c) 2020 James Henry","https://github.com/angular-eslint/angular-eslint" +"@angular-eslint/bundled-angular-compiler@14.4.0","MIT","Copyright (c) 2020 James Henry","https://github.com/angular-eslint/angular-eslint" +"@angular-eslint/eslint-plugin-template@14.4.0","MIT","Copyright (c) 2020 James Henry","https://github.com/angular-eslint/angular-eslint" +"@angular-eslint/eslint-plugin@14.4.0","MIT","Copyright (c) 2020 James Henry","https://github.com/angular-eslint/angular-eslint" +"@angular-eslint/schematics@14.4.0","MIT","Copyright (c) 2020 James Henry","https://github.com/angular-eslint/angular-eslint" +"@angular-eslint/template-parser@14.4.0","MIT","Copyright (c) 2020 James Henry","https://github.com/angular-eslint/angular-eslint" +"@angular-eslint/utils@14.4.0","MIT","Copyright (c) 2020 James Henry","" +"@angular/animations@14.2.12","MIT","","https://github.com/angular/angular" +"@angular/cdk@14.2.7","MIT","Copyright (c) 2022 Google LLC.","https://github.com/angular/components" +"@angular/cli@14.2.10","MIT","Copyright (c) 2017 Google, Inc.","https://github.com/angular/angular-cli" +"@angular/common@14.2.12","MIT","","https://github.com/angular/angular" +"@angular/compiler-cli@14.2.12","MIT","","https://github.com/angular/angular" +"@angular/compiler@14.2.12","MIT","","https://github.com/angular/angular" +"@angular/core@14.2.12","MIT","","https://github.com/angular/angular" +"@angular/forms@14.2.12","MIT","","https://github.com/angular/angular" +"@angular/language-service@14.2.12","MIT","","https://github.com/angular/angular" +"@angular/localize@14.2.12","MIT","","https://github.com/angular/angular" +"@angular/platform-browser-dynamic@14.2.12","MIT","","https://github.com/angular/angular" +"@angular/platform-browser@14.2.12","MIT","","https://github.com/angular/angular" +"@angular/platform-server@14.2.12","MIT","","https://github.com/angular/angular" +"@angular/router@14.2.12","MIT","","https://github.com/angular/angular" +"@angular/service-worker@14.2.12","MIT","","https://github.com/angular/angular" "@assemblyscript/loader@0.10.1","Apache-2.0","","https://github.com/AssemblyScript/assemblyscript" "@babel/code-frame@7.18.6","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel" "@babel/compat-data@7.19.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel" @@ -143,19 +143,20 @@ "@babel/types@7.19.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel" "@bcherny/json-schema-ref-parser@9.0.9","MIT","Copyright (c) 2015 James Messinger","https://github.com/APIDevTools/json-schema-ref-parser" "@bcoe/v8-coverage@0.2.3","MIT","Copyright © 2015-2017 Charles Samborski","https://github.com/demurgos/v8-coverage" -"@commitlint/cli@17.1.2","MIT","Copyright (c) 2016 - present Mario Nebl","https://github.com/conventional-changelog/commitlint" +"@commitlint/cli@17.3.0","MIT","Copyright (c) 2016 - present Mario Nebl","https://github.com/conventional-changelog/commitlint" +"@commitlint/config-conventional@17.3.0","MIT","Copyright (c) 2016 - present Mario Nebl","https://github.com/conventional-changelog/commitlint" "@commitlint/config-validator@17.1.0","MIT","Copyright (c) 2016 - present Mario Nebl","https://github.com/conventional-changelog/commitlint" -"@commitlint/ensure@17.0.0","MIT","Copyright (c) 2016 - present Mario Nebl","https://github.com/conventional-changelog/commitlint" +"@commitlint/ensure@17.3.0","MIT","Copyright (c) 2016 - present Mario Nebl","https://github.com/conventional-changelog/commitlint" "@commitlint/execute-rule@17.0.0","MIT","Copyright (c) 2016 - present Mario Nebl","https://github.com/conventional-changelog/commitlint" "@commitlint/format@17.0.0","MIT","Copyright (c) 2016 - present Mario Nebl","https://github.com/conventional-changelog/commitlint" -"@commitlint/is-ignored@17.1.0","MIT","Copyright (c) 2016 - present Mario Nebl","https://github.com/conventional-changelog/commitlint" -"@commitlint/lint@17.1.0","MIT","Copyright (c) 2016 - present Mario Nebl","https://github.com/conventional-changelog/commitlint" -"@commitlint/load@17.1.2","MIT","Copyright (c) 2016 - present Mario Nebl","https://github.com/conventional-changelog/commitlint" -"@commitlint/message@17.0.0","MIT","Copyright (c) 2016 - present Mario Nebl","https://github.com/conventional-changelog/commitlint" -"@commitlint/parse@17.0.0","MIT","Copyright (c) 2016 - present Mario Nebl","https://github.com/conventional-changelog/commitlint" -"@commitlint/read@17.1.0","MIT","Copyright (c) 2016 - present Mario Nebl","https://github.com/conventional-changelog/commitlint" -"@commitlint/resolve-extends@17.1.0","MIT","Copyright (c) 2016 - present Mario Nebl","https://github.com/conventional-changelog/commitlint" -"@commitlint/rules@17.0.0","MIT","Copyright (c) 2016 - present Mario Nebl","https://github.com/conventional-changelog/commitlint" +"@commitlint/is-ignored@17.2.0","MIT","Copyright (c) 2016 - present Mario Nebl","https://github.com/conventional-changelog/commitlint" +"@commitlint/lint@17.3.0","MIT","Copyright (c) 2016 - present Mario Nebl","https://github.com/conventional-changelog/commitlint" +"@commitlint/load@17.3.0","MIT","Copyright (c) 2016 - present Mario Nebl","https://github.com/conventional-changelog/commitlint" +"@commitlint/message@17.2.0","MIT","Copyright (c) 2016 - present Mario Nebl","https://github.com/conventional-changelog/commitlint" +"@commitlint/parse@17.2.0","MIT","Copyright (c) 2016 - present Mario Nebl","https://github.com/conventional-changelog/commitlint" +"@commitlint/read@17.2.0","MIT","Copyright (c) 2016 - present Mario Nebl","https://github.com/conventional-changelog/commitlint" +"@commitlint/resolve-extends@17.3.0","MIT","Copyright (c) 2016 - present Mario Nebl","https://github.com/conventional-changelog/commitlint" +"@commitlint/rules@17.3.0","MIT","Copyright (c) 2016 - present Mario Nebl","https://github.com/conventional-changelog/commitlint" "@commitlint/to-lines@17.0.0","MIT","Copyright (c) 2016 - present Mario Nebl","https://github.com/conventional-changelog/commitlint" "@commitlint/top-level@17.0.0","MIT","Copyright (c) 2016 - present Mario Nebl","https://github.com/conventional-changelog/commitlint" "@commitlint/types@17.0.0","MIT","Copyright (c) 2016 - present Mario Nebl","https://github.com/conventional-changelog/commitlint" @@ -163,54 +164,56 @@ "@compodoc/live-server@1.2.3","MIT","Copyright (c) 2012 Tapio Vierros","https://github.com/compodoc/live-server" "@compodoc/ngd-core@2.1.0","MIT","","https://github.com/compodoc/ngd" "@compodoc/ngd-transformer@2.1.0","MIT","","https://github.com/compodoc/ngd" -"@cspell/cspell-bundled-dicts@6.12.0","MIT","Copyright (c) 2017 Jason Dent","https://github.com/streetsidesoftware/cspell" -"@cspell/cspell-pipe@6.12.0","MIT","Copyright (c) 2017 Jason Dent","https://github.com/streetsidesoftware/cspell" -"@cspell/cspell-service-bus@6.12.0","MIT","Copyright (c) 2017 Jason Dent","https://github.com/streetsidesoftware/cspell" -"@cspell/cspell-types@6.12.0","MIT","Copyright (c) 2017 Jason Dent","https://github.com/streetsidesoftware/cspell" -"@cspell/dict-ada@2.0.1","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" -"@cspell/dict-aws@2.0.0","MIT","Copyright (c) 2019 Daniel Schroeder . Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" -"@cspell/dict-bash@2.0.4","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" -"@cspell/dict-companies@2.0.14","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" -"@cspell/dict-cpp@3.2.1","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" -"@cspell/dict-cryptocurrencies@2.0.0","MIT","Copyright (c) 2020 Shane Fontaine . Copyright (c) 2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" -"@cspell/dict-csharp@3.0.1","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" -"@cspell/dict-css@2.1.0","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" -"@cspell/dict-dart@1.1.1","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" +"@cspell/cspell-bundled-dicts@6.17.0","MIT","Copyright (c) 2017 Jason Dent","https://github.com/streetsidesoftware/cspell" +"@cspell/cspell-pipe@6.17.0","MIT","Copyright (c) 2017 Jason Dent","https://github.com/streetsidesoftware/cspell" +"@cspell/cspell-service-bus@6.17.0","MIT","Copyright (c) 2017 Jason Dent","https://github.com/streetsidesoftware/cspell" +"@cspell/cspell-types@6.17.0","MIT","Copyright (c) 2017 Jason Dent","https://github.com/streetsidesoftware/cspell" +"@cspell/dict-ada@4.0.0","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" +"@cspell/dict-aws@3.0.0","MIT","Copyright (c) 2019 Daniel Schroeder . Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" +"@cspell/dict-bash@4.1.0","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" +"@cspell/dict-companies@3.0.3","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" +"@cspell/dict-cpp@4.0.0","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" +"@cspell/dict-cryptocurrencies@3.0.1","MIT","Copyright (c) 2020 Shane Fontaine . Copyright (c) 2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" +"@cspell/dict-csharp@4.0.2","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" +"@cspell/dict-css@4.0.0","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" +"@cspell/dict-dart@2.0.0","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" "@cspell/dict-de-de@1.1.32","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" -"@cspell/dict-django@2.0.0","MIT","Copyright (c) 2017-2020 Renaud Canarduck . Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" -"@cspell/dict-docker@1.1.1","MIT","Copyright (c) 2022 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" -"@cspell/dict-dotnet@2.0.1","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" -"@cspell/dict-elixir@2.0.1","MIT","Copyright (c) 2018 Todoroki (Ryo Konishi) . Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" +"@cspell/dict-django@4.0.0","MIT","Copyright (c) 2017-2020 Renaud Canarduck . Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" +"@cspell/dict-docker@1.1.3","MIT","Copyright (c) 2022 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" +"@cspell/dict-dotnet@4.0.0","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" +"@cspell/dict-elixir@4.0.0","MIT","Copyright (c) 2018 Todoroki (Ryo Konishi) . Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" "@cspell/dict-en-gb@1.1.33","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" -"@cspell/dict-en_us@2.3.3","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" -"@cspell/dict-filetypes@2.1.1","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" -"@cspell/dict-fonts@2.1.0","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" +"@cspell/dict-en_us@4.1.0","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" +"@cspell/dict-filetypes@3.0.0","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" +"@cspell/dict-fonts@3.0.0","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" "@cspell/dict-fr-fr@2.1.1","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" -"@cspell/dict-fullstack@2.0.6","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" -"@cspell/dict-git@1.0.1","MIT","Copyright (c) 2017-2022 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" -"@cspell/dict-golang@3.0.1","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" -"@cspell/dict-haskell@2.0.1","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" -"@cspell/dict-html-symbol-entities@3.0.0","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" -"@cspell/dict-html@3.3.2","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" -"@cspell/dict-java@3.0.7","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" -"@cspell/dict-latex@2.0.9","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" -"@cspell/dict-lorem-ipsum@2.0.1","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" -"@cspell/dict-lua@2.0.0","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" -"@cspell/dict-node@3.0.1","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" -"@cspell/dict-npm@3.1.3","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" -"@cspell/dict-php@2.0.0","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" -"@cspell/dict-powershell@2.0.0","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" -"@cspell/dict-public-licenses@1.0.6","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" -"@cspell/dict-python@3.0.6","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" -"@cspell/dict-r@1.0.3","MIT","Copyright (c) 2017-2020 Jason Dent , Matthew Toohey ","https://github.com/streetsidesoftware/cspell-dicts" -"@cspell/dict-ruby@2.0.2","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" -"@cspell/dict-rust@2.0.1","MIT","Copyright (c) 2017-2020 Alexander Andreev . Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" -"@cspell/dict-scala@2.0.0","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" -"@cspell/dict-software-terms@2.2.12","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" -"@cspell/dict-sql@1.0.4","MIT","Copyright (c) 2017-2022 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" -"@cspell/dict-swift@1.0.3","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" -"@cspell/dict-typescript@2.0.2","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" -"@cspell/dict-vue@2.0.2","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" +"@cspell/dict-fullstack@3.0.0","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" +"@cspell/dict-git@2.0.0","MIT","Copyright (c) 2017-2022 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" +"@cspell/dict-golang@5.0.0","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" +"@cspell/dict-haskell@4.0.0","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" +"@cspell/dict-html-symbol-entities@4.0.0","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" +"@cspell/dict-html@4.0.1","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" +"@cspell/dict-java@5.0.2","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" +"@cspell/dict-latex@3.0.0","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" +"@cspell/dict-lorem-ipsum@3.0.0","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" +"@cspell/dict-lua@3.0.0","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" +"@cspell/dict-node@4.0.1","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" +"@cspell/dict-npm@5.0.0","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" +"@cspell/dict-php@3.0.3","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" +"@cspell/dict-powershell@3.0.0","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" +"@cspell/dict-public-licenses@2.0.0","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" +"@cspell/dict-python@4.0.0","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" +"@cspell/dict-r@2.0.0","MIT","Copyright (c) 2017-2020 Jason Dent , Matthew Toohey ","https://github.com/streetsidesoftware/cspell-dicts" +"@cspell/dict-ruby@3.0.0","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" +"@cspell/dict-rust@3.0.0","MIT","Copyright (c) 2017-2020 Alexander Andreev . Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" +"@cspell/dict-scala@3.0.0","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" +"@cspell/dict-software-terms@3.0.5","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" +"@cspell/dict-sql@2.0.0","MIT","Copyright (c) 2017-2022 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" +"@cspell/dict-svelte@1.0.0","MIT","Copyright (c) 2017-2022 Street Side Software ","https://github.com/streetsidesoftware/cspell-dicts" +"@cspell/dict-swift@2.0.0","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" +"@cspell/dict-typescript@3.0.1","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" +"@cspell/dict-vue@3.0.0","MIT","Copyright (c) 2017-2020 Jason Dent ","https://github.com/streetsidesoftware/cspell-dicts" +"@cspell/strong-weak-map@6.17.0","MIT","Copyright (c) 2017 Jason Dent","https://github.com/streetsidesoftware/cspell" "@cspotcode/source-map-support@0.8.1","MIT","Copyright (c) 2014 Evan Wallace","https://github.com/cspotcode/node-source-map-support" "@csstools/postcss-cascade-layers@1.1.1","CC0-1.0","","https://github.com/csstools/postcss-plugins" "@csstools/postcss-color-function@1.1.1","CC0-1.0","","https://github.com/csstools/postcss-plugins" @@ -228,20 +231,20 @@ "@csstools/postcss-unset-value@1.0.2","CC0-1.0","","https://github.com/csstools/postcss-plugins" "@csstools/selector-specificity@2.0.2","CC0-1.0","","https://github.com/csstools/postcss-plugins" "@discoveryjs/json-ext@0.5.7","MIT","Copyright (c) 2020 Roman Dvornov ","https://github.com/discoveryjs/json-ext" -"@es-joy/jsdoccomment@0.31.0","MIT","Copyright JS Foundation and other contributors, https://js.foundation. Copyright (c) 2021 Brett Zamir","https://github.com/es-joy/jsdoccomment" -"@eslint/eslintrc@1.3.2","MIT","Copyright OpenJS Foundation and other contributors, ","https://github.com/eslint/eslintrc" +"@es-joy/jsdoccomment@0.36.1","MIT","Copyright JS Foundation and other contributors, https://js.foundation. Copyright (c) 2021 Brett Zamir","https://github.com/es-joy/jsdoccomment" +"@eslint-community/eslint-utils@4.1.2","MIT","Copyright (c) 2018 Toru Nagashima","https://github.com/eslint-community/eslint-utils" +"@eslint/eslintrc@1.3.3","MIT","Copyright OpenJS Foundation and other contributors, ","https://github.com/eslint/eslintrc" "@foliojs-fork/fontkit@1.9.1","MIT","","https://github.com/foliojs-fork/fontkit" "@foliojs-fork/linebreak@1.1.1","MIT","Copyright (c) 2014-present Devon Govett","https://github.com/foliojs-fork/linebreaker" "@foliojs-fork/pdfkit@0.13.0","MIT","","https://github.com/foliojs-fork/pdfkit" "@foliojs-fork/restructure@2.0.2","MIT","Copyright (c) 2015-present Devon Govett","https://github.com/foliojs-fork/restructure" "@fortawesome/angular-fontawesome@0.11.1","MIT","Copyright (c) 2018 Fonticons, Inc. and contributors","https://github.com/FortAwesome/angular-fontawesome" -"@fortawesome/fontawesome-common-types@6.2.0","MIT","Copyright (c) 2022 Fonticons, Inc. (https://fontawesome.com). with Reserved Font Name: "Font Awesome".*","https://github.com/FortAwesome/Font-Awesome" -"@fortawesome/fontawesome-svg-core@6.2.0","MIT","Copyright (c) 2022 Fonticons, Inc. (https://fontawesome.com). with Reserved Font Name: "Font Awesome".*","https://github.com/FortAwesome/Font-Awesome" -"@fortawesome/free-solid-svg-icons@6.2.0","(CC-BY-4.0 AND MIT)","Copyright (c) 2022 Fonticons, Inc. (https://fontawesome.com). with Reserved Font Name: "Font Awesome".*","https://github.com/FortAwesome/Font-Awesome" +"@fortawesome/fontawesome-common-types@6.2.1","MIT","Copyright (c) 2022 Fonticons, Inc. (https://fontawesome.com). with Reserved Font Name: "Font Awesome".*","https://github.com/FortAwesome/Font-Awesome" +"@fortawesome/fontawesome-svg-core@6.2.1","MIT","Copyright (c) 2022 Fonticons, Inc. (https://fontawesome.com). with Reserved Font Name: "Font Awesome".*","https://github.com/FortAwesome/Font-Awesome" +"@fortawesome/free-solid-svg-icons@6.2.1","(CC-BY-4.0 AND MIT)","Copyright (c) 2022 Fonticons, Inc. (https://fontawesome.com). with Reserved Font Name: "Font Awesome".*","https://github.com/FortAwesome/Font-Awesome" "@gar/promisify@1.1.3","MIT","Copyright © 2020-2022 Michael Garvin","https://github.com/wraithgar/gar-promisify" -"@googlemaps/js-api-loader@1.14.3","Apache-2.0","","https://github.com/googlemaps/js-api-loader" -"@humanwhocodes/config-array@0.10.7","Apache-2.0","","https://github.com/humanwhocodes/config-array" -"@humanwhocodes/gitignore-to-minimatch@1.0.2","Apache-2.0","","https://github.com/humanwhocodes/gitignore-to-minimatch" +"@googlemaps/js-api-loader@1.15.1","Apache-2.0","","https://github.com/googlemaps/js-api-loader" +"@humanwhocodes/config-array@0.11.7","Apache-2.0","","https://github.com/humanwhocodes/config-array" "@humanwhocodes/module-importer@1.0.1","Apache-2.0","","https://github.com/humanwhocodes/module-importer" "@humanwhocodes/object-schema@1.2.1","BSD-3-Clause","Copyright (c) 2019, Human Who Codes. All rights reserved.","https://github.com/humanwhocodes/object-schema" "@hutson/parse-repository-url@3.0.2","Apache-2.0","","git+https://gitlab.com/hyper-expanse/open-source/parse-repository-url" @@ -289,11 +292,11 @@ "@ngrx/router-store@14.3.2","MIT","","https://github.com/ngrx/platform" "@ngrx/store-devtools@14.3.2","MIT","","https://github.com/ngrx/platform" "@ngrx/store@14.3.2","MIT","","https://github.com/ngrx/platform" -"@ngtools/webpack@14.2.5","MIT","Copyright (c) 2017 Google, Inc.","https://github.com/angular/angular-cli" -"@nguniversal/builders@14.2.0","MIT","","https://github.com/angular/universal" -"@nguniversal/common@14.2.0","MIT","","https://github.com/angular/universal" -"@nguniversal/express-engine@14.2.0","MIT","","https://github.com/angular/universal" -"@ngx-formly/core@5.12.7","MIT","","https://github.com/ngx-formly/ngx-formly" +"@ngtools/webpack@14.2.10","MIT","Copyright (c) 2017 Google, Inc.","https://github.com/angular/angular-cli" +"@nguniversal/builders@14.2.3","MIT","","https://github.com/angular/universal" +"@nguniversal/common@14.2.3","MIT","","https://github.com/angular/universal" +"@nguniversal/express-engine@14.2.3","MIT","","https://github.com/angular/universal" +"@ngx-formly/core@6.0.4","MIT","","https://github.com/ngx-formly/ngx-formly" "@ngx-translate/core@14.0.0","MIT","","https://github.com/ngx-translate/core" "@nodelib/fs.scandir@2.1.5","MIT","Copyright (c) Denis Malinochkin","https://github.com/nodelib/nodelib/tree/master/packages/fs/fs.scandir" "@nodelib/fs.stat@2.0.5","MIT","Copyright (c) Denis Malinochkin","https://github.com/nodelib/nodelib/tree/master/packages/fs/fs.stat" @@ -315,12 +318,11 @@ "@pm2/js-api@0.6.7","Apache*","","https://github.com/keymetrics/km.js" "@pm2/pm2-version-check@1.0.4","MIT","","" "@rx-angular/state@1.7.0","MIT","","https://github.com/rx-angular/rx-angular" -"@schematics/angular@14.2.5","MIT","Copyright (c) 2017 Google, Inc.","https://github.com/angular/angular-cli" -"@sentry/browser@7.14.1","BSD-3-Clause","Copyright (c) 2019, Sentry. All rights reserved.","https://github.com/getsentry/sentry-javascript" -"@sentry/core@7.14.1","BSD-3-Clause","Copyright (c) 2019, Sentry. All rights reserved.","https://github.com/getsentry/sentry-javascript" -"@sentry/hub@7.14.1","BSD-3-Clause","Copyright (c) 2019, Sentry. All rights reserved.","https://github.com/getsentry/sentry-javascript" -"@sentry/types@7.14.1","BSD-3-Clause","Copyright (c) 2019, Sentry. All rights reserved.","https://github.com/getsentry/sentry-javascript" -"@sentry/utils@7.14.1","BSD-3-Clause","Copyright (c) 2019, Sentry. All rights reserved.","https://github.com/getsentry/sentry-javascript" +"@schematics/angular@14.2.10","MIT","Copyright (c) 2017 Google, Inc.","https://github.com/angular/angular-cli" +"@sentry/browser@7.25.0","MIT","Copyright (c) 2019 Sentry (https://sentry.io) and individual contributors. All rights reserved.","https://github.com/getsentry/sentry-javascript" +"@sentry/core@7.25.0","MIT","Copyright (c) 2019 Sentry (https://sentry.io) and individual contributors. All rights reserved.","https://github.com/getsentry/sentry-javascript" +"@sentry/types@7.25.0","MIT","Copyright (c) 2019 Sentry (https://sentry.io) and individual contributors. All rights reserved.","https://github.com/getsentry/sentry-javascript" +"@sentry/utils@7.25.0","MIT","Copyright (c) 2019 Sentry (https://sentry.io) and individual contributors. All rights reserved.","https://github.com/getsentry/sentry-javascript" "@sinclair/typebox@0.24.44","MIT","Copyright (c) 2022 Haydn Paterson (sinclair) ","https://github.com/sinclairzx81/typebox" "@sinonjs/commons@1.8.3","BSD-3-Clause","Copyright (c) 2018, Sinon.JS. All rights reserved.","https://github.com/sinonjs/commons" "@sinonjs/fake-timers@9.1.2","BSD-3-Clause","Copyright (c) 2010-2014, Christian Johansen, christian@cjohansen.no. All rights reserved.","https://github.com/sinonjs/fake-timers" @@ -345,13 +347,13 @@ "@types/cookie@0.4.1","MIT","","https://github.com/DefinitelyTyped/DefinitelyTyped" "@types/cors@2.8.12","MIT","","https://github.com/DefinitelyTyped/DefinitelyTyped" "@types/eslint-scope@3.7.4","MIT","","https://github.com/DefinitelyTyped/DefinitelyTyped" -"@types/eslint@8.4.6","MIT","","https://github.com/DefinitelyTyped/DefinitelyTyped" +"@types/eslint@8.4.10","MIT","","https://github.com/DefinitelyTyped/DefinitelyTyped" "@types/estree@0.0.51","MIT","","https://github.com/DefinitelyTyped/DefinitelyTyped" "@types/estree@1.0.0","MIT","","https://github.com/DefinitelyTyped/DefinitelyTyped" "@types/express-serve-static-core@4.17.31","MIT","","https://github.com/DefinitelyTyped/DefinitelyTyped" "@types/express@4.17.14","MIT","","https://github.com/DefinitelyTyped/DefinitelyTyped" "@types/glob@7.2.0","MIT","","https://github.com/DefinitelyTyped/DefinitelyTyped" -"@types/google.maps@3.50.2","MIT","","https://github.com/DefinitelyTyped/DefinitelyTyped" +"@types/google.maps@3.51.0","MIT","","https://github.com/DefinitelyTyped/DefinitelyTyped" "@types/graceful-fs@4.1.5","MIT","","https://github.com/DefinitelyTyped/DefinitelyTyped" "@types/grecaptcha@3.0.4","MIT","","https://github.com/DefinitelyTyped/DefinitelyTyped" "@types/http-proxy@1.17.9","MIT","","https://github.com/DefinitelyTyped/DefinitelyTyped" @@ -367,8 +369,8 @@ "@types/mime@3.0.1","MIT","","https://github.com/DefinitelyTyped/DefinitelyTyped" "@types/minimatch@3.0.5","MIT","","https://github.com/DefinitelyTyped/DefinitelyTyped" "@types/minimist@1.2.2","MIT","","https://github.com/DefinitelyTyped/DefinitelyTyped" -"@types/node@14.18.31","MIT","","https://github.com/DefinitelyTyped/DefinitelyTyped" -"@types/node@16.11.64","MIT","","https://github.com/DefinitelyTyped/DefinitelyTyped" +"@types/node@14.18.34","MIT","","https://github.com/DefinitelyTyped/DefinitelyTyped" +"@types/node@16.18.8","MIT","","https://github.com/DefinitelyTyped/DefinitelyTyped" "@types/normalize-package-data@2.4.1","MIT","","https://github.com/DefinitelyTyped/DefinitelyTyped" "@types/parse-json@4.0.0","MIT","","https://github.com/DefinitelyTyped/DefinitelyTyped" "@types/parse5@6.0.3","MIT","","https://github.com/DefinitelyTyped/DefinitelyTyped" @@ -376,31 +378,37 @@ "@types/qs@6.9.7","MIT","","https://github.com/DefinitelyTyped/DefinitelyTyped" "@types/range-parser@1.2.4","MIT","","https://github.com/DefinitelyTyped/DefinitelyTyped" "@types/retry@0.12.0","MIT","","https://github.com/DefinitelyTyped/DefinitelyTyped" +"@types/semver@7.3.13","MIT","","https://github.com/DefinitelyTyped/DefinitelyTyped" "@types/serve-index@1.9.1","MIT","","https://github.com/DefinitelyTyped/DefinitelyTyped" "@types/serve-static@1.15.0","MIT","","https://github.com/DefinitelyTyped/DefinitelyTyped" "@types/sockjs@0.3.33","MIT","","https://github.com/DefinitelyTyped/DefinitelyTyped" "@types/stack-utils@2.0.1","MIT","","https://github.com/DefinitelyTyped/DefinitelyTyped" "@types/tough-cookie@4.0.2","MIT","","https://github.com/DefinitelyTyped/DefinitelyTyped" -"@types/uuid@8.3.4","MIT","","https://github.com/DefinitelyTyped/DefinitelyTyped" +"@types/uuid@9.0.0","MIT","","https://github.com/DefinitelyTyped/DefinitelyTyped" "@types/webpack@5.28.0","MIT","","https://github.com/DefinitelyTyped/DefinitelyTyped" "@types/ws@8.5.3","MIT","","https://github.com/DefinitelyTyped/DefinitelyTyped" "@types/yargs-parser@21.0.0","MIT","","https://github.com/DefinitelyTyped/DefinitelyTyped" "@types/yargs@17.0.13","MIT","","https://github.com/DefinitelyTyped/DefinitelyTyped" -"@typescript-eslint/eslint-plugin@5.39.0","MIT","Copyright (c) 2019 TypeScript ESLint and other contributors","https://github.com/typescript-eslint/typescript-eslint" +"@typescript-eslint/eslint-plugin@5.46.1","MIT","Copyright (c) 2019 typescript-eslint and other contributors","https://github.com/typescript-eslint/typescript-eslint" "@typescript-eslint/experimental-utils@5.39.0","MIT","Copyright (c) 2019 TypeScript ESLint and other contributors","https://github.com/typescript-eslint/typescript-eslint" -"@typescript-eslint/parser@5.39.0","BSD-2-Clause","","https://github.com/typescript-eslint/typescript-eslint" -"@typescript-eslint/scope-manager@5.37.0","MIT","Copyright (c) 2019 TypeScript ESLint and other contributors","https://github.com/typescript-eslint/typescript-eslint" +"@typescript-eslint/parser@5.46.1","BSD-2-Clause","","https://github.com/typescript-eslint/typescript-eslint" "@typescript-eslint/scope-manager@5.39.0","MIT","Copyright (c) 2019 TypeScript ESLint and other contributors","https://github.com/typescript-eslint/typescript-eslint" -"@typescript-eslint/type-utils@5.37.0","MIT","Copyright (c) 2021 TypeScript ESLint and other contributors","https://github.com/typescript-eslint/typescript-eslint" -"@typescript-eslint/type-utils@5.39.0","MIT","Copyright (c) 2021 TypeScript ESLint and other contributors","https://github.com/typescript-eslint/typescript-eslint" -"@typescript-eslint/types@5.37.0","MIT","Copyright (c) 2019 TypeScript ESLint and other contributors","https://github.com/typescript-eslint/typescript-eslint" +"@typescript-eslint/scope-manager@5.43.0","MIT","Copyright (c) 2019 TypeScript ESLint and other contributors","https://github.com/typescript-eslint/typescript-eslint" +"@typescript-eslint/scope-manager@5.46.1","MIT","Copyright (c) 2019 typescript-eslint and other contributors","https://github.com/typescript-eslint/typescript-eslint" +"@typescript-eslint/type-utils@5.43.0","MIT","Copyright (c) 2021 TypeScript ESLint and other contributors","https://github.com/typescript-eslint/typescript-eslint" +"@typescript-eslint/type-utils@5.46.1","MIT","Copyright (c) 2021 typescript-eslint and other contributors","https://github.com/typescript-eslint/typescript-eslint" "@typescript-eslint/types@5.39.0","MIT","Copyright (c) 2019 TypeScript ESLint and other contributors","https://github.com/typescript-eslint/typescript-eslint" -"@typescript-eslint/typescript-estree@5.37.0","BSD-2-Clause","","https://github.com/typescript-eslint/typescript-eslint" +"@typescript-eslint/types@5.43.0","MIT","Copyright (c) 2019 TypeScript ESLint and other contributors","https://github.com/typescript-eslint/typescript-eslint" +"@typescript-eslint/types@5.46.1","MIT","Copyright (c) 2019 typescript-eslint and other contributors","https://github.com/typescript-eslint/typescript-eslint" "@typescript-eslint/typescript-estree@5.39.0","BSD-2-Clause","","https://github.com/typescript-eslint/typescript-eslint" -"@typescript-eslint/utils@5.37.0","MIT","Copyright (c) 2019 TypeScript ESLint and other contributors","https://github.com/typescript-eslint/typescript-eslint" +"@typescript-eslint/typescript-estree@5.43.0","BSD-2-Clause","","https://github.com/typescript-eslint/typescript-eslint" +"@typescript-eslint/typescript-estree@5.46.1","BSD-2-Clause","","https://github.com/typescript-eslint/typescript-eslint" "@typescript-eslint/utils@5.39.0","MIT","Copyright (c) 2019 TypeScript ESLint and other contributors","https://github.com/typescript-eslint/typescript-eslint" -"@typescript-eslint/visitor-keys@5.37.0","MIT","Copyright (c) 2019 TypeScript ESLint and other contributors","https://github.com/typescript-eslint/typescript-eslint" +"@typescript-eslint/utils@5.43.0","MIT","Copyright (c) 2019 TypeScript ESLint and other contributors","https://github.com/typescript-eslint/typescript-eslint" +"@typescript-eslint/utils@5.46.1","MIT","Copyright (c) 2019 typescript-eslint and other contributors","https://github.com/typescript-eslint/typescript-eslint" "@typescript-eslint/visitor-keys@5.39.0","MIT","Copyright (c) 2019 TypeScript ESLint and other contributors","https://github.com/typescript-eslint/typescript-eslint" +"@typescript-eslint/visitor-keys@5.43.0","MIT","Copyright (c) 2019 TypeScript ESLint and other contributors","https://github.com/typescript-eslint/typescript-eslint" +"@typescript-eslint/visitor-keys@5.46.1","MIT","Copyright (c) 2019 typescript-eslint and other contributors","https://github.com/typescript-eslint/typescript-eslint" "@webassemblyjs/ast@1.11.1","MIT","Copyright (c) 2018 Sven Sauleau ","https://github.com/xtuc/webassemblyjs" "@webassemblyjs/floating-point-hex-parser@1.11.1","MIT","Copyright (c) 2017 Mauro Bringolf","https://github.com/xtuc/webassemblyjs" "@webassemblyjs/helper-api-error@1.11.1","MIT","Copyright (c) 2018 Sven Sauleau ","https://github.com/xtuc/webassemblyjs" @@ -447,7 +455,7 @@ "amp-message@0.1.2","MIT","","https://github.com/visionmedia/node-amp-message" "amp@0.3.1","MIT","","https://github.com/visionmedia/node-amp" "angular-oauth2-oidc@13.0.1","MIT","Copyright (c) 2017 Manfred Steyer","https://github.com/manfredsteyer/angular-oauth2-oidc" -"angulartics2@12.1.0","MIT","Copyright (c) 2021 angulartics","https://github.com/angulartics/angulartics2" +"angulartics2@12.2.0","MIT","Copyright (c) 2021 angulartics","https://github.com/angulartics/angulartics2" "ansi-colors@4.1.3","MIT","Copyright (c) 2015-present, Brian Woodward.","https://github.com/doowb/ansi-colors" "ansi-escapes@3.2.0","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)","https://github.com/sindresorhus/ansi-escapes" "ansi-escapes@4.3.2","MIT","Copyright (c) Sindre Sorhus (https://sindresorhus.com)","https://github.com/sindresorhus/ansi-escapes" @@ -468,13 +476,12 @@ "anymatch@3.1.2","ISC","Copyright (c) 2019 Elan Shanker, Paul Miller (https://paulmillr.com)","https://github.com/micromatch/anymatch" "apache-crypt@1.2.6","MIT","Copyright (c) Gevorg Harutyunyan","https://github.com/gevorg/apache-crypt" "apache-md5@1.1.8","MIT","Copyright (c) Gevorg Harutyunyan","https://github.com/gevorg/apache-md5" -"app-root-path@3.0.0","MIT","Copyright (c) 2014 Chris Morrell","https://github.com/inxilpro/node-app-root-path" "aproba@2.0.0","ISC","Copyright (c) 2015, Rebecca Turner ","https://github.com/iarna/aproba" "are-we-there-yet@3.0.1","ISC","Copyright npm, Inc.","https://github.com/npm/are-we-there-yet" "arg@4.1.3","MIT","Copyright (c) 2017-2019 Zeit, Inc.","https://github.com/zeit/arg" "argparse@1.0.10","MIT","Copyright (C) 2012 by Vitaly Puzrin","https://github.com/nodeca/argparse" "argparse@2.0.1","Python-2.0","Copyright (c) 1991 - 1995, Stichting Mathematisch Centrum Amsterdam,. The Netherlands. All rights reserved.","https://github.com/nodeca/argparse" -"aria-query@5.0.2","Apache-2.0","Copyright 2020 A11yance","https://github.com/A11yance/aria-query" +"aria-query@5.1.3","Apache-2.0","Copyright 2020 A11yance","https://github.com/A11yance/aria-query" "array-differ@3.0.0","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)","https://github.com/sindresorhus/array-differ" "array-flatten@1.1.1","MIT","Copyright (c) 2014 Blake Embrey (hello@blakeembrey.com)","https://github.com/blakeembrey/array-flatten" "array-flatten@2.1.2","MIT","Copyright (c) 2014 Blake Embrey (hello@blakeembrey.com)","https://github.com/blakeembrey/array-flatten" @@ -494,9 +501,10 @@ "async@3.2.4","MIT","Copyright (c) 2010-2018 Caolan McMahon","https://github.com/caolan/async" "asynckit@0.4.0","MIT","Copyright (c) 2016 Alex Indigo","https://github.com/alexindigo/asynckit" "at-least-node@1.0.0","ISC","","https://github.com/RyanZim/at-least-node" -"autoprefixer@10.4.12","MIT","Copyright 2013 Andrey Sitnik ","https://github.com/postcss/autoprefixer" +"autoprefixer@10.4.13","MIT","Copyright 2013 Andrey Sitnik ","https://github.com/postcss/autoprefixer" +"available-typed-arrays@1.0.5","MIT","Copyright (c) 2020 Inspect JS","https://github.com/inspect-js/available-typed-arrays" "axios@0.21.4","MIT","Copyright (c) 2014-present Matt Zabriskie","https://github.com/axios/axios" -"axobject-query@3.0.1","Apache-2.0","Copyright 2020 A11yance","https://github.com/A11yance/axobject-query" +"axobject-query@3.1.1","Apache-2.0","Copyright 2020 A11yance","https://github.com/A11yance/axobject-query" "babel-jest@28.1.3","MIT","Copyright (c) Facebook, Inc. and its affiliates.","https://github.com/facebook/jest" "babel-loader@8.2.5","MIT","Copyright (c) 2014-2019 Luís Couto ","https://github.com/babel/babel-loader" "babel-plugin-dynamic-import-node@2.3.3","MIT","Copyright (c) 2016 Airbnb","https://github.com/airbnb/babel-plugin-dynamic-import-node" @@ -522,7 +530,7 @@ "bl@4.1.0","MIT","Copyright (c) 2013-2019 bl contributors. ----------------------------------","https://github.com/rvagg/bl" "blessed@0.1.81","MIT","Copyright (c) 2013-2015, Christopher Jeffrey and contributors. https://github.com/chjj/","https://github.com/chjj/blessed" "bodec@0.1.0","MIT","Copyright (c) 2014 Tim Caswell","https://github.com/creationix/bodec" -"body-parser@1.20.0","MIT","Copyright (c) 2014 Jonathan Ong . Copyright (c) 2014-2015 Douglas Christopher Wilson ","https://github.com/expressjs/body-parser" +"body-parser@1.20.1","MIT","Copyright (c) 2014 Jonathan Ong . Copyright (c) 2014-2015 Douglas Christopher Wilson ","https://github.com/expressjs/body-parser" "bonjour-service@1.0.14","MIT","Copyright (https://github.com/onlxltd/bonjour-service) (c) 2021 ON LX Limited","https://github.com/onlxltd/bonjour-service" "boolbase@1.0.0","ISC","","https://github.com/fb55/boolbase" "bootstrap@4.6.2","MIT","Copyright (c) 2011-2022 Twitter, Inc.. Copyright (c) 2011-2022 The Bootstrap Authors","https://github.com/twbs/bootstrap" @@ -551,7 +559,6 @@ "bytes@3.1.2","MIT","Copyright (c) 2012-2014 TJ Holowaychuk . Copyright (c) 2015 Jed Watson ","https://github.com/visionmedia/bytes.js" "bytesish@0.4.4","(Apache-2.0 AND MIT)","","https://github.com/mikeal/bytesish" "cacache@16.1.2","ISC","Copyright (c) npm, Inc.","https://github.com/npm/cacache" -"cachedir@2.3.0","MIT","Copyright (c) 2013-2014, 2016, 2018 Linus Unnebäck","https://github.com/LinusU/node-cachedir" "call-bind@1.0.2","MIT","Copyright (c) 2020 Jordan Harband","https://github.com/ljharb/call-bind" "call-me-maybe@1.0.1","MIT","Copyright (c) 2015 Eric McCarthy","https://github.com/limulus/call-me-maybe" "callsite@1.0.0","MIT*","","" @@ -559,7 +566,7 @@ "camelcase-keys@6.2.2","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)","https://github.com/sindresorhus/camelcase-keys" "camelcase@5.3.1","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)","https://github.com/sindresorhus/camelcase" "camelcase@6.3.0","MIT","Copyright (c) Sindre Sorhus (https://sindresorhus.com)","https://github.com/sindresorhus/camelcase" -"caniuse-lite@1.0.30001416","CC-BY-4.0","","https://github.com/browserslist/caniuse-lite" +"caniuse-lite@1.0.30001439","CC-BY-4.0","","https://github.com/browserslist/caniuse-lite" "caseless@0.12.0","Apache-2.0","","https://github.com/mikeal/caseless" "chalk@1.1.3","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)","https://github.com/chalk/chalk" "chalk@2.4.2","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)","https://github.com/chalk/chalk" @@ -573,7 +580,7 @@ "chokidar@3.5.3","MIT","Copyright (c) 2012-2019 Paul Miller (https://paulmillr.com), Elan Shanker","https://github.com/paulmillr/chokidar" "chownr@2.0.0","ISC","Copyright (c) Isaac Z. Schlueter and Contributors","https://github.com/isaacs/chownr" "chrome-trace-event@1.0.3","MIT","Copyright (c) 2015 Joyent Inc. All rights reserved.","https://github.com/samccone/chrome-trace-event" -"ci-info@3.4.0","MIT","Copyright (c) 2016-2021 Thomas Watson Steen","https://github.com/watson/ci-info" +"ci-info@3.7.0","MIT","Copyright (c) 2016-2022 Thomas Watson Steen","https://github.com/watson/ci-info" "cjs-module-lexer@1.2.2","MIT","Copyright (C) 2018-2020 Guy Bedford","https://github.com/guybedford/cjs-module-lexer" "clean-regexp@1.0.0","MIT","Copyright (c) Sam Verschueren (github.com/SamVerschueren)","https://github.com/SamVerschueren/clean-regexp" "clean-stack@2.2.0","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)","https://github.com/sindresorhus/clean-stack" @@ -608,8 +615,6 @@ "commander@9.4.1","MIT","Copyright (c) 2011 TJ Holowaychuk ","https://github.com/tj/commander.js" "comment-json@4.2.3","MIT","Copyright (c) 2013 kaelzhang <>, contributors. http://kael.me/","https://github.com/kaelzhang/node-comment-json" "comment-parser@1.3.1","MIT","Copyright (c) 2014 Sergii Iavorskyi","https://github.com/yavorskiy/comment-parser" -"commitizen@4.2.5","MIT","","https://github.com/commitizen/cz-cli" -"commitlint-config-cz@0.13.3","MIT","Copyright (c) 2016 Whizark","https://github.com/whizark/commitlint-config-cz" "common-tags@1.8.2","MIT","Copyright © Declan de Wet","https://github.com/zspecza/common-tags" "commondir@1.0.1","MIT","Copyright (c) 2013 James Halliday (mail@substack.net)","https://github.com/substack/node-commondir" "compare-func@2.0.0","MIT","Copyright (c) 2015 Steve Mao","https://github.com/stevemao/compare-func" @@ -631,6 +636,7 @@ "conventional-changelog-cli@2.2.2","MIT","Copyright (c) 2015 Steve Mao (https://github.com/stevemao)","https://github.com/conventional-changelog/conventional-changelog" "conventional-changelog-codemirror@2.0.8","ISC","Copyright © [conventional-changelog team](https://github.com/conventional-changelog)","https://github.com/conventional-changelog/conventional-changelog" "conventional-changelog-conventionalcommits@4.6.3","ISC","Copyright © [conventional-changelog team](https://github.com/conventional-changelog)","https://github.com/conventional-changelog/conventional-changelog" +"conventional-changelog-conventionalcommits@5.0.0","ISC","Copyright © [conventional-changelog team](https://github.com/conventional-changelog)","https://github.com/conventional-changelog/conventional-changelog" "conventional-changelog-core@4.2.4","MIT","Copyright © [conventional-changelog team](https://github.com/conventional-changelog)","https://github.com/conventional-changelog/conventional-changelog" "conventional-changelog-ember@2.0.9","ISC","Copyright © [conventional-changelog team](https://github.com/conventional-changelog)","https://github.com/conventional-changelog/conventional-changelog" "conventional-changelog-eslint@3.0.9","ISC","Copyright © [conventional-changelog team](https://github.com/conventional-changelog)","https://github.com/conventional-changelog/conventional-changelog" @@ -640,7 +646,6 @@ "conventional-changelog-preset-loader@2.3.4","MIT","Copyright © [conventional-changelog team](https://github.com/conventional-changelog)","https://github.com/conventional-changelog/conventional-changelog" "conventional-changelog-writer@5.0.1","MIT","Copyright © [conventional-changelog team](https://github.com/conventional-changelog)","https://github.com/conventional-changelog/conventional-changelog" "conventional-changelog@3.1.25","MIT","Copyright © [conventional-changelog team](https://github.com/conventional-changelog)","https://github.com/conventional-changelog/conventional-changelog" -"conventional-commit-types@3.0.0","ISC","","https://github.com/commitizen/conventional-commit-types" "conventional-commits-filter@2.0.7","MIT","Copyright (c) 2015 Steve Mao (https://github.com/stevemao)","https://github.com/conventional-changelog/conventional-changelog" "conventional-commits-parser@3.2.4","MIT","Copyright © [conventional-changelog team](https://github.com/conventional-changelog)","https://github.com/conventional-changelog/conventional-changelog" "convert-source-map@1.8.0","MIT","Copyright 2013 Thorsten Lorenz. . All rights reserved.","https://github.com/thlorenz/convert-source-map" @@ -652,8 +657,9 @@ "core-js-compat@3.25.5","MIT","Copyright (c) 2014-2022 Denis Pushkarev","https://github.com/zloirock/core-js" "core-util-is@1.0.3","MIT","Copyright Node.js contributors. All rights reserved.","https://github.com/isaacs/core-util-is" "cors@2.8.5","MIT","Copyright (c) 2013 Troy Goode ","https://github.com/expressjs/cors" -"cosmiconfig-typescript-loader@4.1.1","MIT","Copyright (c) 2021 Alex Miller ","https://github.com/Codex-/cosmiconfig-typescript-loader" -"cosmiconfig@7.0.1","MIT","Copyright (c) 2015 David Clark","https://github.com/davidtheclark/cosmiconfig" +"cosmiconfig-typescript-loader@4.3.0","MIT","Copyright (c) 2021 Alex Miller ","https://github.com/Codex-/cosmiconfig-typescript-loader" +"cosmiconfig@7.1.0","MIT","Copyright (c) 2015 David Clark","https://github.com/davidtheclark/cosmiconfig" +"cosmiconfig@8.0.0","MIT","Copyright (c) 2015 David Clark","https://github.com/davidtheclark/cosmiconfig" "create-require@1.1.1","MIT","Copyright (c) 2020","https://github.com/nuxt-contrib/create-require" "critters@0.0.16","Apache-2.0","","https://github.com/GoogleChromeLabs/critters" "croner@4.1.97","MIT","Copyright (c) 2015-2021 Hexagon ","https://github.com/hexagon/croner" @@ -661,14 +667,14 @@ "cross-spawn@7.0.3","MIT","Copyright (c) 2018 Made With MOXY Lda ","https://github.com/moxystudio/node-cross-spawn" "crypto-js@4.1.1","MIT","Copyright (c) 2009-2013 Jeff Mott . Copyright (c) 2013-2016 Evan Vosberg","https://github.com/brix/crypto-js" "crypto-random-string@2.0.0","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)","https://github.com/sindresorhus/crypto-random-string" -"cspell-dictionary@6.12.0","MIT","Copyright (c) 2022 Jason Dent","https://github.com/streetsidesoftware/cspell" -"cspell-gitignore@6.12.0","MIT","Copyright (c) 2017 Jason Dent","https://github.com/streetsidesoftware/cspell" -"cspell-glob@6.12.0","MIT","Copyright (c) 2017 Jason Dent","https://github.com/streetsidesoftware/cspell" -"cspell-grammar@6.12.0","MIT","Copyright (c) 2017 Jason Dent","https://github.com/streetsidesoftware/cspell" -"cspell-io@6.12.0","MIT","Copyright (c) 2017 Jason Dent","https://github.com/streetsidesoftware/cspell" -"cspell-lib@6.12.0","MIT","Copyright (c) 2017 Jason Dent","https://github.com/streetsidesoftware/cspell" -"cspell-trie-lib@6.12.0","MIT","Copyright (c) 2017 Jason Dent","https://github.com/streetsidesoftware/cspell" -"cspell@6.12.0","MIT","Copyright (c) 2017 Jason Dent","https://github.com/streetsidesoftware/cspell" +"cspell-dictionary@6.17.0","MIT","Copyright (c) 2022 Jason Dent","https://github.com/streetsidesoftware/cspell" +"cspell-gitignore@6.17.0","MIT","Copyright (c) 2017 Jason Dent","https://github.com/streetsidesoftware/cspell" +"cspell-glob@6.17.0","MIT","Copyright (c) 2017 Jason Dent","https://github.com/streetsidesoftware/cspell" +"cspell-grammar@6.17.0","MIT","Copyright (c) 2017 Jason Dent","https://github.com/streetsidesoftware/cspell" +"cspell-io@6.17.0","MIT","Copyright (c) 2017 Jason Dent","https://github.com/streetsidesoftware/cspell" +"cspell-lib@6.17.0","MIT","Copyright (c) 2017 Jason Dent","https://github.com/streetsidesoftware/cspell" +"cspell-trie-lib@6.17.0","MIT","Copyright (c) 2017 Jason Dent","https://github.com/streetsidesoftware/cspell" +"cspell@6.17.0","MIT","Copyright (c) 2017 Jason Dent","https://github.com/streetsidesoftware/cspell" "css-blank-pseudo@3.0.3","CC0-1.0","","https://github.com/csstools/postcss-plugins" "css-functions-list@3.1.0","MIT","Copyright (c) Ivan Nikolić ","https://github.com/niksy/css-functions-list" "css-has-pseudo@3.0.4","CC0-1.0","","https://github.com/csstools/postcss-plugins" @@ -677,14 +683,13 @@ "css-select@4.3.0","BSD-2-Clause","Copyright (c) Felix Böhm. All rights reserved.","https://github.com/fb55/css-select" "css-select@5.1.0","BSD-2-Clause","Copyright (c) Felix Böhm. All rights reserved.","https://github.com/fb55/css-select" "css-what@6.1.0","BSD-2-Clause","Copyright (c) Felix Böhm. All rights reserved.","https://github.com/fb55/css-what" -"cssdb@7.0.1","CC0-1.0","","https://github.com/csstools/cssdb" +"cssdb@7.2.0","CC0-1.0","","https://github.com/csstools/cssdb" "cssesc@3.0.0","MIT","Copyright Mathias Bynens ","https://github.com/mathiasbynens/cssesc" "cssom@0.3.8","MIT","Copyright (c) Nikita Vasilyev","https://github.com/NV/CSSOM" "cssom@0.4.4","MIT","Copyright (c) Nikita Vasilyev","https://github.com/NV/CSSOM" "cssom@0.5.0","MIT","Copyright (c) Nikita Vasilyev","https://github.com/NV/CSSOM" "cssstyle@2.3.0","MIT","Copyright (c) Chad Walker","https://github.com/jsdom/cssstyle" "culvert@0.1.2","MIT","Copyright (c) 2014 Tim Caswell","https://github.com/creationix/culvert" -"cz-conventional-changelog@3.3.0","MIT","Copyright (c) 2015-2018 Commitizen Contributors","https://github.com/commitizen/cz-conventional-changelog" "cz-customizable@7.0.0","MIT","Copyright (c) 2016 Leonardo Correa","https://github.com/leoforfree/cz-customizable" "d@1.0.1","ISC","Copyright (c) 2013-2019, Mariusz Nowak, @medikoo, medikoo.com","https://github.com/medikoo/d" "dargs@7.0.0","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)","https://github.com/sindresorhus/dargs" @@ -694,6 +699,7 @@ "data-urls@3.0.2","MIT","Copyright © Domenic Denicola ","https://github.com/jsdom/data-urls" "date-fns@2.29.3","MIT","Copyright (c) 2021 Sasha Koss and Lesha Koss https://kossnocorp.mit-license.org","https://github.com/date-fns/date-fns" "dateformat@3.0.3","MIT","","https://github.com/felixge/node-dateformat" +"dayjs@1.11.6","MIT","Copyright (c) 2018-present, iamkun","https://github.com/iamkun/dayjs" "dayjs@1.8.36","MIT","Copyright (c) 2018-present, iamkun","https://github.com/iamkun/dayjs" "debug@2.6.9","MIT","Copyright (c) 2014 TJ Holowaychuk ","https://github.com/visionmedia/debug" "debug@3.2.7","MIT","Copyright (c) 2014 TJ Holowaychuk ","https://github.com/visionmedia/debug" @@ -706,6 +712,7 @@ "decimal.js@10.4.1","MIT","Copyright (c) 2022 Michael Mclaughlin","https://github.com/MikeMcl/decimal.js" "dedent@0.7.0","MIT","Copyright (c) 2015 Desmond Brand (dmnd@desmondbrand.com)","https://github.com/dmnd/dedent" "deep-equal@1.1.1","MIT","Copyright (c) 2012, 2013, 2014 James Halliday , 2009 Thomas Robinson <280north.com>","https://github.com/substack/node-deep-equal" +"deep-equal@2.1.0","MIT","Copyright (c) 2012, 2013, 2014 James Halliday , 2009 Thomas Robinson <280north.com>","https://github.com/inspect-js/node-deep-equal" "deep-is@0.1.4","MIT","Copyright (c) 2012, 2013 Thorsten Lorenz . Copyright (c) 2012 James Halliday . Copyright (c) 2009 Thomas Robinson <280north.com>","https://github.com/thlorenz/deep-is" "deepmerge@4.2.2","MIT","Copyright (c) 2012 James Halliday, Josh Duff, and other contributors","https://github.com/TehShrike/deepmerge" "default-gateway@6.0.3","BSD-2-Clause","Copyright (c) silverwind. All rights reserved.","https://github.com/silverwind/default-gateway" @@ -720,9 +727,7 @@ "dependency-graph@0.11.0","MIT","Copyright (C) 2013-2020 by Jim Riecken","https://github.com/jriecken/dependency-graph" "destroy@1.0.4","MIT","Copyright (c) 2014 Jonathan Ong me@jongleberry.com","https://github.com/stream-utils/destroy" "destroy@1.2.0","MIT","Copyright (c) 2014 Jonathan Ong me@jongleberry.com. Copyright (c) 2015-2022 Douglas Christopher Wilson doug@somethingdoug.com","https://github.com/stream-utils/destroy" -"detect-file@1.0.0","MIT","Copyright (c) 2016-2017, Brian Woodward.","https://github.com/doowb/detect-file" "detect-indent@5.0.0","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)","https://github.com/sindresorhus/detect-indent" -"detect-indent@6.1.0","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)","https://github.com/sindresorhus/detect-indent" "detect-newline@2.1.0","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)","https://github.com/sindresorhus/detect-newline" "detect-newline@3.1.0","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)","https://github.com/sindresorhus/detect-newline" "detect-node@2.1.0","MIT","Copyright (c) 2017 Ilya Kantor","https://github.com/iliakan/detect-node" @@ -768,7 +773,7 @@ "end-of-stream@1.4.4","MIT","Copyright (c) 2014 Mathias Buus","https://github.com/mafintosh/end-of-stream" "engine.io-client@6.2.2","MIT","Copyright (c) 2014-2015 Automattic ","https://github.com/socketio/engine.io-client" "engine.io-parser@5.0.4","MIT","Copyright (c) 2016 Guillermo Rauch (@rauchg)","https://github.com/socketio/engine.io-parser" -"engine.io@6.2.0","MIT","Copyright (c) 2014 Guillermo Rauch ","https://github.com/socketio/engine.io" +"engine.io@6.2.1","MIT","Copyright (c) 2014 Guillermo Rauch ","https://github.com/socketio/engine.io" "enhanced-resolve@5.10.0","MIT","Copyright JS Foundation and other contributors","https://github.com/webpack/enhanced-resolve" "enquirer@2.3.6","MIT","Copyright (c) 2016-present, Jon Schlinkert.","https://github.com/enquirer/enquirer" "entities@2.2.0","BSD-2-Clause","Copyright (c) Felix Böhm. All rights reserved.","https://github.com/fb55/entities" @@ -778,6 +783,7 @@ "errno@0.1.8","MIT","","https://github.com/rvagg/node-errno" "error-ex@1.3.2","MIT","Copyright (c) 2015 JD Ballard","https://github.com/qix-/node-error-ex" "es-abstract@1.20.3","MIT","Copyright (C) 2015 Jordan Harband","https://github.com/ljharb/es-abstract" +"es-get-iterator@1.1.2","MIT","Copyright (c) 2019 Jordan Harband","https://github.com/ljharb/es-get-iterator" "es-module-lexer@0.9.3","MIT","Copyright (C) 2018-2021 Guy Bedford","https://github.com/guybedford/es-module-lexer" "es-to-primitive@1.2.1","MIT","Copyright (c) 2015 Jordan Harband","https://github.com/ljharb/es-to-primitive" "es5-ext@0.10.62","ISC","Copyright (c) 2011-2022, Mariusz Nowak, @medikoo, medikoo.com","https://github.com/medikoo/es5-ext" @@ -803,12 +809,12 @@ "eslint-plugin-ban@1.6.0","ISC","Copyright (c) 2021 Rémi Thomas","https://github.com/remithomas/eslint-plugin-ban" "eslint-plugin-etc@2.0.2","MIT","Copyright (c) 2019-2021 Nicholas Jamieson and contributors","https://github.com/cartant/eslint-plugin-etc" "eslint-plugin-ish-custom-rules@0.0.1","UNKNOWN","","" -"eslint-plugin-jest@27.1.1","MIT","Copyright (c) 2018 Jonathan Kim","https://github.com/jest-community/eslint-plugin-jest" -"eslint-plugin-jsdoc@39.3.6","BSD-3-Clause","Copyright (c) 2018, Gajus Kuizinas (http://gajus.com/). All rights reserved.","https://github.com/gajus/eslint-plugin-jsdoc" +"eslint-plugin-jest@27.1.6","MIT","Copyright (c) 2018 Jonathan Kim","https://github.com/jest-community/eslint-plugin-jest" +"eslint-plugin-jsdoc@39.6.4","BSD-3-Clause","Copyright (c) 2018, Gajus Kuizinas (http://gajus.com/). All rights reserved.","https://github.com/gajus/eslint-plugin-jsdoc" "eslint-plugin-prettier@4.2.1","MIT","Copyright © 2017 Andres Suarez and Teddy Katz","https://github.com/prettier/eslint-plugin-prettier" "eslint-plugin-rxjs-angular@2.0.0","MIT","Copyright (c) 2019 Nicholas Jamieson","https://github.com/cartant/eslint-plugin-rxjs-angular" "eslint-plugin-rxjs@5.0.2","MIT","Copyright (c) 2019 Nicholas Jamieson and contributors","https://github.com/cartant/eslint-plugin-rxjs" -"eslint-plugin-unicorn@44.0.1","MIT","Copyright (c) Sindre Sorhus (https://sindresorhus.com)","https://github.com/sindresorhus/eslint-plugin-unicorn" +"eslint-plugin-unicorn@45.0.2","MIT","Copyright (c) Sindre Sorhus (https://sindresorhus.com)","https://github.com/sindresorhus/eslint-plugin-unicorn" "eslint-plugin-unused-imports@2.0.0","MIT","","https://github.com/sweepline/eslint-plugin-unused-imports" "eslint-rule-composer@0.3.0","MIT","Copyright © 2017 Teddy Katz","https://github.com/not-an-aardvark/eslint-rule-composer" "eslint-scope@5.1.1","BSD-2-Clause","Copyright JS Foundation and other contributors, https://js.foundation. Copyright (C) 2012-2013 Yusuke Suzuki (twitter: @Constellation) and other contributors.","https://github.com/eslint/eslint-scope" @@ -816,8 +822,8 @@ "eslint-utils@3.0.0","MIT","Copyright (c) 2018 Toru Nagashima","https://github.com/mysticatea/eslint-utils" "eslint-visitor-keys@2.1.0","Apache-2.0","","https://github.com/eslint/eslint-visitor-keys" "eslint-visitor-keys@3.3.0","Apache-2.0","","https://github.com/eslint/eslint-visitor-keys" -"eslint@8.24.0","MIT","Copyright OpenJS Foundation and other contributors, ","https://github.com/eslint/eslint" -"espree@9.4.0","BSD-2-Clause","Copyright (c) Open JS Foundation. All rights reserved.","https://github.com/eslint/espree" +"eslint@8.29.0","MIT","Copyright OpenJS Foundation and other contributors, ","https://github.com/eslint/eslint" +"espree@9.4.1","BSD-2-Clause","Copyright (c) Open JS Foundation. All rights reserved.","https://github.com/eslint/espree" "esprima@1.0.4","BSD","Copyright (C) 2012, 2011 [Ariya Hidayat](http://ariya.ofilabs.com/about). and other contributors.","https://github.com/ariya/esprima" "esprima@4.0.1","BSD-2-Clause","Copyright JS Foundation and other contributors, https://js.foundation/","https://github.com/jquery/esprima" "esquery@1.4.0","BSD-3-Clause","Copyright (c) 2013, Joel Feenstra. All rights reserved.","https://github.com/estools/esquery" @@ -841,12 +847,11 @@ "execa@5.1.1","MIT","Copyright (c) Sindre Sorhus (https://sindresorhus.com)","https://github.com/sindresorhus/execa" "execa@6.1.0","MIT","Copyright (c) Sindre Sorhus (https://sindresorhus.com)","https://github.com/sindresorhus/execa" "exit@0.1.2","MIT","Copyright (c) 2013 "Cowboy" Ben Alman","https://github.com/cowboy/node-exit" -"expand-tilde@2.0.2","MIT","Copyright (c) 2015-2016, Jon Schlinkert.","https://github.com/jonschlinkert/expand-tilde" "expect@28.1.3","MIT","Copyright (c) Facebook, Inc. and its affiliates.","https://github.com/facebook/jest" "expect@29.1.2","MIT","Copyright (c) Facebook, Inc. and its affiliates.","https://github.com/facebook/jest" "express-http-proxy@1.6.3","MIT","Copyright (c) 2013 villadora , contributors. http://kael.me/","https://github.com/villadora/express-http-proxy" "express-robots-txt@1.0.0","MIT","","https://github.com/modosc/express-robots-txt" -"express@4.18.1","MIT","Copyright (c) 2009-2014 TJ Holowaychuk . Copyright (c) 2013-2014 Roman Shtylman . Copyright (c) 2014-2015 Douglas Christopher Wilson ","https://github.com/expressjs/express" +"express@4.18.2","MIT","Copyright (c) 2009-2014 TJ Holowaychuk . Copyright (c) 2013-2014 Roman Shtylman . Copyright (c) 2014-2015 Douglas Christopher Wilson ","https://github.com/expressjs/express" "ext@1.7.0","ISC","Copyright (c) 2011-2022, Mariusz Nowak, @medikoo, medikoo.com","https://github.com/medikoo/es5-ext.git#ext" "external-editor@3.1.0","MIT","Copyright (c) 2016 Kevin Gravier","https://github.com/mrkmg/node-external-editor" "fancy-log@1.3.3","MIT","Copyright (c) 2014, 2015, 2018 Blaine Bublitz and Eric Schoffstall ","https://github.com/gulpjs/fancy-log" @@ -875,16 +880,14 @@ "finalhandler@1.2.0","MIT","Copyright (c) 2014-2022 Douglas Christopher Wilson ","https://github.com/pillarjs/finalhandler" "find-cache-dir@3.3.2","MIT","Copyright (c) Sindre Sorhus (https://sindresorhus.com)","https://github.com/avajs/find-cache-dir" "find-config@1.0.0","MIT","","https://github.com/shannonmoeller/find-config" -"find-node-modules@2.1.3","MIT","","https://github.com/callumacrae/find-node-modules" -"find-root@1.1.0","MIT","Copyright © 2017 jsdnxx","https://github.com/js-n/find-root" "find-up@2.1.0","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)","https://github.com/sindresorhus/find-up" "find-up@4.1.0","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)","https://github.com/sindresorhus/find-up" "find-up@5.0.0","MIT","Copyright (c) Sindre Sorhus (https://sindresorhus.com)","https://github.com/sindresorhus/find-up" "findit2@2.2.3","MIT","Copyright (c) 2014 Andrew Kelley. Copyright (c) 2014 James Halliday","https://github.com/andrewrk/node-findit" -"findup-sync@4.0.0","MIT","Copyright (c) 2013-2019 Ben Alman , Blaine Bublitz , and Eric Schoffstall ","https://github.com/gulpjs/findup-sync" "flat-cache@3.0.4","MIT","Copyright (c) 2015 Roy Riojas","https://github.com/royriojas/flat-cache" "flatted@3.2.7","ISC","Copyright (c) 2018-2020, Andrea Giammarchi, @WebReflection","https://github.com/WebReflection/flatted" "follow-redirects@1.15.2","MIT","Copyright 2014–present Olivier Lalonde , James Talmage , Ruben Verborgh","https://github.com/follow-redirects/follow-redirects" +"for-each@0.3.3","MIT","Copyright (c) 2012 Raynos.","https://github.com/Raynos/for-each" "form-data@3.0.1","MIT","Copyright (c) 2012 Felix Geisendörfer (felix@debuggable.com) and contributors","https://github.com/form-data/form-data" "form-data@4.0.0","MIT","Copyright (c) 2012 Felix Geisendörfer (felix@debuggable.com) and contributors","https://github.com/form-data/form-data" "forwarded@0.2.0","MIT","Copyright (c) 2014-2017 Douglas Christopher Wilson","https://github.com/jshttp/forwarded" @@ -903,7 +906,7 @@ "function.prototype.name@1.1.5","MIT","Copyright (c) 2016 Jordan Harband","https://github.com/es-shims/Function.prototype.name" "functions-have-names@1.2.3","MIT","Copyright (c) 2019 Jordan Harband","https://github.com/inspect-js/functions-have-names" "gauge@4.0.4","ISC","Copyright npm, Inc.","https://github.com/npm/gauge" -"gensequence@4.0.2","MIT","Copyright (c) 2016 Jason Dent","https://github.com/Jason3S/GenSequence" +"gensequence@4.0.3","MIT","Copyright (c) 2016 Jason Dent","https://github.com/Jason3S/GenSequence" "gensync@1.0.0-beta.2","MIT","Copyright 2018 Logan Smyth ","https://github.com/loganfsmyth/gensync" "get-assigned-identifiers@1.2.0","Apache-2.0","Copyright 2017 Renée Kooi ","https://github.com/goto-bus-stop/get-assigned-identifiers" "get-caller-file@2.0.5","ISC","","https://github.com/stefanpenner/get-caller-file" @@ -928,15 +931,15 @@ "glob@7.2.3","ISC","Copyright (c) Isaac Z. Schlueter and Contributors","https://github.com/isaacs/node-glob" "glob@8.0.3","ISC","Copyright (c) 2009-2022 Isaac Z. Schlueter and Contributors","https://github.com/isaacs/node-glob" "global-dirs@0.1.1","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)","https://github.com/sindresorhus/global-dirs" -"global-modules@1.0.0","MIT","Copyright (c) 2015-2017, Jon Schlinkert.","https://github.com/jonschlinkert/global-modules" "global-modules@2.0.0","MIT","Copyright (c) 2015-present, Jon Schlinkert.","https://github.com/jonschlinkert/global-modules" -"global-prefix@1.0.2","MIT","Copyright (c) 2015-2017, Jon Schlinkert.","https://github.com/jonschlinkert/global-prefix" "global-prefix@3.0.0","MIT","Copyright (c) 2015-present, Jon Schlinkert.","https://github.com/jonschlinkert/global-prefix" "globals@11.12.0","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)","https://github.com/sindresorhus/globals" "globals@13.17.0","MIT","Copyright (c) Sindre Sorhus (https://sindresorhus.com)","https://github.com/sindresorhus/globals" +"globals@13.19.0","MIT","Copyright (c) Sindre Sorhus (https://sindresorhus.com)","https://github.com/sindresorhus/globals" "globby@11.1.0","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)","https://github.com/sindresorhus/globby" "globby@13.1.2","MIT","Copyright (c) Sindre Sorhus (https://sindresorhus.com)","https://github.com/sindresorhus/globby" "globjoin@0.1.4","MIT","Copyright (c) 2016 amobiz","https://github.com/amobiz/globjoin" +"gopd@1.0.1","MIT","Copyright (c) 2022 Jordan Harband","https://github.com/ljharb/gopd" "graceful-fs@4.2.10","ISC","Copyright (c) 2011-2022 Isaac Z. Schlueter, Ben Noordhuis, and Contributors","https://github.com/isaacs/node-graceful-fs" "grapheme-splitter@1.0.4","MIT","Copyright (c) 2015 Orlin Georgiev","https://github.com/orling/grapheme-splitter" "guess-parser@0.4.22","MIT","Copyright (c) 2018 Minko Gechev and the Guess . contributors","https://github.com/guess-js/guess" @@ -955,7 +958,6 @@ "has@1.0.3","MIT","Copyright (c) 2013 Thiago de Arruda","https://github.com/tarruda/has" "hdr-histogram-js@2.0.3","BSD*","Copyright (c) 2016, Alexandre Victoor. All rights reserved.","https://github.com/HdrHistogram/HdrHistogramJS" "hdr-histogram-percentiles-obj@3.0.0","MIT","Copyright (c) 2016 Glen Keane","https://github.com/GlenTiki/hdr-histogram-percentiles-obj" -"homedir-polyfill@1.0.3","MIT","Copyright (c) 2016 Brian Woodward","https://github.com/doowb/homedir-polyfill" "hosted-git-info@2.8.9","ISC","Copyright (c) 2015, Rebecca Turner","https://github.com/npm/hosted-git-info" "hosted-git-info@4.1.0","ISC","Copyright (c) 2015, Rebecca Turner","https://github.com/npm/hosted-git-info" "hosted-git-info@5.1.0","ISC","Copyright (c) 2015, Rebecca Turner","https://github.com/npm/hosted-git-info" @@ -982,7 +984,7 @@ "human-signals@2.1.0","Apache-2.0","","https://github.com/ehmicky/human-signals" "human-signals@3.0.1","Apache-2.0","","https://github.com/ehmicky/human-signals" "humanize-ms@1.2.1","MIT","","https://github.com/node-modules/humanize-ms" -"husky@8.0.1","MIT","Copyright (c) 2021 typicode","https://github.com/typicode/husky" +"husky@8.0.2","MIT","Copyright (c) 2021 typicode","https://github.com/typicode/husky" "i18next@21.9.2","MIT","Copyright (c) 2022 i18next","https://github.com/i18next/i18next" "iconv-lite@0.4.24","MIT","Copyright (c) 2011 Alexander Shtuchkin","https://github.com/ashtuchkin/iconv-lite" "iconv-lite@0.6.3","MIT","Copyright (c) 2011 Alexander Shtuchkin","https://github.com/ashtuchkin/iconv-lite" @@ -990,6 +992,7 @@ "ieee754@1.2.1","BSD-3-Clause","Copyright 2008 Fair Oaks Labs, Inc.","https://github.com/feross/ieee754" "ignore-walk@5.0.1","ISC","Copyright (c) Isaac Z. Schlueter and Contributors","https://github.com/npm/ignore-walk" "ignore@5.2.0","MIT","Copyright (c) 2013 Kael Zhang , contributors. http://kael.me/","https://github.com/kaelzhang/node-ignore" +"ignore@5.2.1","MIT","Copyright (c) 2013 Kael Zhang , contributors. http://kael.me/","https://github.com/kaelzhang/node-ignore" "image-size@0.5.5","MIT","Copyright © 2017 Aditya Yadav, http://netroy.in","https://github.com/image-size/image-size" "immutable@3.8.2","MIT","Copyright (c) 2014-present, Facebook, Inc.","https://github.com/facebook/immutable-js" "immutable@4.1.0","MIT","Copyright (c) 2014-present, Lee Byron and other contributors.","https://github.com/immutable-js/immutable-js" @@ -1008,7 +1011,7 @@ "inquirer@8.2.4","MIT","Copyright (c) 2022 Simon Boudrias","https://github.com/SBoudrias/Inquirer.js" "inside@1.0.0","Public Domain","","https://github.com/aantthony/node-self" "internal-slot@1.0.3","MIT","Copyright (c) 2019 Jordan Harband","https://github.com/ljharb/internal-slot" -"intershop-pwa@3.1.0","UNLICENSED","Copyright (c) 2022 Intershop Communications AG, http://www.intershop.de","" +"intershop-pwa@3.2.0","UNLICENSED","Copyright (c) 2022 Intershop Communications AG, http://www.intershop.de","" "intershop-schematics@0.0.1","UNKNOWN","","https://github.com/intershop/intershop-pwa" "ip@1.1.8","MIT","Copyright Fedor Indutny, 2012.","https://github.com/indutny/node-ip" "ip@2.0.0","MIT","Copyright Fedor Indutny, 2012.","https://github.com/indutny/node-ip" @@ -1032,11 +1035,13 @@ "is-glob@4.0.3","MIT","Copyright (c) 2014-2017, Jon Schlinkert.","https://github.com/micromatch/is-glob" "is-interactive@1.0.0","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)","https://github.com/sindresorhus/is-interactive" "is-lambda@1.0.1","MIT","Copyright (c) 2016-2017 Thomas Watson Steen","https://github.com/watson/is-lambda" +"is-map@2.0.2","MIT","Copyright (c) 2019 Inspect JS","https://github.com/inspect-js/is-map" "is-negative-zero@2.0.2","MIT","Copyright (c) 2014 Jordan Harband","https://github.com/inspect-js/is-negative-zero" "is-number-like@1.0.8","ISC","Copyright (c) 2016, Vigour.io","https://github.com/vigour-io/is-number-like" "is-number-object@1.0.7","MIT","Copyright (c) 2015 Jordan Harband","https://github.com/inspect-js/is-number-object" "is-number@7.0.0","MIT","Copyright (c) 2014-present, Jon Schlinkert.","https://github.com/jonschlinkert/is-number" "is-obj@2.0.0","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)","https://github.com/sindresorhus/is-obj" +"is-path-inside@3.0.3","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)","https://github.com/sindresorhus/is-path-inside" "is-plain-obj@1.1.0","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)","https://github.com/sindresorhus/is-plain-obj" "is-plain-obj@3.0.0","MIT","Copyright (c) Sindre Sorhus (https://sindresorhus.com)","https://github.com/sindresorhus/is-plain-obj" "is-plain-object@2.0.4","MIT","Copyright (c) 2014-2017, Jon Schlinkert.","https://github.com/jonschlinkert/is-plain-object" @@ -1044,22 +1049,25 @@ "is-potential-custom-element-name@1.0.1","MIT","Copyright Mathias Bynens ","https://github.com/mathiasbynens/is-potential-custom-element-name" "is-promise@2.2.2","MIT","Copyright (c) 2014 Forbes Lindesay","https://github.com/then/is-promise" "is-regex@1.1.4","MIT","Copyright (c) 2014 Jordan Harband","https://github.com/inspect-js/is-regex" +"is-set@2.0.2","MIT","Copyright (c) 2019 Inspect JS","https://github.com/inspect-js/is-set" "is-shared-array-buffer@1.0.2","MIT","Copyright (c) 2021 Inspect JS","https://github.com/inspect-js/is-shared-array-buffer" "is-stream@2.0.1","MIT","Copyright (c) Sindre Sorhus (https://sindresorhus.com)","https://github.com/sindresorhus/is-stream" "is-stream@3.0.0","MIT","Copyright (c) Sindre Sorhus (https://sindresorhus.com)","https://github.com/sindresorhus/is-stream" "is-string@1.0.7","MIT","Copyright (c) 2015 Jordan Harband","https://github.com/ljharb/is-string" "is-symbol@1.0.4","MIT","Copyright (c) 2015 Jordan Harband","https://github.com/inspect-js/is-symbol" "is-text-path@1.0.1","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)","https://github.com/sindresorhus/is-text-path" +"is-typed-array@1.1.10","MIT","Copyright (c) 2015 Jordan Harband","https://github.com/inspect-js/is-typed-array" "is-typedarray@1.0.0","MIT","","https://github.com/hughsk/is-typedarray" "is-unicode-supported@0.1.0","MIT","Copyright (c) Sindre Sorhus (https://sindresorhus.com)","https://github.com/sindresorhus/is-unicode-supported" -"is-utf8@0.2.1","MIT","Copyright (C) 2014 Wei Fanzhe","https://github.com/wayfind/is-utf8" +"is-weakmap@2.0.1","MIT","Copyright (c) 2019 Inspect JS","https://github.com/inspect-js/is-weakmap" "is-weakref@1.0.2","MIT","Copyright (c) 2020 Inspect JS","https://github.com/inspect-js/is-weakref" +"is-weakset@2.0.2","MIT","Copyright (c) 2019 Inspect JS","https://github.com/inspect-js/is-weakset" "is-what@3.14.1","MIT","Copyright (c) 2018 Luca Ban - Mesqueeb","https://github.com/mesqueeb/is-what" -"is-windows@1.0.2","MIT","Copyright (c) 2015-2018, Jon Schlinkert.","https://github.com/jonschlinkert/is-windows" "is-wsl@1.1.0","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)","https://github.com/sindresorhus/is-wsl" "is-wsl@2.2.0","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)","https://github.com/sindresorhus/is-wsl" "isarray@0.0.1","MIT","Copyright (c) 2013 Julian Gruber <julian@juliangruber.com>","https://github.com/juliangruber/isarray" "isarray@1.0.0","MIT","Copyright (c) 2013 Julian Gruber <julian@juliangruber.com>","https://github.com/juliangruber/isarray" +"isarray@2.0.5","MIT","Copyright (c) 2013 Julian Gruber ","https://github.com/juliangruber/isarray" "isexe@2.0.0","ISC","Copyright (c) Isaac Z. Schlueter and Contributors","https://github.com/isaacs/isexe" "isobject@3.0.1","MIT","Copyright (c) 2014-2017, Jon Schlinkert.","https://github.com/jonschlinkert/isobject" "istanbul-lib-coverage@3.2.0","BSD-3-Clause","Copyright 2012-2015 Yahoo! Inc.. All rights reserved.","https://github.com/istanbuljs/istanbuljs" @@ -1125,6 +1133,7 @@ "jsdom@20.0.0","MIT","Copyright (c) 2010 Elijah Insua","https://github.com/jsdom/jsdom" "jsesc@0.5.0","MIT","Copyright Mathias Bynens ","https://github.com/mathiasbynens/jsesc" "jsesc@2.5.2","MIT","Copyright Mathias Bynens ","https://github.com/mathiasbynens/jsesc" +"jsesc@3.0.2","MIT","Copyright Mathias Bynens ","https://github.com/mathiasbynens/jsesc" "json-parse-better-errors@1.0.2","MIT","Copyright 2017 Kat Marchán","https://github.com/zkat/json-parse-better-errors" "json-parse-even-better-errors@2.3.1","MIT","Copyright 2017 Kat Marchán. Copyright npm, Inc.","https://github.com/npm/json-parse-even-better-errors" "json-schema-to-typescript@11.0.2","MIT","","https://github.com/bcherny/json-schema-to-typescript" @@ -1144,7 +1153,7 @@ "kind-of@6.0.3","MIT","Copyright (c) 2014-2017, Jon Schlinkert.","https://github.com/jonschlinkert/kind-of" "kleur@3.0.3","MIT","Copyright (c) Luke Edwards (lukeed.com)","https://github.com/lukeed/kleur" "klona@2.0.5","MIT","Copyright (c) Luke Edwards (lukeed.com)","https://github.com/lukeed/klona" -"known-css-properties@0.25.0","MIT","Copyright (c) 2017 Mavrix Technologies","https://github.com/known-css/known-css-properties" +"known-css-properties@0.26.0","MIT","Copyright (c) 2017 Mavrix Technologies","https://github.com/known-css/known-css-properties" "lazy@1.0.11","MIT","","https://github.com/pkrumins/node-lazy" "less-loader@11.0.0","MIT","Copyright JS Foundation and other contributors","https://github.com/webpack-contrib/less-loader" "less@4.1.3","Apache-2.0","","https://github.com/less/less.js" @@ -1152,35 +1161,41 @@ "levn@0.3.0","MIT","Copyright (c) George Zahariev","https://github.com/gkz/levn" "levn@0.4.1","MIT","Copyright (c) George Zahariev","https://github.com/gkz/levn" "license-webpack-plugin@4.0.2","ISC","Copyright (c) 2016, S K (xz64)","https://github.com/xz64/license-webpack-plugin" -"lilconfig@2.0.5","MIT","","https://github.com/antonk52/lilconfig" +"lilconfig@2.0.6","MIT","Copyright (c) 2022 Anton Kastritskiy","https://github.com/antonk52/lilconfig" "limiter@1.1.5","MIT","Copyright (C) 2011 by John Hurliman","https://github.com/jhurliman/node-rate-limiter" "lines-and-columns@1.2.4","MIT","Copyright (c) 2015 Brian Donovan","https://github.com/eventualbuddha/lines-and-columns" -"lint-staged@13.0.3","MIT","Copyright (c) 2016 Andrey Okonetchnikov","https://github.com/okonet/lint-staged" -"listr2@4.0.5","MIT","Copyright (c) Cenk Kilic (https://srcs.kilic.dev), Sam Verschueren (github.com/SamVerschueren)","https://github.com/cenk1cenk2/listr2" +"lint-staged@13.1.0","MIT","Copyright (c) 2016 Andrey Okonetchnikov","https://github.com/okonet/lint-staged" +"listr2@5.0.6","MIT","Copyright (c) Cenk Kilic (https://srcs.kilic.dev), Sam Verschueren (github.com/SamVerschueren)","https://github.com/cenk1cenk2/listr2" "load-json-file@4.0.0","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)","https://github.com/sindresorhus/load-json-file" "loader-runner@4.3.0","MIT","Copyright (c) Tobias Koppers @sokra","https://github.com/webpack/loader-runner" -"loader-utils@2.0.2","MIT","Copyright JS Foundation and other contributors","https://github.com/webpack/loader-utils" -"loader-utils@3.2.0","MIT","Copyright JS Foundation and other contributors","https://github.com/webpack/loader-utils" +"loader-utils@2.0.4","MIT","Copyright JS Foundation and other contributors","https://github.com/webpack/loader-utils" +"loader-utils@3.2.1","MIT","Copyright JS Foundation and other contributors","https://github.com/webpack/loader-utils" "localtunnel@2.0.2","MIT","Copyright (c) 2018 Roman Shtylman","https://github.com/localtunnel/localtunnel" "locate-path@2.0.0","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)","https://github.com/sindresorhus/locate-path" "locate-path@5.0.0","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)","https://github.com/sindresorhus/locate-path" "locate-path@6.0.0","MIT","Copyright (c) Sindre Sorhus (https://sindresorhus.com)","https://github.com/sindresorhus/locate-path" "lodash-es@4.17.21","MIT","Copyright OpenJS Foundation and other contributors ","https://github.com/lodash/lodash" -"lodash.clonedeep@4.5.0","MIT","Copyright jQuery Foundation and other contributors ","https://github.com/lodash/lodash" +"lodash.camelcase@4.3.0","MIT","Copyright jQuery Foundation and other contributors ","https://github.com/lodash/lodash" "lodash.debounce@4.0.8","MIT","Copyright jQuery Foundation and other contributors ","https://github.com/lodash/lodash" "lodash.isfinite@3.3.2","MIT","Copyright jQuery Foundation and other contributors ","https://github.com/lodash/lodash" +"lodash.isfunction@3.0.9","MIT","Copyright JS Foundation and other contributors ","https://github.com/lodash/lodash" "lodash.ismatch@4.4.0","MIT","Copyright jQuery Foundation and other contributors ","https://github.com/lodash/lodash" -"lodash.map@4.6.0","MIT","Copyright jQuery Foundation and other contributors ","https://github.com/lodash/lodash" +"lodash.isplainobject@4.0.6","MIT","Copyright jQuery Foundation and other contributors ","https://github.com/lodash/lodash" +"lodash.kebabcase@4.1.1","MIT","Copyright jQuery Foundation and other contributors ","https://github.com/lodash/lodash" "lodash.memoize@4.1.2","MIT","Copyright jQuery Foundation and other contributors ","https://github.com/lodash/lodash" "lodash.merge@4.6.2","MIT","Copyright OpenJS Foundation and other contributors ","https://github.com/lodash/lodash" +"lodash.mergewith@4.6.2","MIT","Copyright OpenJS Foundation and other contributors ","https://github.com/lodash/lodash" +"lodash.snakecase@4.1.1","MIT","Copyright jQuery Foundation and other contributors ","https://github.com/lodash/lodash" +"lodash.startcase@4.4.0","MIT","Copyright jQuery Foundation and other contributors ","https://github.com/lodash/lodash" "lodash.truncate@4.4.2","MIT","Copyright jQuery Foundation and other contributors ","https://github.com/lodash/lodash" +"lodash.uniq@4.5.0","MIT","Copyright jQuery Foundation and other contributors ","https://github.com/lodash/lodash" +"lodash.upperfirst@4.3.1","MIT","Copyright jQuery Foundation and other contributors ","https://github.com/lodash/lodash" "lodash@4.17.21","MIT","Copyright OpenJS Foundation and other contributors ","https://github.com/lodash/lodash" "log-driver@1.2.7","ISC","Copyright (c) 2014, Gregg Caines, gregg@caines.ca","https://github.com/cainus/logdriver" "log-symbols@4.1.0","MIT","Copyright (c) Sindre Sorhus (https://sindresorhus.com)","https://github.com/sindresorhus/log-symbols" "log-update@4.0.0","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)","https://github.com/sindresorhus/log-update" "loglevel-plugin-prefix@0.8.4","MIT","Copyright (c) 2017 Evgeniy Pavlov","https://github.com/kutuluk/loglevel-plugin-prefix" "loglevel@1.8.0","MIT","Copyright (c) 2013 Tim Perry","https://github.com/pimterry/loglevel" -"longest@2.0.1","MIT","Copyright (c) 2014-2017, Jon Schlinkert","https://github.com/jonschlinkert/longest" "lru-cache@5.1.1","ISC","Copyright (c) Isaac Z. Schlueter and Contributors","https://github.com/isaacs/node-lru-cache" "lru-cache@6.0.0","ISC","Copyright (c) Isaac Z. Schlueter and Contributors","https://github.com/isaacs/node-lru-cache" "lru-cache@7.14.0","ISC","Copyright (c) 2010-2022 Isaac Z. Schlueter and Contributors","https://github.com/isaacs/node-lru-cache" @@ -1201,7 +1216,7 @@ "marked@4.1.1","MIT","Copyright (c) 2018+, MarkedJS (https://github.com/markedjs/). Copyright (c) 2011-2018, Christopher Jeffrey (https://github.com/chjj/)*","https://github.com/markedjs/marked" "mathml-tag-names@2.1.3","MIT","Copyright (c) 2016 Titus Wormer ","https://github.com/wooorm/mathml-tag-names" "media-typer@0.3.0","MIT","Copyright (c) 2014 Douglas Christopher Wilson","https://github.com/jshttp/media-typer" -"memfs@3.4.7","Unlicense","","https://github.com/streamich/memfs" +"memfs@3.4.12","Unlicense","","https://github.com/streamich/memfs" "memoizee@0.4.15","ISC","Copyright (c) 2012-2018, Mariusz Nowak, @medikoo, medikoo.com","https://github.com/medikoo/memoizee" "memorystream@0.3.1","MIT","Copyright (C) 2011 Dmitry Nizovtsev","https://github.com/JSBizon/node-memorystream" "meow@8.1.2","MIT","Copyright (c) Sindre Sorhus (https://sindresorhus.com)","https://github.com/sindresorhus/meow" @@ -1210,7 +1225,6 @@ "merge-source-map@1.0.4","MIT","Copyright (c) keik ","https://github.com/keik/merge-source-map" "merge-stream@2.0.0","MIT","Copyright (c) Stephen Sugden (stephensugden.com)","https://github.com/grncdr/merge-stream" "merge2@1.4.1","MIT","Copyright (c) 2014-2020 Teambition","https://github.com/teambition/merge2" -"merge@2.1.1","MIT","","https://github.com/yeikos/js.merge" "methods@1.1.2","MIT","Copyright (c) 2013-2014 TJ Holowaychuk . Copyright (c) 2015-2016 Douglas Christopher Wilson ","https://github.com/jshttp/methods" "micromatch@4.0.5","MIT","Copyright (c) 2014-present, Jon Schlinkert.","https://github.com/micromatch/micromatch" "mime-db@1.52.0","MIT","Copyright (c) 2014 Jonathan Ong . Copyright (c) 2015-2022 Douglas Christopher Wilson ","https://github.com/jshttp/mime-db" @@ -1251,18 +1265,19 @@ "mute-stream@0.0.8","ISC","Copyright (c) Isaac Z. Schlueter and Contributors","https://github.com/isaacs/mute-stream" "mz@2.7.0","MIT","Copyright (c) 2014-2016 Jonathan Ong me@jongleberry.com and Contributors","https://github.com/normalize/mz" "nanoid@3.3.4","MIT","Copyright 2017 Andrey Sitnik ","https://github.com/ai/nanoid" +"natural-compare-lite@1.4.0","MIT","Copyright (c) 2012-2015 Lauri Rooden <lauri@rooden.ee> . [The MIT License](http://lauri.rooden.ee/mit-license.txt)","https://github.com/litejs/natural-compare-lite" "natural-compare@1.4.0","MIT","Copyright (c) 2012-2015 Lauri Rooden <lauri@rooden.ee> . [The MIT License](http://lauri.rooden.ee/mit-license.txt)","https://github.com/litejs/natural-compare-lite" "needle@2.4.0","MIT","Copyright (c) Fork, Ltd.","https://github.com/tomas/needle" -"needle@3.1.0","MIT","Copyright (c) Fork, Ltd.","https://github.com/tomas/needle" +"needle@3.2.0","MIT","Copyright (c) Fork, Ltd.","https://github.com/tomas/needle" "negotiator@0.6.3","MIT","Copyright (c) 2012-2014 Federico Romero. Copyright (c) 2012-2014 Isaac Z. Schlueter. Copyright (c) 2014-2015 Douglas Christopher Wilson","https://github.com/jshttp/negotiator" "neo-async@2.6.2","MIT","Copyright (c) 2014-2018 Suguru Motegi. Based on Async.js, Copyright Caolan McMahon","https://github.com/suguru03/neo-async" "netmask@2.0.2","MIT","Copyright (c) 2011 Olivier Poitrey ","https://github.com/rs/node-netmask" "next-tick@1.1.0","ISC","Copyright (c) 2012-2020, Mariusz Nowak, @medikoo, medikoo.com","https://github.com/medikoo/next-tick" -"ng-mocks@14.2.3","MIT","Copyright (c) 2017 Isaac Datlof","https://github.com/help-me-mom/ng-mocks" +"ng-mocks@14.5.0","MIT","Copyright (c) 2017 Isaac Datlof","https://github.com/help-me-mom/ng-mocks" "ng-morph@2.1.1","Apache-2.0","","https://github.com/TinkoffCreditSystems/ng-morph" "ng-recaptcha@10.0.0","MIT","Copyright (c) 2016 Ruslan Arkhipau","https://github.com/DethAriel/ng-recaptcha" -"ngx-infinite-scroll@14.0.0","MIT","","https://github.com/orizens/ngx-infinite-scroll" -"ngx-toastr@15.2.0","MIT","Copyright (c) Scott Cooper ","https://github.com/scttcper/ngx-toastr" +"ngx-infinite-scroll@14.0.1","MIT","","https://github.com/orizens/ngx-infinite-scroll" +"ngx-toastr@15.2.2","MIT","Copyright (c) Scott Cooper ","https://github.com/scttcper/ngx-toastr" "nice-try@1.0.5","MIT","Copyright (c) 2018 Tobias Reich","https://github.com/electerious/nice-try" "node-fetch@2.6.7","MIT","Copyright (c) 2016 David Frank","https://github.com/bitinn/node-fetch" "node-forge@1.3.1","(BSD-3-Clause OR GPL-2.0)","","https://github.com/digitalbazaar/forge" @@ -1335,7 +1350,6 @@ "parse-json@4.0.0","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)","https://github.com/sindresorhus/parse-json" "parse-json@5.2.0","MIT","Copyright (c) Sindre Sorhus (https://sindresorhus.com)","https://github.com/sindresorhus/parse-json" "parse-node-version@1.0.1","MIT","Copyright (c) 2018 Blaine Bublitz and Eric Schoffstall ","https://github.com/gulpjs/parse-node-version" -"parse-passwd@1.0.0","MIT","Copyright (c) 2016 Brian Woodward","https://github.com/doowb/parse-passwd" "parse5-html-rewriting-stream@6.0.1","MIT","Copyright (c) 2013-2019 Ivan Nikulin (ifaaan@gmail.com, https://github.com/inikulin)","https://github.com/inikulin/parse5" "parse5-htmlparser2-tree-adapter@6.0.1","MIT","Copyright (c) 2013-2019 Ivan Nikulin (ifaaan@gmail.com, https://github.com/inikulin)","https://github.com/inikulin/parse5" "parse5-htmlparser2-tree-adapter@7.0.0","MIT","Copyright (c) 2013-2019 Ivan Nikulin (ifaaan@gmail.com, https://github.com/inikulin)","https://github.com/inikulin/parse5" @@ -1343,6 +1357,7 @@ "parse5@5.1.1","MIT","Copyright (c) 2013-2019 Ivan Nikulin (ifaaan@gmail.com, https://github.com/inikulin)","https://github.com/inikulin/parse5" "parse5@6.0.1","MIT","Copyright (c) 2013-2019 Ivan Nikulin (ifaaan@gmail.com, https://github.com/inikulin)","https://github.com/inikulin/parse5" "parse5@7.1.1","MIT","Copyright (c) 2013-2019 Ivan Nikulin (ifaaan@gmail.com, https://github.com/inikulin)","https://github.com/inikulin/parse5" +"parse5@7.1.2","MIT","Copyright (c) 2013-2019 Ivan Nikulin (ifaaan@gmail.com, https://github.com/inikulin)","https://github.com/inikulin/parse5" "parseurl@1.3.3","MIT","Copyright (c) 2014 Jonathan Ong . Copyright (c) 2014-2017 Douglas Christopher Wilson ","https://github.com/pillarjs/parseurl" "path-browserify@1.0.1","MIT","Copyright (c) 2013 James Halliday","https://github.com/browserify/path-browserify" "path-exists@3.0.0","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)","https://github.com/sindresorhus/path-exists" @@ -1376,7 +1391,7 @@ "pm2-deploy@1.0.2","MIT","Copyright (c) 2010-2015","https://github.com/Unitech/pm2-deploy" "pm2-multimeter@0.1.2","MIT*","","https://github.com/Unitech/node-multimeter" "pm2-sysmonit@1.2.8","Apache*","","" -"pm2@5.2.0","AGPL-3.0","","https://github.com/Unitech/pm2" +"pm2@5.2.2","AGPL-3.0","","https://github.com/Unitech/pm2" "png-js@1.0.0","MIT*","Copyright (c) 2017 Devon Govett","https://github.com/devongovett/png.js" "popper.js@1.16.1","MIT","","https://github.com/FezVrasta/popper.js" "portscanner@2.2.0","MIT","Copyright (c) 2011 Brandon Ace Alexander","https://github.com/baalexander/node-portscanner" @@ -1386,7 +1401,7 @@ "postcss-color-hex-alpha@8.0.4","MIT","Copyright © PostCSS","https://github.com/csstools/postcss-plugins" "postcss-color-rebeccapurple@7.1.1","CC0-1.0","","https://github.com/csstools/postcss-plugins" "postcss-custom-media@8.0.2","MIT","Copyright © PostCSS","https://github.com/csstools/postcss-plugins" -"postcss-custom-properties@12.1.9","MIT","Copyright © PostCSS","https://github.com/csstools/postcss-plugins" +"postcss-custom-properties@12.1.11","MIT","Copyright © PostCSS","https://github.com/csstools/postcss-plugins" "postcss-custom-selectors@6.0.3","MIT","Copyright © PostCSS","https://github.com/csstools/postcss-plugins" "postcss-dir-pseudo-class@6.0.5","CC0-1.0","","https://github.com/csstools/postcss-plugins" "postcss-double-position-gradients@3.1.2","CC0-1.0","","https://github.com/csstools/postcss-plugins" @@ -1419,10 +1434,11 @@ "postcss-safe-parser@6.0.0","MIT","Copyright 2013 Andrey Sitnik ","https://github.com/postcss/postcss-safe-parser" "postcss-scss@4.0.5","MIT","Copyright 2013 Andrey Sitnik ","https://github.com/postcss/postcss-scss" "postcss-selector-not@6.0.1","MIT","Copyright (c) 2017 Maxime Thirouin","https://github.com/csstools/postcss-plugins" -"postcss-selector-parser@6.0.10","MIT","Copyright (c) Ben Briggs (http://beneb.info)","https://github.com/postcss/postcss-selector-parser" +"postcss-selector-parser@6.0.11","MIT","Copyright (c) Ben Briggs (http://beneb.info)","https://github.com/postcss/postcss-selector-parser" "postcss-sorting@7.0.1","MIT","Copyright 2015-present Aleks Hudochenkov ","https://github.com/hudochenkov/postcss-sorting" "postcss-value-parser@4.2.0","MIT","Copyright (c) Bogdan Chadkin ","https://github.com/TrySound/postcss-value-parser" "postcss@8.4.16","MIT","Copyright 2013 Andrey Sitnik ","https://github.com/postcss/postcss" +"postcss@8.4.20","MIT","Copyright 2013 Andrey Sitnik ","https://github.com/postcss/postcss" "prelude-ls@1.1.2","MIT","Copyright (c) George Zahariev","https://github.com/gkz/prelude-ls" "prelude-ls@1.2.1","MIT","Copyright (c) George Zahariev","https://github.com/gkz/prelude-ls" "prettier-linter-helpers@1.0.0","MIT","Copyright © 2017 Andres Suarez and Teddy Katz","https://github.com/prettier/prettier-linter-helpers" @@ -1448,7 +1464,7 @@ "purgecss-webpack-plugin@5.0.0","MIT","","https://github.com/FullHuman/purgecss" "purgecss@5.0.0","MIT","","https://github.com/FullHuman/purgecss" "q@1.5.1","MIT","Copyright 2009–2017 Kristopher Michael Kowal. All rights reserved.. Permission is hereby granted, free of charge, to any person obtaining a copy. of this software and associated documentation files (the "Software"), to. deal in the Software without restriction, including without limitation the. rights to use, copy, modify, merge, publish, distribute, sublicense, and/or. sell copies of the Software, and to permit persons to whom the Software is. furnished to do so, subject to the following conditions:","https://github.com/kriskowal/q" -"qs@6.10.3","BSD-3-Clause","Copyright (c) 2014, Nathan LaFreniere and other [contributors](https://github.com/ljharb/qs/graphs/contributors). All rights reserved.","https://github.com/ljharb/qs" +"qs@6.11.0","BSD-3-Clause","Copyright (c) 2014, Nathan LaFreniere and other [contributors](https://github.com/ljharb/qs/graphs/contributors). All rights reserved.","https://github.com/ljharb/qs" "qs@6.2.3","BSD-3-Clause","Copyright (c) 2014 Nathan LaFreniere and other contributors.. All rights reserved.","https://github.com/ljharb/qs" "querystringify@2.2.0","MIT","Copyright (c) 2015 Unshift.io, Arnout Kazemier, the Contributors.","https://github.com/unshiftio/querystringify" "queue-microtask@1.2.3","MIT","Copyright (c) Feross Aboukhadijeh","https://github.com/feross/queue-microtask" @@ -1490,7 +1506,6 @@ "requireindex@1.2.0","MIT","","https://github.com/stephenhandley/requireindex" "requires-port@1.0.0","MIT","Copyright (c) 2015 Unshift.io, Arnout Kazemier, the Contributors.","https://github.com/unshiftio/requires-port" "resolve-cwd@3.0.0","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)","https://github.com/sindresorhus/resolve-cwd" -"resolve-dir@1.0.1","MIT","Copyright (c) 2015-2016, Jon Schlinkert","https://github.com/jonschlinkert/resolve-dir" "resolve-from@4.0.0","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)","https://github.com/sindresorhus/resolve-from" "resolve-from@5.0.0","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)","https://github.com/sindresorhus/resolve-from" "resolve-global@1.0.0","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)","https://github.com/sindresorhus/resolve-global" @@ -1535,6 +1550,7 @@ "semver@6.3.0","ISC","Copyright (c) Isaac Z. Schlueter and Contributors","https://github.com/npm/node-semver" "semver@7.2.3","ISC","Copyright (c) Isaac Z. Schlueter and Contributors","https://github.com/npm/node-semver" "semver@7.3.7","ISC","Copyright (c) Isaac Z. Schlueter and Contributors","https://github.com/npm/node-semver" +"semver@7.3.8","ISC","Copyright (c) Isaac Z. Schlueter and Contributors","https://github.com/npm/node-semver" "send@0.16.2","MIT","Copyright (c) 2012 TJ Holowaychuk. Copyright (c) 2014-2016 Douglas Christopher Wilson","https://github.com/pillarjs/send" "send@0.18.0","MIT","Copyright (c) 2012 TJ Holowaychuk. Copyright (c) 2014-2022 Douglas Christopher Wilson","https://github.com/pillarjs/send" "serialize-javascript@6.0.0","BSD-3-Clause","Copyright 2014 Yahoo! Inc.. All rights reserved.","https://github.com/yahoo/serialize-javascript" @@ -1574,7 +1590,6 @@ "source-map-js@1.0.2","BSD-3-Clause","","https://github.com/7rulnik/source-map-js" "source-map-loader@4.0.0","MIT","Copyright JS Foundation and other contributors","https://github.com/webpack-contrib/source-map-loader" "source-map-support@0.5.13","MIT","Copyright (c) 2014 Evan Wallace","https://github.com/evanw/node-source-map-support" -"source-map-support@0.5.19","MIT","Copyright (c) 2014 Evan Wallace","https://github.com/evanw/node-source-map-support" "source-map-support@0.5.21","MIT","Copyright (c) 2014 Evan Wallace","https://github.com/evanw/node-source-map-support" "source-map@0.1.43","BSD","","https://github.com/mozilla/source-map" "source-map@0.5.7","BSD-3-Clause","","https://github.com/mozilla/source-map" @@ -1626,16 +1641,15 @@ "strip-indent@3.0.0","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)","https://github.com/sindresorhus/strip-indent" "strip-json-comments@3.1.1","MIT","Copyright (c) Sindre Sorhus (https://sindresorhus.com)","https://github.com/sindresorhus/strip-json-comments" "style-search@0.1.0","ISC","Copyright (c) 2016, David Clark","https://github.com/davidtheclark/style-search" -"stylelint-config-prettier@9.0.3","MIT","Copyright (c) Shannon Moeller (shannonmoeller.com). Copyright (c) Hugo Dias (https://hugodias.me). Copyright (c) 2017 Simon Lydell","https://github.com/prettier/stylelint-config-prettier" +"stylelint-config-prettier@9.0.4","MIT","Copyright (c) Shannon Moeller (shannonmoeller.com). Copyright (c) Hugo Dias (https://hugodias.me). Copyright (c) 2017 Simon Lydell","https://github.com/prettier/stylelint-config-prettier" "stylelint-config-recess-order@3.0.0","ISC","Copyright Jeff Nelson","https://github.com/stormwarning/stylelint-config-recess-order" -"stylelint-config-recommended-scss@7.0.0","MIT","Copyright (c) 2016 Krister Kari","https://github.com/stylelint-scss/stylelint-config-recommended-scss" -"stylelint-config-recommended@8.0.0","MIT","Copyright (c) 2018 - present stylelint","https://github.com/stylelint/stylelint-config-recommended" +"stylelint-config-recommended-scss@8.0.0","MIT","Copyright (c) 2016 Krister Kari","https://github.com/stylelint-scss/stylelint-config-recommended-scss" "stylelint-config-recommended@9.0.0","MIT","Copyright (c) 2018 - present stylelint","https://github.com/stylelint/stylelint-config-recommended" -"stylelint-config-standard@28.0.0","MIT","Copyright (c) 2015 - present stylelint authors","https://github.com/stylelint/stylelint-config-standard" +"stylelint-config-standard@29.0.0","MIT","Copyright (c) 2015 - present stylelint authors","https://github.com/stylelint/stylelint-config-standard" "stylelint-order@5.0.0","MIT","Copyright 2016–present Aleks Hudochenkov ","https://github.com/hudochenkov/stylelint-order" "stylelint-prettier@2.0.0","MIT","Copyright © 2018 Ben Scott","https://github.com/prettier/stylelint-prettier" "stylelint-scss@4.3.0","MIT","Copyright (c) 2016 Krister Kari","https://github.com/stylelint-scss/stylelint-scss" -"stylelint@14.13.0","MIT","Copyright (c) 2015 - present Maxime Thirouin, David Clark & Richard Hallows","https://github.com/stylelint/stylelint" +"stylelint@14.16.0","MIT","Copyright (c) 2015 - present Maxime Thirouin, David Clark & Richard Hallows","https://github.com/stylelint/stylelint" "stylus-loader@7.0.0","MIT","Copyright JS Foundation and other contributors","https://github.com/webpack-contrib/stylus-loader" "stylus@0.59.0","MIT","Copyright (c) Automattic ","https://github.com/stylus/stylus" "supports-color@2.0.0","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)","https://github.com/chalk/supports-color" @@ -1645,12 +1659,12 @@ "supports-hyperlinks@2.3.0","MIT","Copyright (c) James Talmage (github.com/jamestalmage)","https://github.com/jamestalmage/supports-hyperlinks" "supports-preserve-symlinks-flag@1.0.0","MIT","Copyright (c) 2022 Inspect JS","https://github.com/inspect-js/node-supports-preserve-symlinks-flag" "svg-tags@1.0.0","MIT","Copyright (c) 2014 Athan Reines.","https://github.com/element-io/svg-tags" -"swiper@8.4.2","MIT","Copyright (c) 2019 Vladimir Kharlampidi","https://github.com/nolimits4web/Swiper" +"swiper@8.4.5","MIT","Copyright (c) 2019 Vladimir Kharlampidi","https://github.com/nolimits4web/Swiper" "symbol-observable@1.0.1","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com). Copyright (c) Ben Lesh ","https://github.com/blesh/symbol-observable" "symbol-observable@4.0.0","MIT","Copyright (c) 2021 Sindre Sorhus (sindresorhus.com). Copyright (c) 2021 Ben Lesh ","https://github.com/blesh/symbol-observable" "symbol-tree@3.2.4","MIT","Copyright (c) 2015 Joris van der Wel","https://github.com/jsdom/js-symbol-tree" "systeminformation@5.12.6","MIT","Copyright (c) 2014-2021 Sebastian Hildebrandt","https://github.com/sebhildebrandt/systeminformation" -"table@6.8.0","BSD-3-Clause","Copyright (c) 2018, Gajus Kuizinas (http://gajus.com/). All rights reserved.","https://github.com/gajus/table" +"table@6.8.1","BSD-3-Clause","Copyright (c) 2018, Gajus Kuizinas (http://gajus.com/). All rights reserved.","https://github.com/gajus/table" "tapable@2.2.1","MIT","Copyright JS Foundation and other contributors","https://github.com/webpack/tapable" "tar@6.1.11","ISC","Copyright (c) Isaac Z. Schlueter and Contributors","https://github.com/npm/node-tar" "tdigest@0.1.2","MIT","Copyright (c) 2015 Will Welch","https://github.com/welch/tdigest" @@ -1697,6 +1711,7 @@ "tslib@1.14.1","0BSD","Copyright (c) Microsoft Corporation.","https://github.com/Microsoft/tslib" "tslib@1.9.3","Apache-2.0","","https://github.com/Microsoft/tslib" "tslib@2.4.0","0BSD","Copyright (c) Microsoft Corporation.","https://github.com/Microsoft/tslib" +"tslib@2.4.1","0BSD","Copyright (c) Microsoft Corporation.","https://github.com/Microsoft/tslib" "tsutils-etc@1.4.1","MIT","Copyright (c) 2019 Nicholas Jamieson","https://github.com/cartant/tsutils-etc" "tsutils@3.21.0","MIT","Copyright (c) 2017 Klaus Meinhardt","https://github.com/ajafff/tsutils" "tv4@1.3.0","Public Domain,MIT","","https://github.com/geraintluff/tv4" @@ -1750,7 +1765,7 @@ "vary@1.1.2","MIT","Copyright (c) 2014-2017 Douglas Christopher Wilson","https://github.com/jshttp/vary" "vizion@2.2.1","Apache-2.0","Copyright 2016 Keymetrics, Inc.","https://github.com/keymetrics/vizion" "vm2@3.9.11","MIT","Copyright (c) 2014-2022 Patrik Simek and contributors","https://github.com/patriksimek/vm2" -"vscode-languageserver-textdocument@1.0.7","MIT","Copyright (c) Microsoft Corporation","https://github.com/Microsoft/vscode-languageserver-node" +"vscode-languageserver-textdocument@1.0.8","MIT","Copyright (c) Microsoft Corporation","https://github.com/Microsoft/vscode-languageserver-node" "vscode-uri@3.0.6","MIT","Copyright (c) Microsoft","https://github.com/microsoft/vscode-uri" "w3c-hr-time@1.0.2","MIT","Copyright (c) 2017 Tiancheng "Timothy" Gu and other contributors","https://github.com/jsdom/w3c-hr-time" "w3c-xmlserializer@2.0.0","MIT","Copyright © 2016 Sebastian Mayr","https://github.com/jsdom/w3c-xmlserializer" @@ -1781,6 +1796,8 @@ "whatwg-url@5.0.0","MIT","Copyright (c) 2015–2016 Sebastian Mayr","https://github.com/jsdom/whatwg-url" "whatwg-url@8.7.0","MIT","Copyright (c) 2015–2016 Sebastian Mayr","https://github.com/jsdom/whatwg-url" "which-boxed-primitive@1.0.2","MIT","Copyright (c) 2019 Jordan Harband","https://github.com/inspect-js/which-boxed-primitive" +"which-collection@1.0.1","MIT","Copyright (c) 2019 Inspect JS","https://github.com/inspect-js/which-collection" +"which-typed-array@1.1.9","MIT","Copyright (c) 2015 Jordan Harband","https://github.com/inspect-js/which-typed-array" "which@1.3.1","ISC","Copyright (c) Isaac Z. Schlueter and Contributors","https://github.com/isaacs/node-which" "which@2.0.2","ISC","Copyright (c) Isaac Z. Schlueter and Contributors","https://github.com/isaacs/node-which" "wide-align@1.1.5","ISC","Copyright (c) 2015, Rebecca Turner ","https://github.com/iarna/wide-align" diff --git a/CHANGELOG.md b/CHANGELOG.md index 619e4d630d..478ff62461 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,59 @@ kb_everyone # Changelog +## [3.2.0](https://github.com/intershop/intershop-pwa/releases/tag/3.2.0) (2022-12-22) + +**required Intershop Commerce Management version: 7.10.38.11-LTS** + +**required/tested Node.js version: 16.16.0 LTS (including npm 8.11.0)** + +### Features + +- use ICM '/token' REST endpoint for authentication (#1156) ([4e02efd](https://github.com/intershop/intershop-pwa/commit/4e02efd)) +- introduce additional components for product variation select display (#1317) ([ddd6e2e](https://github.com/intershop/intershop-pwa/commit/ddd6e2e)) +- introduce variation attribute mapping with extended /variations call (#1317) ([d9e4b17](https://github.com/intershop/intershop-pwa/commit/d9e4b17)) +- provide and combine metrics of theme instances (#1340) ([88b4206](https://github.com/intershop/intershop-pwa/commit/88b4206)) +- route to product detail page if only one search result was found (#1316) ([9964ebd](https://github.com/intershop/intershop-pwa/commit/9964ebd)) +- save desired delivery date at basket items (#1325) ([f8fba29](https://github.com/intershop/intershop-pwa/commit/f8fba29)) +- add zebra striped table style for attributes in product details tab (#1326) ([7999f02](https://github.com/intershop/intershop-pwa/commit/7999f02)) +- customer address update in the My Account section (#1315) ([a98d391](https://github.com/intershop/intershop-pwa/commit/a98d391)) + +### Bug Fixes + +- apply ordered-import rule on multiline import statements (#1344) ([5887c41](https://github.com/intershop/intershop-pwa/commit/5887c41)) +- prevent outdated basket information on /basket route (#1342) ([1a730f8](https://github.com/intershop/intershop-pwa/commit/1a730f8)) +- remove check for variations or variation master data for variation product data handling ([41e674f](https://github.com/intershop/intershop-pwa/commit/41e674f)) +- error when submitting consecutive search after submitting search from search suggestion (#1332) ([9d063a9](https://github.com/intershop/intershop-pwa/commit/9d063a9)) +- add SSR hybrid backend configuration option for kubernetes deployments (#1320) ([3e293fa](https://github.com/intershop/intershop-pwa/commit/3e293fa)) +- prevent budget bar arrow and product label ribbons to be shown in the subcategories layer (#1329) ([7f4d34c](https://github.com/intershop/intershop-pwa/commit/7f4d34c)) +- replace the product label image sprite, use CSS only styling and localized HTML text (#1319) ([7f63863](https://github.com/intershop/intershop-pwa/commit/7f63863)) +- replace the empty cart image with pure CSS and remove the image file (#1319) ([eebebec](https://github.com/intershop/intershop-pwa/commit/eebebec)) +- remove active_catalog.png and budget-bar-indicator.png and replace with CSS styling (#1319) ([9aeafaf](https://github.com/intershop/intershop-pwa/commit/9aeafaf)) +- display company input fields for anonymous b2b users on checkout edit address form (#1312) ([23a9257](https://github.com/intershop/intershop-pwa/commit/23a9257)) +- change and display an anonymous user`s email during the checkout process (#1312) ([b2c265b](https://github.com/intershop/intershop-pwa/commit/b2c265b)) +- validate email during the checkout process of an anonymous user (#1312) ([5ba41ec](https://github.com/intershop/intershop-pwa/commit/5ba41ec)) +- apiToken cookie should be shared between same host (#1321) ([80d5f9d](https://github.com/intershop/intershop-pwa/commit/80d5f9d)) +- add promotion scope to the validation of the first basket checkout step (#1322) ([8da52d6](https://github.com/intershop/intershop-pwa/commit/8da52d6)) +- keep the footer at the bottom of the page (#1318) ([feb1648](https://github.com/intershop/intershop-pwa/commit/feb1648)) +- 'npm install' not working with PWA release zip file (#1314) ([33be4cc](https://github.com/intershop/intershop-pwa/commit/33be4cc)) +- display login modal after authentication token has expired (#1280, #1311) ([025818c](https://github.com/intershop/intershop-pwa/commit/025818c)) +- add matrix parameter spgid to promotion REST calls (#1310) ([1cae0d8](https://github.com/intershop/intershop-pwa/commit/1cae0d8)) + +### Documentation + +- improve authentication documentation (#1156) ([cf89956](https://github.com/intershop/intershop-pwa/commit/cf89956)) +- extend PurgeCSS integration documentation (#1313) ([d4db9d6](https://github.com/intershop/intershop-pwa/commit/d4db9d6)) + +### BREAKING CHANGES + +- PWA uses the ICM `/token` REST endpoint to retrieve user token, every anonymous user will get a anonymous user token, every identity provider has to configure the `oAuthService` with information about the token endpoint, before expiration the given token should be refreshed. +- Changed the rendering of the `ProductVariationSelectComponent` and introduced additional product variation select rendering components (see [Migrations / 3.1 to 3.2](https://github.com/intershop/intershop-pwa/blob/develop/docs/guides/migrations.md#31-to-32) for more details). +- `ProductsService` was changed to use an `extended=true` details and variations call. `VariationAttribute` model was cleaned up and extended (see [Migrations / 3.1 to 3.2](https://github.com/intershop/intershop-pwa/blob/develop/docs/guides/migrations.md#31-to-32) for more details). +- The product label ribbon image is replaced with localized text and CSS styling. +- The empty cart image is removed and replaced with localized text and CSS styling. +- The `active_catalog.png` and `budget-bar-indicator.png` are removed and replaced with CSS styling. +- Formly has been upgraded from version 5 to 6 (see [Migrations / 3.1 to 3.2](https://github.com/intershop/intershop-pwa/blob/develop/docs/guides/migrations.md#31-to-32) for more details). + ## [3.1.0](https://github.com/intershop/intershop-pwa/releases/tag/3.1.0) (2022-10-17) **required Intershop Commerce Management version: 7.10.38.11-LTS** diff --git a/Dockerfile b/Dockerfile index ab7032aaeb..223d700b9f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -33,7 +33,7 @@ RUN cd dist && npm install ARG displayVersion= LABEL displayVersion="${displayVersion}" ENV DISPLAY_VERSION=${displayVersion} NODE_PATH=/dist/node_modules PATH=$PATH:/dist/node_modules/.bin -EXPOSE 4200 +EXPOSE 4200 9113 RUN mkdir /.pm2 && chmod 777 -Rf /.pm2 && touch /dist/ecosystem.yml && chmod 777 -f /dist/ecosystem.yml USER nobody HEALTHCHECK --interval=60s --timeout=20s --start-period=2s CMD node /dist/healthcheck.js diff --git a/docker-compose.yml b/docker-compose.yml index c70eb572cf..622a322442 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -25,6 +25,14 @@ services: # FEATURES: | # - compare # - rating + # IDENTITY_PROVIDER: 'Auth0' + # IDENTITY_PROVIDERS: | + # Auth0: + # type: auth0 + # domain: some-domain.auth0.com + # clientID: ASDF12345 + # Punchout: + # type: PUNCHOUT # # add 127.0.0.1 mypwa.net to your hosts file and @@ -81,6 +89,10 @@ services: # BASIC_AUTH_IP_WHITELIST: | # # - 172.22.0.1 # - 1.2.3.4 + # OVERRIDE_IDENTITY_PROVIDERS: | + # .+: + # - path: /en/punchout + # type: Punchout MULTI_CHANNEL: | .+: - baseHref: /en diff --git a/docs/README.md b/docs/README.md index efa8cacdeb..60c3fa7029 100644 --- a/docs/README.md +++ b/docs/README.md @@ -27,7 +27,10 @@ kb_sync_latest_only - [Guide - Formly](./guides/formly.md) - [Guide - Field Library](./guides/field-library.md) - [Concept - Deployment Scenarios for Angular Applications](./concepts/deployment-angular.md) -- [Concept - Single Sign-On (SSO) for PWA](./concepts/sso.md) +- [Concept - Authentication](./concepts/authentication.md) + - [Guide - Authentication by the ICM Server](./guides/authentication_icm.md) + - [Guide - Authentication with Single Sign-On (SSO)](./guides/authentication_sso.md) + - [Guide - Authentication with the Punchout Identity Provider](./guides/authentication_punchout.md) ### Developing @@ -80,5 +83,4 @@ kb_sync_latest_only - [Guide - Client-Side Error Monitoring with Sentry](./guides/sentry-error-monitoring.md) - [Guide - Extended Product Configurations with Tacton](./guides/tacton-product-configuration.md) - [Guide - Monitoring with Prometheus](./guides/prometheus-monitoring.md) -- [Guide - SSO with Auth0 for PWA](./guides/sso-auth0.md) - [Guide - Store Locator with Google Maps](./guides/store-locator.md) diff --git a/docs/check-sentence-newline.js b/docs/check-sentence-newline.js index 20d9b62e6f..110271a3bd 100644 --- a/docs/check-sentence-newline.js +++ b/docs/check-sentence-newline.js @@ -15,7 +15,7 @@ files.forEach(file => { if (/^(>|#|\||\s*-|\s*[0-9]+\.)/.test(line)) { return line; } else { - return line.replace(/((?!i\.e)\.) ([A-Z0-9])/g, '$1\n$2'); + return line.replace(/((? + +# Authentication Concept + +## Introduction + +Several ICM REST operations require an authenticated user. +Authentication also assures enterprise information security. +In the PWA a user can be verified with the help of an identity provider. +An identity provider (IdP) is a service that stores and manages digital identities. +The following identity providers are supported: The default [ICM server](../guides/authentication_icm.md), the [SSO Auth0](../guides/authentication_sso.md) and the [Punchout](../guides/authentication_punchout.md) identity provider. + +## Library angular-oauth2-oidc + +There is a lot of functionality related to authentication, e.g., logging a user in and out, registering a new user, keeping the user identified even if the user opens further browser tabs, etc. + +The PWA uses the library [angular-oauth2-oidc](https://github.com/manfredsteyer/angular-oauth2-oidc#readme) to support the implementation of these functionalities. +It can be configured to provide access to identity providers. +You can find the initialization of this library in the [oauth-configuration-service.ts](../../src/app/shared/../core/utils/oauth-configuration/oauth-configuration.service.ts). + +## Implementation and Configuration of Identity Providers + +To add or change the functionality of an identity provider, the following steps are necessary: + +1. Create/change an `.identity-provider.ts` class that implements the interface [`IdentityProvider`](../../src/app/core/identity-provider/identity-provider.interface.ts). In this interface all methods are declared which have to be implemented in your IdP class. + + In the following code you see a typical implementation of the init method of an IdP class. + + Note that all authentication-related functionality must not be executed before the oAuth service has been configured. + + ```typescript + @Injectable({ providedIn: 'root' }) + export class ExampleIdentityProvider implements IdentityProvider { + private configured$ = new BehaviorSubject(false); + + constructor(private oAuthService: OAuthService, private configService: OAuthConfigurationService) {} + + init() { + this.configService.config$.subscribe(config => { + this.oAuthService.configure(config); + this.configured.next(true); + }); + + this.configured + .pipe( + whenTruthy(), + switchMap(() => from(this.oAuthService.fetchTokenUsingGrant('anonymous'))) + ) + .subscribe(); + } + } + ``` + +2. Register the `.identity-provider.ts` in the [`IdentityProviderModule`](../../src/app/core/identity-provider.module.ts). The `APP_INITIALIZER` injection token is used to configure and initialize the identity provider before app initialization. + +3. Set the environment variables `IdentityProviders` and `IdentityProvider` accordingly. + +## PWA Initialization + +A PWA user has to be identified by the ICM server by a unique authentication token, even if it is an anonymous user. +Once a user opens the PWA for the first time, an authentication token is requested by the [ICM Token REST endpoint](https://support.intershop.com/kb/index.php?c=Display&q1=U29770&q2=Text). +This happens in the [`init()`](../../src/app/core/identity-provider/icm.identity-provider.ts) method of the active identity provider. +Subsequently, this token will be saved as `apiToken` cookie and added to all REST requests in the request header, e.g.: + +```typescript +authentication-token: encryption0@PBEWithMD5AndTripleDES:1D7T8HyFqQ0=|k3PQLgujzUq0tudtw+6HLjWnExiwrd4o9/jVU7ZH74kTfTy3RS7/sYadsg7ODRM2 +``` + +This way it is possible to identify users even they are opening a new browser tab or refreshing the PWA in the browser. + +If a user opens the PWA and already has a valid apiToken cookie, no new token is requested by the ICM server but this token is used in the header of the REST requests. + +## Login, Registration, Token Refreshment, Logout + +All these functionalities strongly depend on the implementation of the used identity provider. +This is described in the appropriate identity provider guides in more detail, see [Further References](#further-references) below. + +## Vanishing of the apiToken Cookie + +The PWA needs to react in case the `apiToken` cookie is not available anymore. +This could happen if a PWA is opened in many tabs and the user logs out, or when users remove the cookie themselves. +When the cookie vanishes, the PWA emits a new value for the [`cookieVanishes$` subject](../../src/app/core/utils/api-token/api-token.service.ts). +The identity provider implementation defines how the application should behave in such a case. +With the ICM identity provider, for example, the user is then automatically logged out and routed to the `/login` page. + +## Further References + +- [Guide - ICM Identity Provider](../guides/authentication_icm.md) +- [Guide - Punchout Identity Provider](../guides/authentication_punchout.md) +- [Guide - Single Sign-On (SSO) Identity Provider](../guides/authentication_sso.md) diff --git a/docs/concepts/hybrid-approach.md b/docs/concepts/hybrid-approach.md index fcc509f4c6..317e7a5b45 100644 --- a/docs/concepts/hybrid-approach.md +++ b/docs/concepts/hybrid-approach.md @@ -13,6 +13,15 @@ A possible scenario would be to have the shopping experience with all its SEO op ## Requirements +The best way to deploy a Hybrid Approach installation is with the Intershop provided [PWA Helm chart](https://github.com/intershop/helm-charts/tree/main/charts/pwa) (0.4.0 and above). +How to configure the PWA Helm chart for the PWA and the ICM is explained in the according [Hybrid mode](https://github.com/intershop/helm-charts/tree/main/charts/pwa#hybrid-mode) paragraph. +The version requirements for the involved systems are the following. + +- Intershop 11 +- PWA 3.2.0 + +The functional requirements for the Hybrid Approach to work are already available with the following versions of ICM and PWA but this way they cannot be deployed together with a combined Helm chart. + - ICM 7.10.32.16-LTS or 7.10.38.6-LTS - PWA 2.3.0 @@ -39,7 +48,7 @@ See [Concept - Integration of Progressive Web App and inSPIRED Storefront](https If you also want to support the correct handling for links generated in e-mails, the property `intershop.WebServerSecureURL` must point to nginx. -_\$SERVER/share/system/config/cluster/appserver.properties_: +_configuration via \$SERVER/share/system/config/cluster/appserver.properties_: ```properties SecureAccessOnly=true @@ -48,14 +57,20 @@ intershop.apitoken.cookie.sslmode=true intershop.WebServerSecureURL=https:// ``` +_configuration via `icm_as` Helm chart_ + +```yaml +INTERSHOP_APITOKEN_COOKIE_ENABLED: true +INTERSHOP_APITOKEN_COOKIE_SSLMODE: true +INTERSHOP_WEBSERVERSECUREURL: https:// +``` + ### Intershop Progressive Web App The server-side rendering process must be started with `SSR_HYBRID=1`. In addition, the PWA must be run with secure URLs as well. -See [SSR Startup](../guides/ssr-startup.md#running-with-https)) for reference how you can achieve that locally. - -> :warning: **Don't use this option for production environments**, above means to switch on hybrid mode and https are only to ease local development. +See [SSR Startup - Development](../guides/ssr-startup.md#development) for reference how you can achieve that locally. > :warning: **Only for development environments**: It might be necessary to set `TRUST_ICM=1` if the used development ICM is deployed with an insecure certificate. diff --git a/docs/concepts/styling-behavior.md b/docs/concepts/styling-behavior.md index 96a9b76366..94165b25f5 100644 --- a/docs/concepts/styling-behavior.md +++ b/docs/concepts/styling-behavior.md @@ -51,6 +51,11 @@ To integrate an icon If an icon is not available yet, you need to add it to `src\app\core\icon.module.ts` in the `import {}` and the `constructor(){}`. +## Optimization + +The PWA uses [PurgeCSS](https://purgecss.com/) for bundled styles optimization. +Please read [the additional documentation](../guides/optimizations.md#purgecss) for information on the usage and configuration of PurgeCSS in the Intershop PWA. + ## References [Guide - Multiple Themes](../guides/multiple-themes.md) diff --git a/docs/guides/authentication_icm.md b/docs/guides/authentication_icm.md new file mode 100644 index 0000000000..51b07a1c6f --- /dev/null +++ b/docs/guides/authentication_icm.md @@ -0,0 +1,38 @@ + + +# Authentication by the ICM Server + +This document describes the main authentication mechanism if the ICM server is used as identity provider. +If you need an introduction to this topic, read the [Authentication Concept](../concepts/authentication.md) first. + +## Login + +If the user wants to login by clicking a login link or navigating to the `/login` route, either a popup or a page is displayed containing a login form. +After the user has entered the credentials (e-mail/user name and password) and could be verified successfully by the ICM server, a new token is fetched from the ICM `/token` REST endpoint. +The token of the registered user is saved as `apiToken` cookie and attached to the request header of the subsequent REST requests. +After logging in, the pgid of the user is requested from the ICM server (`/personalization` REST call) and the action `personalizationStatusDetermined` will be triggered. +If you want to request user-specific non-cached data from the ICM server, use the option `sendPGID` or `sendSPGID`, respectively when you call the _get_ method of the `ApiTokenService`. + +## Registration + +The registration of a user is similar to the login. +After the user has completed the registration form, the data are validated by the ICM server and a new user will be created. +Afterwards, the authentication token is requested from the server and the user will be logged in, see above. + +## Token Lifetime + +Each authentication token has a predefined lifetime. +That means, the token has to be refreshed to prevent it from expiring. +Once 75% of the token's lifetime have passed (this time can be configured in the oAuth library), an info event is emitted. +This event is used to call the [refresh mechanism `setupRefreshTokenMechanism$`](../../src/app/core/utils/oauth-configuration/oauth-configuration.service.ts) of the oAuth configuration service and the authentication token will be renewed. +Hence, the token will not expire as long as the user keeps the PWA open in the browser. + +## Logout + +When the user logs out by clicking the logout link or navigating to the `/logout` route, the configured [`logout()`](../../src/app/core/identity-provider/icm.identity-provider.ts) function will be executed, which will call the [`revokeApiToken()`](../../src/app/core/services/user/user.service.ts) user service in order to deactivate the token on server side. +Besides this, the PWA removes the token on browser side, fetches a new anonymous user token, and sets it as `apiToken` cookie. diff --git a/docs/guides/authentication_punchout.md b/docs/guides/authentication_punchout.md new file mode 100644 index 0000000000..1444f9330b --- /dev/null +++ b/docs/guides/authentication_punchout.md @@ -0,0 +1,79 @@ + + +# Authentication with the Punchout Identity Provider + +This document describes the main authentication mechanism if punchout is used as identity provider. +If you need an introduction to this topic, read the [Authentication Concept](../concepts/authentication.md) first. + +## Configuration + +The PWA must be configured in a correct way to use punchout as an identity provider. +Apart from the enabled `punchout` feature flag, the following configuration can be added to the Angular CLI environment files for development purposes: + +```typescript +features: [ + 'punchout' +], +identityProvider: 'Punchout', +identityProviders: { + 'Punchout': { + type: 'PUNCHOUT', + } +}, +``` + +For production, this configuration should be provided to the SSR process via environment variables (see [Building and Running Server-Side Rendering][ssr-startup]). +The usage of identity providers can also be set in the multi-channel configuration (see [Building and Running nginx Docker Image][nginx-startup]). + +Additionally, the PWA can be configured to use the punchout identity provider only, when the user enters the punchout route. +In that case the nginx should be configured with the `OVERRIDE_IDENTITY_PROVIDERS` environment variable (see [Override Identity Providers by Path][nginx-startup]). +Nevertheless, the SSR process needs to be provided with the punchout identity provider configuration. + +```yaml +pwa: + environment: + IDENTITY_PROVIDERS: | + Punchout: + type: PUNCHOUT + +nginx: + environment: + OVERRIDE_IDENTITY_PROVIDERS: | + .+: + - path: /punchout + type: Punchout +``` + +## Login + +A user can login by navigating to the `/punchout` or `/login` route. +For this purpose [specific query params](../../src/app/extensions/punchout/identity-provider/punchout-identity-provider.ts) need to be added to the given route depending on whether the OCI or the cXML punchout should be used. +For the OCI punchout login the user needs to add the `HOOK_URL`, `USERNAME` and `PASSWORD` as query parameters, while the cXML user has to include the `sid` and `access-token`. +In addition, the [cXML punchout tester](https://punchoutcommerce.com/tools/cxml-punchout-tester) could be used to log in a cXML punchout user. +The request [/customers/${CustomersKey}/punchouts/cxml1.2/setuprequest](https://support.intershop.com/kb/index.php/Display/29L952#l1142) to create a new cXML punchout session must be inserted as the URL with the credentials of the cXML punchout user. +When the session is created successfully, the punchout tester will redirect to the ICM configured PWA deployment `/punchout` route. + +## Registration + +There is currently no possibility to register a new punchout user in the PWA. + +## Token Lifetime + +Each authentication token has a predefined lifetime. +That means, the token has to be refreshed to prevent it from expiring. +Once 75% of the token's lifetime have passed ( this time can be configured in the oAuth library), an info event is emitted. +This event is used to call the [refresh mechanism `setupRefreshTokenMechanism$`](../../src/app/core/utils/oauth-configuration/oauth-configuration.service.ts) of the oAuth configuration service and the authentication token will be renewed. +Hence, the token will not expire as long as the user keeps the PWA open in the browser. + +## Logout + +When the user logs out by clicking the logout link or navigating to the `/logout` route, the configured [`logout()`](../../src/app/extensions/punchout/identity-provider/punchout-identity-provider.ts) function will be executed, which will call the [`revokeApiToken()`](../../src/app/core/services/user/user.service.ts) user service in order to deactivate the token on server side. +Besides this, the PWA removes the token and basket-id on browser side, fetches a new anonymous user token, and sets it as `apiToken` cookie. + +[ssr-startup]: ../guides/ssr-startup.md +[nginx-startup]: ../guides/nginx-startup.md diff --git a/docs/concepts/sso.md b/docs/guides/authentication_sso.md similarity index 52% rename from docs/concepts/sso.md rename to docs/guides/authentication_sso.md index fd6c08c1e6..a03dcecadb 100644 --- a/docs/concepts/sso.md +++ b/docs/guides/authentication_sso.md @@ -1,11 +1,11 @@ -# Single Sign-On (SSO) for PWA +# Authentication with Single Sign-On (SSO) Intershop Commerce Management supports logging in clients via SSO (see [Concept - Single Sign-On (SSO)][kb-concept-sso]). @@ -15,9 +15,9 @@ After setting up the ICM side with the identity provider, an implementation for For development purposes the configuration can be added to the Angular CLI environment files: ```typescript - identityProvider: 'MyProvider', + identityProvider: 'Auth0', identityProviders: { - 'MyProvider': { + 'Auth0': { type: 'auth0', domain: 'some-domain.auth0.com', clientID: 'ASDF12345', @@ -28,30 +28,51 @@ For development purposes the configuration can be added to the Angular CLI envir For production, this configuration should be provided to the SSR process via environment variables (see [Building and Running Server-Side Rendering][ssr-startup]). The usage of identity providers can also be set in the multi-channel configuration (see [Building and Running nginx Docker Image][nginx-startup]). -## Business cases +```yaml +pwa: + environment: + IDENTITY_PROVIDER: 'Auth0' + IDENTITY_PROVIDERS: | + Auth0: + type: auth0 + domain: some-domain.auth0.com + clientID: ASDF12345 +``` + +## SSO with Auth0 for PWA + +Follow [this guide](https://manfredsteyer.github.io/angular-oauth2-oidc/docs/additional-documentation/authorization-servers/auth0.html) to set up an application in the Auth0 configuration. + +The PWA contains a default SSO with Auth0 identity provider implementation located in the [`Auth0IdentityProvider`](../../src/app/core/identity-provider/auth0.identity-provider.ts). + +Use the configuration fields `domain` and `clientID` for configuring the provider. + +## Business Cases -### Create new user +### Create New User -| Authentication Provider | Route in ICM email | Behavior of PWA | -| ----------------------- | ------------------ | ------------------------------------------ | -| ICM | /invite | Redirect to /forgotPassword/updatePassword | -| SSO | /invite | Redirect to SSO provider | +| Authentication Provider | Route in ICM e-mail | Behavior of PWA | +| ----------------------- | ------------------- | ------------------------------------------ | +| ICM | /invite | Redirect to /forgotPassword/updatePassword | +| SSO | /invite | Redirect to SSO provider | -### User forgot password +### User Forgot Password -| Authentication Provider | Route in ICM email | Behavior of PWA | -| ----------------------- | ------------------------------ | ------------------------- | -| ICM | /forgotPassword/updatePassword | Show change password form | -| SSO | /forgotPassword/updatePassword | Redirect to SSO provider | +| Authentication Provider | Route in ICM e-mail | Behavior of PWA | +| ----------------------- | ------------------------------ | --------------------------- | +| ICM | /forgotPassword/updatePassword | Show _change password_ form | +| SSO | /forgotPassword/updatePassword | Redirect to SSO provider | -# Further References +## Further References - PWA - - [Guide - SSO with Auth0 for PWA](../guides/sso-auth0.md) + - [Concept - Authentication](../concepts/authentication.md) - [Guide - Building and Running Server-Side Rendering][ssr-startup] - [Guide - Building and Running nginx Docker Image][nginx-startup] - ICM - [Concept - Single Sign-On (SSO)][kb-concept-sso] +- General + - [SSO with OAuth 2 and OpenId Connect](https://angular.de/artikel/oauth-odic-plugin/) (in German) [kb-concept-sso]: https://support.intershop.com/kb/index.php/Display/29A407 [ssr-startup]: ../guides/ssr-startup.md diff --git a/docs/guides/customizations.md b/docs/guides/customizations.md index e47c4a9109..511c411e5f 100644 --- a/docs/guides/customizations.md +++ b/docs/guides/customizations.md @@ -81,7 +81,7 @@ Typical hot-spots where copying is a good idea are header-related or product-det #### Theme Specific Overrides The [customized webpack build](./optimizations.md) supports replacing any file with an environment suffix in front of the file extension. -If you for example want to customize the template `product-detail.component.html`, put your customized content in the parallel file `product-detail.component.brand.html` and run a build with `--configuration=brand`. +If you for example want to customize the template `product-detail.component.html`, put your customized content in the parallel file `product-detail.component.theme.html` and run a build with `--configuration=theme`. Then this overridden component template will be swapped in. This also works for multiple configurations: `product-detail.component.foo.bar.baz.html` will be active for configurations `foo`, `bar` and `baz`, but not for `foobar`. @@ -155,7 +155,7 @@ There are two approaches to apply a theme specific styling: 1. Copy only the `*.scss` files you need to change to your themes folder and adjust the file references. All files which are not overwritten in your theme will be taken from the standard and all changes and bugfixes in these files when migrating the PWA will be applied and used in your project. 2. Copy the complete set of standard `*.scss` files to your themes folder and adjust the file references. All standard changes and bugfixes to `*.scss` files will not be applied to your theme during a PWA migration. -Just putting a brand override file next to the original file in the `src/styles` folder will not lead to the expected results. +Just putting a theme override file next to the original file in the `src/styles` folder will not lead to the expected results. The lookup starts with the file `style.scss` in the theme specific folder. > **Note:** You should @@ -164,6 +164,7 @@ The lookup starts with the file `style.scss` in the theme specific folder. > - not delete the standard theme folders to prevent merge conflicts when migrating the PWA (changes in standard files but deleted in your project). When styling is done on component level, all styling is encapsulated to exactly this component (default behavior). +On component level, theme-specific overrides for `.scss` files work as expected. You can re-use variables from the global styling on component level by importing only the styling file that defines the theme variables, e.g. @@ -173,10 +174,14 @@ You can re-use variables from the global styling on component level by importing > **Note:** Be aware that Visual Studio Code will not resolve all import references correctly but it works in the build PWA version anyways. +> **Note:** For bundled styles optimization PurgeCSS is used. Please read [the additional documentation](./optimizations.md#purgecss) regarding the usage and configuration of PurgeCSS in the Intershop PWA. + +### Static Assets + To add static assets (images, favicon, manifest file), create a theme specific folder in `src/assets/themes/` and adjust the theme specific references in the `*.scss` files accordingly. -The `index.html` does not support the theme specific overrides, see [Theme Specific Overrides](../guides/customizations.md#theme-specific-overrides). -Therefore, any theme specific references have to be changed directly in this file. +The `index.html` does not support theme specific overrides, see [Theme Specific Overrides](../guides/customizations.md#theme-specific-overrides). +For this file, any theme specific differences are handled via [theme.service.ts](../../src/app/core/utils/theme/theme.service.ts). ### Dependencies diff --git a/docs/guides/migrations.md b/docs/guides/migrations.md index 7a714ed873..5d9cb0f742 100644 --- a/docs/guides/migrations.md +++ b/docs/guides/migrations.md @@ -7,14 +7,43 @@ kb_sync_latest_only # Migrations +## 3.1 to 3.2 + +A styling adaption was made to the application shell to expand it to the full page height, so the footer now always stays at the bottom. +Together with that an inline style of the `main-container` was moved to the global styling definition. + +Formly has been upgraded from version 5 to 6. +Find more information in the [Formly Upgrade Guide](https://github.com/ngx-formly/ngx-formly/blob/main/UPGRADE-6.0.md). +We still use deprecated form properties like `templateOptions` and `expressionProperties` for compatibility reasons but we are going to replace them in the next major release. + +The two small black triangle images `active_catalog.png` (header: when hovering a catalog) and `budget-bar-indicator.png` (my account: budget bar) are removed and replaced by CSS styling. +The image for an empty basket `empty-cart.png` is removed and replaced with CSS styling. +The sprite image `product_sprite.png` is removed and replaced with localized text for "New", "Sale", and "Top" with the according CSS styling. + +After entering a desired delivery date on the checkout shipping page and after submitting the order, the desired delivery date will be saved at all basket items if necessary. +In case of large baskets (> 20 items) this might cause long response times. +You can keep the existing behavior by modifying the `updateBasketItemsDesiredDeliveryDate()` method of the basket service to always return an empty array without doing anything. + +The `ProductsService` was changed to use `extended=true` REST calls for product details and variations to fetch variation attributes with additional `attributeType` and `metaData` information that can be used to control the rendering of different variation select types. +The added `VariationAttributeMapper` maps the additional information in a backwards compatible way. +To handle the different variation select rendering types, the existing `ProductVariationSelectComponent` now contains the logic to select the fitting variation select rendering component. +The rendering and behavior of the existing `ProductVariationSelectComponent` as a standard select box was moved to the new `ProductVariationSelectDefaultComponent`. +A `ProductVariationSelectSwatchComponent` for colorCode and swatchImage variation select rendering and a `ProductVariationSelectEnhancedComponent` for a select box rendering with color codes or swatch images and a mobile optimization were added. + +The user authentication process has changed. +User authentication tokens are requested from the ICM server using the `/token` REST endpoint now. +Regarding this, the logout action triggers a service which revokes the currently available access token on the ICM backend. +If the logout was successful, all personalized information is removed from the ngrx store. +Please use `logoutUser({ revokeToken: false })` from the account facade or dispatch `logoutUserSuccess` instead of the `logoutUser` action to use the old behavior. + ## 3.0 to 3.1 The SSR environment variable 'ICM_IDENTITY_PROVIDER' will be removed in a future release ( PWA 5.0 ). Use variable 'IDENTITY_PROVIDER' to select the provider to be used instead. Keep this in mind before deploying or starting the Intershop PWA in server-side rendering mode. -The default value of the input parameter ['queryParamsHandling'](https://angular.io/api/router/QueryParamsHandling) has been changed from 'merge' to '' for the components product-name.component and product-image.component. -This has been done to prevent an unintentional application of filters for product variation master links if the product detail link does not originates from a product listing context (product list page, search result page). +The default value of the input parameter ['queryParamsHandling'](https://angular.io/api/router/QueryParamsHandling) has been changed from 'merge' to '' for the components `product-name.component` and `product-image.component`. +This has been done to prevent an unintentional application of filters for product variation master links if the product detail link does not originate from a product listing context (product list page, search result page). To prevent deprecation warnings we removed the unnecessary `~` from all 3rd party SCSS imports (see https://webpack.js.org/loaders/sass-loader/#resolving-import-at-rules - "Using ~ is deprecated and can be removed from your code (we recommend it)"). This should be done for additional imports in the customizations as well. @@ -24,22 +53,22 @@ For that reason we removed it. Use the validator `equalTo` instead. Find more information in the method description in the [`special-validators.ts`](https://github.com/intershop/intershop-pwa/blob/3.0.0/src/app/shared/forms/validators/special-validators.ts#L82-L87). -The "Product Image Not Available" PNG image `not_available.png` is removed and replaced by an SVG image `not-available.svg` which does not include a text inside the image any more to avoid localization issues. -The file references are updated accordingly, the product image component is updated to use the correct image attributes, a localized alternative text is added and the product and image mapper files are updated to provide the correct data. -In case the current PNG image file and the handling is customized in a project, you have to make sure to keep the project changes. +The "Product Image Not Available" PNG image `not_available.png` is removed and replaced by an SVG image `not-available.svg` which does not include a text inside the image anymore to avoid localization issues. +The file references are updated accordingly, the product image component is updated to use the correct image attributes, a localized alternative text is added, and the product and image mapper files are updated to provide the correct data. +In case the current PNG image file and the handling is customized in a project, you have to ensure to keep the project changes. ## 2.4 to 3.0 With the 2.4.1 Hotfix we introduced a more fixed Node.js version handling to the version used and tested by us. We set Node.js 16.16.0 and npm 8.11.0 as our application runtime and package management versions. This is supposed to prevent unexpected build issues in the future but requires manual updating of Node.js to newer versions if tested successfully. -Other Node.js versions might still work but you might get warnings regarding the projects recommended settings. +Other Node.js versions might still work but you might get warnings regarding the project's recommended settings. The Intershop PWA 3.0 release includes a Jest Update to version 28, see also https://jestjs.io/docs/upgrading-to-jest28. The jest-marbles package has been replaced by jasmine-marbles. It also contains the Angular 14 update and updates to a lot of other dependencies (NgRx, Typescript). -These updates require some code adaptions, e.g. form classes have been prefixed with _Untyped_ wherever necessary. +These updates require some code adaptions, e.g., form classes have been prefixed with _Untyped_ wherever necessary. The following official guides might help to migrate custom code as well: - https://update.angular.io/?v=13.0-14.0 @@ -54,7 +83,7 @@ Cypress has been upgraded from version 9 to 10. We went through the interactive migration to move our spec files from cypress/integration folder to the cypress/e2e folder and updated the config file as well as some scripts. Find more information in the [Cypress Migration Guide](https://docs.cypress.io/guides/references/migration-guide#Migrating-to-Cypress-version-10-0). -Since the used deferred load library is no longer maintained it is removed and replaced with similar standard browser functionality [`loading="lazy"`](https://developer.mozilla.org/en-US/docs/Web/Performance/Lazy_loading#images_and_iframes). +Since the used deferred load library is no longer maintained, it is removed and has been replaced with similar standard browser functionality [`loading="lazy"`](https://developer.mozilla.org/en-US/docs/Web/Performance/Lazy_loading#images_and_iframes). All uses of the `(deferLoad)` directive in custom code need to be replaced. We removed the unmaintained `angular2-uuid` library in favor of the standard `uuid` library that is already included as an Angular dependency. @@ -70,9 +99,9 @@ The deprecated `customized-copy` schematic for copying components and replacing We introduced a build variable `SSR` that is now used for all checks if the application is running in SSR or Browser context. We no longer use the verbose way of injecting the `PLATFORM_ID` and check it with the methods `isPlatformBrowser` or `isPlatformServer`. This way still works but it is discouraged by a new ESLint rule that suggests using the new `SSR` variable instead. -So running `npm run lint` will help with finding custom code that still relies on the platform checks. +So running `npm run lint` will help finding custom code that still relies on the platform checks. -To support e.g. special characters in email addresses with newer versions of ICM (7.10.38.x), like `+`, double encoding of resource ids in the REST API calls is necessary. +To support, e.g., special characters in e-mail addresses with newer versions of ICM (7.10.38.x), like `+`, double encoding of resource ids in the REST API calls is necessary. With the method `encodeResourceID` we provide a central place that implements the fitting resource encoding. In the PWA this was applied to all user logins in REST API calls. For project customizations the usage of the native `encodeURIComponent` functionality should be replaced with `encodeResourceID` for user logins in REST calls as well. @@ -85,7 +114,7 @@ For categories it was changed from `cat` to `ctg` and for products from `sku`to This way, it is intended to have less conflicts and limitations with potential category/product ids, e.g., 'cats' or 'skunks'. To improve the support of large baskets we update the ngrx store immediately after adding, updating and deleting basket items now. -Therefore we had to change the return values of the corresponding basket service functions as well as the payload of the success actions. +Therefore, we had to change the return values of the corresponding basket service functions as well as the payload of the success actions. We also limited the number of displayed line items in the mini basket and introduced a paging bar on the basket page to speed up the rendering of these components. ## 2.3 to 2.4 diff --git a/docs/guides/nginx-startup.md b/docs/guides/nginx-startup.md index 05f33f96b6..c365ff44ae 100644 --- a/docs/guides/nginx-startup.md +++ b/docs/guides/nginx-startup.md @@ -7,34 +7,33 @@ kb_sync_latest_only # Building and Running NGINX Docker Image -We provide a docker image based on [nginx](https://nginx.org/) for the [PWA deployment](../concepts/pwa-building-blocks.md#pwa---nginx). +We provide a Docker image based on [nginx](https://nginx.org/) for the [PWA deployment](../concepts/pwa-building-blocks.md#pwa---nginx). ## Building -The docker image can be built by running a docker build with the `Dockerfile` located in the `nginx` folder. +The Docker image can be built by running a Docker build with the `Dockerfile` located in the `nginx` folder. ## Configuration Mandatory environment variables: -- Connect it to the PWA with `UPSTREAM_PWA` in the form of `http://:` +- Connect the nginx to the PWA with the `UPSTREAM_PWA` value in the form of `http://:` For HTTP, the server will run on default port 80. For HTTPS, the server will run on default port 443. -We're using the standard NGinx Docker image. -Therefore we inherit all their configuration capabilities. -For further information please refer to [the official NGinx Docker image page](https://hub.docker.com/_/nginx?tab=description) +We are using the standard nginx Docker image. +Therefore, we inherit all their configuration capabilities. +For further information please refer to [the official nginx Docker image page](https://hub.docker.com/_/nginx?tab=description) ### HTTPS or SSL -You can switch on HTTPS for the nginx container to execute a production like setup locally or for demo purposes. -Just by changing `ENV SSL=0` to `ENV SSL=1` and adjusting the port mapping in `docker-compose.yml`. +You can switch on HTTPS for the nginx container to execute a production-like setup locally or for demo purposes by changing `ENV SSL=0` to `ENV SSL=1` and adjusting the port mapping in `docker-compose.yml`. No need to supply a certificate and a key. They are automatically generated inside the running container. The certificate is self-signed and will not work in your browser. You have to confirm the security exception. -As developer convenience you can volume mount an internal folder to your host system to effectively trust the generated cert. +As developer convenience you can volume mount an internal folder to your host system to effectively trust the generated certificate. Please check the nginx logs for the following output. @@ -47,8 +46,8 @@ You can now export the local CA by adjusting your docker-compose.yml /home/your- ### Basic Auth -For deploying to test environments that should not be indexed by search bots or should not be accessible by the public, the nginx container can be set up with basic authentication. -Just supply a single user-password combination as environment variable, i.e. `BASIC_AUTH=:`. +For deploying to test environments that are not to be indexed by search bots or are not to be accessible by the public, the nginx container can be set up with basic authentication. +To do so, supply a single user-password combination as environment variable, i.e. `BASIC_AUTH=:`. You can also whitelist IPs by supplying a YAML list to the environment variable `BASIC_AUTH_IP_WHITELIST`: ```yaml @@ -63,7 +62,7 @@ nginx: Entries of the IP whitelist are added to the nginx config as [`allow`](http://nginx.org/en/docs/http/ngx_http_access_module.html) statements, which also supports IP ranges. Please refer to the linked nginx documentation on how to configure this. -After globally activating basic authentication for your setup you can also disable it selectively per site. +After globally activating basic authentication for your setup, you can also disable it selectively per site. See [Multi-Site Configurations](../guides/multi-site-configurations.md#Examples) for examples on how to do that. ### Multi-Site @@ -73,22 +72,22 @@ Multiple PWA channels can be set up by supplying a [YAML](https://yaml.org) conf For more information on the multi-site syntax, refer to [Multi-Site Configurations](../guides/multi-site-configurations.md#Syntax) -The configuration can be supplied simply by setting the environment variable `MULTI_CHANNEL`. +The configuration can be supplied by setting the environment variable `MULTI_CHANNEL`. Alternatively, the source can be supplied by setting `MULTI_CHANNEL_SOURCE` in any [supported format by gomplate](https://docs.gomplate.ca/datasources/). If no environment variables for multi-channel configuration are provided, the configuration will fall back to the content of [`nginx/multi-channel.yaml`](../../nginx/multi-channel.yaml), which can also be customized. -> :warning: Multi-Channel configuration with context paths does not work in conjunction with [service workers](../concepts/progressive-web-app.md#service-worker) +> :warning: Multi-Channel configuration with context paths does not work in conjunction with [service workers](../concepts/progressive-web-app.md#service-worker). An extended list of examples can be found in the [Multi-Site Configurations](../guides/multi-site-configurations.md#Syntax) guide. ### Ignore Parameters During Caching Often, nginx receives requests from advertising networks or various user agents that append unused query parameters when making a request, for example `utm_source`.
-These parameters can lead to inefficient caching because even if the same URL is requested multiple times, if it is accessed with different query parameters, the cached version will not be used. +These parameters can lead to inefficient caching, because even if the same URL is requested multiple times, the cached version will not be used if the URL is accessed with different query parameters. To prevent this, you can define any number of blacklisted parameters that will be ignored by nginx during caching. -As with multi-site handling above, the configuration can be supplied simply by setting the environment variable `CACHING_IGNORE_PARAMS`.
+As with multi-site handling above, the configuration can be supplied by setting the environment variable `CACHING_IGNORE_PARAMS`.
Alternatively, the source can be supplied by setting `CACHING_IGNORE_PARAMS_SOURCE` in any [supported format by gomplate](https://docs.gomplate.ca/datasources/). Be aware that the supplied list of parameters must be declared under a `params` property. @@ -96,14 +95,14 @@ If no environment variables for ignoring parameters are provided, the configurat ### Access ICM Sitemap -Please refer to [this](https://support.intershop.com/kb/index.php/Display/23D962#ConceptXMLSitemaps-XMLSitemapsandIntershopPWAxml_sitemap_pwa) Intershop knowledge base article on how to configure ICM to generate PWA sitemap files. +Please refer to [Concept - XML Sitemaps](https://support.intershop.com/kb/index.php/Display/23D962#ConceptXMLSitemaps-XMLSitemapsandIntershopPWAxml_sitemap_pwa) on how to configure ICM to generate PWA sitemap files. ``` http://pwa/sitemap_pwa.xml ``` -To make above sitemap index file available under your deployment you need to add the environment variable `ICM_BASE_URL` to your nginx container. -Let `ICM_BASE_URL` point to your ICM backend installation, e.g. `https://pwa-ish-demo.test.intershop.com`. +To make above sitemap index file available under your deployment, you need to add the environment variable `ICM_BASE_URL` to your nginx container. +Let `ICM_BASE_URL` point to your ICM backend installation, e.g., `https://pwa-ish-demo.test.intershop.com`. When the container is started it will process cache-ignore and multi-channel templates as well as sitemap proxy rules like this: ```yaml @@ -118,7 +117,7 @@ Be sure to include `application` if you deviate from standard `rest` application ### Override Identity Providers by Path The PWA can be configured with multiple identity providers. -In some use cases a specific identity provider must be selected, when a certain route is requested. +In some use cases a specific identity provider must be selected when a certain route is requested. For example, a punchout user should be logged in by the punchout identity provider requesting a punchout route. For all other possible routes the default identity provider must be selected. This can be done by setting only the environment variable `OVERRIDE_IDENTITY_PROVIDER`. @@ -128,8 +127,8 @@ nginx: environment: OVERRIDE_IDENTITY_PROVIDERS: | .+: - - path: /b2b/punchout - type: PUNCHOUT + - path: /punchout + type: Punchout ``` This setting will generate rewrite rules for the URL paths for all given domains. @@ -146,27 +145,26 @@ Built-in features can be enabled and disabled: - `COMPRESSION=off` disables compression (default `on`) - `DEVICE_DETECTION=off` disables user-agent detection (default `on`) - `PROMETHEUS=on` enables [Prometheus](https://prometheus.io) metrics exports on port `9113` (default `off`) -- `SSL=on` to switch on HTTPS. Look above for further explanation. +- `SSL=on` to switch on HTTPS. See [HTTPS or SSL](#https-or-ssl) above for further explanation. ## Features New features can be supplied in the folder `nginx/features`. -A file named `.conf` is included if the environment variable `` is set to `on`, `1`, `true` or `yes` (case in-sensitive). -The feature is disabled otherwise and an optional file `-off.conf` is included in the configuration. -The feature name must only contain word characters (letters, numbers and underscore). +A file named `.conf` is included if the environment variable `` is set to `on`, `1`, `true` or `yes` (case insensitive). +Otherwise, the feature is disabled and an optional file `-off.conf` is included in the configuration. +The feature name must only contain word characters (letters, numbers, and underscore). ### Cache If the cache feature is switched off, all caching for pre-rendered pages is disabled. The cache duration for pre-rendered pages can be customized using `CACHE_DURATION_NGINX_OK` (for successful responses) and `CACHE_DURATION_NGINX_NF` (for 404 responses). -The value supplied must be in the `time` format that is supported by [nginx proxy_cache_valid](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_cache_valid) +The value supplied must be in the `time` format that is supported by [nginx proxy_cache_valid](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_cache_valid). -# Further References +## Further References - [Concept - Multi-Site Handling](../concepts/multi-site-handling.md) - [Concept - Configuration](../concepts/configuration.md) - [Concept - Logging](../concepts/logging.md) -- [Concept - Single Sign-On (SSO) for PWA](../concepts/sso.md) - [Guide - Monitoring with Prometheus](./prometheus-monitoring.md) -- [README of official NGinx Docker image](https://hub.docker.com/_/nginx?tab=description) +- [README of official nginx Docker image](https://hub.docker.com/_/nginx?tab=description) diff --git a/docs/guides/optimizations.md b/docs/guides/optimizations.md index 41cdd20924..5a02a56393 100644 --- a/docs/guides/optimizations.md +++ b/docs/guides/optimizations.md @@ -27,7 +27,43 @@ If the PWA is built using `production` configuration. (Either by building with ` - Webpack [SplitChunksPlugin](https://webpack.js.org/plugins/split-chunks-plugin/) is instructed to produce only `main`, `vendor`, `polyfills` and one `common` bundle for the code for optimized compression and download of the application. - All `data-testing` attributes are removed from the HTML templates to reduce output. - [PurgeCSS](https://purgecss.com) is used to remove unused CSS classes from the CSS output. - [Configuration](https://purgecss.com/configuration.html), especially [safelisting](https://purgecss.com/safelisting.html) certain classes, can be done on the plugin configuration or directly in your CSS with a special comment. + +## PurgeCSS + +> PurgeCSS is a tool to remove unused CSS. It can be part of your development workflow. When you are building a website, you might decide to use a CSS framework like TailwindCSS, Bootstrap, MaterializeCSS, Foundation, etc... But you will only use a small set of the framework, and a lot of unused CSS styles will be included. + +> This is where PurgeCSS comes into play. PurgeCSS analyzes your content and your CSS files. Then it matches the selectors used in your files with the one in your content files. It removes unused selectors from your CSS, resulting in smaller CSS files. + +While the described function for deleting unused CSS styles is very helpful, the mechanism for determining which styles are used is not without problems. +PurgeCSS can only analyze the strings in the actual source code of the project for used styles. + +So, styles that get added to the rendered HTML by third-party libraries (e.g. Bootstrap, Swiper) would not be found. +The same applies for styles used in server-loaded content (e.g. CMS, product descriptions). +Also style selectors that are dynamically generated would not be found. + +### Safelisting + +To solve this problem PurgeCSS provides different [options for safelisting](https://purgecss.com/safelisting.html) specific styles. +This can either be done in the plugin configuration or directly in your SCSS/CSS files with special comments. + +The PurgeCSS plugin configuration can be found in the project's [`webpack.custom.ts`](https://github.com/intershop/intershop-pwa/blob/3.1.0/templates/webpack/webpack.custom.ts#L231-L246). +This method is used and recommended to include required styles of the third-party libraries used, which would otherwise be purged. +For the different [configuration options](https://purgecss.com/configuration.html), refer to the PurgeCSS documentation. + +To protect styles defined in the Intershop PWA project source code, Intershop recommends safelisting them directly in your SCSS/CSS with [special comments](https://purgecss.com/safelisting.html#in-the-css-directly). +To include nested SCSS definitions, use `/* purgecss start ignore */` and `/* purgecss end ignore */`. + +### Development + +When using the standard way of developing the PWA with `ng s`, PurgeCSS is not activated and styling should work as expected. +This way missing styling issues because of PurgeCSS often first show up in deployed environments. +To test or develop with enabled PurgeCSS, the development server needs to be started with `ng s -c=b2b,production` (or your desired theme instead of `b2b`). + +In this startup process the following line can be read, indicating the usage of PurgeCSS similar to the deployed builds: + +``` +serve@b2b,production: setting up purgecss CSS minification +``` # Further References diff --git a/docs/guides/sso-auth0.md b/docs/guides/sso-auth0.md deleted file mode 100644 index 635768c469..0000000000 --- a/docs/guides/sso-auth0.md +++ /dev/null @@ -1,29 +0,0 @@ - - -# SSO with Auth0 for PWA - -Follow [this guide](https://manfredsteyer.github.io/angular-oauth2-oidc/docs/additional-documentation/authorization-servers/auth0.html) to set up an application in the Auth0 configuration. - -The PWA implementation for this identity provider is located in [`Auth0IdentityProvider`](../../src/app/core/identity-provider/auth0.identity-provider.ts). - -Use the fields "Domain" and "Client ID" for configuring the provider: - -```typescript - identityProvider: 'MyProvider', - identityProviders: { - 'MyProvider': { - type: 'auth0', - domain: 'some-domain.auth0.com', - clientID: 'ASDF12345', - } - }, -``` - -# Further References - -- [Concept - Single Sign-On (SSO) for PWA](../concepts/sso.md) diff --git a/docs/guides/ssr-startup.md b/docs/guides/ssr-startup.md index 54b515b09b..dfe1bbb020 100644 --- a/docs/guides/ssr-startup.md +++ b/docs/guides/ssr-startup.md @@ -21,7 +21,7 @@ The `package.json` property `config.active-themes` determines which themes shoul This will build server and client bundles for all active themes and supply them in the `dist` folder. The SSR process for each theme can be run individually using the generated scripts `dist//run-standalone`. -To run multiple themes with [PM2][pm2] the script `src/ssr/server-scripts/build-ecosystem.js` can be used to generate the ecosystem. +To run multiple themes with [PM2][pm2], the script `src/ssr/server-scripts/build-ecosystem.js` can be used to generate the ecosystem. If only one theme is active, the theme-specific SSR process will be run in cluster mode on the default port. If more themes are active, PM2 is provisioned to run a distributor process in front of all theme-specific processes, to direct incoming traffic to the correct SSR process. @@ -33,9 +33,9 @@ This will automatically build all active themes and configure [PM2][pm2] for run Overwriting configurations of the PWA is entirely done by environment variables. This approach was chosen to have the best possible compatibility when running the PWA either from the command line or in an orchestrator. -To [set environment variables in windows](https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/set_1) run for example `set SSR_HYBRID=true` on the command line before executing the `npm run` commands. +To [set environment variables in windows](https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/set_1), run, for example, `set SSR_HYBRID=true` on the command line before executing the `npm run` commands. -If the format is _any_, then the environment variable has to be set to any value to be active. +If the format is _any_, the environment variable has to be set to any value to be active. Setting it to `"false"` still counts as active. Only empty strings count as inactive. @@ -44,41 +44,41 @@ If the format is _switch_, the property is switched on by supplying `on`, `1`, ` All parameters are **case sensitive**. Make sure to use them as written in the table below. -| | parameter | format | comment | -| ------------------- | ------------------------------------------- | -------------------- | -------------------------------------------------------------------------------------------- | -| **SSR Specific** | PORT | number | Port for running the application | -| | SSL | any | Enables SSL/TLS | -| | CONCURRENCY_SSR | number \| max | concurrency for SSR instances per theme (default: 2) | -| | CACHE_ICM_CALLS | recommended \| JSON | enable caching for ICM calls, see [Local ICM Cache](#local-icm-cache) (default: disabled) | -| **General** | ICM_BASE_URL | string | Sets the base URL for the ICM | -| | ICM_CHANNEL | string | Overrides the default channel | -| | ICM_APPLICATION | string | Overrides the default application | -| | FEATURES | comma-separated list | Overrides active features | -| | THEME | string | Overrides the default theme | -| | MULTI_SITE_LOCALE_MAP | JSON \| false | Used to map locales to [url modification parameters](../guides/multi-site-configurations.md) | -| | DEPLOY_URL | string | Set a [Deploy URL][concept-deploy-url] (default `/`) | -| **Debug** :warning: | TRUST_ICM | any | Use this if ICM is deployed with an insecure certificate | -| | LOGGING | switch | Enables extra log output | -| | SOURCE_MAPS | switch | Exposes source maps if activated | -| **Hybrid Approach** | SSR_HYBRID | any | Enables running PWA and ICM in [Hybrid Mode][concept-hybrid] | -| | PROXY_ICM | any \| URL | Proxy ICM via `/INTERSHOP` (enabled if SSR_HYBRID is active) | -| **Third party** | GTM_TOKEN | string | Token for Google Tag Manager | -| | GMA_KEY | string | API key for Google Maps | -| | SENTRY_DSN | string | Sentry DSN URL for using Sentry Error Monitor | -| | PROMETHEUS | switch | Exposes Prometheus metrics | -| | IDENTITY_PROVIDER ~~ICM_IDENTITY_PROVIDER~~ | string | ID of Identity Provider for [SSO][concept-sso] | -| | IDENTITY_PROVIDERS | JSON | Configuration of Identity Providers for [SSO][concept-sso] | +| | parameter | format | comment | +| ------------------- | ------------------------------------------- | -------------------- | ------------------------------------------------------------------------------------------------ | +| **SSR Specific** | PORT | number | Port for running the application | +| | CONCURRENCY_SSR | number \| max | Concurrency for SSR instances per theme (default: 2) | +| | CACHE_ICM_CALLS | recommended \| JSON | Enable caching for ICM calls, see [Local ICM Cache](#local-icm-cache) (default: disabled) | +| **General** | ICM_BASE_URL | string | Sets the base URL for the ICM | +| | ICM_CHANNEL | string | Overrides the default channel | +| | ICM_APPLICATION | string | Overrides the default application | +| | FEATURES | comma-separated list | Overrides active features | +| | THEME | string | Overrides the default theme | +| | MULTI_SITE_LOCALE_MAP | JSON \| false | Used to map locales to [url modification parameters](../guides/multi-site-configurations.md) | +| | DEPLOY_URL | string | Set a [Deploy URL][concept-deploy-url] (default `/`) | +| **Debug** :warning: | TRUST_ICM | any | Use this if ICM is deployed with an insecure certificate | +| | LOGGING | switch | Enables extra log output | +| | SOURCE_MAPS | switch | Exposes source maps if activated | +| **Hybrid Approach** | SSR_HYBRID | any | Enables running PWA and ICM in [Hybrid Mode][concept-hybrid] | +| | SSR_HYBRID_BACKEND | URL | When running in K8S, this contains the ICM WA service URL. For none K8S you can use ICM_BASE_URL | +| | PROXY_ICM | any \| URL | Proxy ICM via `/INTERSHOP` (enabled if SSR_HYBRID is active) | +| **Third party** | GTM_TOKEN | string | Token for Google Tag Manager | +| | GMA_KEY | string | API key for Google Maps | +| | SENTRY_DSN | string | Sentry DSN URL for using Sentry Error Monitor | +| | PROMETHEUS | switch | Exposes Prometheus metrics | +| | IDENTITY_PROVIDER ~~ICM_IDENTITY_PROVIDER~~ | string | ID of the default Identity Provider if other than `ICM` | +| | IDENTITY_PROVIDERS | JSON | Configuration of additional Identity Providers besides the default `ICM` | ## Development For live Angular Universal (SSR) development, you have to use means provided by Angular CLI. -The following command starts a SSR development environment. +The following command starts an SSR development environment. ``` npm run start:ssr-dev ``` -If the SSR development environment needs to run with `https` this can be achieved like this. +If the SSR development environment needs to run with `https`, this can be achieved like this: ``` npm run start:ssr-dev -- --ssl @@ -105,17 +105,16 @@ You can further customize the caching by supplying a JSON structure to the `CACH } ``` -This example will cache `/configurations` for 20 Minutes, product variations for 2 hours and everything else for 2 Minutes. +This example will cache `/configurations` for 20 minutes, product variations for 2 hours, and everything else for 2 minutes. This feature can also be used to benchmark the SSR render performance locally by caching all ICM calls. -# Further References +## Further References - [Concept - Configuration](../concepts/configuration.md) - [Concept - Deploy URL][concept-deploy-url] - [Concept - Hybrid Approach][concept-hybrid] - [Concept - Logging](../concepts/logging.md) -- [Concept - Single Sign-On (SSO) for PWA][concept-sso] - [Guide - Multiple Themes][multiple-themes] - [Guide - Client-Side Error Monitoring with Sentry](./sentry-error-monitoring.md) - [Guide - Google Tag Manager](./google-tag-manager.md) @@ -124,7 +123,6 @@ This feature can also be used to benchmark the SSR render performance locally by - [YouTube - Server Side Rendering and Pre Rendering with Angular Universal](https://www.youtube.com/watch?v=-VDOAjzLcvQ) - [Google Developers - Rendering on the Web](https://developers.google.com/web/updates/2019/02/rendering-on-the-web) -[concept-sso]: ../concepts/sso.md [concept-hybrid]: ../concepts/hybrid-approach.md [concept-deploy-url]: ../concepts/deploy-url.md [multiple-themes]: ./multiple-themes.md diff --git a/e2e/cypress/e2e/pages/account/addresses.page.ts b/e2e/cypress/e2e/pages/account/addresses.page.ts new file mode 100644 index 0000000000..00b1e4a32c --- /dev/null +++ b/e2e/cypress/e2e/pages/account/addresses.page.ts @@ -0,0 +1,87 @@ +import { fillFormField } from '../../framework'; +import { Registration } from '../account/registration.page'; +import { HeaderModule } from '../header.module'; + +export type AddressDetailsTypes = Partial< + Pick +>; +export class AddressesPage { + readonly header = new HeaderModule(); + readonly tag = 'ish-account-addresses'; + + get defaultAddress() { + return cy.get(this.tag).find('[data-testing-id="preferred-invoice-and-shipping-address"]'); + } + + get furtherAddress() { + return cy.get(this.tag).find('[data-testing-id="further-addresses"]'); + } + + get shippingAddress() { + return cy.get(this.tag).find('[data-testing-id="preferred-shipping-address"]'); + } + + get invoiceAddress() { + return cy.get(this.tag).find('[data-testing-id="preferred-invoice-address"]'); + } + + createAddress() { + cy.get('[data-testing-id="create-address-button"]').click(); + } + + fillForm(user: string, password: string) { + cy.get('input[data-testing-id="login"]').clear().type(user).blur(); + cy.get('input[data-testing-id="password"]').clear().type(password).blur(); + return this; + } + + fillCreateAddressForm(address: AddressDetailsTypes) { + Object.keys(address).forEach(key => fillFormField('[data-testing-id="create-address-form"]', key, address[key])); + return this; + } + + fillUpdateAddressForm(address: AddressDetailsTypes) { + Object.keys(address).forEach(key => fillFormField('[data-testing-id="update-address-form"]', key, address[key])); + return this; + } + + cancel() { + cy.get('button').contains('Cancel').click(); + } + + saveAddress() { + cy.get('button').contains('Save Address').click(); + } + + selectShippingAddress() { + cy.get('select[placeholder="Change preferred shipping address"]').select(1); + } + + selectInvoiceAddress() { + cy.get('select[placeholder="Change preferred invoice address"]').select(2); + } + + updateAddress() { + cy.get('[data-testing-id="update-address-button"]').last().click(); + } + + submit() { + cy.intercept('PUT', '**/customers/**').as('customers'); + cy.wait(500); + + cy.get(this.tag).find('button[type="submit"]').click(); + + return cy.wait('@customers'); + } + + deleteAddress() { + cy.get('[data-testing-id="delete-address-icon"]').last().click(); + cy.get('button').contains('Delete').click(); + } + + get successMessage() { + return { + message: cy.get('#toast-container').find('.toast-message'), + }; + } +} diff --git a/e2e/cypress/e2e/pages/account/login.page.ts b/e2e/cypress/e2e/pages/account/login.page.ts index 4915d803dd..4aa4307296 100644 --- a/e2e/cypress/e2e/pages/account/login.page.ts +++ b/e2e/cypress/e2e/pages/account/login.page.ts @@ -21,12 +21,12 @@ export class LoginPage { } submit() { - cy.intercept('GET', /.*\/customers\/-.*/).as('currentCustomer'); + cy.intercept('POST', /.*\/token/).as('token'); cy.wait(500); cy.get('button[name="login"]').click(); - return cy.wait('@currentCustomer'); + return cy.wait('@token'); } get errorText() { diff --git a/e2e/cypress/e2e/pages/header.module.ts b/e2e/cypress/e2e/pages/header.module.ts index cc344ae5c7..ef06eb0a6d 100644 --- a/e2e/cypress/e2e/pages/header.module.ts +++ b/e2e/cypress/e2e/pages/header.module.ts @@ -26,7 +26,7 @@ export class HeaderModule { gotoLoginPage(wait: () => unknown = waitLoadingEnd) { cy.scrollTo('top'); - cy.get('[data-testing-id="user-status-desktop"] .my-account-login').click(); + this.loginLink.click(); wait(); } @@ -51,8 +51,13 @@ export class HeaderModule { wait(); } - logout() { + logout(wait: () => unknown = waitLoadingEnd) { cy.get('[data-testing-id="link-logout"]').first().click(); + wait(); + } + + get loginLink() { + return cy.get('[data-testing-id="user-status-desktop"] .my-account-login'); } get myAccountLink() { diff --git a/e2e/cypress/e2e/specs/account/addresses-crud.b2b.e2e-spec.ts b/e2e/cypress/e2e/specs/account/addresses-crud.b2b.e2e-spec.ts new file mode 100644 index 0000000000..d0d2da8d26 --- /dev/null +++ b/e2e/cypress/e2e/specs/account/addresses-crud.b2b.e2e-spec.ts @@ -0,0 +1,98 @@ +import { at } from '../../framework'; +import { createB2BUserViaREST } from '../../framework/b2b-user'; +import { AddressDetailsTypes, AddressesPage } from '../../pages/account/addresses.page'; +import { LoginPage } from '../../pages/account/login.page'; +import { Registration, sensibleDefaults } from '../../pages/account/registration.page'; + +const _ = { + user: { + login: `testuser${new Date().getTime()}@test.intershop.de`, + ...sensibleDefaults, + companyName1: 'Big Foods', + } as Registration, + address: { + countryCode: 'DE', + companyName1: 'Intershop', + firstName: 'Pablo', + lastName: 'Parked', + addressLine1: 'Marcher Str. 87', + city: 'Stuttgart', + postalCode: '12345', + } as AddressDetailsTypes, + furtherAddress: { + companyName1: 'Samsung', + firstName: 'Daniel', + lastName: 'Circus', + addressLine1: 'Berg Str. 83', + city: 'Heidelberg', + postalCode: '36890', + countryCode: 'DE', + } as AddressDetailsTypes, + newAddress: { + companyName1: 'Samsung DE', + firstName: 'Daniels', + lastName: 'Decorous', + addressLine1: 'HeidelBerg Str. 83', + city: 'Heidelberg', + postalCode: '36890', + countryCode: 'DE', + } as AddressDetailsTypes, +}; + +describe('Addresses Page Functionality', () => { + before(() => { + createB2BUserViaREST(_.user); + LoginPage.navigateTo('/account/addresses'); + at(LoginPage, page => { + page.fillForm(_.user.login, _.user.password); + page.submit().its('response.statusCode').should('equal', 200); + }); + at(AddressesPage, page => { + page.defaultAddress.should('exist'); + }); + }); + + it('should be able to create address and assign as shipping address', () => { + at(AddressesPage, page => { + page.createAddress(); + cy.wait(500); + page.fillCreateAddressForm(_.address); + page.saveAddress(); + page.furtherAddress.should('contain', _.address.addressLine1); + page.selectShippingAddress(); + page.shippingAddress.should('contain', _.address.addressLine1); + }); + }); + + it('should be able to create a further address and see changes', () => { + at(AddressesPage, page => { + page.createAddress(); + page.fillCreateAddressForm(_.furtherAddress); + page.saveAddress(); + page.furtherAddress.should('contain', _.furtherAddress.addressLine1); + }); + }); + + it('should be able to assign the further address as default invoice address', () => { + at(AddressesPage, page => { + page.selectInvoiceAddress(); + page.invoiceAddress.should('contain', _.furtherAddress.addressLine1); + }); + }); + + it('should be able to update address details and see changes', () => { + at(AddressesPage, page => { + page.updateAddress(); + page.fillUpdateAddressForm(_.newAddress).submit().its('response.statusCode').should('equal', 200); + page.successMessage.message.should('contain', 'updated'); + page.furtherAddress.should('contain', `${_.newAddress.firstName} ${_.newAddress.lastName}`); + }); + }); + + it('should be able to delete an address and see changes', () => { + at(AddressesPage, page => { + page.deleteAddress(); + page.successMessage.message.should('contain', 'deleted'); + }); + }); +}); diff --git a/e2e/cypress/e2e/specs/account/register-user.b2b.e2e-spec.ts b/e2e/cypress/e2e/specs/account/register-user.b2b.e2e-spec.ts index 792d10ab9f..b321a7e190 100644 --- a/e2e/cypress/e2e/specs/account/register-user.b2b.e2e-spec.ts +++ b/e2e/cypress/e2e/specs/account/register-user.b2b.e2e-spec.ts @@ -37,10 +37,16 @@ describe('New B2B User', () => { }); }); - it('should log out and log in and log out again', () => { + it('should log out', () => { at(MyAccountPage, page => { page.header.logout(); }); + at(HomePage, page => { + page.header.loginLink.should('be.visible'); + }); + }); + + it('should log in and log out again', () => { at(HomePage, page => { page.header.gotoLoginPage(); }); diff --git a/e2e/cypress/e2e/specs/shopping/search-products.b2c.e2e-spec.ts b/e2e/cypress/e2e/specs/shopping/search-products.b2c.e2e-spec.ts index 087fae0868..772f9ec3f4 100644 --- a/e2e/cypress/e2e/specs/shopping/search-products.b2c.e2e-spec.ts +++ b/e2e/cypress/e2e/specs/shopping/search-products.b2c.e2e-spec.ts @@ -5,9 +5,12 @@ import { SearchResultPage } from '../../pages/shopping/search-result.page'; const _ = { suggestTerm: 'ko', - searchTerm: 'kodak M552', suggestItemText: 'Kodak', + searchTerm: 'kodak M552', product: '7912057', + searchTermWithMoreResults: 'acer', + searchTermWithOneResult: 'acer c110', + oneResultProduct: '9438012', }; describe('Searching User', () => { @@ -36,4 +39,16 @@ describe('Searching User', () => { page.breadcrumb.items.should('have.length', 4); }); }); + + it(`should perform another search and land on search result page`, () => { + at(ProductDetailPage, page => page.header.searchBox.search(_.searchTermWithMoreResults)); + at(SearchResultPage, page => page.productList.visibleProducts.should('have.length.gte', 1)); + }); + + it(`should perform search with only one search result and land on product detail page`, () => { + at(SearchResultPage, page => page.header.searchBox.search(_.searchTermWithOneResult)); + at(ProductDetailPage, page => { + page.sku.should('have.text', _.oneResultProduct); + }); + }); }); diff --git a/e2e/cypress/e2e/specs/system/change-language-search-result.b2c.e2e-spec.ts b/e2e/cypress/e2e/specs/system/change-language-search-result.b2c.e2e-spec.ts index ff5dd0cf0f..4b6edd69de 100644 --- a/e2e/cypress/e2e/specs/system/change-language-search-result.b2c.e2e-spec.ts +++ b/e2e/cypress/e2e/specs/system/change-language-search-result.b2c.e2e-spec.ts @@ -12,7 +12,7 @@ const _ = { dollarPrice: '33.75', euroPrice: '25,00', }, - searchTerm: 'conversion lens', + searchTerm: 'lens', }; describe('Language Changing User', () => { diff --git a/e2e/cypress/e2e/specs/system/cookie-consent.b2c.e2e-spec.ts b/e2e/cypress/e2e/specs/system/cookie-consent.b2c.e2e-spec.ts index c791ec35d3..8b8e35d1a8 100644 --- a/e2e/cypress/e2e/specs/system/cookie-consent.b2c.e2e-spec.ts +++ b/e2e/cypress/e2e/specs/system/cookie-consent.b2c.e2e-spec.ts @@ -17,10 +17,12 @@ describe('Cookie Consent', () => { it('should accept all cookies', () => { at(HomePage, () => { cy.get('[data-testing-id="acceptAllButton"]').click(); - cy.wait(3000); + cy.wait(4000); cy.getCookies().then(cookies => { expect(cookies[cookies.length - 1]).to.have.property('name', 'cookieConsent'); + cy.wait(500); + cy.get('.cookies-banner').should('not.exist'); }); }); }); diff --git a/e2e/cypress/e2e/specs/system/retain-authentication.b2c.e2e-spec.ts b/e2e/cypress/e2e/specs/system/retain-authentication.b2c.e2e-spec.ts index 06fae38a38..9a7b8f109e 100644 --- a/e2e/cypress/e2e/specs/system/retain-authentication.b2c.e2e-spec.ts +++ b/e2e/cypress/e2e/specs/system/retain-authentication.b2c.e2e-spec.ts @@ -26,32 +26,52 @@ describe('Returning User', () => { at(MyAccountPage, page => page.header.myAccountLink.should('have.text', `${_.user.firstName} ${_.user.lastName}`) ); - cy.getCookie('apiToken').should('not.be.empty'); + cy.getCookie('apiToken') + .should('not.be.empty') + .should(cookie => { + cy.wrap(JSON.parse(decodeURIComponent(cookie.value))).should('have.property', 'type', 'user'); + }); }); it('should stay logged in when refreshing page once', () => { MyAccountPage.navigateTo(); at(MyAccountPage); - cy.getCookie('apiToken').should('not.be.empty'); + cy.getCookie('apiToken') + .should('not.be.empty') + .should(cookie => { + cy.wrap(JSON.parse(decodeURIComponent(cookie.value))).should('have.property', 'type', 'user'); + }); }); it('should stay logged in when refreshing page twice', () => { MyAccountPage.navigateTo(); at(MyAccountPage); - cy.getCookie('apiToken').should('not.be.empty'); + cy.getCookie('apiToken') + .should('not.be.empty') + .should(cookie => { + cy.wrap(JSON.parse(decodeURIComponent(cookie.value))).should('have.property', 'type', 'user'); + }); }); it('should stay logged in when refreshing page thrice', () => { MyAccountPage.navigateTo(); at(MyAccountPage); - cy.getCookie('apiToken').should('not.be.empty'); + cy.getCookie('apiToken') + .should('not.be.empty') + .should(cookie => { + cy.wrap(JSON.parse(decodeURIComponent(cookie.value))).should('have.property', 'type', 'user'); + }); }); - it('should log out and loose the cookie', () => { + it('should log out and get the anonymous token', () => { at(MyAccountPage, page => page.header.logout()); at(HomePage); // eslint-disable-next-line unicorn/no-null - cy.getCookie('apiToken').should('equal', null); + cy.getCookie('apiToken') + .should('not.be.empty') + .should(cookie => { + cy.wrap(JSON.parse(decodeURIComponent(cookie.value))).should('have.property', 'type', 'anonymous'); + }); }); }); diff --git a/eslint-rules/src/rules/no-assignment-to-inputs.ts b/eslint-rules/src/rules/no-assignment-to-inputs.ts index 6fdc3e003e..26a28d13cd 100644 --- a/eslint-rules/src/rules/no-assignment-to-inputs.ts +++ b/eslint-rules/src/rules/no-assignment-to-inputs.ts @@ -28,7 +28,7 @@ const noAssignmentToInputsRule: TSESLint.RuleModule = { */ function checkIsInput(node: TSESTree.PropertyDefinition): boolean { const decorators = node.decorators; - if (!decorators || !decorators.length) { + if (!decorators?.length) { return false; } return decorators diff --git a/eslint-rules/src/rules/ordered-imports.ts b/eslint-rules/src/rules/ordered-imports.ts index 7793168dc5..5dddf491ec 100644 --- a/eslint-rules/src/rules/ordered-imports.ts +++ b/eslint-rules/src/rules/ordered-imports.ts @@ -35,7 +35,14 @@ const orderedImportsRule: TSESLint.RuleModule = { .map(imp => context.getSourceCode().getText(imp)) .sort(); - return nodeText.replace(/\{.*\}/, `{ ${sortedNamedImports.join(', ')} }`); + if (/\{.*\}/.test(nodeText)) { + return nodeText.replace(/\{.*\}/, `{ ${sortedNamedImports.join(', ')} }`); + } + + return nodeText.replace( + /\{(.|\n)*\}/, + `{${lineEnding} ${sortedNamedImports.join(`,${lineEnding} `)},${lineEnding}}` + ); } const importDeclarations: TSESTree.ImportDeclaration[] = []; diff --git a/nginx/Dockerfile b/nginx/Dockerfile index 9c15c1c14e..c0e6fdba46 100644 --- a/nginx/Dockerfile +++ b/nginx/Dockerfile @@ -1,4 +1,4 @@ -FROM nginx:1.20 +FROM nginx:1.22 RUN apt-get update \ && apt-get install --no-install-recommends --no-install-suggests -y apache2-utils libnss3-tools COPY nginx.conf /etc/nginx/nginx.conf @@ -11,7 +11,7 @@ ADD https://github.com/hairyhenderson/gomplate/releases/download/v3.8.0/gomplate RUN chmod 700 /gomplate ADD https://github.com/FiloSottile/mkcert/releases/download/v1.4.4/mkcert-v1.4.4-linux-amd64 /usr/bin/mkcert RUN chmod 700 /usr/bin/mkcert -COPY --from=nginx/nginx-prometheus-exporter:0.10.0 /usr/bin/nginx-prometheus-exporter /nginx-prometheus-exporter +COPY --from=nginx/nginx-prometheus-exporter:0.11.0 /usr/bin/nginx-prometheus-exporter /nginx-prometheus-exporter ENV CACHE=on ENV COMPRESSION=on ENV DEVICE_DETECTION=on diff --git a/package-lock.json b/package-lock.json index 30aaba2c26..efb427e1b1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,113 +1,112 @@ { "name": "intershop-pwa", - "version": "3.1.0", + "version": "3.2.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "intershop-pwa", - "version": "3.1.0", + "version": "3.2.0", "hasInstallScript": true, "license": "Intershop Standard Software End User License Agreement Intershop 7", "dependencies": { - "@angular-devkit/schematics": "^14.2.5", - "@angular/animations": "14.2.5", - "@angular/cdk": "14.2.4", - "@angular/common": "14.2.5", - "@angular/compiler": "14.2.5", - "@angular/core": "14.2.5", - "@angular/forms": "14.2.5", - "@angular/localize": "14.2.5", - "@angular/platform-browser": "14.2.5", - "@angular/platform-browser-dynamic": "14.2.5", - "@angular/platform-server": "14.2.5", - "@angular/router": "14.2.5", - "@angular/service-worker": "14.2.5", + "@angular-devkit/schematics": "^14.2.10", + "@angular/animations": "^14.2.12", + "@angular/cdk": "^14.2.7", + "@angular/common": "^14.2.12", + "@angular/compiler": "^14.2.12", + "@angular/core": "^14.2.12", + "@angular/forms": "^14.2.12", + "@angular/localize": "^14.2.12", + "@angular/platform-browser": "^14.2.12", + "@angular/platform-browser-dynamic": "^14.2.12", + "@angular/platform-server": "^14.2.12", + "@angular/router": "^14.2.12", + "@angular/service-worker": "^14.2.12", "@fortawesome/angular-fontawesome": "^0.11.1", - "@fortawesome/fontawesome-svg-core": "^6.2.0", - "@fortawesome/free-solid-svg-icons": "^6.2.0", - "@googlemaps/js-api-loader": "^1.14.3", + "@fortawesome/fontawesome-svg-core": "^6.2.1", + "@fortawesome/free-solid-svg-icons": "^6.2.1", + "@googlemaps/js-api-loader": "^1.15.1", "@ng-bootstrap/ng-bootstrap": "^11.0.1", - "@ngrx/effects": "14.3.2", - "@ngrx/entity": "14.3.2", - "@ngrx/router-store": "14.3.2", - "@ngrx/store": "14.3.2", - "@ngrx/store-devtools": "14.3.2", - "@nguniversal/express-engine": "14.2.0", - "@ngx-formly/core": "^5.12.7", + "@ngrx/effects": "^14.3.2", + "@ngrx/entity": "^14.3.2", + "@ngrx/router-store": "^14.3.2", + "@ngrx/store": "^14.3.2", + "@ngrx/store-devtools": "^14.3.2", + "@nguniversal/express-engine": "^14.2.3", + "@ngx-formly/core": "^6.0.4", "@ngx-translate/core": "^14.0.0", - "@rx-angular/state": "1.7.0", - "@sentry/browser": "^7.14.1", - "angular-oauth2-oidc": "13.0.1", - "angulartics2": "^12.1.0", + "@rx-angular/state": "^1.7.0", + "@sentry/browser": "^7.25.0", + "angular-oauth2-oidc": "^13.0.1", + "angulartics2": "^12.2.0", "bootstrap": "^4.6.2", "date-fns": "^2.29.3", - "express": "^4.18.1", + "express": "^4.18.2", "express-http-proxy": "^1.6.3", - "express-robots-txt": "1.0.0", + "express-robots-txt": "^1.0.0", "file-replace-loader": "^1.4.0", "js-yaml": "^4.1.0", "lodash-es": "^4.17.21", "morgan": "^1.10.0", "ng-recaptcha": "^10.0.0", - "ngx-infinite-scroll": "^14.0.0", - "ngx-toastr": "^15.2.0", + "ngx-infinite-scroll": "^14.0.1", + "ngx-toastr": "^15.2.2", "rxjs": "~7.5.7", - "swiper": "^8.4.2", - "tslib": "^2.4.0", - "typeface-roboto": "1.1.13", - "typeface-roboto-condensed": "1.1.13", + "swiper": "^8.4.5", + "tslib": "^2.4.1", + "typeface-roboto": "^1.1.13", + "typeface-roboto-condensed": "^1.1.13", "zone.js": "~0.11.8" }, "devDependencies": { - "@angular-builders/custom-webpack": "14.0.1", - "@angular-devkit/build-angular": "14.2.5", - "@angular-eslint/builder": "14.1.2", - "@angular-eslint/eslint-plugin": "14.1.2", - "@angular-eslint/eslint-plugin-template": "14.1.2", - "@angular-eslint/schematics": "14.1.2", - "@angular-eslint/template-parser": "14.1.2", - "@angular/cli": "^14.2.5", - "@angular/compiler-cli": "14.2.5", - "@angular/language-service": "14.2.5", - "@commitlint/cli": "^17.1.2", + "@angular-builders/custom-webpack": "^14.1.0", + "@angular-devkit/build-angular": "^14.2.10", + "@angular-eslint/builder": "^14.4.0", + "@angular-eslint/eslint-plugin": "^14.4.0", + "@angular-eslint/eslint-plugin-template": "^14.4.0", + "@angular-eslint/schematics": "^14.4.0", + "@angular-eslint/template-parser": "^14.4.0", + "@angular/cli": "^14.2.10", + "@angular/compiler-cli": "^14.2.12", + "@angular/language-service": "^14.2.12", + "@commitlint/cli": "^17.3.0", + "@commitlint/config-conventional": "^17.3.0", "@compodoc/compodoc": "^1.1.19", "@cspell/dict-de-de": "1.1.32", "@cspell/dict-fr-fr": "^2.1.1", "@ngrx/eslint-plugin": "^14.3.2", - "@nguniversal/builders": "14.2.0", + "@nguniversal/builders": "^14.2.3", "@phenomnomnominal/tsquery": "^5.0.0", - "@schematics/angular": "14.2.5", - "@types/eslint": "^8.4.6", - "@types/estree": "1.0.0", + "@schematics/angular": "^14.2.10", + "@types/eslint": "^8.4.10", + "@types/estree": "^1.0.0", "@types/express": "^4.17.14", - "@types/google.maps": "^3.50.2", + "@types/google.maps": "^3.51.0", "@types/jest": "^28.1.8", "@types/lodash-es": "^4.17.6", - "@types/node": "^16.11.64", - "@types/uuid": "^8.3.4", + "@types/node": "^16.18.8", + "@types/uuid": "^9.0.0", "@types/webpack": "^5.28.0", - "@typescript-eslint/eslint-plugin": "^5.39.0", - "@typescript-eslint/parser": "^5.39.0", + "@typescript-eslint/eslint-plugin": "^5.46.1", + "@typescript-eslint/parser": "^5.46.1", "comment-json": "^4.2.3", - "commitizen": "^4.2.5", - "commitlint-config-cz": "^0.13.3", - "conventional-changelog-cli": "2.2.2", - "cspell": "^6.12.0", + "conventional-changelog-cli": "^2.2.2", + "cspell": "^6.17.0", "cz-customizable": "^7.0.0", - "eslint": "^8.24.0", + "eslint": "^8.29.0", "eslint-config-prettier": "^8.5.0", - "eslint-plugin-ban": "1.6.0", - "eslint-plugin-etc": "2.0.2", + "eslint-plugin-ban": "^1.6.0", + "eslint-plugin-etc": "^2.0.2", "eslint-plugin-ish-custom-rules": "file:eslint-rules", - "eslint-plugin-jest": "^27.1.1", - "eslint-plugin-jsdoc": "39.3.6", + "eslint-plugin-jest": "^27.1.6", + "eslint-plugin-jsdoc": "^39.6.4", "eslint-plugin-prettier": "^4.2.1", - "eslint-plugin-rxjs": "5.0.2", + "eslint-plugin-rxjs": "^5.0.2", "eslint-plugin-rxjs-angular": "^2.0.0", - "eslint-plugin-unicorn": "44.0.1", + "eslint-plugin-unicorn": "^45.0.2", "eslint-plugin-unused-imports": "^2.0.0", - "husky": "^8.0.1", + "husky": "^8.0.2", "intershop-schematics": "file:schematics", "jasmine-marbles": "^0.9.2", "jest": "^28.1.3", @@ -115,24 +114,24 @@ "jest-jasmine2": "^29.1.2", "jest-preset-angular": "^12.2.2", "json-schema-to-typescript": "^11.0.2", - "lint-staged": "^13.0.3", - "ng-mocks": "^14.2.3", + "lint-staged": "^13.1.0", + "ng-mocks": "^14.5.0", "npm-run-all": "^4.1.5", - "pm2": "^5.2.0", + "pm2": "^5.2.2", "prettier": "^2.7.1", "prom-client": "^14.1.0", "purgecss-webpack-plugin": "^5.0.0", "sort-json": "^2.0.1", - "stylelint": "14.13.0", - "stylelint-config-prettier": "^9.0.3", + "stylelint": "^14.16.0", + "stylelint-config-prettier": "^9.0.4", "stylelint-config-recess-order": "^3.0.0", - "stylelint-config-recommended-scss": "^7.0.0", - "stylelint-config-standard": "^28.0.0", + "stylelint-config-recommended-scss": "^8.0.0", + "stylelint-config-standard": "^29.0.0", "stylelint-prettier": "^2.0.0", "stylelint-scss": "^4.3.0", "treeify": "^1.1.0", - "ts-mockito": "2.6.1", - "ts-morph": "16.0.0", + "ts-mockito": "^2.6.1", + "ts-morph": "^16.0.0", "ts-node": "~10.9.1", "typescript": "~4.8.4", "xliff": "^6.1.0" @@ -172,9 +171,9 @@ } }, "node_modules/@angular-builders/custom-webpack": { - "version": "14.0.1", - "resolved": "https://registry.npmjs.org/@angular-builders/custom-webpack/-/custom-webpack-14.0.1.tgz", - "integrity": "sha512-QDsSFo80I8oLBzvr7qIxcdEfvDMEeJmwYRrJ/hG8O+XVdYsUkkj4nEvBI5fKKBOfcRgx1R/XrEDtJEeolEQeig==", + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/@angular-builders/custom-webpack/-/custom-webpack-14.1.0.tgz", + "integrity": "sha512-FLGDrBOg04cYvzCudeb15LWY2v91dtJ5+AfmP0aS/0T0D0AYmY4uM3FxZeh4jJcWETLvnHVFBCjan6y2Ct9J3A==", "dev": true, "dependencies": { "@angular-devkit/architect": ">=0.1400.0 < 0.1500.0", @@ -193,12 +192,12 @@ } }, "node_modules/@angular-devkit/architect": { - "version": "0.1402.5", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1402.5.tgz", - "integrity": "sha512-vtJEwB51UEY1Q7FCI7xGLdhdb2SRTtI1Qs0or95momn85NuxlaMQsXK1Wxu9/EwtWKZK8dXePXbB/hpiNt61JQ==", + "version": "0.1402.10", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1402.10.tgz", + "integrity": "sha512-/6YmPrgataj1jD2Uqd1ED+CG4DaZGacoeZd/89hH7hF76Nno8K18DrSOqJAEmDnOWegpSRGVLd0qP09IHmaG5w==", "dev": true, "dependencies": { - "@angular-devkit/core": "14.2.5", + "@angular-devkit/core": "14.2.10", "rxjs": "6.6.7" }, "engines": { @@ -226,15 +225,15 @@ "dev": true }, "node_modules/@angular-devkit/build-angular": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-14.2.5.tgz", - "integrity": "sha512-jSgH11E+zs1C24lXj7R/PgXsTUpoYoMr1GtO6mpVROgXL5czVlL+b/B1p2HwbcAKuI9WXb48X6OZ6fOZhDQlSg==", + "version": "14.2.10", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-14.2.10.tgz", + "integrity": "sha512-VCeZAyq4uPCJukKInaSiD4i/GgxgcU4jFlLFQtoYNmaBS4xbPOymL19forRIihiV0dwNEa2L694vRTAPMBxIfw==", "dev": true, "dependencies": { "@ampproject/remapping": "2.2.0", - "@angular-devkit/architect": "0.1402.5", - "@angular-devkit/build-webpack": "0.1402.5", - "@angular-devkit/core": "14.2.5", + "@angular-devkit/architect": "0.1402.10", + "@angular-devkit/build-webpack": "0.1402.10", + "@angular-devkit/core": "14.2.10", "@babel/core": "7.18.10", "@babel/generator": "7.18.12", "@babel/helper-annotate-as-pure": "7.18.6", @@ -245,7 +244,7 @@ "@babel/runtime": "7.18.9", "@babel/template": "7.18.10", "@discoveryjs/json-ext": "0.5.7", - "@ngtools/webpack": "14.2.5", + "@ngtools/webpack": "14.2.10", "ansi-colors": "4.1.3", "babel-loader": "8.2.5", "babel-plugin-istanbul": "6.1.1", @@ -263,7 +262,7 @@ "less": "4.1.3", "less-loader": "11.0.0", "license-webpack-plugin": "4.0.2", - "loader-utils": "3.2.0", + "loader-utils": "3.2.1", "mini-css-extract-plugin": "2.6.1", "minimatch": "5.1.0", "open": "8.4.0", @@ -351,13 +350,19 @@ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", "dev": true }, + "node_modules/@angular-devkit/build-angular/node_modules/tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", + "dev": true + }, "node_modules/@angular-devkit/build-webpack": { - "version": "0.1402.5", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1402.5.tgz", - "integrity": "sha512-h+o0GZD9iATwWjaTiUR0lJ3QZ9twUOJ1sotRchXHzAXMuaDk8wqqPriL5S0qDMlA2QqpNt4OD9rodUCRwae7fw==", + "version": "0.1402.10", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1402.10.tgz", + "integrity": "sha512-h+2MaSY7QSvoJ3R+Hvin21jVCfPGOTLdASIUk4Jmq6J3y5BSku3KSSaV8dWoBOBkFCwQyPQMRjiHoHKLpC1K7g==", "dev": true, "dependencies": { - "@angular-devkit/architect": "0.1402.5", + "@angular-devkit/architect": "0.1402.10", "rxjs": "6.6.7" }, "engines": { @@ -389,9 +394,9 @@ "dev": true }, "node_modules/@angular-devkit/core": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-14.2.5.tgz", - "integrity": "sha512-lSje+HX0fx9Y2A4k63jVHrWdGT4wellhwcZpTCv9P6LvdfTkAlrfra3TaYhUPjavCsPwlRC/VVQN3Qkzk5m6gA==", + "version": "14.2.10", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-14.2.10.tgz", + "integrity": "sha512-K4AO7mROTdbhQ7chtyQd6oPwmuL+BPUh+wn6Aq1qrmYJK4UZYFOPp8fi/Ehs8meCEeywtrssOPfrOE4Gsre9dg==", "dependencies": { "ajv": "8.11.0", "ajv-formats": "2.1.1", @@ -430,11 +435,11 @@ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, "node_modules/@angular-devkit/schematics": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-14.2.5.tgz", - "integrity": "sha512-3a//d8f/yuR1F2QXAyX4pShWdkHBWbY1qpqqVnN9gRJ+ye6pY098gsCQKpKXPZGeV08ugu5v79f5JELMthBBSQ==", + "version": "14.2.10", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-14.2.10.tgz", + "integrity": "sha512-MMp31KpJTwKHisXOq+6VOXYApq97hZxFaFmZk396X5aIFTCELUwjcezQDk+u2nEs5iK/COUfnN3plGcfJxYhQA==", "dependencies": { - "@angular-devkit/core": "14.2.5", + "@angular-devkit/core": "14.2.10", "jsonc-parser": "3.1.0", "magic-string": "0.26.2", "ora": "5.4.1", @@ -463,9 +468,9 @@ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, "node_modules/@angular-eslint/builder": { - "version": "14.1.2", - "resolved": "https://registry.npmjs.org/@angular-eslint/builder/-/builder-14.1.2.tgz", - "integrity": "sha512-J+LRidjlJOGfRNXJwUyOhz5TnasEBK+kL3QkkCE4ZSt/dH40QqT+3q9qV5zc45wdaAeJM4/jp1IhI6kPwWI5Yw==", + "version": "14.4.0", + "resolved": "https://registry.npmjs.org/@angular-eslint/builder/-/builder-14.4.0.tgz", + "integrity": "sha512-AhAUFvSg0urtb6Lsowvuxwu6DMXUy0BPwrnfNOBGjRt9vG7F9kgXXAsm5DnIS0GNy/mLZ9mSfa86fv++1e0KUA==", "dev": true, "peerDependencies": { "eslint": "^7.0.0 || ^8.0.0", @@ -473,19 +478,19 @@ } }, "node_modules/@angular-eslint/bundled-angular-compiler": { - "version": "14.1.2", - "resolved": "https://registry.npmjs.org/@angular-eslint/bundled-angular-compiler/-/bundled-angular-compiler-14.1.2.tgz", - "integrity": "sha512-d5/jTKXP+t9hNSucj3m8zZYBl62fZ2xFMVNbAOArYAkA7WwwX3D7Gae57BNW54cd2fl2/is7Dn6UgYhu1wqkSQ==", + "version": "14.4.0", + "resolved": "https://registry.npmjs.org/@angular-eslint/bundled-angular-compiler/-/bundled-angular-compiler-14.4.0.tgz", + "integrity": "sha512-KMHPHd24s0HVvAP/DxSSqhYBWhwW8FgS/r0Uwv8eWpsIdc/z/Chd2ush2SgPchmmquAXTgOZsbEY7ZmW+XkJfQ==", "dev": true }, "node_modules/@angular-eslint/eslint-plugin": { - "version": "14.1.2", - "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin/-/eslint-plugin-14.1.2.tgz", - "integrity": "sha512-5pJaTcFfM7yDHNtMxw3uNTpBTLjNYH9mlOLX5FFQ9EahAuycwCtV8VJkIntK2ZiOTdRVJYA9/PEdD/xVxX02rw==", + "version": "14.4.0", + "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin/-/eslint-plugin-14.4.0.tgz", + "integrity": "sha512-2rZQ4mt7tEUW+lI5jjuj3HWaT4VQtWTG6+LDnmuUmx76m8hqQ7NvFUpOcNDofu5KbEVBP+oF2DA6wjoZOIuSOA==", "dev": true, "dependencies": { - "@angular-eslint/utils": "14.1.2", - "@typescript-eslint/utils": "5.37.0" + "@angular-eslint/utils": "14.4.0", + "@typescript-eslint/utils": "5.43.0" }, "peerDependencies": { "eslint": "^7.0.0 || ^8.0.0", @@ -493,16 +498,17 @@ } }, "node_modules/@angular-eslint/eslint-plugin-template": { - "version": "14.1.2", - "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin-template/-/eslint-plugin-template-14.1.2.tgz", - "integrity": "sha512-gMgYJ8ZwPvq2H/YEzPztVRAK2NYs2cJFUDZD4iGjSRtDgYq9OHjyTo+r6tkcyjcK2qvesy0RccHQKh+x3hYMTA==", + "version": "14.4.0", + "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin-template/-/eslint-plugin-template-14.4.0.tgz", + "integrity": "sha512-d3GM/EU2iWzr+BrITwO4gBf9WfDfuOdTjfinV/zN84oXMFaK2ENo+IP6OEsD9hh36rdPps+m2gFGDdx+rTzBpg==", "dev": true, "dependencies": { - "@angular-eslint/bundled-angular-compiler": "14.1.2", - "@typescript-eslint/type-utils": "5.37.0", - "@typescript-eslint/utils": "5.37.0", - "aria-query": "5.0.2", - "axobject-query": "3.0.1" + "@angular-eslint/bundled-angular-compiler": "14.4.0", + "@angular-eslint/utils": "14.4.0", + "@typescript-eslint/type-utils": "5.43.0", + "@typescript-eslint/utils": "5.43.0", + "aria-query": "5.1.3", + "axobject-query": "3.1.1" }, "peerDependencies": { "eslint": "^7.0.0 || ^8.0.0", @@ -510,13 +516,13 @@ } }, "node_modules/@angular-eslint/schematics": { - "version": "14.1.2", - "resolved": "https://registry.npmjs.org/@angular-eslint/schematics/-/schematics-14.1.2.tgz", - "integrity": "sha512-jyaCDQf+MGjMCf+U6KXvvpPESKMUoSGXYhsh2XYtSSUhXook9f2cPI6bHBMyrDgV43zH42jMS+yMC1EO24ZP1w==", + "version": "14.4.0", + "resolved": "https://registry.npmjs.org/@angular-eslint/schematics/-/schematics-14.4.0.tgz", + "integrity": "sha512-BrGkPug+CZQWOfmNRsJDrEtYJcxvzF/kLlV7RjvIN9Ky5TjUiJVCeafl3VY6COSY32tjlh2GvBdl1AQKWWovbA==", "dev": true, "dependencies": { - "@angular-eslint/eslint-plugin": "14.1.2", - "@angular-eslint/eslint-plugin-template": "14.1.2", + "@angular-eslint/eslint-plugin": "14.4.0", + "@angular-eslint/eslint-plugin-template": "14.4.0", "ignore": "5.2.0", "strip-json-comments": "3.1.1", "tmp": "0.2.1" @@ -526,27 +532,49 @@ } }, "node_modules/@angular-eslint/template-parser": { - "version": "14.1.2", - "resolved": "https://registry.npmjs.org/@angular-eslint/template-parser/-/template-parser-14.1.2.tgz", - "integrity": "sha512-bQI+poQDIyR3OU9EQzJeLYRtmsvjFGtV5dc+4XPJ6eIyRAc8baCG/0V/cOrpofIdSf7e/sCV8H7rXcFg6tSdUw==", + "version": "14.4.0", + "resolved": "https://registry.npmjs.org/@angular-eslint/template-parser/-/template-parser-14.4.0.tgz", + "integrity": "sha512-zq888KpQB0YTEK26mkKcT4fs8LDWWT1oAEXU8DrXhvkikS8XavTSHOWJye/bVZR4oJRFCF5YTJV75DEMcGNIpQ==", "dev": true, "dependencies": { - "@angular-eslint/bundled-angular-compiler": "14.1.2", - "eslint-scope": "^5.1.0" + "@angular-eslint/bundled-angular-compiler": "14.4.0", + "eslint-scope": "^7.0.0" }, "peerDependencies": { "eslint": "^7.0.0 || ^8.0.0", "typescript": "*" } }, + "node_modules/@angular-eslint/template-parser/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/@angular-eslint/template-parser/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/@angular-eslint/utils": { - "version": "14.1.2", - "resolved": "https://registry.npmjs.org/@angular-eslint/utils/-/utils-14.1.2.tgz", - "integrity": "sha512-EtblG9zO0+kWG9EHsoEshFKvsH5DMSK1DqwQsNOVGAF0Aa5DFOqrwouJUyBNJ0d4fSWI9QcuzVkZ1x9JyLIeXQ==", + "version": "14.4.0", + "resolved": "https://registry.npmjs.org/@angular-eslint/utils/-/utils-14.4.0.tgz", + "integrity": "sha512-dPHklAVfh+JfueDfXre9Xooq7p5bFyKO2Z6y1agYeofAgHCPIJOPx2AhtFPrOtsc4VXFFiyE9XbowlXh4ogoKQ==", "dev": true, "dependencies": { - "@angular-eslint/bundled-angular-compiler": "14.1.2", - "@typescript-eslint/utils": "5.37.0" + "@angular-eslint/bundled-angular-compiler": "14.4.0", + "@typescript-eslint/utils": "5.43.0" }, "peerDependencies": { "eslint": "^7.0.0 || ^8.0.0", @@ -554,9 +582,9 @@ } }, "node_modules/@angular/animations": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-14.2.5.tgz", - "integrity": "sha512-4BhR9jSjgIwoK/alu7FSwSU5SxISMVFBAl/4cEYchfCqnflMNkZ8WwRVKTQjyeuYW5KtQTw9jRNp4tGK1YQWYw==", + "version": "14.2.12", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-14.2.12.tgz", + "integrity": "sha512-gwdnFZkvVUr+enUNfhfCGRGGqNHn1+vTA81apLfHYhJxgjiLUtETc4KTOrQevtDm022pEd+LSrvr8r+7ag+jkw==", "dependencies": { "tslib": "^2.3.0" }, @@ -564,13 +592,13 @@ "node": "^14.15.0 || >=16.10.0" }, "peerDependencies": { - "@angular/core": "14.2.5" + "@angular/core": "14.2.12" } }, "node_modules/@angular/cdk": { - "version": "14.2.4", - "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-14.2.4.tgz", - "integrity": "sha512-5jngZcOyC2n9pRYec/D0iCw72QSnCkGYjtfgIlOK/FZYGhpOa34GMGObPuv4F0u7J2TEtbO6xIFsCFaK0FLIWQ==", + "version": "14.2.7", + "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-14.2.7.tgz", + "integrity": "sha512-/tEsYaUbDSnfEmKVvAMramIptmhI67O+9STjOV0i+74XR2NospeK0fkbywIANu1n3w6AHGMotvRWJrjmbCElFg==", "dependencies": { "tslib": "^2.3.0" }, @@ -584,15 +612,15 @@ } }, "node_modules/@angular/cli": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-14.2.5.tgz", - "integrity": "sha512-jrvQ7nv/8k8i6D7LXrZi+DXQQkpmqoxC/NZL7hH1zyB9shlnG/ekMl+T4y7tvg3MWKxJuIfWVtz/EwOkMKmEaA==", + "version": "14.2.10", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-14.2.10.tgz", + "integrity": "sha512-gX9sAKOwq4lKdPWeABB7TzKDHdjQXvkUU8NmPJA6mEAVXvm3lhQtFvHDalZstwK8au2LY0LaXTcEtcKYOt3AXQ==", "dev": true, "dependencies": { - "@angular-devkit/architect": "0.1402.5", - "@angular-devkit/core": "14.2.5", - "@angular-devkit/schematics": "14.2.5", - "@schematics/angular": "14.2.5", + "@angular-devkit/architect": "0.1402.10", + "@angular-devkit/core": "14.2.10", + "@angular-devkit/schematics": "14.2.10", + "@schematics/angular": "14.2.10", "@yarnpkg/lockfile": "1.1.0", "ansi-colors": "4.1.3", "debug": "4.3.4", @@ -620,9 +648,9 @@ } }, "node_modules/@angular/common": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-14.2.5.tgz", - "integrity": "sha512-v2fIK6imfMkUvYNjZQO+drE39QO3eSS95Yy7UN+6inb47DkAfzx6hipA9zKrMENjsS3kDv1d7cgDHE7WuOCzIw==", + "version": "14.2.12", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-14.2.12.tgz", + "integrity": "sha512-oZunh9wfInFWhNO1P8uoEs/o4u8kerKMhw8GruywKm1TV7gHDP2Fi5WHGjFqq3XYptgBTPCTSEfyLX6Cwq1PUw==", "dependencies": { "tslib": "^2.3.0" }, @@ -630,14 +658,14 @@ "node": "^14.15.0 || >=16.10.0" }, "peerDependencies": { - "@angular/core": "14.2.5", + "@angular/core": "14.2.12", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/compiler": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-14.2.5.tgz", - "integrity": "sha512-L7d2/D6o9wlB2ugqRYpev6a8JntqS+7lF2o6z8y7RR2YAlAu71nq0BDsQez4/aSCK3HnDq0yhEnns7vcmOq/jA==", + "version": "14.2.12", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-14.2.12.tgz", + "integrity": "sha512-u2MH9+NRwbbFDRNiPWPexed9CnCq9+pGHLuyACSP2uR6Ik68cE6cayeZbIeoEV5vWpda/XsLmJgPJysw7dAZLQ==", "dependencies": { "tslib": "^2.3.0" }, @@ -645,7 +673,7 @@ "node": "^14.15.0 || >=16.10.0" }, "peerDependencies": { - "@angular/core": "14.2.5" + "@angular/core": "14.2.12" }, "peerDependenciesMeta": { "@angular/core": { @@ -654,9 +682,9 @@ } }, "node_modules/@angular/compiler-cli": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-14.2.5.tgz", - "integrity": "sha512-3GYzTPw96TfJjw7Aso+f+uN6VFBWedqRATUQ6v+BAEyZIboirdLI1JQFOcCfuKWUM2B48RW+pdIduZmG3ckotA==", + "version": "14.2.12", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-14.2.12.tgz", + "integrity": "sha512-9Gkb9KFkaQPz8XaS8ZwwTioRZ4ywykdAWyceICEi78/Y9ConYrTX2SbFogzI2dPUZU8a04tMlbqTSmHjVbJftQ==", "dependencies": { "@babel/core": "^7.17.2", "chokidar": "^3.0.0", @@ -678,14 +706,14 @@ "node": "^14.15.0 || >=16.10.0" }, "peerDependencies": { - "@angular/compiler": "14.2.5", + "@angular/compiler": "14.2.12", "typescript": ">=4.6.2 <4.9" } }, "node_modules/@angular/core": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-14.2.5.tgz", - "integrity": "sha512-Ok78Abq0puMGlolvNVzKFvsX7ePDkyxpZzztDzXDdRA4x4o6bAuuDG9Y7Wab2+wsdY6NktO+dFQjq1UBWClgSg==", + "version": "14.2.12", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-14.2.12.tgz", + "integrity": "sha512-sGQxU5u4uawwvJa6jOTmGoisJiQ5HIN/RoBw99CmoqZIVyUSg9IRJJC1KVdH8gbpWBNLkElZv21lwJTL/msWyg==", "dependencies": { "tslib": "^2.3.0" }, @@ -694,13 +722,13 @@ }, "peerDependencies": { "rxjs": "^6.5.3 || ^7.4.0", - "zone.js": "~0.11.4" + "zone.js": "~0.11.4 || ~0.12.0" } }, "node_modules/@angular/forms": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-14.2.5.tgz", - "integrity": "sha512-aMH5Vrftny0KF0XzWQIGfHoI0LVQ2aatpWzdUWiUqBeX/Q+ucmxeP5rZyKtUsi0flETWxdRZSBTjbXZ3dsIcTA==", + "version": "14.2.12", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-14.2.12.tgz", + "integrity": "sha512-7abYlGIT2JnAtutQUlH3fQS6QEpbfftgvsVcZJCyvX0rXL3u2w2vUQkDHJH4YJJp3AHFVCH4/l7R4VcaPnrwvA==", "dependencies": { "tslib": "^2.3.0" }, @@ -708,25 +736,25 @@ "node": "^14.15.0 || >=16.10.0" }, "peerDependencies": { - "@angular/common": "14.2.5", - "@angular/core": "14.2.5", - "@angular/platform-browser": "14.2.5", + "@angular/common": "14.2.12", + "@angular/core": "14.2.12", + "@angular/platform-browser": "14.2.12", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/language-service": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-14.2.5.tgz", - "integrity": "sha512-YqbsCbCq470ve6+MGjeEf2I6L5LcBYALvh+S5XsZkfEQEjSYYC1ZE1ftq7clICrMOOoM4XSghq8b/eNtZoTJkg==", + "version": "14.2.12", + "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-14.2.12.tgz", + "integrity": "sha512-YmW6simyEVmpDmbYVUhZ2IxSP6pmsWrV120rB9Y21/BeM39WIXA4NCNirVWlAd/KAKY9O7Sbn1nXI6rSDfhopQ==", "dev": true, "engines": { "node": "^14.15.0 || >=16.10.0" } }, "node_modules/@angular/localize": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@angular/localize/-/localize-14.2.5.tgz", - "integrity": "sha512-QKDa0stq5vRadvYKThh1kE2+/7a2fg6Ue7OFwOZNzuBSItKoXVdEWdkz1idcY7IoGNtMYv6TeHbTDdaFZZDC7Q==", + "version": "14.2.12", + "resolved": "https://registry.npmjs.org/@angular/localize/-/localize-14.2.12.tgz", + "integrity": "sha512-6TTnuvubvYL1LDIJhDfd7ygxTaj0ShTILCDXT4URBhZKQbQ3HAorDqsc6SXqZVGCHdqF0hGTaeN/7zVvgP9kzA==", "dependencies": { "@babel/core": "7.18.9", "glob": "8.0.3", @@ -741,8 +769,8 @@ "node": "^14.15.0 || >=16.10.0" }, "peerDependencies": { - "@angular/compiler": "14.2.5", - "@angular/compiler-cli": "14.2.5" + "@angular/compiler": "14.2.12", + "@angular/compiler-cli": "14.2.12" } }, "node_modules/@angular/localize/node_modules/@babel/core": { @@ -783,9 +811,9 @@ } }, "node_modules/@angular/platform-browser": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-14.2.5.tgz", - "integrity": "sha512-FDZm23N9veSEouQX1YuZUjv7Nillroi+v0VbN1x5iPpFZEudaoZYT3A7bpJwdlxUx/4rGS0caaXNhN3CowtIeQ==", + "version": "14.2.12", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-14.2.12.tgz", + "integrity": "sha512-vOarWym8ucl1gjYWCzdwyBha+MTvL381mvTTUu8aUx6nVhHFjv4bvpjlZnZgojecqUPyxOwmPLLHvCZPJVHZYg==", "dependencies": { "tslib": "^2.3.0" }, @@ -793,9 +821,9 @@ "node": "^14.15.0 || >=16.10.0" }, "peerDependencies": { - "@angular/animations": "14.2.5", - "@angular/common": "14.2.5", - "@angular/core": "14.2.5" + "@angular/animations": "14.2.12", + "@angular/common": "14.2.12", + "@angular/core": "14.2.12" }, "peerDependenciesMeta": { "@angular/animations": { @@ -804,9 +832,9 @@ } }, "node_modules/@angular/platform-browser-dynamic": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-14.2.5.tgz", - "integrity": "sha512-7W8oLs8YEGRr8izgUlpHgBfg3vUb5H0yicTHJY4zIqHJJbG1rTl46CjULaMjYM/FWcS8o7y6XJJcHx0c7pKNsw==", + "version": "14.2.12", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-14.2.12.tgz", + "integrity": "sha512-oZhNJeaBmgw8+KBSYpKz2RYqEDyETC+HJXH8dwIFcP6BqqwL2NE70FdSR7EnOa5c41MEtTmMCGhrJSFR60x5/w==", "dependencies": { "tslib": "^2.3.0" }, @@ -814,16 +842,16 @@ "node": "^14.15.0 || >=16.10.0" }, "peerDependencies": { - "@angular/common": "14.2.5", - "@angular/compiler": "14.2.5", - "@angular/core": "14.2.5", - "@angular/platform-browser": "14.2.5" + "@angular/common": "14.2.12", + "@angular/compiler": "14.2.12", + "@angular/core": "14.2.12", + "@angular/platform-browser": "14.2.12" } }, "node_modules/@angular/platform-server": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@angular/platform-server/-/platform-server-14.2.5.tgz", - "integrity": "sha512-cRYf0rf6ctHvEnDwtAyIsTHrCvlGHHszE9KK7o2c5fYGfzhYXLw7CX/JMTN+9xwvT2H7QZFrkm2AaNjPvkKd7Q==", + "version": "14.2.12", + "resolved": "https://registry.npmjs.org/@angular/platform-server/-/platform-server-14.2.12.tgz", + "integrity": "sha512-RDxNh47Rp0EYrimbzviqhagdbL58Z3S88PDYybYbshFwV+MgWsvWasK/WntTMP/JtRP4FBU0Uiwxy7mgVdxb0g==", "dependencies": { "domino": "^2.1.2", "tslib": "^2.3.0", @@ -833,18 +861,18 @@ "node": "^14.15.0 || >=16.10.0" }, "peerDependencies": { - "@angular/animations": "14.2.5", - "@angular/common": "14.2.5", - "@angular/compiler": "14.2.5", - "@angular/core": "14.2.5", - "@angular/platform-browser": "14.2.5", - "@angular/platform-browser-dynamic": "14.2.5" + "@angular/animations": "14.2.12", + "@angular/common": "14.2.12", + "@angular/compiler": "14.2.12", + "@angular/core": "14.2.12", + "@angular/platform-browser": "14.2.12", + "@angular/platform-browser-dynamic": "14.2.12" } }, "node_modules/@angular/router": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@angular/router/-/router-14.2.5.tgz", - "integrity": "sha512-AUHcr9Lln7emJ/aete08UoqWQFZOLH1MhuP78r2pixvnNiZ9C8hcevX1rGGax0Po/Gy4PSJ4wnFhZPgifqCguQ==", + "version": "14.2.12", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-14.2.12.tgz", + "integrity": "sha512-r5tVus5RJDNc4U2v0jMtjPiAS1xDsVsJ70lS313DgZmBDHIVZP1cWIehdxwgNlGwQQtAA36eG7toBwqUU3gb/A==", "dependencies": { "tslib": "^2.3.0" }, @@ -852,16 +880,16 @@ "node": "^14.15.0 || >=16.10.0" }, "peerDependencies": { - "@angular/common": "14.2.5", - "@angular/core": "14.2.5", - "@angular/platform-browser": "14.2.5", + "@angular/common": "14.2.12", + "@angular/core": "14.2.12", + "@angular/platform-browser": "14.2.12", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/service-worker": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@angular/service-worker/-/service-worker-14.2.5.tgz", - "integrity": "sha512-0OCp3U4+kO2H+275JlaOhHl2KtFBobByo9WpHyQV+iWIAxwBcStxuL7NXRcPTxmrvzyM6doZt1d/V3NA5eiIPA==", + "version": "14.2.12", + "resolved": "https://registry.npmjs.org/@angular/service-worker/-/service-worker-14.2.12.tgz", + "integrity": "sha512-7aAHb9XfToHQyHoPF9CmZSfsO5vFmKALDmTBWf8i3DCztrZvY+B8PCbfpJkpgFiF7LyF+hGaExI4fa6GmHZv+g==", "dependencies": { "tslib": "^2.3.0" }, @@ -872,8 +900,8 @@ "node": "^14.15.0 || >=16.10.0" }, "peerDependencies": { - "@angular/common": "14.2.5", - "@angular/core": "14.2.5" + "@angular/common": "14.2.12", + "@angular/core": "14.2.12" } }, "node_modules/@assemblyscript/loader": { @@ -2608,18 +2636,18 @@ "dev": true }, "node_modules/@commitlint/cli": { - "version": "17.1.2", - "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-17.1.2.tgz", - "integrity": "sha512-h/4Hlka3bvCLbnxf0Er2ri5A44VMlbMSkdTRp8Adv2tRiklSTRIoPGs7OEXDv3EoDs2AAzILiPookgM4Gi7LOw==", + "version": "17.3.0", + "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-17.3.0.tgz", + "integrity": "sha512-/H0md7TsKflKzVPz226VfXzVafJFO1f9+r2KcFvmBu08V0T56lZU1s8WL7/xlxqLMqBTVaBf7Ixtc4bskdEEZg==", "dev": true, "dependencies": { "@commitlint/format": "^17.0.0", - "@commitlint/lint": "^17.1.0", - "@commitlint/load": "^17.1.2", - "@commitlint/read": "^17.1.0", + "@commitlint/lint": "^17.3.0", + "@commitlint/load": "^17.3.0", + "@commitlint/read": "^17.2.0", "@commitlint/types": "^17.0.0", "execa": "^5.0.0", - "lodash": "^4.17.19", + "lodash.isfunction": "^3.0.9", "resolve-from": "5.0.0", "resolve-global": "1.0.0", "yargs": "^17.0.0" @@ -2631,6 +2659,32 @@ "node": ">=v14" } }, + "node_modules/@commitlint/config-conventional": { + "version": "17.3.0", + "resolved": "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-17.3.0.tgz", + "integrity": "sha512-hgI+fN5xF8nhS9uG/V06xyT0nlcyvHHMkq0kwRSr96vl5BFlRGaL2C0/YY4kQagfU087tmj01bJkG9Ek98Wllw==", + "dev": true, + "dependencies": { + "conventional-changelog-conventionalcommits": "^5.0.0" + }, + "engines": { + "node": ">=v14" + } + }, + "node_modules/@commitlint/config-conventional/node_modules/conventional-changelog-conventionalcommits": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-5.0.0.tgz", + "integrity": "sha512-lCDbA+ZqVFQGUj7h9QBKoIpLhl8iihkO0nCTyRNzuXtcd7ubODpYB04IFy31JloiJgG0Uovu8ot8oxRzn7Nwtw==", + "dev": true, + "dependencies": { + "compare-func": "^2.0.0", + "lodash": "^4.17.15", + "q": "^1.5.1" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@commitlint/config-validator": { "version": "17.1.0", "resolved": "https://registry.npmjs.org/@commitlint/config-validator/-/config-validator-17.1.0.tgz", @@ -2645,13 +2699,17 @@ } }, "node_modules/@commitlint/ensure": { - "version": "17.0.0", - "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-17.0.0.tgz", - "integrity": "sha512-M2hkJnNXvEni59S0QPOnqCKIK52G1XyXBGw51mvh7OXDudCmZ9tZiIPpU882p475Mhx48Ien1MbWjCP1zlyC0A==", + "version": "17.3.0", + "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-17.3.0.tgz", + "integrity": "sha512-kWbrQHDoW5veIUQx30gXoLOCjWvwC6OOEofhPCLl5ytRPBDAQObMbxTha1Bt2aSyNE/IrJ0s0xkdZ1Gi3wJwQg==", "dev": true, "dependencies": { "@commitlint/types": "^17.0.0", - "lodash": "^4.17.19" + "lodash.camelcase": "^4.3.0", + "lodash.kebabcase": "^4.1.1", + "lodash.snakecase": "^4.1.1", + "lodash.startcase": "^4.4.0", + "lodash.upperfirst": "^4.3.1" }, "engines": { "node": ">=v14" @@ -2750,9 +2808,9 @@ } }, "node_modules/@commitlint/is-ignored": { - "version": "17.1.0", - "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-17.1.0.tgz", - "integrity": "sha512-JITWKDMHhIh8IpdIbcbuH9rEQJty1ZWelgjleTFrVRAcEwN/sPzk1aVUXRIZNXMJWbZj8vtXRJnFihrml8uECQ==", + "version": "17.2.0", + "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-17.2.0.tgz", + "integrity": "sha512-rgUPUQraHxoMLxiE8GK430HA7/R2vXyLcOT4fQooNrZq9ERutNrP6dw3gdKLkq22Nede3+gEHQYUzL4Wu75ndg==", "dev": true, "dependencies": { "@commitlint/types": "^17.0.0", @@ -2763,14 +2821,14 @@ } }, "node_modules/@commitlint/lint": { - "version": "17.1.0", - "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-17.1.0.tgz", - "integrity": "sha512-ltpqM2ogt/+SDhUaScFo0MdscncEF96lvQTPMM/VTTWlw7sTGLLWkOOppsee2MN/uLNNWjQ7kqkd4h6JqoM9AQ==", + "version": "17.3.0", + "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-17.3.0.tgz", + "integrity": "sha512-VilOTPg0i9A7CCWM49E9bl5jytfTvfTxf9iwbWAWNjxJ/A5mhPKbm3sHuAdwJ87tDk1k4j8vomYfH23iaY+1Rw==", "dev": true, "dependencies": { - "@commitlint/is-ignored": "^17.1.0", - "@commitlint/parse": "^17.0.0", - "@commitlint/rules": "^17.0.0", + "@commitlint/is-ignored": "^17.2.0", + "@commitlint/parse": "^17.2.0", + "@commitlint/rules": "^17.3.0", "@commitlint/types": "^17.0.0" }, "engines": { @@ -2778,20 +2836,22 @@ } }, "node_modules/@commitlint/load": { - "version": "17.1.2", - "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-17.1.2.tgz", - "integrity": "sha512-sk2p/jFYAWLChIfOIp/MGSIn/WzZ0vkc3afw+l4X8hGEYkvDe4gQUUAVxjl/6xMRn0HgnSLMZ04xXh5pkTsmgg==", + "version": "17.3.0", + "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-17.3.0.tgz", + "integrity": "sha512-u/pV6rCAJrCUN+HylBHLzZ4qj1Ew3+eN9GBPhNi9otGxtOfA8b+8nJSxaNbcC23Ins/kcpjGf9zPSVW7628Umw==", "dev": true, "dependencies": { "@commitlint/config-validator": "^17.1.0", "@commitlint/execute-rule": "^17.0.0", - "@commitlint/resolve-extends": "^17.1.0", + "@commitlint/resolve-extends": "^17.3.0", "@commitlint/types": "^17.0.0", "@types/node": "^14.0.0", "chalk": "^4.1.0", "cosmiconfig": "^7.0.0", "cosmiconfig-typescript-loader": "^4.0.0", - "lodash": "^4.17.19", + "lodash.isplainobject": "^4.0.6", + "lodash.merge": "^4.6.2", + "lodash.uniq": "^4.5.0", "resolve-from": "^5.0.0", "ts-node": "^10.8.1", "typescript": "^4.6.4" @@ -2801,9 +2861,9 @@ } }, "node_modules/@commitlint/load/node_modules/@types/node": { - "version": "14.18.31", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.31.tgz", - "integrity": "sha512-vQAnaReSQkEDa8uwAyQby8bYGKu84R/deEc6mg5T8fX6gzCn8QW6rziSgsti1fNvsrswKUKPnVTi7uoB+u62Mw==", + "version": "14.18.34", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.34.tgz", + "integrity": "sha512-hcU9AIQVHmPnmjRK+XUUYlILlr9pQrsqSrwov/JK1pnf3GTQowVBhx54FbvM0AU/VXGH4i3+vgXS5EguR7fysA==", "dev": true }, "node_modules/@commitlint/load/node_modules/ansi-styles": { @@ -2877,18 +2937,18 @@ } }, "node_modules/@commitlint/message": { - "version": "17.0.0", - "resolved": "https://registry.npmjs.org/@commitlint/message/-/message-17.0.0.tgz", - "integrity": "sha512-LpcwYtN+lBlfZijHUdVr8aNFTVpHjuHI52BnfoV01TF7iSLnia0jttzpLkrLmI8HNQz6Vhr9UrxDWtKZiMGsBw==", + "version": "17.2.0", + "resolved": "https://registry.npmjs.org/@commitlint/message/-/message-17.2.0.tgz", + "integrity": "sha512-/4l2KFKxBOuoEn1YAuuNNlAU05Zt7sNsC9H0mPdPm3chOrT4rcX0pOqrQcLtdMrMkJz0gC7b3SF80q2+LtdL9Q==", "dev": true, "engines": { "node": ">=v14" } }, "node_modules/@commitlint/parse": { - "version": "17.0.0", - "resolved": "https://registry.npmjs.org/@commitlint/parse/-/parse-17.0.0.tgz", - "integrity": "sha512-cKcpfTIQYDG1ywTIr5AG0RAiLBr1gudqEsmAGCTtj8ffDChbBRxm6xXs2nv7GvmJN7msOt7vOKleLvcMmRa1+A==", + "version": "17.2.0", + "resolved": "https://registry.npmjs.org/@commitlint/parse/-/parse-17.2.0.tgz", + "integrity": "sha512-vLzLznK9Y21zQ6F9hf8D6kcIJRb2haAK5T/Vt1uW2CbHYOIfNsR/hJs0XnF/J9ctM20Tfsqv4zBitbYvVw7F6Q==", "dev": true, "dependencies": { "@commitlint/types": "^17.0.0", @@ -2900,9 +2960,9 @@ } }, "node_modules/@commitlint/read": { - "version": "17.1.0", - "resolved": "https://registry.npmjs.org/@commitlint/read/-/read-17.1.0.tgz", - "integrity": "sha512-73BoFNBA/3Ozo2JQvGsE0J8SdrJAWGfZQRSHqvKaqgmY042Su4gXQLqvAzgr55S9DI1l9TiU/5WDuh8IE86d/g==", + "version": "17.2.0", + "resolved": "https://registry.npmjs.org/@commitlint/read/-/read-17.2.0.tgz", + "integrity": "sha512-bbblBhrHkjxra3ptJNm0abxu7yeAaxumQ8ZtD6GIVqzURCETCP7Dm0tlVvGRDyXBuqX6lIJxh3W7oyKqllDsHQ==", "dev": true, "dependencies": { "@commitlint/top-level": "^17.0.0", @@ -2916,15 +2976,15 @@ } }, "node_modules/@commitlint/resolve-extends": { - "version": "17.1.0", - "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-17.1.0.tgz", - "integrity": "sha512-jqKm00LJ59T0O8O4bH4oMa4XyJVEOK4GzH8Qye9XKji+Q1FxhZznxMV/bDLyYkzbTodBt9sL0WLql8wMtRTbqQ==", + "version": "17.3.0", + "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-17.3.0.tgz", + "integrity": "sha512-Lf3JufJlc5yVEtJWC8o4IAZaB8FQAUaVlhlAHRACd0TTFizV2Lk2VH70et23KgvbQNf7kQzHs/2B4QZalBv6Cg==", "dev": true, "dependencies": { "@commitlint/config-validator": "^17.1.0", "@commitlint/types": "^17.0.0", "import-fresh": "^3.0.0", - "lodash": "^4.17.19", + "lodash.mergewith": "^4.6.2", "resolve-from": "^5.0.0", "resolve-global": "^1.0.0" }, @@ -2933,13 +2993,13 @@ } }, "node_modules/@commitlint/rules": { - "version": "17.0.0", - "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-17.0.0.tgz", - "integrity": "sha512-45nIy3dERKXWpnwX9HeBzK5SepHwlDxdGBfmedXhL30fmFCkJOdxHyOJsh0+B0RaVsLGT01NELpfzJUmtpDwdQ==", + "version": "17.3.0", + "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-17.3.0.tgz", + "integrity": "sha512-s2UhDjC5yP2utx3WWqsnZRzjgzAX8BMwr1nltC0u0p8T/nzpkx4TojEfhlsOUj1t7efxzZRjUAV0NxNwdJyk+g==", "dev": true, "dependencies": { - "@commitlint/ensure": "^17.0.0", - "@commitlint/message": "^17.0.0", + "@commitlint/ensure": "^17.3.0", + "@commitlint/message": "^17.2.0", "@commitlint/to-lines": "^17.0.0", "@commitlint/types": "^17.0.0", "execa": "^5.0.0" @@ -3426,137 +3486,138 @@ } }, "node_modules/@cspell/cspell-bundled-dicts": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/@cspell/cspell-bundled-dicts/-/cspell-bundled-dicts-6.12.0.tgz", - "integrity": "sha512-myfsDwSJcAMjKbztKBG424wIp/YV9/lvxsgHFKxBGPi+nNx1p7TbOjAAO9EWk0mZVHyGKZwCFJS2ohkoqxJWoQ==", - "dev": true, - "dependencies": { - "@cspell/dict-ada": "^2.0.1", - "@cspell/dict-aws": "^2.0.0", - "@cspell/dict-bash": "^2.0.4", - "@cspell/dict-companies": "^2.0.14", - "@cspell/dict-cpp": "^3.2.1", - "@cspell/dict-cryptocurrencies": "^2.0.0", - "@cspell/dict-csharp": "^3.0.1", - "@cspell/dict-css": "^2.1.0", - "@cspell/dict-dart": "^1.1.1", - "@cspell/dict-django": "^2.0.0", - "@cspell/dict-docker": "^1.1.1", - "@cspell/dict-dotnet": "^2.0.1", - "@cspell/dict-elixir": "^2.0.1", - "@cspell/dict-en_us": "^2.3.3", - "@cspell/dict-en-gb": "^1.1.33", - "@cspell/dict-filetypes": "^2.1.1", - "@cspell/dict-fonts": "^2.1.0", - "@cspell/dict-fullstack": "^2.0.6", - "@cspell/dict-git": "^1.0.1", - "@cspell/dict-golang": "^3.0.1", - "@cspell/dict-haskell": "^2.0.1", - "@cspell/dict-html": "^3.3.2", - "@cspell/dict-html-symbol-entities": "^3.0.0", - "@cspell/dict-java": "^3.0.7", - "@cspell/dict-latex": "^2.0.9", - "@cspell/dict-lorem-ipsum": "^2.0.1", - "@cspell/dict-lua": "^2.0.0", - "@cspell/dict-node": "^3.0.1", - "@cspell/dict-npm": "^3.1.2", - "@cspell/dict-php": "^2.0.0", - "@cspell/dict-powershell": "^2.0.0", - "@cspell/dict-public-licenses": "^1.0.6", - "@cspell/dict-python": "^3.0.6", - "@cspell/dict-r": "^1.0.3", - "@cspell/dict-ruby": "^2.0.2", - "@cspell/dict-rust": "^2.0.1", - "@cspell/dict-scala": "^2.0.0", - "@cspell/dict-software-terms": "^2.2.11", - "@cspell/dict-sql": "^1.0.4", - "@cspell/dict-swift": "^1.0.3", - "@cspell/dict-typescript": "^2.0.2", - "@cspell/dict-vue": "^2.0.2" + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/@cspell/cspell-bundled-dicts/-/cspell-bundled-dicts-6.17.0.tgz", + "integrity": "sha512-BA5cg2mfESbF3Fm/fIGXgbm0LhD8HKxCCiQDRN9FLaj4c69QUgFpQ9LpzGPZEtNn2Pjl2Jn/BEXX27hgaURG9g==", + "dev": true, + "dependencies": { + "@cspell/dict-ada": "^4.0.0", + "@cspell/dict-aws": "^3.0.0", + "@cspell/dict-bash": "^4.1.0", + "@cspell/dict-companies": "^3.0.3", + "@cspell/dict-cpp": "^4.0.0", + "@cspell/dict-cryptocurrencies": "^3.0.1", + "@cspell/dict-csharp": "^4.0.2", + "@cspell/dict-css": "^4.0.0", + "@cspell/dict-dart": "^2.0.0", + "@cspell/dict-django": "^4.0.0", + "@cspell/dict-docker": "^1.1.3", + "@cspell/dict-dotnet": "^4.0.0", + "@cspell/dict-elixir": "^4.0.0", + "@cspell/dict-en_us": "^4.1.0", + "@cspell/dict-en-gb": "1.1.33", + "@cspell/dict-filetypes": "^3.0.0", + "@cspell/dict-fonts": "^3.0.0", + "@cspell/dict-fullstack": "^3.0.0", + "@cspell/dict-git": "^2.0.0", + "@cspell/dict-golang": "^5.0.0", + "@cspell/dict-haskell": "^4.0.0", + "@cspell/dict-html": "^4.0.1", + "@cspell/dict-html-symbol-entities": "^4.0.0", + "@cspell/dict-java": "^5.0.2", + "@cspell/dict-latex": "^3.0.0", + "@cspell/dict-lorem-ipsum": "^3.0.0", + "@cspell/dict-lua": "^3.0.0", + "@cspell/dict-node": "^4.0.1", + "@cspell/dict-npm": "^5.0.0", + "@cspell/dict-php": "^3.0.3", + "@cspell/dict-powershell": "^3.0.0", + "@cspell/dict-public-licenses": "^2.0.0", + "@cspell/dict-python": "^4.0.0", + "@cspell/dict-r": "^2.0.0", + "@cspell/dict-ruby": "^3.0.0", + "@cspell/dict-rust": "^3.0.0", + "@cspell/dict-scala": "^3.0.0", + "@cspell/dict-software-terms": "^3.0.5", + "@cspell/dict-sql": "^2.0.0", + "@cspell/dict-svelte": "^1.0.0", + "@cspell/dict-swift": "^2.0.0", + "@cspell/dict-typescript": "^3.0.1", + "@cspell/dict-vue": "^3.0.0" }, "engines": { "node": ">=14" } }, "node_modules/@cspell/cspell-pipe": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/@cspell/cspell-pipe/-/cspell-pipe-6.12.0.tgz", - "integrity": "sha512-Nkm+tIJ5k+jZPovZCdmZhrWrwRFwnDq+7yCxhov0C7UX3hsSNtTJIpFuaCNEQJ+Whpvxdh1YKflvHiHYygEgTg==", + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/@cspell/cspell-pipe/-/cspell-pipe-6.17.0.tgz", + "integrity": "sha512-/VlX1cQtVBK9PFvSsaYVzV59i/2de9wrMSYDk+oGLXQzGBf5+5rPDZMJJ+QQkaexMdxoOXjCYTEXnNkPoVFyFA==", "dev": true, "engines": { "node": ">=14" } }, "node_modules/@cspell/cspell-service-bus": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/@cspell/cspell-service-bus/-/cspell-service-bus-6.12.0.tgz", - "integrity": "sha512-GgvciSeMUekl8z8vP8//cs5/qRQJSLz9IVREf6fxQW4upjw6zXZ1KonwPqOF5uLocIMAr8eCdrJzHKuKvigJIA==", + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/@cspell/cspell-service-bus/-/cspell-service-bus-6.17.0.tgz", + "integrity": "sha512-HrzR23aeC/ykSOJvUr+uX6Dv7JLc5meNABLxauiC9jexOXFB3DKmo+DvJFerRDOGz6eYSwM0VXAR62OCHrWK/Q==", "dev": true, "engines": { "node": ">=14" } }, "node_modules/@cspell/cspell-types": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/@cspell/cspell-types/-/cspell-types-6.12.0.tgz", - "integrity": "sha512-BcZTt05fNy9SGXfbPgUyxS4FfIaUpcVq8IOJ0noN+jsKsmlbssOUgJOB2ApN1h66FfWcKuFy/uNrjfcrQ7PTqg==", + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/@cspell/cspell-types/-/cspell-types-6.17.0.tgz", + "integrity": "sha512-4FStDRqZVEP6oYtXqj1wUlF02EC5PN7giJ5f4YPeChwXyQBdZWUPQgEIKn0K9GIgKDMlKRo9tloAHVgtaZ+zOA==", "dev": true, "engines": { "node": ">=14" } }, "node_modules/@cspell/dict-ada": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-ada/-/dict-ada-2.0.1.tgz", - "integrity": "sha512-vopTJ1oHrrFYV5GU55Sr+AzItR78Uj5YbCaspYABmYKlq4NRrcUAUsr4bWgymDcspMIHO7e7IFcj48OKs1fndA==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-ada/-/dict-ada-4.0.0.tgz", + "integrity": "sha512-M0n4ZYmpLOXbDD07Qb/Ekk0K5pX2C+mCuJ2ZxPgbTq9HGlrN43PmqrGJHWcgtVHE3fd1D4VxS85QcQP6r1Y+KQ==", "dev": true }, "node_modules/@cspell/dict-aws": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-aws/-/dict-aws-2.0.0.tgz", - "integrity": "sha512-NKz7pDZ7pwj/b33i3f4WLpC1rOOUMmENwYgftxU+giU2YBeKM2wZbMTSEIzsrel56r0UlQYmdIVlP/B4nnVaoQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-aws/-/dict-aws-3.0.0.tgz", + "integrity": "sha512-O1W6nd5y3Z00AMXQMzfiYrIJ1sTd9fB1oLr+xf/UD7b3xeHeMeYE2OtcWbt9uyeHim4tk+vkSTcmYEBKJgS5bQ==", "dev": true }, "node_modules/@cspell/dict-bash": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@cspell/dict-bash/-/dict-bash-2.0.4.tgz", - "integrity": "sha512-uK/ehmp5LYrmRH2Gv3nbvdPswpkybJUn34WYKLpeuYHQktmi+pOI1A9uPdBPnSbMDffSvwQlQohIyKawz+X8Ag==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-bash/-/dict-bash-4.1.0.tgz", + "integrity": "sha512-8pFL03ZKejynfbsa2UZ3iZ7BrT1TAGTD8ZlK822ioAb7aoDvQhYao2Bjz5cXU0uk7CyrlgsSnYX94sLfqDfTxQ==", "dev": true }, "node_modules/@cspell/dict-companies": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/@cspell/dict-companies/-/dict-companies-2.0.14.tgz", - "integrity": "sha512-Sq1X29Z05OZ/UNqTwVhf3/WaqvJQy4/S6gS8qYI5AQRX45gVe8CPhNBLmZOTC6z8m716bfQCxa5rRT9YNSdTZg==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@cspell/dict-companies/-/dict-companies-3.0.3.tgz", + "integrity": "sha512-qBWdwA97HdnLbxPLOUTZ+/mg9eYhi14hM7PEUM1PZ004MEIxQHum0IQpypKAwP3teR1KEsyxEPHp8v24Dw45Zg==", "dev": true }, "node_modules/@cspell/dict-cpp": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-cpp/-/dict-cpp-3.2.1.tgz", - "integrity": "sha512-XcmzrKIghqFfrYLLaHtWKOp9rupiuGdc5ODONk+emsq0W5CIc3Abn27IQHwUzxzF+Cm5IfKAIJ5Kpe6hkzm0HQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-cpp/-/dict-cpp-4.0.0.tgz", + "integrity": "sha512-NrCmer14tTSbPs1TwqyCjFEmWCBw0UFvAn4O3pdWuxktArHxRJ5vUQOoL2Gus2H9s3ihhOJZkcuJ47Kd21E7BQ==", "dev": true }, "node_modules/@cspell/dict-cryptocurrencies": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-cryptocurrencies/-/dict-cryptocurrencies-2.0.0.tgz", - "integrity": "sha512-nREysmmfOp7L2YCRAUufQahwD5/Punzb5AZ6eyg4zUamdRWHgBFphb5/9h2flt1vgdUfhc6hZcML21Ci7iXjaA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-cryptocurrencies/-/dict-cryptocurrencies-3.0.1.tgz", + "integrity": "sha512-Tdlr0Ahpp5yxtwM0ukC13V6+uYCI0p9fCRGMGZt36rWv8JQZHIuHfehNl7FB/Qc09NCF7p5ep0GXbL+sVTd/+w==", "dev": true }, "node_modules/@cspell/dict-csharp": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-csharp/-/dict-csharp-3.0.1.tgz", - "integrity": "sha512-xkfQu03F388w4sdVQSSjrVMkxAxpTYB2yW7nw0XYtTjl3L/jBgvTr/j1BTjdFbQhdNf10Lg0Ak1kXOjmHodVqA==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@cspell/dict-csharp/-/dict-csharp-4.0.2.tgz", + "integrity": "sha512-1JMofhLK+4p4KairF75D3A924m5ERMgd1GvzhwK2geuYgd2ZKuGW72gvXpIV7aGf52E3Uu1kDXxxGAiZ5uVG7g==", "dev": true }, "node_modules/@cspell/dict-css": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-css/-/dict-css-2.1.0.tgz", - "integrity": "sha512-glASAELcGhh4Ru0rTQ4G9mTQxSyPwsZOON/5BYflB6Kks8YC8nUvKrtMCoo5W7CPKPfSEa8zUNctFQ1+IUYDHA==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-css/-/dict-css-4.0.0.tgz", + "integrity": "sha512-ieSeG9KAJGIr5eK0JRWqD5KXstPPUw6JUTmGWc7P/qiqj/sjmhWqWKEt7HhoSNcb8uQxAkAoxhrNpfbKzqnKAw==", "dev": true }, "node_modules/@cspell/dict-dart": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-dart/-/dict-dart-1.1.1.tgz", - "integrity": "sha512-XBOCpezXrgFN18kGEwqMpTUGZdw4BjCoJrNOo6qBdcdZySCrEHLwELraLOkcSba2kM4stmTp0t59FkwtP8TKOA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-dart/-/dict-dart-2.0.0.tgz", + "integrity": "sha512-p7vHszsu2uJt+F04gvNy1e5okypFfVEYHBWgpOV/Jrvs0F5A+gUzFTG2Ix9b1jkCigAULYKQkIGue+qlhSoK5Q==", "dev": true }, "node_modules/@cspell/dict-de-de": { @@ -3566,33 +3627,33 @@ "dev": true }, "node_modules/@cspell/dict-django": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-django/-/dict-django-2.0.0.tgz", - "integrity": "sha512-GkJdJv6cmzrKcmq2/oxTXjKF5uv71r4eTqnFmgPbNBW1t+G4VYpzOf0QrVQrhx2RC4DdW5XfcTf+iS0FxHOTmw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-django/-/dict-django-4.0.0.tgz", + "integrity": "sha512-k0npSzQrPQSqjR2XtumV14sv9waTRMUzPx0UfOuJZcnCCZY8ofPeqFYoku+O+9Kc9etFOziOxnScshKVDzYWOQ==", "dev": true }, "node_modules/@cspell/dict-docker": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-docker/-/dict-docker-1.1.1.tgz", - "integrity": "sha512-UEYoeRDm7oUN9yz1mYSozz6D4+2N14S/cd2Re9et6Xzq6yi62s4ky3knF92Of2weelADjnN41UA22VBhRAf7Sw==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@cspell/dict-docker/-/dict-docker-1.1.3.tgz", + "integrity": "sha512-Iz7EQGnLBgnnmzCC8iLQ7JssCCQlCjZLiCs0qhooETWLifob3nzsI9AVBh3gkYLhISLIIjBpfa4LTknskT7LzA==", "dev": true }, "node_modules/@cspell/dict-dotnet": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-dotnet/-/dict-dotnet-2.0.1.tgz", - "integrity": "sha512-b1n4crJRW0WZVf9Gp/52j/tDtjYiZ3N81fIyfqPlBrjsh/5AivfA697DYwQ2mr8ngNX7RsqRtYNQjealA1rEnQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-dotnet/-/dict-dotnet-4.0.0.tgz", + "integrity": "sha512-biZiTWyDqwVV2m+c17lLIliPDXPjOR1VwwmyMxvb3nFS84aP9x52SAVCf0w7Io1CIpUiY7XnG6/xeI7esYU78w==", "dev": true }, "node_modules/@cspell/dict-elixir": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-elixir/-/dict-elixir-2.0.1.tgz", - "integrity": "sha512-eTTTxZt1FqGkM780yFDxsGHvTbWqvlK8YISSccK8FyrB6ULW+uflQlNS5AnWg3uWKC48b7pQott+odYCsPJ+Ow==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-elixir/-/dict-elixir-4.0.0.tgz", + "integrity": "sha512-0TqqdQjg/zu3wAjk2FQkZ87pPIS9tA9kl6he5NJB729ysrWhND/7aSPC48QrP46VZ+oFrvFZK8DC8ZlYs16cjQ==", "dev": true }, "node_modules/@cspell/dict-en_us": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/@cspell/dict-en_us/-/dict-en_us-2.3.3.tgz", - "integrity": "sha512-csyKeaNktfpvMkmE2GOPTwsrQm3wWhLKVaDRaGU0qTcIjDiCvqv/iYgrVrKRkoddA3kdNTZ8YNCcix7lb6VkOg==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-en_us/-/dict-en_us-4.1.0.tgz", + "integrity": "sha512-EnfxP/5U3kDhmTWcHV7Xs2Fxa9KAE5fbHm+4u8LGBOUZvSkZC5+ayjQ50CfEyTGuaI/946ITQYPRNxUZ7oqOiQ==", "dev": true }, "node_modules/@cspell/dict-en-gb": { @@ -3602,15 +3663,15 @@ "dev": true }, "node_modules/@cspell/dict-filetypes": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-filetypes/-/dict-filetypes-2.1.1.tgz", - "integrity": "sha512-Oo0/mUbFHzsaATqRLdkV1RMoYns3aGzeKFIpVJg415GYtJ8EABXtEArYTXeMwlboyGTPvEk+PR2hBSTSfQTqmg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-filetypes/-/dict-filetypes-3.0.0.tgz", + "integrity": "sha512-Fiyp0z5uWaK0d2TfR9GMUGDKmUMAsOhGD5A0kHoqnNGswL2iw0KB0mFBONEquxU65fEnQv4R+jdM2d9oucujuA==", "dev": true }, "node_modules/@cspell/dict-fonts": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-fonts/-/dict-fonts-2.1.0.tgz", - "integrity": "sha512-hk7xsbfWEUhc136Xj7I2TD7ouKAfWwzCVAQaHBxcVXAsVxu7bDOGj4FvE2jBzlkSUY8A9Ww8qS0GOFvowJshVg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-fonts/-/dict-fonts-3.0.0.tgz", + "integrity": "sha512-zTZni0AbwBVG1MKA0WpwPyIJPVF+gp6neXDQzHcu4RUnuQ4uDu0PVEuZjGHCJWwwFoR5JmkqZxVSg1y3ufJODA==", "dev": true }, "node_modules/@cspell/dict-fr-fr": { @@ -3620,155 +3681,170 @@ "dev": true }, "node_modules/@cspell/dict-fullstack": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@cspell/dict-fullstack/-/dict-fullstack-2.0.6.tgz", - "integrity": "sha512-R2E2xvbHvvRwwurxfpBJDRIJjXBMfEPF5WNV3LTOEMRqkZtoYCeJK9aqc8LHlmJMtAbnN1cx//BCDIyTJ0rO0A==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-fullstack/-/dict-fullstack-3.0.0.tgz", + "integrity": "sha512-BMQRTaeReLufjMwgWqqwPdrXQ7jkVGTv7/YvOLsHFZvcAP3eM7WqX+rvdXckLhJmuuzbceFRDKs5F/9Ig2x/tQ==", "dev": true }, "node_modules/@cspell/dict-git": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-git/-/dict-git-1.0.1.tgz", - "integrity": "sha512-Rk+eTof/9inF11lvxmkCRK+gODatA3qai8kSASv6OG/JfPvpj7fTHErx/rdgPw/LOTDUafnoTjTYmj7B2MOQXg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-git/-/dict-git-2.0.0.tgz", + "integrity": "sha512-n1AxyX5Kgxij/sZFkxFJlzn3K9y/sCcgVPg/vz4WNJ4K9YeTsUmyGLA2OQI7d10GJeiuAo2AP1iZf2A8j9aj2w==", "dev": true }, "node_modules/@cspell/dict-golang": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-golang/-/dict-golang-3.0.1.tgz", - "integrity": "sha512-0KNfXTbxHW2l8iVjxeOf+KFv9Qrw3z5cyKnkuYJWlBTSB5KcUBfeKCb4fsds26VdANqiy6U91b4gDx5kNEmBjQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-golang/-/dict-golang-5.0.0.tgz", + "integrity": "sha512-Cbx4mVHsGbr5D+wlT0yU3n/0c5iLvciU48rSOQR7SCAzu5mTXyM1mqRu6nqnRiMv6G6mO50EL2LCTq6RZrlIOg==", "dev": true }, "node_modules/@cspell/dict-haskell": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-haskell/-/dict-haskell-2.0.1.tgz", - "integrity": "sha512-ooA23qIG7InOOxlLm67CNH5O2J85QsPHEAzEU9KEqVfYG5ovFs5tx6n9pHekDVk3MpQULpqfNUYDR0KigPLg5g==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-haskell/-/dict-haskell-4.0.0.tgz", + "integrity": "sha512-U/DPpDoitGeUvduM9teDkDc1zs4Plgh0pNONDP3YbsEICErSlp1NfatD0i35Z6cR0C7I8uEe4gG2phG00zrSqw==", "dev": true }, "node_modules/@cspell/dict-html": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/@cspell/dict-html/-/dict-html-3.3.2.tgz", - "integrity": "sha512-cM5pQSEiqjrdk6cRFLrlLdWNT/J8399f/A6DjwjfYhHrGy0e/Rsjv76HZT0GlE1OqMoq9eG9jdQsfoYYgWTIpQ==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-html/-/dict-html-4.0.1.tgz", + "integrity": "sha512-q5fCzkoOz+8BW79qLrnANEDnG+Jb2WS2fXERxg9xwgKBXwXUxH8ttGVNhfkLpNWe/UMm00U1IZMnVGyYLNTO5w==", "dev": true }, "node_modules/@cspell/dict-html-symbol-entities": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-html-symbol-entities/-/dict-html-symbol-entities-3.0.0.tgz", - "integrity": "sha512-04K7cPTcbYXmHICfiob4gZA1yaj4hpfM+Nl5WIJ1EAZsSGHdqmGEF28GuCjyQ8ZeKiJAsPt/vXuLBbjxkHqZyQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-html-symbol-entities/-/dict-html-symbol-entities-4.0.0.tgz", + "integrity": "sha512-HGRu+48ErJjoweR5IbcixxETRewrBb0uxQBd6xFGcxbEYCX8CnQFTAmKI5xNaIt2PKaZiJH3ijodGSqbKdsxhw==", "dev": true }, "node_modules/@cspell/dict-java": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@cspell/dict-java/-/dict-java-3.0.7.tgz", - "integrity": "sha512-IL7ubsRvKX6dZSx++TplJCfhiS7kkEGpbTPG0gMEP50DTNAVM4icZS8zmer2UBCU5PTwF85abJjdX7mRADWKVg==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@cspell/dict-java/-/dict-java-5.0.2.tgz", + "integrity": "sha512-HWgdp8plZOdYjOkndwmgHGVxoewylZcl886PqSL6TMcDshyI0+2nePft31nIuALRvt7HL8IX++DM1uk4UfY4kg==", "dev": true }, "node_modules/@cspell/dict-latex": { - "version": "2.0.9", - "resolved": "https://registry.npmjs.org/@cspell/dict-latex/-/dict-latex-2.0.9.tgz", - "integrity": "sha512-d1kTK6dJb5z6UcfASQWjqQlsjZvnoVOvMWxYtLpGksYf6gM4IgqoPVNMLYYK6xBS4T/uAnLIj975A6YuAeyZpg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-latex/-/dict-latex-3.0.0.tgz", + "integrity": "sha512-QsRWj+Jll4ueVbce8ofKa743oQ2exmbVNZN70MaMbmu8PSbjW2+Rj3OdExVStesANMj7qc20inS/TgPr8DrInQ==", "dev": true }, "node_modules/@cspell/dict-lorem-ipsum": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-lorem-ipsum/-/dict-lorem-ipsum-2.0.1.tgz", - "integrity": "sha512-s7Ft8UiloUJwgz4z8uLeFvCkeTcZ43HQl7mSAlZd76eW+keLSsdeGmLDx2zaciqo+MftPGyzygVCwaJjTGxiew==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-lorem-ipsum/-/dict-lorem-ipsum-3.0.0.tgz", + "integrity": "sha512-msEV24qEpzWZs2kcEicqYlhyBpR0amfDkJOs+iffC07si9ftqtQ+yP3lf1VFLpgqw3SQh1M1vtU7RD4sPrNlcQ==", "dev": true }, "node_modules/@cspell/dict-lua": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-lua/-/dict-lua-2.0.0.tgz", - "integrity": "sha512-7WUEBEspSKtsq104WdIys1+DLqAxpJPzw74Py1TuE3fI5GvlzeSZkRFP2ya54GB2lCO4C3mq4M8EnitpibVDfw==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-lua/-/dict-lua-3.0.0.tgz", + "integrity": "sha512-WOhSCgS5wMxkGQJ8siB90iTB9ElquJB7FeqYSbJqqs6cUwH8G7MM/CEDPL6h7vCo0+v3GuxQ8yKWDSUcUhz9Lg==", "dev": true }, "node_modules/@cspell/dict-node": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-node/-/dict-node-3.0.1.tgz", - "integrity": "sha512-sK2cpuV0EAc43Amd5xeQXkI9MeRTECMw+yjap06gKSModbgI7BqJUHeKZed+0Hii+LpaJ4TYpLGiRVsO+qSk0w==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-node/-/dict-node-4.0.1.tgz", + "integrity": "sha512-4EmT5yZFitdwnG0hYEd+Ek19zzD81Bp+n7w0kglZKldS5AvapwW6GM/SAps5YMQQc5zZMi+bMgV7NIzapREqUg==", "dev": true }, "node_modules/@cspell/dict-npm": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/@cspell/dict-npm/-/dict-npm-3.1.3.tgz", - "integrity": "sha512-xnGp+TMpArdMLBUSG+ZrbEuhvY016rb76Yh35/OPDDEEz4ulENxLSZJxtN2/A0tZ9FJngDNSdFh7eJsOFmciZQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-npm/-/dict-npm-5.0.0.tgz", + "integrity": "sha512-eegoQrzfAl6yht+BgQu7YkqeKbVb3FsFIobW3pBE/c8TqEnfnxRHnS4/e80PA16rO9uJgSF5iKBxTbtEIGYvsg==", "dev": true }, "node_modules/@cspell/dict-php": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-php/-/dict-php-2.0.0.tgz", - "integrity": "sha512-29WgU77eTO985LvMHwPi1pcpfopfCWfTdffDyqya0JIfOSaFUrlYKzGPkE4mRxcz2G3hXsaM0SRvBNdIRwEdUg==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@cspell/dict-php/-/dict-php-3.0.3.tgz", + "integrity": "sha512-7dvXdPTfbIF2xEob9w94/eV5SU8BkYoN0R7EQghXi0fcF7T1unK+JwDgfoEs6wqApB5aCVYwguiaj8HGX2IRIQ==", "dev": true }, "node_modules/@cspell/dict-powershell": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-powershell/-/dict-powershell-2.0.0.tgz", - "integrity": "sha512-6uvEhLiGmG3u9TFkM1TYcky6aL9Yk7Sk3KJwoTYBaQJY2KqrprgyQtW6yxIw9oU52VRHlq3KKvSAA9Q26+SIkQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-powershell/-/dict-powershell-3.0.0.tgz", + "integrity": "sha512-pkztY9Ak4oc33q+Qxcn9/CTOKo4N8YIRRE6v67WwQOncA5QIJfcOPUrjfR3Z8SpzElXhu3s9qtWWSqbCy6qmcA==", "dev": true }, "node_modules/@cspell/dict-public-licenses": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@cspell/dict-public-licenses/-/dict-public-licenses-1.0.6.tgz", - "integrity": "sha512-Z9IUFPkkOpOsEdgPUfQOJNQ+qU6+iBAZWS/CR5sUqTX+s5VkPNVwQyVC2kdmgmE2U5qwzAPewG6nVKr2MVogwg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-public-licenses/-/dict-public-licenses-2.0.0.tgz", + "integrity": "sha512-NdMHnS6xiYJKlzVoTV5CBhMiDpXMZ/PDcvXiOpxeR50xkjR18O/XFP4f4eDZpxGiBSUCMFRWf4JjILJ04Rpcfg==", "dev": true }, "node_modules/@cspell/dict-python": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@cspell/dict-python/-/dict-python-3.0.6.tgz", - "integrity": "sha512-tzxJ4sd9ZGhAUKg/WJJpQGDNtoHvM8Wn+iS2+PnQj2/LTHBW4mnaCogsGsBtYu8C4b2+BEQs+tc5808AeEfLug==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-python/-/dict-python-4.0.0.tgz", + "integrity": "sha512-MC6CKbYOly3Ig25ZnhlCzPbE/QozqfQv4VYW6HcoMQ5IbHu33ddf2lzkZ89qTXlxsF5NT5qfZEkQYHYuhuL6AQ==", "dev": true }, "node_modules/@cspell/dict-r": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@cspell/dict-r/-/dict-r-1.0.3.tgz", - "integrity": "sha512-u2qeXd4cx/TvTVcmkvA+sK6f4K1uMAMO6QPMSr1pSvqGElPRP1mIBXmuiSuBzLO3LbsJuUEHw5Cp3/bxIB6rNA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-r/-/dict-r-2.0.0.tgz", + "integrity": "sha512-rdt1cKc3VL2uXJ2X088gRhTFreN/MkJWK1jccW1EWdFHLzDwhKfrlAkoLCp0paD6HvmloLQ+eSR09D58DdsYfA==", "dev": true }, "node_modules/@cspell/dict-ruby": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@cspell/dict-ruby/-/dict-ruby-2.0.2.tgz", - "integrity": "sha512-vVnUpSmGDbPjs7MHq741DsLHhQcoA4CnUCM9wsTorQ9AQRDAkDTbK/LcY8nM19MoXCb3eF8PFku5Jq+gqH0u7w==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-ruby/-/dict-ruby-3.0.0.tgz", + "integrity": "sha512-sA98T8Y1Pmq3RStVkO14E8vTWkq6JUn8c8PldiMyYgV0yfQgwhQfFAzlSfF3Gg2B0VkIdqt2et2SPN7f9wp7fQ==", "dev": true }, "node_modules/@cspell/dict-rust": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-rust/-/dict-rust-2.0.1.tgz", - "integrity": "sha512-ATDpIh0VWpQdUIZa8zqqJY4wQz3q00BTXlQCodeOmObYSb23+L6KWWzJ8mKLgpbc1lqTkogWrqxiCxlrCmqNmg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-rust/-/dict-rust-3.0.0.tgz", + "integrity": "sha512-L1T1IBsYJZVDmfOGAbVLcpc6arWxRRCSJYvHSwEDBGrNuMyJ4jx/NvBEz5crcKf4vVKgwVlXgzQlJJZ8AVxU9w==", "dev": true }, "node_modules/@cspell/dict-scala": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-scala/-/dict-scala-2.0.0.tgz", - "integrity": "sha512-MUwA2YKpqaQOSR4V1/CVGRNk8Ii5kf6I8Ch+4/BhRZRQXuwWbi21rDRYWPqdQWps7VNzAbbMA+PQDWsD5YY38g==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-scala/-/dict-scala-3.0.0.tgz", + "integrity": "sha512-sIiCQDIMMnNns/fzD61z5npbh5pypaKq07Orqe0+eRfdQpika8iRSGUGFHVbtdd1JzB1DyTCV2e8OwdaQiXqJQ==", "dev": true }, "node_modules/@cspell/dict-software-terms": { - "version": "2.2.12", - "resolved": "https://registry.npmjs.org/@cspell/dict-software-terms/-/dict-software-terms-2.2.12.tgz", - "integrity": "sha512-wVVy4on8Uq5VAWm3cqrrhewTRRbpmNxtmTURGQ5rT6FqUtJvZ7W2Pj3QquzXsA9zSFZhGFQR3U7IdFesET9yAg==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@cspell/dict-software-terms/-/dict-software-terms-3.0.5.tgz", + "integrity": "sha512-xZVcX1zsIUbLvUc/RX+YgJRvbHaGMcdkRR+Vw8UoLjmhnT0yXWLds5uwRwAVjlQIrIcHylfDWuG70Cq5nmJHfA==", "dev": true }, "node_modules/@cspell/dict-sql": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@cspell/dict-sql/-/dict-sql-1.0.4.tgz", - "integrity": "sha512-+9nMcwsCzdYH0tyv2LeuVvQ+DdecS2C1N+hw6sl0FTHWI5GwULHAGW840RBwcKw0s+dl7sc0WpZhS1EW7b0pXg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-sql/-/dict-sql-2.0.0.tgz", + "integrity": "sha512-J3X8VSgWpc/4McQEs138abtBw/SO3Z+vGaYi5X7XV1pKPBxjupHTTNQHSS/HWUDmVWj6fR3OV+ZGptcmvv3Clg==", + "dev": true + }, + "node_modules/@cspell/dict-svelte": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-svelte/-/dict-svelte-1.0.0.tgz", + "integrity": "sha512-5mE1bPMv+0Zdv6fiaHw86kZ47FhqNy9waUyGOT/wSWf6M5lxCZ3ze15rDruit6/62DaYo7A4/1dgKxpRo6/ZBQ==", "dev": true }, "node_modules/@cspell/dict-swift": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@cspell/dict-swift/-/dict-swift-1.0.3.tgz", - "integrity": "sha512-yOBLSaRD0AnkkkndJ8PuB82Evp6lA2xItf2AWsnPfCCgxp5Ojk6uUBC/WQBSkzkCAOGbXyHsu9D97tsOx2c6cw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-swift/-/dict-swift-2.0.0.tgz", + "integrity": "sha512-VStJ0fKPPNIXKmxJrbGH6vKNtJCwAnQatfSH0fVj+Unf3QHHlmuLKRG0cN0aVgEIolpRkxNXJcSB3CPbYr0Xhw==", "dev": true }, "node_modules/@cspell/dict-typescript": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@cspell/dict-typescript/-/dict-typescript-2.0.2.tgz", - "integrity": "sha512-OIoSJsCw9WHX4eDikoF5/0QbptMPZjElOcMYdYCyV03nqV5n4ot72ysTexW95yW4+fQU6uDPNQvnrUnhXXEkTA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-typescript/-/dict-typescript-3.0.1.tgz", + "integrity": "sha512-nKEtOpj+rJNIUK268/mCFDCIv1MWFdK1efm9YL4q1q3NHT+qCKhkXoA0eG8k4AaDIpsvebB8CgNIYFPxY92r4A==", "dev": true }, "node_modules/@cspell/dict-vue": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@cspell/dict-vue/-/dict-vue-2.0.2.tgz", - "integrity": "sha512-/MB0RS0Gn01s4pgmjy0FvsLfr3RRMrRphEuvTRserNcM8XVtoIVAtrjig/Gg0DPwDrN8Clm0L1j7iQay6S8D0g==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-vue/-/dict-vue-3.0.0.tgz", + "integrity": "sha512-niiEMPWPV9IeRBRzZ0TBZmNnkK3olkOPYxC1Ny2AX4TGlYRajcW0WUtoSHmvvjZNfWLSg2L6ruiBeuPSbjnG6A==", "dev": true }, + "node_modules/@cspell/strong-weak-map": { + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/@cspell/strong-weak-map/-/strong-weak-map-6.17.0.tgz", + "integrity": "sha512-fRghm6eoUEH7Uz57t0SEKJNm4lqODF2/DRiLd2ek7QkzUHKrCetre/5UrvdE78GIUyl0+8GLx9iFwo/XFa6dDA==", + "dev": true, + "engines": { + "node": ">=14.6" + } + }, "node_modules/@cspotcode/source-map-support": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", @@ -4082,9 +4158,9 @@ } }, "node_modules/@es-joy/jsdoccomment": { - "version": "0.31.0", - "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.31.0.tgz", - "integrity": "sha512-tc1/iuQcnaiSIUVad72PBierDFpsxdUHtEF/OrfqvM1CBAsIoMP51j52jTMb3dXriwhieTo289InzZj72jL3EQ==", + "version": "0.36.1", + "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.36.1.tgz", + "integrity": "sha512-922xqFsTpHs6D0BUiG4toiyPOMc8/jafnWKxz1KWgS4XzKPy2qXf1Pe6UFuNSCQqt6tOuhAWXBNuuyUhJmw9Vg==", "dev": true, "dependencies": { "comment-parser": "1.3.1", @@ -4092,7 +4168,7 @@ "jsdoc-type-pratt-parser": "~3.1.0" }, "engines": { - "node": "^14 || ^16 || ^17 || ^18" + "node": "^14 || ^16 || ^17 || ^18 || ^19" } }, "node_modules/@esbuild/linux-loong64": { @@ -4111,10 +4187,25 @@ "node": ">=12" } }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.1.2.tgz", + "integrity": "sha512-7qELuQWWjVDdVsFQ5+beUl+KPczrEDA7S3zM4QUd/bJl7oXgsmpXaEVqrRTnOBqenOV4rWf2kVZk2Ot085zPWA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, "node_modules/@eslint/eslintrc": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.2.tgz", - "integrity": "sha512-AXYd23w1S/bv3fTs3Lz0vjiYemS08jWkI3hYyS9I1ry+0f+Yjs1wm+sU0BS8qDOPrBIkp4qHYC16I8uVtpLajQ==", + "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", @@ -4161,9 +4252,9 @@ } }, "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==", + "version": "13.19.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz", + "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -4271,33 +4362,33 @@ } }, "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==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.2.1.tgz", + "integrity": "sha512-Sz07mnQrTekFWLz5BMjOzHl/+NooTdW8F8kDQxjWwbpOJcnoSg4vUDng8d/WR1wOxM0O+CY9Zw0nR054riNYtQ==", "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==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.2.1.tgz", + "integrity": "sha512-HELwwbCz6C1XEcjzyT1Jugmz2NNklMrSPjZOWMlc+ZsHIVk+XOvOXLGGQtFBwSyqfJDNgRq4xBCwWOaZ/d9DEA==", "hasInstallScript": true, "dependencies": { - "@fortawesome/fontawesome-common-types": "6.2.0" + "@fortawesome/fontawesome-common-types": "6.2.1" }, "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==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.2.1.tgz", + "integrity": "sha512-oKuqrP5jbfEPJWTij4sM+/RvgX+RMFwx3QZCZcK9PrBDgxC35zuc7AOFsyMjMd/PIFPeB2JxyqDr5zs/DZFPPw==", "hasInstallScript": true, "dependencies": { - "@fortawesome/fontawesome-common-types": "6.2.0" + "@fortawesome/fontawesome-common-types": "6.2.1" }, "engines": { "node": ">=6" @@ -4310,22 +4401,22 @@ "dev": true }, "node_modules/@googlemaps/js-api-loader": { - "version": "1.14.3", - "resolved": "https://registry.npmjs.org/@googlemaps/js-api-loader/-/js-api-loader-1.14.3.tgz", - "integrity": "sha512-6iIb+qpGgQpgIHmIFO44WhE1rDUxPVHuezNFL30wRJnkvhwFm94tD291UvNg9L05hLDSoL16jd0lbqqmdy4C5g==", + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/@googlemaps/js-api-loader/-/js-api-loader-1.15.1.tgz", + "integrity": "sha512-AsnEgNsB7S/VdrHGEQUaUM2e5tmjFGKBAfzR/AqO8O7TPq/jQGvoRw5liPBw4EMF38RDsHmKDV89q/X+qiUREQ==", "dependencies": { "fast-deep-equal": "^3.1.3" } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.10.7", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.7.tgz", - "integrity": "sha512-MDl6D6sBsaV452/QSdX+4CXIjZhIcI0PELsxUjk4U828yd58vk3bTIvk/6w5FY+4hIy9sLW0sfrV7K7Kc++j/w==", + "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.4" + "minimatch": "^3.0.5" }, "engines": { "node": ">=10.10.0" @@ -4353,16 +4444,6 @@ "node": "*" } }, - "node_modules/@humanwhocodes/gitignore-to-minimatch": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/gitignore-to-minimatch/-/gitignore-to-minimatch-1.0.2.tgz", - "integrity": "sha512-rSqmMJDdLFUsyxR6FMtD00nfQKKLFb1kv+qBbOVKqErvloEIJLo5bDTJTQNTYgeyp78JsA7u/NPi5jT1GR/MuA==", - "dev": true, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", @@ -5356,9 +5437,9 @@ } }, "node_modules/@ngtools/webpack": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-14.2.5.tgz", - "integrity": "sha512-Thwq1WyOOq1PIWMcjAAqKI1hbvGC0ywxbNoDadOlWpEFm6k0dvXC6Zm9lnVkePjxlPfagvbnv55+Lv9Vmygc1g==", + "version": "14.2.10", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-14.2.10.tgz", + "integrity": "sha512-sLHapZLVub6mEz5b19tf1VfIV1w3tYfg7FNPLeni79aldxu1FbP1v2WmiFAnMzrswqyK0bhTtxrl+Z/CLKqyoQ==", "dev": true, "engines": { "node": "^14.15.0 || >=16.10.0", @@ -5372,14 +5453,14 @@ } }, "node_modules/@nguniversal/builders": { - "version": "14.2.0", - "resolved": "https://registry.npmjs.org/@nguniversal/builders/-/builders-14.2.0.tgz", - "integrity": "sha512-7rElvsL1OdLtYmn1zNwijga21KhDtjkhuM2o2Mwqafiud3a4zfxzmdv/hOAvFapVTlpUYgb+m4pBwq7V4DYiUA==", + "version": "14.2.3", + "resolved": "https://registry.npmjs.org/@nguniversal/builders/-/builders-14.2.3.tgz", + "integrity": "sha512-4WpQ5zMfw4BIH/2ymWchFm2bbN8w0/sC0Rg3IracJ9ESsfTJMaIg8CzVer6NBqC+5As9iLZwau7nrfzt7sQf1A==", "dev": true, "dependencies": { "@angular-devkit/architect": "^0.1402.0", "@angular-devkit/core": "^14.2.0", - "@nguniversal/common": "14.2.0", + "@nguniversal/common": "14.2.3", "browser-sync": "^2.26.7", "express": "^4.17.1", "guess-parser": "^0.4.12", @@ -5415,9 +5496,9 @@ "dev": true }, "node_modules/@nguniversal/common": { - "version": "14.2.0", - "resolved": "https://registry.npmjs.org/@nguniversal/common/-/common-14.2.0.tgz", - "integrity": "sha512-6dpPSpCo6Kz4OrFa0RRFu8kmR6QDAEhwgTjD2MNU+WVf5ngwBAcakxW5/3bIx6A17et+Zr1/EVyhpyXFYSUjhw==", + "version": "14.2.3", + "resolved": "https://registry.npmjs.org/@nguniversal/common/-/common-14.2.3.tgz", + "integrity": "sha512-FWoZY+DZCNw24tNnnWkgTpNAlshkfiaxiT7V+fx2WFpY0LNXLWk45+hWhl4+wFEknOXr/DT/oU1m/RjR6FgXZQ==", "dependencies": { "critters": "0.0.16", "jsdom": "20.0.0", @@ -5432,11 +5513,11 @@ } }, "node_modules/@nguniversal/express-engine": { - "version": "14.2.0", - "resolved": "https://registry.npmjs.org/@nguniversal/express-engine/-/express-engine-14.2.0.tgz", - "integrity": "sha512-t6JlyjXuC4CAD2YIcO7uTiEQ88qgRauWivrpy0YqH37M3jw7OE10NmSxTxsorN8b+A6xcHEJ7mXFVHD03gxbeQ==", + "version": "14.2.3", + "resolved": "https://registry.npmjs.org/@nguniversal/express-engine/-/express-engine-14.2.3.tgz", + "integrity": "sha512-8G60LgQViz7caJbmL5f0Cw3mUtchVOiLUf9q1PKKhPVYMv9PVs1roKWuq1yAd4ZVMztBo93gyPt8vQGOo+C9WA==", "dependencies": { - "@nguniversal/common": "14.2.0", + "@nguniversal/common": "14.2.3", "tslib": "^2.3.0" }, "engines": { @@ -5450,22 +5531,17 @@ } }, "node_modules/@ngx-formly/core": { - "version": "5.12.7", - "resolved": "https://registry.npmjs.org/@ngx-formly/core/-/core-5.12.7.tgz", - "integrity": "sha512-WE4mVbIgWJ6zVf6WdQTUjQ17th/iZTW5pYlF43JdWxhwzmY6IX/NA2Qg7N4gtdlV3+Z+iSytcocBVx8G4kukZA==", + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@ngx-formly/core/-/core-6.0.4.tgz", + "integrity": "sha512-GH+uIwNivI7EmqIRcGwyWa+CXPBY3ihWi05foMsYV7ghADe2Ap6mHaYdKoejMItLoWz79CrV2pYfwrnjlE3KOQ==", "dependencies": { - "tslib": "^1.7.1" + "tslib": "^2.0.0" }, "peerDependencies": { - "@angular/forms": ">=7.0.0", - "rxjs": ">=6.3.0" + "@angular/forms": ">=13.2.0", + "rxjs": "^6.5.3 || ^7.0.0" } }, - "node_modules/@ngx-formly/core/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - }, "node_modules/@ngx-translate/core": { "version": "14.0.0", "resolved": "https://registry.npmjs.org/@ngx-translate/core/-/core-14.0.0.tgz", @@ -5937,13 +6013,13 @@ } }, "node_modules/@schematics/angular": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-14.2.5.tgz", - "integrity": "sha512-oYtQJi68EcDK940fny9t12JGE6z/ZbLeCZs+cPh4XT7ytRdO4anypBtKx18+E+b6jUnox4FxIGOf2WpkSAosYA==", + "version": "14.2.10", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-14.2.10.tgz", + "integrity": "sha512-YFTc/9QJdx422XcApizEcVLKoyknu8b9zHIlAepZCu7WkV8GPT0hvVEHQ7KBWys5aQ7pPZMT0JpZLeAz0F2xYQ==", "dev": true, "dependencies": { - "@angular-devkit/core": "14.2.5", - "@angular-devkit/schematics": "14.2.5", + "@angular-devkit/core": "14.2.10", + "@angular-devkit/schematics": "14.2.10", "jsonc-parser": "3.1.0" }, "engines": { @@ -5953,13 +6029,13 @@ } }, "node_modules/@sentry/browser": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-7.14.1.tgz", - "integrity": "sha512-b9nW2+kT9Jl/tfzJmvzpnS6F8ziC62TDx04a7kZDtuaVA5rKKTTlLDg8ZamCRFjjnuwuFhLnzxO34N0KfeTqHg==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-7.25.0.tgz", + "integrity": "sha512-vBNWDv8SUtJqgw/Mg9hGxct7dzHucfxq1zfxOdFziZOA/N9l+K52roNLZjYOk1JxaBE4QsHgJJyXelHnPlzCbA==", "dependencies": { - "@sentry/core": "7.14.1", - "@sentry/types": "7.14.1", - "@sentry/utils": "7.14.1", + "@sentry/core": "7.25.0", + "@sentry/types": "7.25.0", + "@sentry/utils": "7.25.0", "tslib": "^1.9.3" }, "engines": { @@ -5972,13 +6048,12 @@ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, "node_modules/@sentry/core": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.14.1.tgz", - "integrity": "sha512-sjk60Gf5o9zynhWe1e0ro9uQO4OrKZ3H9xfgBf2ExgKXeMfKzYp5r2v2OKNevEde36Sr/DzlpiPj8EK67xrWPA==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.25.0.tgz", + "integrity": "sha512-4PMuf+MsLxtbesXFBdXfRQhdxHVMi4e6z52DEdtSN9V41lT/R78qIfVopHs5gAr9j4lxCaiKSnNQDKziWLeQ8w==", "dependencies": { - "@sentry/hub": "7.14.1", - "@sentry/types": "7.14.1", - "@sentry/utils": "7.14.1", + "@sentry/types": "7.25.0", + "@sentry/utils": "7.25.0", "tslib": "^1.9.3" }, "engines": { @@ -5990,38 +6065,20 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, - "node_modules/@sentry/hub": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-7.14.1.tgz", - "integrity": "sha512-BWh5jUvGmzCsJtYy6EX3qA6gTOxwGhA64IEXHbzwIAnBoG+VWao3addaL77AGR9pIgAqn6ssfkX665OZa+GPGw==", - "dependencies": { - "@sentry/types": "7.14.1", - "@sentry/utils": "7.14.1", - "tslib": "^1.9.3" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@sentry/hub/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - }, "node_modules/@sentry/types": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.14.1.tgz", - "integrity": "sha512-PxAfrIwBci6ouHOuRsfVq1B16i92nQNV5IvlqfJIYciazVhDWJvbF52caJAPOFS1WnuQZ4zqBDMYvtnwld3JCA==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.25.0.tgz", + "integrity": "sha512-m/tVeuZpbYNQjp4BYOz7bBxZEWdTHdTgXg9YlztUOCf5JDDujpxYp2Pyp4+cDDulzFIixXzRH7FRiKsOJ0WF7w==", "engines": { "node": ">=8" } }, "node_modules/@sentry/utils": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.14.1.tgz", - "integrity": "sha512-CErQFbJMuhnHFKGkfIazQj5ETKoS7hG8PkoQEBt19F5QMh4+sbrJgnpIrIW8fVGtp0qKWKuIxQwD3b+1cFBozA==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.25.0.tgz", + "integrity": "sha512-1Wct+LvDySYgXBYHjoTzccASK4Rk/88cCifSZF7pLrix3Rzk+8QnPt4vZ/ce62nTNBDs/OeFXO1eFwiz9nCoEg==", "dependencies": { - "@sentry/types": "7.14.1", + "@sentry/types": "7.25.0", "tslib": "^1.9.3" }, "engines": { @@ -6199,9 +6256,9 @@ "dev": true }, "node_modules/@types/eslint": { - "version": "8.4.6", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.6.tgz", - "integrity": "sha512-/fqTbjxyFUaYNO7VcW5g+4npmqVACz1bB7RTHYuLj+PRjw9hrCwrUXVQFpChUS0JsyEFvMZ7U/PfmvWgxJhI9g==", + "version": "8.4.10", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.10.tgz", + "integrity": "sha512-Sl/HOqN8NKPmhWo2VBEPm0nvHnu2LL3v9vKo8MEq0EtbJ4eVzGPl41VNPvn5E1i5poMk4/XD8UriLHpJvEP/Nw==", "dev": true, "dependencies": { "@types/estree": "*", @@ -6258,9 +6315,9 @@ } }, "node_modules/@types/google.maps": { - "version": "3.50.2", - "resolved": "https://registry.npmjs.org/@types/google.maps/-/google.maps-3.50.2.tgz", - "integrity": "sha512-F47YMR1sdAVYk6mWab1J9CyO8J5QnCl62QGx9i87cTB2VW5/j2V5b/qgpXTvtUCg91PffirYKiAXlff/XTp+Zw==", + "version": "3.51.0", + "resolved": "https://registry.npmjs.org/@types/google.maps/-/google.maps-3.51.0.tgz", + "integrity": "sha512-44/oQYjc5D6kxBcI3Qk9rk3IIOMwnlEMWDV7pwPJ2YI89s5Q1OzDrFvR7QJ3LFrpVXEhig+gyagFg54+foinFg==", "dev": true }, "node_modules/@types/graceful-fs": { @@ -6375,9 +6432,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "16.11.64", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.64.tgz", - "integrity": "sha512-z5hPTlVFzNwtJ2LNozTpJcD1Cu44c4LNuzaq1mwxmiHWQh2ULdR6Vjwo1UGldzRpzL0yUEdZddnfqGW2G70z6Q==", + "version": "16.18.8", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.8.tgz", + "integrity": "sha512-TrpoNiaPvBH5h8rQQenMtVsJXtGsVBRJrcp2Ik6oEt99jHfGvDLh20VTTq3ixTbjYujukYz1IlY4N8a8yfY0jA==", "dev": true }, "node_modules/@types/normalize-package-data": { @@ -6422,6 +6479,12 @@ "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", "dev": true }, + "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/@types/serve-index": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.1.tgz", @@ -6463,9 +6526,9 @@ "dev": true }, "node_modules/@types/uuid": { - "version": "8.3.4", - "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", - "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-kr90f+ERiQtKWMz5rP32ltJ/BtULDI5RVO0uavn1HQUOwjx0R1h0rnDYNL0CepF1zL5bSY6FISAfd9tOdDhU5Q==", "dev": true }, "node_modules/@types/webpack": { @@ -6504,16 +6567,17 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.39.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.39.0.tgz", - "integrity": "sha512-xVfKOkBm5iWMNGKQ2fwX5GVgBuHmZBO1tCRwXmY5oAIsPscfwm2UADDuNB8ZVYCtpQvJK4xpjrK7jEhcJ0zY9A==", + "version": "5.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.46.1.tgz", + "integrity": "sha512-YpzNv3aayRBwjs4J3oz65eVLXc9xx0PDbIRisHj+dYhvBn02MjYOD96P8YGiWEIFBrojaUjxvkaUpakD82phsA==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.39.0", - "@typescript-eslint/type-utils": "5.39.0", - "@typescript-eslint/utils": "5.39.0", + "@typescript-eslint/scope-manager": "5.46.1", + "@typescript-eslint/type-utils": "5.46.1", + "@typescript-eslint/utils": "5.46.1", "debug": "^4.3.4", "ignore": "^5.2.0", + "natural-compare-lite": "^1.4.0", "regexpp": "^3.2.0", "semver": "^7.3.7", "tsutils": "^3.21.0" @@ -6535,14 +6599,31 @@ } } }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/scope-manager": { + "version": "5.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.46.1.tgz", + "integrity": "sha512-iOChVivo4jpwUdrJZyXSMrEIM/PvsbbDOX1y3UCKjSgWn+W89skxWaYXACQfxmIGhPVpRWK/VWPYc+bad6smIA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.46.1", + "@typescript-eslint/visitor-keys": "5.46.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils": { - "version": "5.39.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.39.0.tgz", - "integrity": "sha512-KJHJkOothljQWzR3t/GunL0TPKY+fGJtnpl+pX+sJ0YiKTz3q2Zr87SGTmFqsCMFrLt5E0+o+S6eQY0FAXj9uA==", + "version": "5.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.46.1.tgz", + "integrity": "sha512-V/zMyfI+jDmL1ADxfDxjZ0EMbtiVqj8LUGPAGyBkXXStWmCUErMpW873zEHsyguWCuq2iN4BrlWUkmuVj84yng==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "5.39.0", - "@typescript-eslint/utils": "5.39.0", + "@typescript-eslint/typescript-estree": "5.46.1", + "@typescript-eslint/utils": "5.46.1", "debug": "^4.3.4", "tsutils": "^3.21.0" }, @@ -6562,18 +6643,60 @@ } } }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/types": { + "version": "5.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.46.1.tgz", + "integrity": "sha512-Z5pvlCaZgU+93ryiYUwGwLl9AQVB/PQ1TsJ9NZ/gHzZjN7g9IAn6RSDkpCV8hqTwAiaj6fmCcKSQeBPlIpW28w==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/typescript-estree": { + "version": "5.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.46.1.tgz", + "integrity": "sha512-j9W4t67QiNp90kh5Nbr1w92wzt+toiIsaVPnEblB2Ih2U9fqBTyqV9T3pYWZBRt6QoMh/zVWP59EpuCjc4VRBg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.46.1", + "@typescript-eslint/visitor-keys": "5.46.1", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": { - "version": "5.39.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.39.0.tgz", - "integrity": "sha512-+DnY5jkpOpgj+EBtYPyHRjXampJfC0yUZZzfzLuUWVZvCuKqSdJVC8UhdWipIw7VKNTfwfAPiOWzYkAwuIhiAg==", + "version": "5.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.46.1.tgz", + "integrity": "sha512-RBdBAGv3oEpFojaCYT4Ghn4775pdjvwfDOfQ2P6qzNVgQOVrnSPe5/Pb88kv7xzYQjoio0eKHKB9GJ16ieSxvA==", "dev": true, "dependencies": { "@types/json-schema": "^7.0.9", - "@typescript-eslint/scope-manager": "5.39.0", - "@typescript-eslint/types": "5.39.0", - "@typescript-eslint/typescript-estree": "5.39.0", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.46.1", + "@typescript-eslint/types": "5.46.1", + "@typescript-eslint/typescript-estree": "5.46.1", "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0" + "eslint-utils": "^3.0.0", + "semver": "^7.3.7" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -6586,6 +6709,23 @@ "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": { + "version": "5.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.46.1.tgz", + "integrity": "sha512-jczZ9noovXwy59KjRTk1OftT78pwygdcmCuBf8yMoWt/8O8l+6x2LSEze0E4TeepXK4MezW3zGSyoDRZK7Y9cg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.46.1", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/@typescript-eslint/experimental-utils": { "version": "5.39.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.39.0.tgz", @@ -6630,14 +6770,14 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "5.39.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.39.0.tgz", - "integrity": "sha512-PhxLjrZnHShe431sBAGHaNe6BDdxAASDySgsBCGxcBecVCi8NQWxQZMcizNA4g0pN51bBAn/FUfkWG3SDVcGlA==", + "version": "5.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.46.1.tgz", + "integrity": "sha512-RelQ5cGypPh4ySAtfIMBzBGyrNerQcmfA1oJvPj5f+H4jI59rl9xxpn4bonC0tQvUKOEN7eGBFWxFLK3Xepneg==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.39.0", - "@typescript-eslint/types": "5.39.0", - "@typescript-eslint/typescript-estree": "5.39.0", + "@typescript-eslint/scope-manager": "5.46.1", + "@typescript-eslint/types": "5.46.1", + "@typescript-eslint/typescript-estree": "5.46.1", "debug": "^4.3.4" }, "engines": { @@ -6656,6 +6796,80 @@ } } }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/scope-manager": { + "version": "5.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.46.1.tgz", + "integrity": "sha512-iOChVivo4jpwUdrJZyXSMrEIM/PvsbbDOX1y3UCKjSgWn+W89skxWaYXACQfxmIGhPVpRWK/VWPYc+bad6smIA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.46.1", + "@typescript-eslint/visitor-keys": "5.46.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/types": { + "version": "5.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.46.1.tgz", + "integrity": "sha512-Z5pvlCaZgU+93ryiYUwGwLl9AQVB/PQ1TsJ9NZ/gHzZjN7g9IAn6RSDkpCV8hqTwAiaj6fmCcKSQeBPlIpW28w==", + "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/parser/node_modules/@typescript-eslint/typescript-estree": { + "version": "5.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.46.1.tgz", + "integrity": "sha512-j9W4t67QiNp90kh5Nbr1w92wzt+toiIsaVPnEblB2Ih2U9fqBTyqV9T3pYWZBRt6QoMh/zVWP59EpuCjc4VRBg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.46.1", + "@typescript-eslint/visitor-keys": "5.46.1", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/visitor-keys": { + "version": "5.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.46.1.tgz", + "integrity": "sha512-jczZ9noovXwy59KjRTk1OftT78pwygdcmCuBf8yMoWt/8O8l+6x2LSEze0E4TeepXK4MezW3zGSyoDRZK7Y9cg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.46.1", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/@typescript-eslint/scope-manager": { "version": "5.39.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.39.0.tgz", @@ -6674,13 +6888,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "5.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.37.0.tgz", - "integrity": "sha512-BSx/O0Z0SXOF5tY0bNTBcDEKz2Ec20GVYvq/H/XNKiUorUFilH7NPbFUuiiyzWaSdN3PA8JV0OvYx0gH/5aFAQ==", + "version": "5.43.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.43.0.tgz", + "integrity": "sha512-K21f+KY2/VvYggLf5Pk4tgBOPs2otTaIHy2zjclo7UZGLyFH86VfUOm5iq+OtDtxq/Zwu2I3ujDBykVW4Xtmtg==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "5.37.0", - "@typescript-eslint/utils": "5.37.0", + "@typescript-eslint/typescript-estree": "5.43.0", + "@typescript-eslint/utils": "5.43.0", "debug": "^4.3.4", "tsutils": "^3.21.0" }, @@ -6701,9 +6915,9 @@ } }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { - "version": "5.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.37.0.tgz", - "integrity": "sha512-3frIJiTa5+tCb2iqR/bf7XwU20lnU05r/sgPJnRpwvfZaqCJBrl8Q/mw9vr3NrNdB/XtVyMA0eppRMMBqdJ1bA==", + "version": "5.43.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.43.0.tgz", + "integrity": "sha512-jpsbcD0x6AUvV7tyOlyvon0aUsQpF8W+7TpJntfCUWU1qaIKu2K34pMwQKSzQH8ORgUrGYY6pVIh1Pi8TNeteg==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -6714,13 +6928,13 @@ } }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "5.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.37.0.tgz", - "integrity": "sha512-JkFoFIt/cx59iqEDSgIGnQpCTRv96MQnXCYvJi7QhBC24uyuzbD8wVbajMB1b9x4I0octYFJ3OwjAwNqk1AjDA==", + "version": "5.43.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.43.0.tgz", + "integrity": "sha512-BZ1WVe+QQ+igWal2tDbNg1j2HWUkAa+CVqdU79L4HP9izQY6CNhXfkNwd1SS4+sSZAP/EthI1uiCSY/+H0pROg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.37.0", - "@typescript-eslint/visitor-keys": "5.37.0", + "@typescript-eslint/types": "5.43.0", + "@typescript-eslint/visitor-keys": "5.43.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -6741,12 +6955,12 @@ } }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "5.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.37.0.tgz", - "integrity": "sha512-Hp7rT4cENBPIzMwrlehLW/28EVCOcE9U1Z1BQTc8EA8v5qpr7GRGuG+U58V5tTY48zvUOA3KHvw3rA8tY9fbdA==", + "version": "5.43.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.43.0.tgz", + "integrity": "sha512-icl1jNH/d18OVHLfcwdL3bWUKsBeIiKYTGxMJCoGe7xFht+E4QgzOqoWYrU8XSLJWhVw8nTacbm03v23J/hFTg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.37.0", + "@typescript-eslint/types": "5.43.0", "eslint-visitor-keys": "^3.3.0" }, "engines": { @@ -6798,17 +7012,19 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "5.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.37.0.tgz", - "integrity": "sha512-jUEJoQrWbZhmikbcWSMDuUSxEE7ID2W/QCV/uz10WtQqfOuKZUqFGjqLJ+qhDd17rjgp+QJPqTdPIBWwoob2NQ==", + "version": "5.43.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.43.0.tgz", + "integrity": "sha512-8nVpA6yX0sCjf7v/NDfeaOlyaIIqL7OaIGOWSPFqUKK59Gnumd3Wa+2l8oAaYO2lk0sO+SbWFWRSvhu8gLGv4A==", "dev": true, "dependencies": { "@types/json-schema": "^7.0.9", - "@typescript-eslint/scope-manager": "5.37.0", - "@typescript-eslint/types": "5.37.0", - "@typescript-eslint/typescript-estree": "5.37.0", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.43.0", + "@typescript-eslint/types": "5.43.0", + "@typescript-eslint/typescript-estree": "5.43.0", "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0" + "eslint-utils": "^3.0.0", + "semver": "^7.3.7" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -6822,13 +7038,13 @@ } }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/scope-manager": { - "version": "5.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.37.0.tgz", - "integrity": "sha512-F67MqrmSXGd/eZnujjtkPgBQzgespu/iCZ+54Ok9X5tALb9L2v3G+QBSoWkXG0p3lcTJsL+iXz5eLUEdSiJU9Q==", + "version": "5.43.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.43.0.tgz", + "integrity": "sha512-XNWnGaqAtTJsUiZaoiGIrdJYHsUOd3BZ3Qj5zKp9w6km6HsrjPk/TGZv0qMTWyWj0+1QOqpHQ2gZOLXaGA9Ekw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.37.0", - "@typescript-eslint/visitor-keys": "5.37.0" + "@typescript-eslint/types": "5.43.0", + "@typescript-eslint/visitor-keys": "5.43.0" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -6839,9 +7055,9 @@ } }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/types": { - "version": "5.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.37.0.tgz", - "integrity": "sha512-3frIJiTa5+tCb2iqR/bf7XwU20lnU05r/sgPJnRpwvfZaqCJBrl8Q/mw9vr3NrNdB/XtVyMA0eppRMMBqdJ1bA==", + "version": "5.43.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.43.0.tgz", + "integrity": "sha512-jpsbcD0x6AUvV7tyOlyvon0aUsQpF8W+7TpJntfCUWU1qaIKu2K34pMwQKSzQH8ORgUrGYY6pVIh1Pi8TNeteg==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -6852,13 +7068,13 @@ } }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "5.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.37.0.tgz", - "integrity": "sha512-JkFoFIt/cx59iqEDSgIGnQpCTRv96MQnXCYvJi7QhBC24uyuzbD8wVbajMB1b9x4I0octYFJ3OwjAwNqk1AjDA==", + "version": "5.43.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.43.0.tgz", + "integrity": "sha512-BZ1WVe+QQ+igWal2tDbNg1j2HWUkAa+CVqdU79L4HP9izQY6CNhXfkNwd1SS4+sSZAP/EthI1uiCSY/+H0pROg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.37.0", - "@typescript-eslint/visitor-keys": "5.37.0", + "@typescript-eslint/types": "5.43.0", + "@typescript-eslint/visitor-keys": "5.43.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -6879,12 +7095,12 @@ } }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "5.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.37.0.tgz", - "integrity": "sha512-Hp7rT4cENBPIzMwrlehLW/28EVCOcE9U1Z1BQTc8EA8v5qpr7GRGuG+U58V5tTY48zvUOA3KHvw3rA8tY9fbdA==", + "version": "5.43.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.43.0.tgz", + "integrity": "sha512-icl1jNH/d18OVHLfcwdL3bWUKsBeIiKYTGxMJCoGe7xFht+E4QgzOqoWYrU8XSLJWhVw8nTacbm03v23J/hFTg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.37.0", + "@typescript-eslint/types": "5.43.0", "eslint-visitor-keys": "^3.3.0" }, "engines": { @@ -7535,9 +7751,9 @@ } }, "node_modules/adjust-sourcemap-loader/node_modules/loader-utils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz", - "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", "dev": true, "dependencies": { "big.js": "^5.2.2", @@ -7677,9 +7893,9 @@ } }, "node_modules/angulartics2": { - "version": "12.1.0", - "resolved": "https://registry.npmjs.org/angulartics2/-/angulartics2-12.1.0.tgz", - "integrity": "sha512-Avmc2zIf6r8kn9eXpQQ3qzaeIlyYd4Uzjr5a5nOOQfHb8AcMsV1PfUVQ1OJmBdxjde+sIHmY3VvabNjWHh4BpQ==", + "version": "12.2.0", + "resolved": "https://registry.npmjs.org/angulartics2/-/angulartics2-12.2.0.tgz", + "integrity": "sha512-1wl/cPA4PGYj42z80VIR+A0Hy3+rt13POzfTfZ83NUDx2KKbHjtTKS0O7u3umi10cqvi5tn4NTSYIFFJ1fI2Tw==", "dependencies": { "tslib": "^2.3.0" }, @@ -7804,15 +8020,6 @@ "node": ">=8" } }, - "node_modules/app-root-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-3.0.0.tgz", - "integrity": "sha512-qMcx+Gy2UZynHjOHOIXPNvpf+9cjvk3cWrBBK7zg4gH9+clobJRb9NGzcT7mQTcV/6Gm/1WelUtqxVXnNlrwcw==", - "dev": true, - "engines": { - "node": ">= 6.0.0" - } - }, "node_modules/aproba": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", @@ -7844,14 +8051,46 @@ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, "node_modules/aria-query": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.0.2.tgz", - "integrity": "sha512-eigU3vhqSO+Z8BKDnVLN/ompjhf3pYzecKXz8+whRy+9gZu8n1TCGfwzQUUPnqdHl9ax1Hr9031orZ+UOEYr7Q==", + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", + "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", "dev": true, - "engines": { - "node": ">=6.0" + "dependencies": { + "deep-equal": "^2.0.5" + } + }, + "node_modules/aria-query/node_modules/deep-equal": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.1.0.tgz", + "integrity": "sha512-2pxgvWu3Alv1PoWEyVg7HS8YhGlUFUV7N5oOvfL6d+7xAmLSemMwv/c8Zv/i9KFzxV5Kt5CAvQc70fLwVuf4UA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "es-get-iterator": "^1.1.2", + "get-intrinsic": "^1.1.3", + "is-arguments": "^1.1.1", + "is-date-object": "^1.0.5", + "is-regex": "^1.1.4", + "isarray": "^2.0.5", + "object-is": "^1.1.5", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.4.3", + "side-channel": "^1.0.4", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.8" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/aria-query/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, "node_modules/array-differ": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-3.0.0.tgz", @@ -8046,9 +8285,9 @@ } }, "node_modules/autoprefixer": { - "version": "10.4.12", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.12.tgz", - "integrity": "sha512-WrCGV9/b97Pa+jtwf5UGaRjgQIg7OK3D06GnoYoZNcG1Xb8Gt3EfuKjlhh9i/VtT16g6PYjZ69jdJ2g8FxSC4Q==", + "version": "10.4.13", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.13.tgz", + "integrity": "sha512-49vKpMqcZYsJjwotvt4+h/BCjJVnhGwcLpDt5xkcaOG3eLrG/HUYLagrihYsQ+qrIBgIzX1Rw7a6L8I/ZA1Atg==", "dev": true, "funding": [ { @@ -8062,7 +8301,7 @@ ], "dependencies": { "browserslist": "^4.21.4", - "caniuse-lite": "^1.0.30001407", + "caniuse-lite": "^1.0.30001426", "fraction.js": "^4.2.0", "normalize-range": "^0.1.2", "picocolors": "^1.0.0", @@ -8078,6 +8317,18 @@ "postcss": "^8.1.0" } }, + "node_modules/available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/axios": { "version": "0.21.4", "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", @@ -8088,14 +8339,46 @@ } }, "node_modules/axobject-query": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.0.1.tgz", - "integrity": "sha512-vy5JPSOibF9yAeC2PoemRdA1MuSXX7vX5osdoxKf/6OUeppAWekZ3JIJVNWFMH6wgj7uHYyqZUSqE/b/3JLV1A==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.1.1.tgz", + "integrity": "sha512-goKlv8DZrK9hUh975fnHzhNIO4jUnFCfv/dszV5VwUGDFjI6vQ2VwoyjYjYNEbBE8AH87TduWP5uyDR1D+Iteg==", "dev": true, - "engines": { - "node": ">=6.0" + "dependencies": { + "deep-equal": "^2.0.5" + } + }, + "node_modules/axobject-query/node_modules/deep-equal": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.1.0.tgz", + "integrity": "sha512-2pxgvWu3Alv1PoWEyVg7HS8YhGlUFUV7N5oOvfL6d+7xAmLSemMwv/c8Zv/i9KFzxV5Kt5CAvQc70fLwVuf4UA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "es-get-iterator": "^1.1.2", + "get-intrinsic": "^1.1.3", + "is-arguments": "^1.1.1", + "is-date-object": "^1.0.5", + "is-regex": "^1.1.4", + "isarray": "^2.0.5", + "object-is": "^1.1.5", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.4.3", + "side-channel": "^1.0.4", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.8" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/axobject-query/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, "node_modules/babel-jest": { "version": "28.1.3", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-28.1.3.tgz", @@ -8207,9 +8490,9 @@ } }, "node_modules/babel-loader/node_modules/loader-utils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz", - "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", "dev": true, "dependencies": { "big.js": "^5.2.2", @@ -8465,9 +8748,9 @@ "dev": true }, "node_modules/body-parser": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz", - "integrity": "sha512-DfJ+q6EPcGKZD1QWUjSpqp+Q7bDQTsQIF4zfUAtZ6qk+H/3/QRhg9CEp39ss+/T2vw0+HaidC0ecJj/DRLIaKg==", + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", "dependencies": { "bytes": "3.1.2", "content-type": "~1.0.4", @@ -8477,7 +8760,7 @@ "http-errors": "2.0.0", "iconv-lite": "0.4.24", "on-finished": "2.4.1", - "qs": "6.10.3", + "qs": "6.11.0", "raw-body": "2.5.1", "type-is": "~1.6.18", "unpipe": "1.0.0" @@ -8501,9 +8784,9 @@ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, "node_modules/body-parser/node_modules/qs": { - "version": "6.10.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", - "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", "dependencies": { "side-channel": "^1.0.4" }, @@ -9112,15 +9395,6 @@ "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/cachedir": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.3.0.tgz", - "integrity": "sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/call-bind": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", @@ -9184,9 +9458,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001416", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001416.tgz", - "integrity": "sha512-06wzzdAkCPZO+Qm4e/eNghZBDfVNDsCgw33T27OwBH9unE9S478OYw//Q2L7Npf/zBzs7rjZOszIFQkwQKAEqA==", + "version": "1.0.30001439", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001439.tgz", + "integrity": "sha512-1MgUzEkoMO6gKfXflStpYgZDlFM7M/ck/bgfVCACO5vnAf0fXoNVHdWtqGU+MYca+4bL9Z5bpOVmR33cWW9G2A==", "funding": [ { "type": "opencollective", @@ -9333,10 +9607,13 @@ } }, "node_modules/ci-info": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.4.0.tgz", - "integrity": "sha512-t5QdPT5jq3o262DOQ8zA6E1tlH2upmUc4Hlvrbx1pGYJuiiHl7O7rvVNI+l8HTVhd/q3Qc9vqimkNk5yiXsAug==", - "dev": true + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.7.0.tgz", + "integrity": "sha512-2CpRNYmImPx+RXKLq6jko/L07phmS9I02TyqkcNU20GCF/GgaWvc58hPtjxDX8lPpkdwc9sNh72V9k00S7ezog==", + "dev": true, + "engines": { + "node": ">=8" + } }, "node_modules/cjs-module-lexer": { "version": "1.2.2", @@ -9727,103 +10004,6 @@ "node": ">= 12.0.0" } }, - "node_modules/commitizen": { - "version": "4.2.5", - "resolved": "https://registry.npmjs.org/commitizen/-/commitizen-4.2.5.tgz", - "integrity": "sha512-9sXju8Qrz1B4Tw7kC5KhnvwYQN88qs2zbiB8oyMsnXZyJ24PPGiNM3nHr73d32dnE3i8VJEXddBFIbOgYSEXtQ==", - "dev": true, - "dependencies": { - "cachedir": "2.3.0", - "cz-conventional-changelog": "3.3.0", - "dedent": "0.7.0", - "detect-indent": "6.1.0", - "find-node-modules": "^2.1.2", - "find-root": "1.1.0", - "fs-extra": "9.1.0", - "glob": "7.2.3", - "inquirer": "8.2.4", - "is-utf8": "^0.2.1", - "lodash": "4.17.21", - "minimist": "1.2.6", - "strip-bom": "4.0.0", - "strip-json-comments": "3.1.1" - }, - "bin": { - "commitizen": "bin/commitizen", - "cz": "bin/git-cz", - "git-cz": "bin/git-cz" - }, - "engines": { - "node": ">= 12" - } - }, - "node_modules/commitizen/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/commitizen/node_modules/fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "dev": true, - "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/commitizen/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/commitizen/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/commitlint-config-cz": { - "version": "0.13.3", - "resolved": "https://registry.npmjs.org/commitlint-config-cz/-/commitlint-config-cz-0.13.3.tgz", - "integrity": "sha512-6LmCvGiFDTVSmLF0mzVVp1etMM8lAqLmPRlU7Oml1J8J9oOLadf+2g4uMTchdxOvvYLgll99SESFUHgmc6oATA==", - "dev": true, - "dependencies": { - "app-root-path": "~3.0.0", - "lodash.clonedeep": "~4.5.0" - } - }, "node_modules/common-tags": { "version": "1.8.2", "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz", @@ -10276,12 +10456,6 @@ "semver": "bin/semver.js" } }, - "node_modules/conventional-commit-types": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/conventional-commit-types/-/conventional-commit-types-3.0.0.tgz", - "integrity": "sha512-SmmCYnOniSsAa9GqWOeLqc179lfr5TRu5b4QFDkbsrJ5TZjPJx85wtOr3zn+1dbeNiXDKGPbZ72IKbPhLXh/Lg==", - "dev": true - }, "node_modules/conventional-commits-filter": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-2.0.7.tgz", @@ -10467,9 +10641,9 @@ } }, "node_modules/cosmiconfig": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", - "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", "dev": true, "dependencies": { "@types/parse-json": "^4.0.0", @@ -10483,9 +10657,9 @@ } }, "node_modules/cosmiconfig-typescript-loader": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-4.1.1.tgz", - "integrity": "sha512-9DHpa379Gp0o0Zefii35fcmuuin6q92FnLDffzdZ0l9tVd3nEobG3O+MZ06+kuBvFTSVScvNb/oHA13Nd4iipg==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-4.3.0.tgz", + "integrity": "sha512-NTxV1MFfZDLPiBMjxbHRwSh5LaLcPMwNdCutmnHJCKoVnlvldPWlllonKwrsRJ5pYZBIBGRWWU2tfvzxgeSW5Q==", "dev": true, "engines": { "node": ">=12", @@ -10693,24 +10867,24 @@ } }, "node_modules/cspell": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/cspell/-/cspell-6.12.0.tgz", - "integrity": "sha512-ny4xVEPYFP2jVf5w71Mnk4HKj6RbPH+CMSzUrOMbYVVNnQUj3GLfzy5DrSFLG0zGa353ZRC4/s9MsEvnAL8mkA==", + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/cspell/-/cspell-6.17.0.tgz", + "integrity": "sha512-R1TXu1p2vON6rHXxZAUPbdf+v+ckPhWiEb3apq2PyxLSjzMiZDm2ThIwRcsQaMLLZyFOD+J3SHj0lZi1Qoaa8w==", "dev": true, "dependencies": { - "@cspell/cspell-pipe": "^6.12.0", + "@cspell/cspell-pipe": "6.17.0", "chalk": "^4.1.2", - "commander": "^9.4.0", - "cspell-gitignore": "^6.12.0", - "cspell-glob": "^6.12.0", - "cspell-lib": "^6.12.0", + "commander": "^9.4.1", + "cspell-gitignore": "6.17.0", + "cspell-glob": "6.17.0", + "cspell-lib": "6.17.0", "fast-json-stable-stringify": "^2.1.0", "file-entry-cache": "^6.0.1", "fs-extra": "^10.1.0", "get-stdin": "^8.0.0", "glob": "^8.0.3", "imurmurhash": "^0.1.4", - "semver": "^7.3.7", + "semver": "^7.3.8", "strip-ansi": "^6.0.1", "vscode-uri": "^3.0.6" }, @@ -10725,14 +10899,14 @@ } }, "node_modules/cspell-dictionary": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/cspell-dictionary/-/cspell-dictionary-6.12.0.tgz", - "integrity": "sha512-I2cXSdXndt9H7yXmJzLTjgui/SAPGghXwxFeibTbvF68gyQYD5fUXvOygEIPrOEySKlAIb+aouV77SgoURxMHw==", + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/cspell-dictionary/-/cspell-dictionary-6.17.0.tgz", + "integrity": "sha512-jUb/kIR2glYliRem11kCu7gaXUcHKp8L2G73LmzIULx+UKRgTa/100FXqm5lZUWnCaIznMmaA2QtutP+xYy5AQ==", "dev": true, "dependencies": { - "@cspell/cspell-pipe": "^6.12.0", - "@cspell/cspell-types": "^6.12.0", - "cspell-trie-lib": "^6.12.0", + "@cspell/cspell-pipe": "6.17.0", + "@cspell/cspell-types": "6.17.0", + "cspell-trie-lib": "6.17.0", "fast-equals": "^4.0.3", "gensequence": "^4.0.2" }, @@ -10741,12 +10915,12 @@ } }, "node_modules/cspell-gitignore": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/cspell-gitignore/-/cspell-gitignore-6.12.0.tgz", - "integrity": "sha512-gtsN2AAvqdE8CHVzpxsQcd/Wn5GAMTjzHpDXX71g/k8IJn743poGU06O0O1WSVAgK0fWTRsfg+V5OegA1TAo7A==", + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/cspell-gitignore/-/cspell-gitignore-6.17.0.tgz", + "integrity": "sha512-SDyPv6LqBebvoTKFP+ewh51gvmv1z8JDg7llumUFH2u1WoiMZBLLOL2pAa9UM0f6eEzBC1iS6nWQ+20VJx2yQA==", "dev": true, "dependencies": { - "cspell-glob": "^6.12.0", + "cspell-glob": "6.17.0", "find-up": "^5.0.0" }, "bin": { @@ -10757,9 +10931,9 @@ } }, "node_modules/cspell-glob": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/cspell-glob/-/cspell-glob-6.12.0.tgz", - "integrity": "sha512-Q0rMGTxDyFFPm1LmHYM0ziuxQt2aXgr8Oi1glA2s0dBs0hg1DexlAEoLwLiMDUwSTvibEKIidPzlrmZ1AUDWEg==", + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/cspell-glob/-/cspell-glob-6.17.0.tgz", + "integrity": "sha512-iKz2CvUU1HXuNJfxYRwSQFck3pCl9EhTx2qIR0lKf4gccCR89p44qxIR98nTbX1OF89lhfH6sUHtzkJ3nPWh+A==", "dev": true, "dependencies": { "micromatch": "^4.0.5" @@ -10769,13 +10943,13 @@ } }, "node_modules/cspell-grammar": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/cspell-grammar/-/cspell-grammar-6.12.0.tgz", - "integrity": "sha512-WXcDiWJ2pTW0jHY0Bf0DW5s8A9S0a+2tsVZsNxE/0CR5P/8yDSnznE+59uok/JN+GXOKQ6VIaqAZA3/XjDZuuA==", + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/cspell-grammar/-/cspell-grammar-6.17.0.tgz", + "integrity": "sha512-3B9QmKWOjAPzLYqesLP2niIbo6Yvb4rodjIwFXUvL3vmMZF4c9HFU/JVTTerLxrwh3DH8u6Mac52RzUurOJ15Q==", "dev": true, "dependencies": { - "@cspell/cspell-pipe": "^6.12.0", - "@cspell/cspell-types": "^6.12.0" + "@cspell/cspell-pipe": "6.17.0", + "@cspell/cspell-types": "6.17.0" }, "bin": { "cspell-grammar": "bin.js" @@ -10785,12 +10959,12 @@ } }, "node_modules/cspell-io": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/cspell-io/-/cspell-io-6.12.0.tgz", - "integrity": "sha512-1faxDj2OMgq61w7GaiXZD7ytks6PksJlG484LMl2USv58jDky4i2lujJs1C/+aP97Box9EcdwzydHX9GpnqqCw==", + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/cspell-io/-/cspell-io-6.17.0.tgz", + "integrity": "sha512-cofZlvKzXP3QytGM6OlREQIXLFcSdEKOFubSVHkRvAVX3IqeQnKo4oVF85C6McjwXTrJ1OH+SDP0vcpn6mKqTg==", "dev": true, "dependencies": { - "@cspell/cspell-service-bus": "^6.12.0", + "@cspell/cspell-service-bus": "6.17.0", "node-fetch": "^2.6.7" }, "engines": { @@ -10798,23 +10972,24 @@ } }, "node_modules/cspell-lib": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/cspell-lib/-/cspell-lib-6.12.0.tgz", - "integrity": "sha512-IKd2MzH/zoiXohc26Lqb1b8i+41Y2xGreyAe9ihv/7Z2dscGGVy7F/2taZvZK9kJIhaz33Yatxfx3htT6w0hqg==", + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/cspell-lib/-/cspell-lib-6.17.0.tgz", + "integrity": "sha512-oZNkm0UhRa4nkoYPij23z7cbVXFPVHs7SdGC6IAVc71uz44nLNeC3e8+UnTErOU7nlROvjp9k3G90DEwej1TqQ==", "dev": true, "dependencies": { - "@cspell/cspell-bundled-dicts": "^6.12.0", - "@cspell/cspell-pipe": "^6.12.0", - "@cspell/cspell-types": "^6.12.0", + "@cspell/cspell-bundled-dicts": "6.17.0", + "@cspell/cspell-pipe": "6.17.0", + "@cspell/cspell-types": "6.17.0", + "@cspell/strong-weak-map": "6.17.0", "clear-module": "^4.1.2", "comment-json": "^4.2.3", "configstore": "^5.0.1", - "cosmiconfig": "^7.0.1", - "cspell-dictionary": "^6.12.0", - "cspell-glob": "^6.12.0", - "cspell-grammar": "^6.12.0", - "cspell-io": "^6.12.0", - "cspell-trie-lib": "^6.12.0", + "cosmiconfig": "^8.0.0", + "cspell-dictionary": "6.17.0", + "cspell-glob": "6.17.0", + "cspell-grammar": "6.17.0", + "cspell-io": "6.17.0", + "cspell-trie-lib": "6.17.0", "fast-equals": "^4.0.3", "find-up": "^5.0.0", "fs-extra": "^10.1.0", @@ -10825,18 +11000,33 @@ "vscode-languageserver-textdocument": "^1.0.7", "vscode-uri": "^3.0.6" }, + "engines": { + "node": ">=14.6" + } + }, + "node_modules/cspell-lib/node_modules/cosmiconfig": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.0.0.tgz", + "integrity": "sha512-da1EafcpH6b/TD8vDRaWV7xFINlHlF6zKsGwS1TsuVJTZRkquaS5HTMq7uq6h31619QjbsYl21gVDOm32KM1vQ==", + "dev": true, + "dependencies": { + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0" + }, "engines": { "node": ">=14" } }, "node_modules/cspell-trie-lib": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/cspell-trie-lib/-/cspell-trie-lib-6.12.0.tgz", - "integrity": "sha512-SJOdb51Wy3ewaKfttZwc9NYOIXaKlhyr+ykYKBExj3qMfV1J4d4iDLE95FriaRcqnq6X/qEM9jUvZHlvadDk3A==", + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/cspell-trie-lib/-/cspell-trie-lib-6.17.0.tgz", + "integrity": "sha512-hmyZHhemWYLjjEDItAhgAF0tuL2iiQg+5PzUmELKIBSWEsmFdfxh1xWCmo1q0+vzVML+0Ms2cspiGyS9y/CF7A==", "dev": true, "dependencies": { - "@cspell/cspell-pipe": "^6.12.0", - "@cspell/cspell-types": "^6.12.0", + "@cspell/cspell-pipe": "6.17.0", + "@cspell/cspell-types": "6.17.0", "fs-extra": "^10.1.0", "gensequence": "^4.0.2" }, @@ -10902,6 +11092,33 @@ "node": ">=8" } }, + "node_modules/cspell/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/cspell/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/cspell/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -11028,9 +11245,9 @@ } }, "node_modules/cssdb": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-7.0.1.tgz", - "integrity": "sha512-pT3nzyGM78poCKLAEy2zWIVX2hikq6dIrjuZzLV98MumBg+xMTNYfHx7paUlfiRTgg91O/vR889CIf+qiv79Rw==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-7.2.0.tgz", + "integrity": "sha512-JYlIsE7eKHSi0UNuCyo96YuIDFqvhGgHw4Ck6lsN+DP0Tp8M64UTDT2trGbkMDqnCoEjks7CkS0XcjU0rkvBdg==", "dev": true, "funding": { "type": "opencollective", @@ -11076,26 +11293,6 @@ "integrity": "sha512-yi1x3EAWKjQTreYWeSd98431AV+IEE0qoDyOoaHJ7KJ21gv6HtBXHVLX74opVSGqcR8/AbjJBHAHpcOy2bj5Gg==", "dev": true }, - "node_modules/cz-conventional-changelog": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/cz-conventional-changelog/-/cz-conventional-changelog-3.3.0.tgz", - "integrity": "sha512-U466fIzU5U22eES5lTNiNbZ+d8dfcHcssH4o7QsdWaCcRs/feIPCxKYSWkYBNs5mny7MvEfwpTLWjvbm94hecw==", - "dev": true, - "dependencies": { - "chalk": "^2.4.1", - "commitizen": "^4.0.3", - "conventional-commit-types": "^3.0.0", - "lodash.map": "^4.5.1", - "longest": "^2.0.1", - "word-wrap": "^1.0.3" - }, - "engines": { - "node": ">= 10" - }, - "optionalDependencies": { - "@commitlint/load": ">6.1.1" - } - }, "node_modules/cz-customizable": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/cz-customizable/-/cz-customizable-7.0.0.tgz", @@ -11677,24 +11874,6 @@ "npm": "1.2.8000 || >= 1.4.16" } }, - "node_modules/detect-file": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", - "integrity": "sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/detect-indent": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", - "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/detect-newline": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", @@ -12062,9 +12241,9 @@ } }, "node_modules/engine.io": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.2.0.tgz", - "integrity": "sha512-4KzwW3F3bk+KlzSOY57fj/Jx6LyRQ1nbcyIadehl+AnXjKT7gDO0ORdRi/84ixvMKTym6ZKuxvbzN62HDDU1Lg==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.2.1.tgz", + "integrity": "sha512-ECceEFcAaNRybd3lsGQKas3ZlMVjN3cyWwMP25D2i0zWfyiytVbTpRPa34qrr+FHddtpBVOmq4H/DCv1O0lZRA==", "dev": true, "dependencies": { "@types/cookie": "^0.4.1", @@ -12266,6 +12445,31 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/es-get-iterator": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.2.tgz", + "integrity": "sha512-+DTO8GYwbMCwbywjimwZMHp8AuYXOS2JZFWoi2AlPOS3ebnII9w/NLpNZtA7A0YLaVDw+O7KFCeoIV7OPvM7hQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.0", + "has-symbols": "^1.0.1", + "is-arguments": "^1.1.0", + "is-map": "^2.0.2", + "is-set": "^2.0.2", + "is-string": "^1.0.5", + "isarray": "^2.0.5" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-get-iterator/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, "node_modules/es-module-lexer": { "version": "0.9.3", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", @@ -12855,15 +13059,15 @@ } }, "node_modules/eslint": { - "version": "8.24.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.24.0.tgz", - "integrity": "sha512-dWFaPhGhTAiPcCgm3f6LI2MBWbogMnTJzFBbhXVRQDJPkr9pGZvVjlVfXd+vyDcWPA2Ic9L2AXPIQM0+vk/cSQ==", + "version": "8.29.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.29.0.tgz", + "integrity": "sha512-isQ4EEiyUjZFbEKvEGJKKGBwXtvXX+zJbkVKCgTuB9t/+jUBcy8avhkEwWJecI15BkRkOYmvIM5ynbhRjEkoeg==", "dev": true, "dependencies": { - "@eslint/eslintrc": "^1.3.2", - "@humanwhocodes/config-array": "^0.10.5", - "@humanwhocodes/gitignore-to-minimatch": "^1.0.2", + "@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", @@ -12879,14 +13083,14 @@ "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", "find-up": "^5.0.0", - "glob-parent": "^6.0.1", + "glob-parent": "^6.0.2", "globals": "^13.15.0", - "globby": "^11.1.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", @@ -12984,9 +13188,9 @@ "link": true }, "node_modules/eslint-plugin-jest": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-27.1.1.tgz", - "integrity": "sha512-vuSuXGKHHi/UAffIM46QKm4g0tQP+6n52nRxUpMq6x6x9rhnv5WM7ktSu3h9cTnXE4b0Y0ODQTgRlCm9rdRLvg==", + "version": "27.1.6", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-27.1.6.tgz", + "integrity": "sha512-XA7RFLSrlQF9IGtAmhddkUkBuICCTuryfOTfCSWcZHiHb69OilIH05oozH2XA6CEOtztnOd0vgXyvxZodkxGjg==", "dev": true, "dependencies": { "@typescript-eslint/utils": "^5.10.0" @@ -13008,21 +13212,21 @@ } }, "node_modules/eslint-plugin-jsdoc": { - "version": "39.3.6", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-39.3.6.tgz", - "integrity": "sha512-R6dZ4t83qPdMhIOGr7g2QII2pwCjYyKP+z0tPOfO1bbAbQyKC20Y2Rd6z1te86Lq3T7uM8bNo+VD9YFpE8HU/g==", + "version": "39.6.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-39.6.4.tgz", + "integrity": "sha512-fskvdLCfwmPjHb6e+xNGDtGgbF8X7cDwMtVLAP2WwSf9Htrx68OAx31BESBM1FAwsN2HTQyYQq7m4aW4Q4Nlag==", "dev": true, "dependencies": { - "@es-joy/jsdoccomment": "~0.31.0", + "@es-joy/jsdoccomment": "~0.36.1", "comment-parser": "1.3.1", "debug": "^4.3.4", "escape-string-regexp": "^4.0.0", "esquery": "^1.4.0", - "semver": "^7.3.7", + "semver": "^7.3.8", "spdx-expression-parse": "^3.0.1" }, "engines": { - "node": "^14 || ^16 || ^17 || ^18" + "node": "^14 || ^16 || ^17 || ^18 || ^19" }, "peerDependencies": { "eslint": "^7.0.0 || ^8.0.0" @@ -13040,6 +13244,33 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/eslint-plugin-jsdoc/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/eslint-plugin-jsdoc/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/eslint-plugin-prettier": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz", @@ -13100,24 +13331,26 @@ } }, "node_modules/eslint-plugin-unicorn": { - "version": "44.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-44.0.1.tgz", - "integrity": "sha512-ly6Ye9OfgYBCw/FfsdycCzAztcRd+pOA0F6xZwtUsUkgOBjtNR0684xC7u+0RmE3SKr3y7z8MaIWunw36tbZdg==", + "version": "45.0.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-45.0.2.tgz", + "integrity": "sha512-Y0WUDXRyGDMcKLiwgL3zSMpHrXI00xmdyixEGIg90gHnj0PcHY4moNv3Ppje/kDivdAy5vUeUr7z211ImPv2gw==", "dev": true, "dependencies": { "@babel/helper-validator-identifier": "^7.19.1", - "ci-info": "^3.4.0", + "@eslint-community/eslint-utils": "^4.1.2", + "ci-info": "^3.6.1", "clean-regexp": "^1.0.0", - "eslint-utils": "^3.0.0", "esquery": "^1.4.0", "indent-string": "^4.0.0", "is-builtin-module": "^3.2.0", + "jsesc": "^3.0.2", "lodash": "^4.17.21", "pluralize": "^8.0.0", "read-pkg-up": "^7.0.1", "regexp-tree": "^0.1.24", + "regjsparser": "^0.9.1", "safe-regex": "^2.1.1", - "semver": "^7.3.7", + "semver": "^7.3.8", "strip-indent": "^3.0.0" }, "engines": { @@ -13127,7 +13360,7 @@ "url": "https://github.com/sindresorhus/eslint-plugin-unicorn?sponsor=1" }, "peerDependencies": { - "eslint": ">=8.23.1" + "eslint": ">=8.28.0" } }, "node_modules/eslint-plugin-unicorn/node_modules/find-up": { @@ -13149,6 +13382,18 @@ "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", "dev": true }, + "node_modules/eslint-plugin-unicorn/node_modules/jsesc": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", + "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/eslint-plugin-unicorn/node_modules/locate-path": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", @@ -13161,6 +13406,18 @@ "node": ">=8" } }, + "node_modules/eslint-plugin-unicorn/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/eslint-plugin-unicorn/node_modules/normalize-package-data": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", @@ -13250,6 +13507,21 @@ "node": ">=8" } }, + "node_modules/eslint-plugin-unicorn/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/eslint-plugin-unicorn/node_modules/type-fest": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", @@ -13526,9 +13798,9 @@ } }, "node_modules/espree": { - "version": "9.4.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.0.tgz", - "integrity": "sha512-DQmnRpLj7f6TgN/NYb0MTzJXL+vJF9h3pHy4JhCIs3zwcgez8xmGg3sXHcEO97BrmO2OSvCwMdfdlyl+E9KjOw==", + "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", @@ -13711,18 +13983,6 @@ "node": ">= 0.8.0" } }, - "node_modules/expand-tilde": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", - "integrity": "sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==", - "dev": true, - "dependencies": { - "homedir-polyfill": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/expect": { "version": "28.1.3", "resolved": "https://registry.npmjs.org/expect/-/expect-28.1.3.tgz", @@ -13740,13 +14000,13 @@ } }, "node_modules/express": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.1.tgz", - "integrity": "sha512-zZBcOX9TfehHQhtupq57OF8lFZ3UZi08Y97dwFCkD8p9d/d2Y3M+ykKcwaMDEL+4qyUolgBDX6AblpR3fL212Q==", + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.0", + "body-parser": "1.20.1", "content-disposition": "0.5.4", "content-type": "~1.0.4", "cookie": "0.5.0", @@ -13765,7 +14025,7 @@ "parseurl": "~1.3.3", "path-to-regexp": "0.1.7", "proxy-addr": "~2.0.7", - "qs": "6.10.3", + "qs": "6.11.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", "send": "0.18.0", @@ -13840,9 +14100,9 @@ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, "node_modules/express/node_modules/qs": { - "version": "6.10.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", - "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", "dependencies": { "side-channel": "^1.0.4" }, @@ -14073,9 +14333,9 @@ } }, "node_modules/file-replace-loader/node_modules/loader-utils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz", - "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", "dependencies": { "big.js": "^5.2.2", "emojis-list": "^3.0.0", @@ -14188,22 +14448,6 @@ "node": ">= 0.12" } }, - "node_modules/find-node-modules": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/find-node-modules/-/find-node-modules-2.1.3.tgz", - "integrity": "sha512-UC2I2+nx1ZuOBclWVNdcnbDR5dlrOdVb7xNjmT/lHE+LsgztWks3dG7boJ37yTS/venXw84B/mAW9uHVoC5QRg==", - "dev": true, - "dependencies": { - "findup-sync": "^4.0.0", - "merge": "^2.1.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==", - "dev": true - }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -14229,21 +14473,6 @@ "node": ">=0.8.22" } }, - "node_modules/findup-sync": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-4.0.0.tgz", - "integrity": "sha512-6jvvn/12IC4quLBL1KNokxC7wWTvYncaVUYSoxWw7YykPLuRrnv4qdHcSOywOI5RpkOVGeQRtWM8/q+G6W6qfQ==", - "dev": true, - "dependencies": { - "detect-file": "^1.0.0", - "is-glob": "^4.0.0", - "micromatch": "^4.0.2", - "resolve-dir": "^1.0.1" - }, - "engines": { - "node": ">= 8" - } - }, "node_modules/flat-cache": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", @@ -14283,6 +14512,15 @@ } } }, + "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", @@ -14470,9 +14708,9 @@ } }, "node_modules/gensequence": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/gensequence/-/gensequence-4.0.2.tgz", - "integrity": "sha512-mQiFskYFPFDSUpBJ/n3ebAV2Ufu6DZGvUPXzyWYzFfJr6/DyOOZVnjx6VTWE4y0RLvYWnc5tZq5sCjzEWhRjqQ==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/gensequence/-/gensequence-4.0.3.tgz", + "integrity": "sha512-izr+MKqJKjexkvLiPGhW96elQX8TuUR/su/xzILxjqzU1RDz1n1ZbqwDUnNFaRcq0gFR3oQfNH2JOH4Je1x/QA==", "dev": true, "engines": { "node": ">=14" @@ -14827,54 +15065,6 @@ "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", "dev": true }, - "node_modules/global-modules": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", - "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", - "dev": true, - "dependencies": { - "global-prefix": "^1.0.1", - "is-windows": "^1.0.1", - "resolve-dir": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/global-prefix": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", - "integrity": "sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==", - "dev": true, - "dependencies": { - "expand-tilde": "^2.0.2", - "homedir-polyfill": "^1.0.1", - "ini": "^1.3.4", - "is-windows": "^1.0.1", - "which": "^1.2.14" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/global-prefix/node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true - }, - "node_modules/global-prefix/node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } - }, "node_modules/globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", @@ -14909,6 +15099,18 @@ "integrity": "sha512-xYfnw62CKG8nLkZBfWbhWwDw02CHty86jfPcc2cr3ZfeuK9ysoVPPEUxf21bAD/rWAgk52SuBrLJlefNy8mvFg==", "dev": true }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/graceful-fs": { "version": "4.2.10", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", @@ -15097,18 +15299,6 @@ "integrity": "sha512-7kIufnBqdsBGcSZLPJwqHT3yhk1QTsSlFsVD3kx5ixH/AlgBs9yM1q6DPhXZ8f8gtdqgh7N7/5btRLpQsS2gHw==", "dev": true }, - "node_modules/homedir-polyfill": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", - "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", - "dev": true, - "dependencies": { - "parse-passwd": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/hosted-git-info": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", @@ -15362,9 +15552,9 @@ } }, "node_modules/husky": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/husky/-/husky-8.0.1.tgz", - "integrity": "sha512-xs7/chUH/CKdOCs7Zy0Aev9e/dKOMZf3K1Az1nar3tzlv0jfqnYtu235bstsWTmXOR0EfINrPa97yy4Lz6RiKw==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/husky/-/husky-8.0.2.tgz", + "integrity": "sha512-Tkv80jtvbnkK3mYWxPZePGFpQ/tT3HNSs/sasF9P2YfkMezDl3ON37YN6jUUI4eTg5LcyVynlb6r4eyvOmspvg==", "dev": true, "bin": { "husky": "lib/bin.js" @@ -15914,6 +16104,15 @@ "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", "dev": true }, + "node_modules/is-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", + "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-negative-zero": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", @@ -15967,6 +16166,15 @@ "node": ">=8" } }, + "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-obj": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", @@ -16015,6 +16223,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-set": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", + "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-shared-array-buffer": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", @@ -16081,6 +16298,25 @@ "node": ">=0.10.0" } }, + "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-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", @@ -16098,11 +16334,14 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-utf8": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", - "integrity": "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==", - "dev": true + "node_modules/is-weakmap": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", + "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/is-weakref": { "version": "1.0.2", @@ -16116,21 +16355,25 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-weakset": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", + "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-what": { "version": "3.14.1", "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==", "dev": true }, - "node_modules/is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-wsl": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", @@ -18912,9 +19155,9 @@ } }, "node_modules/jsdom/node_modules/parse5": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.1.tgz", - "integrity": "sha512-kwpuwzB+px5WUg9pyK0IcK/shltJN5/OVhQagxhCQNtT9Y9QRZqNY2e1cmbu/paRh5LMnz/oVTVLBpjFmMZhSg==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", "dependencies": { "entities": "^4.4.0" }, @@ -19141,9 +19384,9 @@ } }, "node_modules/known-css-properties": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.25.0.tgz", - "integrity": "sha512-b0/9J1O9Jcyik1GC6KC42hJ41jKwdO/Mq8Mdo5sYN+IuRTXs2YFHZC3kZSx6ueusqa95x3wLYe/ytKjbAfGixA==", + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.26.0.tgz", + "integrity": "sha512-5FZRzrZzNTBruuurWpvZnvP9pum+fe0HcK8z/ooo+U+Hmp4vtbyp1/QDsqmufirXy4egGzbaH/y2uCZf+6W5Kg==", "dev": true }, "node_modules/lazy": { @@ -19285,9 +19528,9 @@ } }, "node_modules/lilconfig": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.5.tgz", - "integrity": "sha512-xaYmXZtTHPAw5m+xLN8ab9C+3a8YmV3asNSPOATITbtwrfbwaLJj8h66H1WMIpALCkqsIzK3h7oQ+PdX+LQ9Eg==", + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.6.tgz", + "integrity": "sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg==", "dev": true, "engines": { "node": ">=10" @@ -19306,24 +19549,24 @@ "dev": true }, "node_modules/lint-staged": { - "version": "13.0.3", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-13.0.3.tgz", - "integrity": "sha512-9hmrwSCFroTSYLjflGI8Uk+GWAwMB4OlpU4bMJEAT5d/llQwtYKoim4bLOyLCuWFAhWEupE0vkIFqtw/WIsPug==", + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-13.1.0.tgz", + "integrity": "sha512-pn/sR8IrcF/T0vpWLilih8jmVouMlxqXxKuAojmbiGX5n/gDnz+abdPptlj0vYnbfE0SQNl3CY/HwtM0+yfOVQ==", "dev": true, "dependencies": { "cli-truncate": "^3.1.0", - "colorette": "^2.0.17", - "commander": "^9.3.0", + "colorette": "^2.0.19", + "commander": "^9.4.1", "debug": "^4.3.4", "execa": "^6.1.0", - "lilconfig": "2.0.5", - "listr2": "^4.0.5", + "lilconfig": "2.0.6", + "listr2": "^5.0.5", "micromatch": "^4.0.5", "normalize-path": "^3.0.0", "object-inspect": "^1.12.2", "pidtree": "^0.6.0", "string-argv": "^0.3.1", - "yaml": "^2.1.1" + "yaml": "^2.1.3" }, "bin": { "lint-staged": "bin/lint-staged.js" @@ -19455,22 +19698,22 @@ } }, "node_modules/listr2": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-4.0.5.tgz", - "integrity": "sha512-juGHV1doQdpNT3GSTs9IUN43QJb7KHdF9uqg7Vufs/tG9VTzpFphqF4pm/ICdAABGQxsyNn9CiYA3StkI6jpwA==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-5.0.6.tgz", + "integrity": "sha512-u60KxKBy1BR2uLJNTWNptzWQ1ob/gjMzIJPZffAENzpZqbMZ/5PrXXOomDcevIS/+IB7s1mmCEtSlT2qHWMqag==", "dev": true, "dependencies": { "cli-truncate": "^2.1.0", - "colorette": "^2.0.16", + "colorette": "^2.0.19", "log-update": "^4.0.0", "p-map": "^4.0.0", "rfdc": "^1.3.0", - "rxjs": "^7.5.5", + "rxjs": "^7.5.7", "through": "^2.3.8", "wrap-ansi": "^7.0.0" }, "engines": { - "node": ">=12" + "node": "^14.13.1 || >=16.0.0" }, "peerDependencies": { "enquirer": ">= 2.3.0 < 3" @@ -19609,9 +19852,9 @@ } }, "node_modules/loader-utils": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.0.tgz", - "integrity": "sha512-HVl9ZqccQihZ7JM85dco1MvO9G+ONvxoGa9rkhzFsneGLKSUg1gJf9bWzhRhcvm2qChhWpebQhP44qxjKIUCaQ==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.1.tgz", + "integrity": "sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw==", "dev": true, "engines": { "node": ">= 12.13.0" @@ -19696,10 +19939,10 @@ "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" }, - "node_modules/lodash.clonedeep": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==", + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", "dev": true }, "node_modules/lodash.debounce": { @@ -19714,16 +19957,28 @@ "integrity": "sha512-7FGG40uhC8Mm633uKW1r58aElFlBlxCrg9JfSi3P6aYiWmfiWF0PgMd86ZUsxE5GwWPdHoS2+48bwTh2VPkIQA==", "dev": true }, + "node_modules/lodash.isfunction": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz", + "integrity": "sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw==", + "dev": true + }, "node_modules/lodash.ismatch": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz", "integrity": "sha512-fPMfXjGQEV9Xsq/8MTSgUf255gawYRbjwMyDbcvDhXgV7enSZA0hynz6vMPnpAb5iONEzBHBPsT+0zes5Z301g==", "dev": true }, - "node_modules/lodash.map": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.map/-/lodash.map-4.6.0.tgz", - "integrity": "sha512-worNHGKLDetmcEYDvh2stPCrrQRkP20E4l0iIS7F8EvzMqBBi7ltvFN5m1HvTf1P7Jk1txKhvFcmYsCr8O2F1Q==", + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "dev": true + }, + "node_modules/lodash.kebabcase": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz", + "integrity": "sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==", "dev": true }, "node_modules/lodash.memoize": { @@ -19738,12 +19993,42 @@ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, + "node_modules/lodash.mergewith": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz", + "integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==", + "dev": true + }, + "node_modules/lodash.snakecase": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz", + "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==", + "dev": true + }, + "node_modules/lodash.startcase": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.startcase/-/lodash.startcase-4.4.0.tgz", + "integrity": "sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==", + "dev": true + }, "node_modules/lodash.truncate": { "version": "4.4.2", "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", "dev": true }, + "node_modules/lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", + "dev": true + }, + "node_modules/lodash.upperfirst": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/lodash.upperfirst/-/lodash.upperfirst-4.3.1.tgz", + "integrity": "sha512-sReKOYJIJf74dhJONhU4e0/shzi1trVbSWDOhKYE5XV2O+H7Sb2Dihwuc7xWxVl+DgFPyTqIN3zMfT9cq5iWDg==", + "dev": true + }, "node_modules/log-driver": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/log-driver/-/log-driver-1.2.7.tgz", @@ -19942,15 +20227,6 @@ "integrity": "sha512-WpG9CcFAOjz/FtNht+QJeGpvVl/cdR6P0z6OcXSkr8wFJOsV2GRj2j10JLfjuA4aYkcKCNIEqRGCyTife9R8/g==", "dev": true }, - "node_modules/longest": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/longest/-/longest-2.0.1.tgz", - "integrity": "sha512-Ajzxb8CM6WAnFjgiloPsI3bF+WCxcvhdIG3KNA2KN962+tdBsHcuQ4k4qX/EcS/2CRkcc0iAkR956Nib6aXU/Q==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/lru-cache": { "version": "7.14.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.14.0.tgz", @@ -20113,9 +20389,9 @@ } }, "node_modules/memfs": { - "version": "3.4.7", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.4.7.tgz", - "integrity": "sha512-ygaiUSNalBX85388uskeCyhSAoOSgzBbtVCr9jA2RROssFL9Q19/ZXFqS+2Th2sr1ewNIWgFdLzLC3Yl1Zv+lw==", + "version": "3.4.12", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.4.12.tgz", + "integrity": "sha512-BcjuQn6vfqP+k100e0E9m61Hyqa//Brp+I3f0OBmN0ATHlFA8vx3Lt8z57R3u2bPqe3WGDBC+nF72fTH7isyEw==", "dev": true, "dependencies": { "fs-monkey": "^1.0.3" @@ -20315,12 +20591,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/merge": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/merge/-/merge-2.1.1.tgz", - "integrity": "sha512-jz+Cfrg9GWOZbQAnDQ4hlVnQky+341Yk5ru8bZSe6sIDTCIg8n9i/u7hSQGSVOF3C7lH6mGtqjkiT9G4wFLL0w==", - "dev": true - }, "node_modules/merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", @@ -20778,10 +21048,16 @@ "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/needle": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/needle/-/needle-3.1.0.tgz", - "integrity": "sha512-gCE9weDhjVGCRqS8dwDR/D3GTAeyXLXuqp7I8EzH6DllZGXSUyxuqqLh+YX9rMAWaaTFyVAg6rHGL25dqvczKw==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/needle/-/needle-3.2.0.tgz", + "integrity": "sha512-oUvzXnyLiVyVGoianLijF9O/RecZUf7TkBfimjGrLM4eQhXyeJwM6GeAWccwfQ9aa4gMCZKqhAOuLaMIcQxajQ==", "dev": true, "optional": true, "dependencies": { @@ -20849,9 +21125,9 @@ "dev": true }, "node_modules/ng-mocks": { - "version": "14.2.3", - "resolved": "https://registry.npmjs.org/ng-mocks/-/ng-mocks-14.2.3.tgz", - "integrity": "sha512-WNNOtz8P05KJCvTGYUjqPJ/d1DdkVL1xtQFgUAoVIpa/SXxjCjq3LGGti9ZK4MWGrEZX6e1wUbAV+3mrywd93Q==", + "version": "14.5.0", + "resolved": "https://registry.npmjs.org/ng-mocks/-/ng-mocks-14.5.0.tgz", + "integrity": "sha512-bLevjrTxNmORUnEohOwy31NuvQxs62xoljWJTWjH/qaFdX9fuzg7nt+zcxUfqERFZumipvGraTdi+/J2PBUisg==", "dev": true, "funding": { "url": "https://github.com/sponsors/satanTime" @@ -20941,9 +21217,9 @@ } }, "node_modules/ngx-infinite-scroll": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/ngx-infinite-scroll/-/ngx-infinite-scroll-14.0.0.tgz", - "integrity": "sha512-YZB5PBPXSERNtCGQRZTVflbgkh5asp01NPfC8KPItemmQik1Ip8ZCCbcyHA77TDTdilmaiu8TbguA3geg/LMWw==", + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/ngx-infinite-scroll/-/ngx-infinite-scroll-14.0.1.tgz", + "integrity": "sha512-PlGL29d2PxNJTn6qdXs4Es0HlJTZ/ZqOVvFWECWm7mK2fN/q+q62s0iUQ7xRf76NuqoNovXvrjZ1zwLFT6c0Wg==", "dependencies": { "tslib": "^2.3.0" }, @@ -20953,9 +21229,9 @@ } }, "node_modules/ngx-toastr": { - "version": "15.2.0", - "resolved": "https://registry.npmjs.org/ngx-toastr/-/ngx-toastr-15.2.0.tgz", - "integrity": "sha512-IrDWKYql3O5yPhmaWu78QilB/9j+J78tyfS/mMoX/yCdVc0zmLsv73OHvckG9XgEhVuQjuxz0yIGVaWff91m4A==", + "version": "15.2.2", + "resolved": "https://registry.npmjs.org/ngx-toastr/-/ngx-toastr-15.2.2.tgz", + "integrity": "sha512-srdxKKf1+B/7z11M4Ty7bnkme2xjdUcnP/t7mNG/2gRM1h0P/7Lbz71FIQHuKZOCdnGdXjsT6OXU0dRvNyrkyg==", "dependencies": { "tslib": "^2.3.0" }, @@ -22027,15 +22303,6 @@ "node": ">= 0.10" } }, - "node_modules/parse-passwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", - "integrity": "sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/parse5": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", @@ -22378,9 +22645,9 @@ } }, "node_modules/pm2": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/pm2/-/pm2-5.2.0.tgz", - "integrity": "sha512-PO5hMVhQ85cTszFM++6v07Me9hPJMkFbHjkFigtMMk+La8ty2wCi2dlBTeZYJDhPUSjK8Ccltpq2buNRcyMOTw==", + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/pm2/-/pm2-5.2.2.tgz", + "integrity": "sha512-mASxgh/MZhtVze/wijGf+tE6JKdA3lEq64FOfXVhhArkuk9Qxl4ePw9XgFJaArOXnU3bde+KbeAJHYxppVvYBQ==", "dev": true, "dependencies": { "@pm2/agent": "~2.0.0", @@ -22390,11 +22657,11 @@ "async": "~3.2.0", "blessed": "0.1.81", "chalk": "3.0.0", - "chokidar": "^3.5.1", + "chokidar": "^3.5.3", "cli-tableau": "^2.0.0", "commander": "2.15.1", "croner": "~4.1.92", - "dayjs": "~1.8.25", + "dayjs": "~1.11.5", "debug": "^4.3.1", "enquirer": "2.3.6", "eventemitter2": "5.0.1", @@ -22408,7 +22675,7 @@ "pm2-multimeter": "^0.1.2", "promptly": "^2", "semver": "^7.2", - "source-map-support": "0.5.19", + "source-map-support": "0.5.21", "sprintf-js": "1.1.2", "vizion": "~2.2.1", "yamljs": "0.3.0" @@ -22587,6 +22854,12 @@ "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", "dev": true }, + "node_modules/pm2/node_modules/dayjs": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.6.tgz", + "integrity": "sha512-zZbY5giJAinCG+7AGaw0wIhNZ6J8AhWuSXKvuc1KAyMiRsvGQWqh4L+MomvhdAYjN+lqvVCMq1I41e3YHvXkyQ==", + "dev": true + }, "node_modules/pm2/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -22622,25 +22895,6 @@ "ms": "^2.1.1" } }, - "node_modules/pm2/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/pm2/node_modules/source-map-support": { - "version": "0.5.19", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", - "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", - "dev": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, "node_modules/pm2/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -22827,9 +23081,9 @@ } }, "node_modules/postcss-custom-properties": { - "version": "12.1.9", - "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-12.1.9.tgz", - "integrity": "sha512-/E7PRvK8DAVljBbeWrcEQJPG72jaImxF3vvCNFwv9cC8CzigVoNIpeyfnJzphnN3Fd8/auBf5wvkw6W9MfmTyg==", + "version": "12.1.11", + "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-12.1.11.tgz", + "integrity": "sha512-0IDJYhgU8xDv1KY6+VgUwuQkVtmYzRwu+dMjnmdMafXYv86SWqfxkc7qdDvWS38vsjaEtv8e0vGOUQrAiMBLpQ==", "dev": true, "dependencies": { "postcss-value-parser": "^4.2.0" @@ -23394,9 +23648,9 @@ } }, "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==", + "version": "6.0.11", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.11.tgz", + "integrity": "sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g==", "dev": true, "dependencies": { "cssesc": "^3.0.0", @@ -24328,19 +24582,6 @@ "node": ">=8" } }, - "node_modules/resolve-dir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", - "integrity": "sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==", - "dev": true, - "dependencies": { - "expand-tilde": "^2.0.0", - "global-modules": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/resolve-from": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", @@ -24379,9 +24620,9 @@ } }, "node_modules/resolve-url-loader/node_modules/loader-utils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz", - "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", "dev": true, "dependencies": { "big.js": "^5.2.2", @@ -26138,15 +26379,15 @@ "dev": true }, "node_modules/stylelint": { - "version": "14.13.0", - "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-14.13.0.tgz", - "integrity": "sha512-NJSAdloiAB/jgVJKxMR90mWlctvmeBFGFVUvyKngi9+j/qPSJ5ZB+u8jOmGbLTnS7OHrII9NFGehPRyar8U5vg==", + "version": "14.16.0", + "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-14.16.0.tgz", + "integrity": "sha512-X6uTi9DcxjzLV8ZUAjit1vsRtSwcls0nl07c9rqOPzvpA8IvTX/xWEkBRowS0ffevRrqkHa/ThDEu86u73FQDg==", "dev": true, "dependencies": { "@csstools/selector-specificity": "^2.0.2", "balanced-match": "^2.0.0", "colord": "^2.9.3", - "cosmiconfig": "^7.0.1", + "cosmiconfig": "^7.1.0", "css-functions-list": "^3.1.0", "debug": "^4.3.4", "fast-glob": "^3.2.12", @@ -26156,21 +26397,21 @@ "globby": "^11.1.0", "globjoin": "^0.1.4", "html-tags": "^3.2.0", - "ignore": "^5.2.0", + "ignore": "^5.2.1", "import-lazy": "^4.0.0", "imurmurhash": "^0.1.4", "is-plain-object": "^5.0.0", - "known-css-properties": "^0.25.0", + "known-css-properties": "^0.26.0", "mathml-tag-names": "^2.1.3", "meow": "^9.0.0", "micromatch": "^4.0.5", "normalize-path": "^3.0.0", "picocolors": "^1.0.0", - "postcss": "^8.4.16", + "postcss": "^8.4.19", "postcss-media-query-parser": "^0.2.3", "postcss-resolve-nested-selector": "^0.1.1", "postcss-safe-parser": "^6.0.0", - "postcss-selector-parser": "^6.0.10", + "postcss-selector-parser": "^6.0.11", "postcss-value-parser": "^4.2.0", "resolve-from": "^5.0.0", "string-width": "^4.2.3", @@ -26178,7 +26419,7 @@ "style-search": "^0.1.0", "supports-hyperlinks": "^2.3.0", "svg-tags": "^1.0.0", - "table": "^6.8.0", + "table": "^6.8.1", "v8-compile-cache": "^2.3.0", "write-file-atomic": "^4.0.2" }, @@ -26194,9 +26435,9 @@ } }, "node_modules/stylelint-config-prettier": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/stylelint-config-prettier/-/stylelint-config-prettier-9.0.3.tgz", - "integrity": "sha512-5n9gUDp/n5tTMCq1GLqSpA30w2sqWITSSEiAWQlpxkKGAUbjcemQ0nbkRvRUa0B1LgD3+hCvdL7B1eTxy1QHJg==", + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/stylelint-config-prettier/-/stylelint-config-prettier-9.0.4.tgz", + "integrity": "sha512-38nIGTGpFOiK5LjJ8Ma1yUgpKENxoKSOhbDNSemY7Ep0VsJoXIW9Iq/2hSt699oB9tReynfWicTAoIHiq8Rvbg==", "dev": true, "bin": { "stylelint-config-prettier": "bin/check.js", @@ -26222,47 +26463,44 @@ } }, "node_modules/stylelint-config-recommended": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-8.0.0.tgz", - "integrity": "sha512-IK6dWvE000+xBv9jbnHOnBq01gt6HGVB2ZTsot+QsMpe82doDQ9hvplxfv4YnpEuUwVGGd9y6nbaAnhrjcxhZQ==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-9.0.0.tgz", + "integrity": "sha512-9YQSrJq4NvvRuTbzDsWX3rrFOzOlYBmZP+o513BJN/yfEmGSr0AxdvrWs0P/ilSpVV/wisamAHu5XSk8Rcf4CQ==", "dev": true, "peerDependencies": { - "stylelint": "^14.8.0" + "stylelint": "^14.10.0" } }, "node_modules/stylelint-config-recommended-scss": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/stylelint-config-recommended-scss/-/stylelint-config-recommended-scss-7.0.0.tgz", - "integrity": "sha512-rGz1J4rMAyJkvoJW4hZasuQBB7y9KIrShb20l9DVEKKZSEi1HAy0vuNlR8HyCKy/jveb/BdaQFcoiYnmx4HoiA==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/stylelint-config-recommended-scss/-/stylelint-config-recommended-scss-8.0.0.tgz", + "integrity": "sha512-BxjxEzRaZoQb7Iinc3p92GS6zRdRAkIuEu2ZFLTxJK2e1AIcCb5B5MXY9KOXdGTnYFZ+KKx6R4Fv9zU6CtMYPQ==", "dev": true, "dependencies": { "postcss-scss": "^4.0.2", - "stylelint-config-recommended": "^8.0.0", + "stylelint-config-recommended": "^9.0.0", "stylelint-scss": "^4.0.0" }, "peerDependencies": { - "stylelint": "^14.4.0" + "postcss": "^8.3.3", + "stylelint": "^14.10.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + } } }, "node_modules/stylelint-config-standard": { - "version": "28.0.0", - "resolved": "https://registry.npmjs.org/stylelint-config-standard/-/stylelint-config-standard-28.0.0.tgz", - "integrity": "sha512-q/StuowDdDmFCravzGHAwgS9pjX0bdOQUEBBDIkIWsQuYGgYz/xsO8CM6eepmIQ1fc5bKdDVimlJZ6MoOUcJ5Q==", + "version": "29.0.0", + "resolved": "https://registry.npmjs.org/stylelint-config-standard/-/stylelint-config-standard-29.0.0.tgz", + "integrity": "sha512-uy8tZLbfq6ZrXy4JKu3W+7lYLgRQBxYTUUB88vPgQ+ZzAxdrvcaSUW9hOMNLYBnwH+9Kkj19M2DHdZ4gKwI7tg==", "dev": true, "dependencies": { "stylelint-config-recommended": "^9.0.0" }, "peerDependencies": { - "stylelint": "^14.11.0" - } - }, - "node_modules/stylelint-config-standard/node_modules/stylelint-config-recommended": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-9.0.0.tgz", - "integrity": "sha512-9YQSrJq4NvvRuTbzDsWX3rrFOzOlYBmZP+o513BJN/yfEmGSr0AxdvrWs0P/ilSpVV/wisamAHu5XSk8Rcf4CQ==", - "dev": true, - "peerDependencies": { - "stylelint": "^14.10.0" + "stylelint": "^14.14.0" } }, "node_modules/stylelint-order": { @@ -26370,6 +26608,15 @@ "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", "dev": true }, + "node_modules/stylelint/node_modules/ignore": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.1.tgz", + "integrity": "sha512-d2qQLzTJ9WxQftPAuEQpSPmKqzxePjzVbpAVv62AQ64NTL+wR4JkrVqR/LqFsFEUsHDAiId52mJteHDFuDkElA==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, "node_modules/stylelint/node_modules/ini": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", @@ -26441,6 +26688,30 @@ "node": ">=8" } }, + "node_modules/stylelint/node_modules/postcss": { + "version": "8.4.20", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.20.tgz", + "integrity": "sha512-6Q04AXR1212bXr5fh03u8aAwbLxAQNGQ/Q1LNa0VfOI06ZAlhPHtQvE4OIdpj4kLThXilalPnmDSOD65DcHt+g==", + "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/stylelint/node_modules/read-pkg": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", @@ -26699,9 +26970,9 @@ "dev": true }, "node_modules/swiper": { - "version": "8.4.2", - "resolved": "https://registry.npmjs.org/swiper/-/swiper-8.4.2.tgz", - "integrity": "sha512-nMD/RHVYxJxrLqjWQX2n0B94ANwpnuUv/3PUDT8Aaf+mSteFvZGFng4ypAYq70zW4svryyV+8TRlbRZ+6cgv9A==", + "version": "8.4.5", + "resolved": "https://registry.npmjs.org/swiper/-/swiper-8.4.5.tgz", + "integrity": "sha512-zveyEFBBv4q1sVkbJHnuH4xCtarKieavJ4SxP0QEHvdpPLJRuD7j/Xg38IVVLbp7Db6qrPsLUePvxohYx39Agw==", "funding": [ { "type": "patreon", @@ -26763,9 +27034,9 @@ } }, "node_modules/table": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/table/-/table-6.8.0.tgz", - "integrity": "sha512-s/fitrbVeEyHKFa7mFdkuQMWlH1Wgw/yEXMt5xACT4ZpzWFluehAxRtUUQKPuWhaLAWhFcVx6w3oC8VKaUfPGA==", + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/table/-/table-6.8.1.tgz", + "integrity": "sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==", "dev": true, "dependencies": { "ajv": "^8.0.1", @@ -27605,9 +27876,9 @@ } }, "node_modules/tslib": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", + "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==" }, "node_modules/tsutils": { "version": "3.21.0", @@ -28115,9 +28386,9 @@ } }, "node_modules/vscode-languageserver-textdocument": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.7.tgz", - "integrity": "sha512-bFJH7UQxlXT8kKeyiyu41r22jCZXG8kuuVVA33OEJn1diWOZK5n8zBSPZFHVBOu8kXZ6h0LIRhf5UnCo61J4Hg==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.8.tgz", + "integrity": "sha512-1bonkGqQs5/fxGT5UchTgjGVnfysL0O8v1AYMBjqTbWQTFn721zaPGDYFkOKtfDgFiSgXM3KwaG3FMGfW4Ed9Q==", "dev": true }, "node_modules/vscode-uri": { @@ -28576,6 +28847,41 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/which-collection": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", + "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", + "dev": true, + "dependencies": { + "is-map": "^2.0.1", + "is-set": "^2.0.1", + "is-weakmap": "^2.0.1", + "is-weakset": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", + "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/wide-align": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", @@ -29022,9 +29328,9 @@ } }, "@angular-builders/custom-webpack": { - "version": "14.0.1", - "resolved": "https://registry.npmjs.org/@angular-builders/custom-webpack/-/custom-webpack-14.0.1.tgz", - "integrity": "sha512-QDsSFo80I8oLBzvr7qIxcdEfvDMEeJmwYRrJ/hG8O+XVdYsUkkj4nEvBI5fKKBOfcRgx1R/XrEDtJEeolEQeig==", + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/@angular-builders/custom-webpack/-/custom-webpack-14.1.0.tgz", + "integrity": "sha512-FLGDrBOg04cYvzCudeb15LWY2v91dtJ5+AfmP0aS/0T0D0AYmY4uM3FxZeh4jJcWETLvnHVFBCjan6y2Ct9J3A==", "dev": true, "requires": { "@angular-devkit/architect": ">=0.1400.0 < 0.1500.0", @@ -29037,12 +29343,12 @@ } }, "@angular-devkit/architect": { - "version": "0.1402.5", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1402.5.tgz", - "integrity": "sha512-vtJEwB51UEY1Q7FCI7xGLdhdb2SRTtI1Qs0or95momn85NuxlaMQsXK1Wxu9/EwtWKZK8dXePXbB/hpiNt61JQ==", + "version": "0.1402.10", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1402.10.tgz", + "integrity": "sha512-/6YmPrgataj1jD2Uqd1ED+CG4DaZGacoeZd/89hH7hF76Nno8K18DrSOqJAEmDnOWegpSRGVLd0qP09IHmaG5w==", "dev": true, "requires": { - "@angular-devkit/core": "14.2.5", + "@angular-devkit/core": "14.2.10", "rxjs": "6.6.7" }, "dependencies": { @@ -29064,15 +29370,15 @@ } }, "@angular-devkit/build-angular": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-14.2.5.tgz", - "integrity": "sha512-jSgH11E+zs1C24lXj7R/PgXsTUpoYoMr1GtO6mpVROgXL5czVlL+b/B1p2HwbcAKuI9WXb48X6OZ6fOZhDQlSg==", + "version": "14.2.10", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-14.2.10.tgz", + "integrity": "sha512-VCeZAyq4uPCJukKInaSiD4i/GgxgcU4jFlLFQtoYNmaBS4xbPOymL19forRIihiV0dwNEa2L694vRTAPMBxIfw==", "dev": true, "requires": { "@ampproject/remapping": "2.2.0", - "@angular-devkit/architect": "0.1402.5", - "@angular-devkit/build-webpack": "0.1402.5", - "@angular-devkit/core": "14.2.5", + "@angular-devkit/architect": "0.1402.10", + "@angular-devkit/build-webpack": "0.1402.10", + "@angular-devkit/core": "14.2.10", "@babel/core": "7.18.10", "@babel/generator": "7.18.12", "@babel/helper-annotate-as-pure": "7.18.6", @@ -29083,7 +29389,7 @@ "@babel/runtime": "7.18.9", "@babel/template": "7.18.10", "@discoveryjs/json-ext": "0.5.7", - "@ngtools/webpack": "14.2.5", + "@ngtools/webpack": "14.2.10", "ansi-colors": "4.1.3", "babel-loader": "8.2.5", "babel-plugin-istanbul": "6.1.1", @@ -29102,7 +29408,7 @@ "less": "4.1.3", "less-loader": "11.0.0", "license-webpack-plugin": "4.0.2", - "loader-utils": "3.2.0", + "loader-utils": "3.2.1", "mini-css-extract-plugin": "2.6.1", "minimatch": "5.1.0", "open": "8.4.0", @@ -29150,16 +29456,22 @@ "dev": true } } + }, + "tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", + "dev": true } } }, "@angular-devkit/build-webpack": { - "version": "0.1402.5", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1402.5.tgz", - "integrity": "sha512-h+o0GZD9iATwWjaTiUR0lJ3QZ9twUOJ1sotRchXHzAXMuaDk8wqqPriL5S0qDMlA2QqpNt4OD9rodUCRwae7fw==", + "version": "0.1402.10", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1402.10.tgz", + "integrity": "sha512-h+2MaSY7QSvoJ3R+Hvin21jVCfPGOTLdASIUk4Jmq6J3y5BSku3KSSaV8dWoBOBkFCwQyPQMRjiHoHKLpC1K7g==", "dev": true, "requires": { - "@angular-devkit/architect": "0.1402.5", + "@angular-devkit/architect": "0.1402.10", "rxjs": "6.6.7" }, "dependencies": { @@ -29181,9 +29493,9 @@ } }, "@angular-devkit/core": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-14.2.5.tgz", - "integrity": "sha512-lSje+HX0fx9Y2A4k63jVHrWdGT4wellhwcZpTCv9P6LvdfTkAlrfra3TaYhUPjavCsPwlRC/VVQN3Qkzk5m6gA==", + "version": "14.2.10", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-14.2.10.tgz", + "integrity": "sha512-K4AO7mROTdbhQ7chtyQd6oPwmuL+BPUh+wn6Aq1qrmYJK4UZYFOPp8fi/Ehs8meCEeywtrssOPfrOE4Gsre9dg==", "requires": { "ajv": "8.11.0", "ajv-formats": "2.1.1", @@ -29208,11 +29520,11 @@ } }, "@angular-devkit/schematics": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-14.2.5.tgz", - "integrity": "sha512-3a//d8f/yuR1F2QXAyX4pShWdkHBWbY1qpqqVnN9gRJ+ye6pY098gsCQKpKXPZGeV08ugu5v79f5JELMthBBSQ==", + "version": "14.2.10", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-14.2.10.tgz", + "integrity": "sha512-MMp31KpJTwKHisXOq+6VOXYApq97hZxFaFmZk396X5aIFTCELUwjcezQDk+u2nEs5iK/COUfnN3plGcfJxYhQA==", "requires": { - "@angular-devkit/core": "14.2.5", + "@angular-devkit/core": "14.2.10", "jsonc-parser": "3.1.0", "magic-string": "0.26.2", "ora": "5.4.1", @@ -29235,101 +29547,120 @@ } }, "@angular-eslint/builder": { - "version": "14.1.2", - "resolved": "https://registry.npmjs.org/@angular-eslint/builder/-/builder-14.1.2.tgz", - "integrity": "sha512-J+LRidjlJOGfRNXJwUyOhz5TnasEBK+kL3QkkCE4ZSt/dH40QqT+3q9qV5zc45wdaAeJM4/jp1IhI6kPwWI5Yw==", + "version": "14.4.0", + "resolved": "https://registry.npmjs.org/@angular-eslint/builder/-/builder-14.4.0.tgz", + "integrity": "sha512-AhAUFvSg0urtb6Lsowvuxwu6DMXUy0BPwrnfNOBGjRt9vG7F9kgXXAsm5DnIS0GNy/mLZ9mSfa86fv++1e0KUA==", "dev": true, "requires": {} }, "@angular-eslint/bundled-angular-compiler": { - "version": "14.1.2", - "resolved": "https://registry.npmjs.org/@angular-eslint/bundled-angular-compiler/-/bundled-angular-compiler-14.1.2.tgz", - "integrity": "sha512-d5/jTKXP+t9hNSucj3m8zZYBl62fZ2xFMVNbAOArYAkA7WwwX3D7Gae57BNW54cd2fl2/is7Dn6UgYhu1wqkSQ==", + "version": "14.4.0", + "resolved": "https://registry.npmjs.org/@angular-eslint/bundled-angular-compiler/-/bundled-angular-compiler-14.4.0.tgz", + "integrity": "sha512-KMHPHd24s0HVvAP/DxSSqhYBWhwW8FgS/r0Uwv8eWpsIdc/z/Chd2ush2SgPchmmquAXTgOZsbEY7ZmW+XkJfQ==", "dev": true }, "@angular-eslint/eslint-plugin": { - "version": "14.1.2", - "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin/-/eslint-plugin-14.1.2.tgz", - "integrity": "sha512-5pJaTcFfM7yDHNtMxw3uNTpBTLjNYH9mlOLX5FFQ9EahAuycwCtV8VJkIntK2ZiOTdRVJYA9/PEdD/xVxX02rw==", + "version": "14.4.0", + "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin/-/eslint-plugin-14.4.0.tgz", + "integrity": "sha512-2rZQ4mt7tEUW+lI5jjuj3HWaT4VQtWTG6+LDnmuUmx76m8hqQ7NvFUpOcNDofu5KbEVBP+oF2DA6wjoZOIuSOA==", "dev": true, "requires": { - "@angular-eslint/utils": "14.1.2", - "@typescript-eslint/utils": "5.37.0" + "@angular-eslint/utils": "14.4.0", + "@typescript-eslint/utils": "5.43.0" } }, "@angular-eslint/eslint-plugin-template": { - "version": "14.1.2", - "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin-template/-/eslint-plugin-template-14.1.2.tgz", - "integrity": "sha512-gMgYJ8ZwPvq2H/YEzPztVRAK2NYs2cJFUDZD4iGjSRtDgYq9OHjyTo+r6tkcyjcK2qvesy0RccHQKh+x3hYMTA==", + "version": "14.4.0", + "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin-template/-/eslint-plugin-template-14.4.0.tgz", + "integrity": "sha512-d3GM/EU2iWzr+BrITwO4gBf9WfDfuOdTjfinV/zN84oXMFaK2ENo+IP6OEsD9hh36rdPps+m2gFGDdx+rTzBpg==", "dev": true, "requires": { - "@angular-eslint/bundled-angular-compiler": "14.1.2", - "@typescript-eslint/type-utils": "5.37.0", - "@typescript-eslint/utils": "5.37.0", - "aria-query": "5.0.2", - "axobject-query": "3.0.1" + "@angular-eslint/bundled-angular-compiler": "14.4.0", + "@angular-eslint/utils": "14.4.0", + "@typescript-eslint/type-utils": "5.43.0", + "@typescript-eslint/utils": "5.43.0", + "aria-query": "5.1.3", + "axobject-query": "3.1.1" } }, "@angular-eslint/schematics": { - "version": "14.1.2", - "resolved": "https://registry.npmjs.org/@angular-eslint/schematics/-/schematics-14.1.2.tgz", - "integrity": "sha512-jyaCDQf+MGjMCf+U6KXvvpPESKMUoSGXYhsh2XYtSSUhXook9f2cPI6bHBMyrDgV43zH42jMS+yMC1EO24ZP1w==", + "version": "14.4.0", + "resolved": "https://registry.npmjs.org/@angular-eslint/schematics/-/schematics-14.4.0.tgz", + "integrity": "sha512-BrGkPug+CZQWOfmNRsJDrEtYJcxvzF/kLlV7RjvIN9Ky5TjUiJVCeafl3VY6COSY32tjlh2GvBdl1AQKWWovbA==", "dev": true, "requires": { - "@angular-eslint/eslint-plugin": "14.1.2", - "@angular-eslint/eslint-plugin-template": "14.1.2", + "@angular-eslint/eslint-plugin": "14.4.0", + "@angular-eslint/eslint-plugin-template": "14.4.0", "ignore": "5.2.0", "strip-json-comments": "3.1.1", "tmp": "0.2.1" } }, "@angular-eslint/template-parser": { - "version": "14.1.2", - "resolved": "https://registry.npmjs.org/@angular-eslint/template-parser/-/template-parser-14.1.2.tgz", - "integrity": "sha512-bQI+poQDIyR3OU9EQzJeLYRtmsvjFGtV5dc+4XPJ6eIyRAc8baCG/0V/cOrpofIdSf7e/sCV8H7rXcFg6tSdUw==", + "version": "14.4.0", + "resolved": "https://registry.npmjs.org/@angular-eslint/template-parser/-/template-parser-14.4.0.tgz", + "integrity": "sha512-zq888KpQB0YTEK26mkKcT4fs8LDWWT1oAEXU8DrXhvkikS8XavTSHOWJye/bVZR4oJRFCF5YTJV75DEMcGNIpQ==", "dev": true, "requires": { - "@angular-eslint/bundled-angular-compiler": "14.1.2", - "eslint-scope": "^5.1.0" + "@angular-eslint/bundled-angular-compiler": "14.4.0", + "eslint-scope": "^7.0.0" + }, + "dependencies": { + "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 + } } }, "@angular-eslint/utils": { - "version": "14.1.2", - "resolved": "https://registry.npmjs.org/@angular-eslint/utils/-/utils-14.1.2.tgz", - "integrity": "sha512-EtblG9zO0+kWG9EHsoEshFKvsH5DMSK1DqwQsNOVGAF0Aa5DFOqrwouJUyBNJ0d4fSWI9QcuzVkZ1x9JyLIeXQ==", + "version": "14.4.0", + "resolved": "https://registry.npmjs.org/@angular-eslint/utils/-/utils-14.4.0.tgz", + "integrity": "sha512-dPHklAVfh+JfueDfXre9Xooq7p5bFyKO2Z6y1agYeofAgHCPIJOPx2AhtFPrOtsc4VXFFiyE9XbowlXh4ogoKQ==", "dev": true, "requires": { - "@angular-eslint/bundled-angular-compiler": "14.1.2", - "@typescript-eslint/utils": "5.37.0" + "@angular-eslint/bundled-angular-compiler": "14.4.0", + "@typescript-eslint/utils": "5.43.0" } }, "@angular/animations": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-14.2.5.tgz", - "integrity": "sha512-4BhR9jSjgIwoK/alu7FSwSU5SxISMVFBAl/4cEYchfCqnflMNkZ8WwRVKTQjyeuYW5KtQTw9jRNp4tGK1YQWYw==", + "version": "14.2.12", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-14.2.12.tgz", + "integrity": "sha512-gwdnFZkvVUr+enUNfhfCGRGGqNHn1+vTA81apLfHYhJxgjiLUtETc4KTOrQevtDm022pEd+LSrvr8r+7ag+jkw==", "requires": { "tslib": "^2.3.0" } }, "@angular/cdk": { - "version": "14.2.4", - "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-14.2.4.tgz", - "integrity": "sha512-5jngZcOyC2n9pRYec/D0iCw72QSnCkGYjtfgIlOK/FZYGhpOa34GMGObPuv4F0u7J2TEtbO6xIFsCFaK0FLIWQ==", + "version": "14.2.7", + "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-14.2.7.tgz", + "integrity": "sha512-/tEsYaUbDSnfEmKVvAMramIptmhI67O+9STjOV0i+74XR2NospeK0fkbywIANu1n3w6AHGMotvRWJrjmbCElFg==", "requires": { "parse5": "^5.0.0", "tslib": "^2.3.0" } }, "@angular/cli": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-14.2.5.tgz", - "integrity": "sha512-jrvQ7nv/8k8i6D7LXrZi+DXQQkpmqoxC/NZL7hH1zyB9shlnG/ekMl+T4y7tvg3MWKxJuIfWVtz/EwOkMKmEaA==", + "version": "14.2.10", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-14.2.10.tgz", + "integrity": "sha512-gX9sAKOwq4lKdPWeABB7TzKDHdjQXvkUU8NmPJA6mEAVXvm3lhQtFvHDalZstwK8au2LY0LaXTcEtcKYOt3AXQ==", "dev": true, "requires": { - "@angular-devkit/architect": "0.1402.5", - "@angular-devkit/core": "14.2.5", - "@angular-devkit/schematics": "14.2.5", - "@schematics/angular": "14.2.5", + "@angular-devkit/architect": "0.1402.10", + "@angular-devkit/core": "14.2.10", + "@angular-devkit/schematics": "14.2.10", + "@schematics/angular": "14.2.10", "@yarnpkg/lockfile": "1.1.0", "ansi-colors": "4.1.3", "debug": "4.3.4", @@ -29349,25 +29680,25 @@ } }, "@angular/common": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-14.2.5.tgz", - "integrity": "sha512-v2fIK6imfMkUvYNjZQO+drE39QO3eSS95Yy7UN+6inb47DkAfzx6hipA9zKrMENjsS3kDv1d7cgDHE7WuOCzIw==", + "version": "14.2.12", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-14.2.12.tgz", + "integrity": "sha512-oZunh9wfInFWhNO1P8uoEs/o4u8kerKMhw8GruywKm1TV7gHDP2Fi5WHGjFqq3XYptgBTPCTSEfyLX6Cwq1PUw==", "requires": { "tslib": "^2.3.0" } }, "@angular/compiler": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-14.2.5.tgz", - "integrity": "sha512-L7d2/D6o9wlB2ugqRYpev6a8JntqS+7lF2o6z8y7RR2YAlAu71nq0BDsQez4/aSCK3HnDq0yhEnns7vcmOq/jA==", + "version": "14.2.12", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-14.2.12.tgz", + "integrity": "sha512-u2MH9+NRwbbFDRNiPWPexed9CnCq9+pGHLuyACSP2uR6Ik68cE6cayeZbIeoEV5vWpda/XsLmJgPJysw7dAZLQ==", "requires": { "tslib": "^2.3.0" } }, "@angular/compiler-cli": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-14.2.5.tgz", - "integrity": "sha512-3GYzTPw96TfJjw7Aso+f+uN6VFBWedqRATUQ6v+BAEyZIboirdLI1JQFOcCfuKWUM2B48RW+pdIduZmG3ckotA==", + "version": "14.2.12", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-14.2.12.tgz", + "integrity": "sha512-9Gkb9KFkaQPz8XaS8ZwwTioRZ4ywykdAWyceICEi78/Y9ConYrTX2SbFogzI2dPUZU8a04tMlbqTSmHjVbJftQ==", "requires": { "@babel/core": "^7.17.2", "chokidar": "^3.0.0", @@ -29382,31 +29713,31 @@ } }, "@angular/core": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-14.2.5.tgz", - "integrity": "sha512-Ok78Abq0puMGlolvNVzKFvsX7ePDkyxpZzztDzXDdRA4x4o6bAuuDG9Y7Wab2+wsdY6NktO+dFQjq1UBWClgSg==", + "version": "14.2.12", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-14.2.12.tgz", + "integrity": "sha512-sGQxU5u4uawwvJa6jOTmGoisJiQ5HIN/RoBw99CmoqZIVyUSg9IRJJC1KVdH8gbpWBNLkElZv21lwJTL/msWyg==", "requires": { "tslib": "^2.3.0" } }, "@angular/forms": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-14.2.5.tgz", - "integrity": "sha512-aMH5Vrftny0KF0XzWQIGfHoI0LVQ2aatpWzdUWiUqBeX/Q+ucmxeP5rZyKtUsi0flETWxdRZSBTjbXZ3dsIcTA==", + "version": "14.2.12", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-14.2.12.tgz", + "integrity": "sha512-7abYlGIT2JnAtutQUlH3fQS6QEpbfftgvsVcZJCyvX0rXL3u2w2vUQkDHJH4YJJp3AHFVCH4/l7R4VcaPnrwvA==", "requires": { "tslib": "^2.3.0" } }, "@angular/language-service": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-14.2.5.tgz", - "integrity": "sha512-YqbsCbCq470ve6+MGjeEf2I6L5LcBYALvh+S5XsZkfEQEjSYYC1ZE1ftq7clICrMOOoM4XSghq8b/eNtZoTJkg==", + "version": "14.2.12", + "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-14.2.12.tgz", + "integrity": "sha512-YmW6simyEVmpDmbYVUhZ2IxSP6pmsWrV120rB9Y21/BeM39WIXA4NCNirVWlAd/KAKY9O7Sbn1nXI6rSDfhopQ==", "dev": true }, "@angular/localize": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@angular/localize/-/localize-14.2.5.tgz", - "integrity": "sha512-QKDa0stq5vRadvYKThh1kE2+/7a2fg6Ue7OFwOZNzuBSItKoXVdEWdkz1idcY7IoGNtMYv6TeHbTDdaFZZDC7Q==", + "version": "14.2.12", + "resolved": "https://registry.npmjs.org/@angular/localize/-/localize-14.2.12.tgz", + "integrity": "sha512-6TTnuvubvYL1LDIJhDfd7ygxTaj0ShTILCDXT4URBhZKQbQ3HAorDqsc6SXqZVGCHdqF0hGTaeN/7zVvgP9kzA==", "requires": { "@babel/core": "7.18.9", "glob": "8.0.3", @@ -29443,25 +29774,25 @@ } }, "@angular/platform-browser": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-14.2.5.tgz", - "integrity": "sha512-FDZm23N9veSEouQX1YuZUjv7Nillroi+v0VbN1x5iPpFZEudaoZYT3A7bpJwdlxUx/4rGS0caaXNhN3CowtIeQ==", + "version": "14.2.12", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-14.2.12.tgz", + "integrity": "sha512-vOarWym8ucl1gjYWCzdwyBha+MTvL381mvTTUu8aUx6nVhHFjv4bvpjlZnZgojecqUPyxOwmPLLHvCZPJVHZYg==", "requires": { "tslib": "^2.3.0" } }, "@angular/platform-browser-dynamic": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-14.2.5.tgz", - "integrity": "sha512-7W8oLs8YEGRr8izgUlpHgBfg3vUb5H0yicTHJY4zIqHJJbG1rTl46CjULaMjYM/FWcS8o7y6XJJcHx0c7pKNsw==", + "version": "14.2.12", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-14.2.12.tgz", + "integrity": "sha512-oZhNJeaBmgw8+KBSYpKz2RYqEDyETC+HJXH8dwIFcP6BqqwL2NE70FdSR7EnOa5c41MEtTmMCGhrJSFR60x5/w==", "requires": { "tslib": "^2.3.0" } }, "@angular/platform-server": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@angular/platform-server/-/platform-server-14.2.5.tgz", - "integrity": "sha512-cRYf0rf6ctHvEnDwtAyIsTHrCvlGHHszE9KK7o2c5fYGfzhYXLw7CX/JMTN+9xwvT2H7QZFrkm2AaNjPvkKd7Q==", + "version": "14.2.12", + "resolved": "https://registry.npmjs.org/@angular/platform-server/-/platform-server-14.2.12.tgz", + "integrity": "sha512-RDxNh47Rp0EYrimbzviqhagdbL58Z3S88PDYybYbshFwV+MgWsvWasK/WntTMP/JtRP4FBU0Uiwxy7mgVdxb0g==", "requires": { "domino": "^2.1.2", "tslib": "^2.3.0", @@ -29469,17 +29800,17 @@ } }, "@angular/router": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@angular/router/-/router-14.2.5.tgz", - "integrity": "sha512-AUHcr9Lln7emJ/aete08UoqWQFZOLH1MhuP78r2pixvnNiZ9C8hcevX1rGGax0Po/Gy4PSJ4wnFhZPgifqCguQ==", + "version": "14.2.12", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-14.2.12.tgz", + "integrity": "sha512-r5tVus5RJDNc4U2v0jMtjPiAS1xDsVsJ70lS313DgZmBDHIVZP1cWIehdxwgNlGwQQtAA36eG7toBwqUU3gb/A==", "requires": { "tslib": "^2.3.0" } }, "@angular/service-worker": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@angular/service-worker/-/service-worker-14.2.5.tgz", - "integrity": "sha512-0OCp3U4+kO2H+275JlaOhHl2KtFBobByo9WpHyQV+iWIAxwBcStxuL7NXRcPTxmrvzyM6doZt1d/V3NA5eiIPA==", + "version": "14.2.12", + "resolved": "https://registry.npmjs.org/@angular/service-worker/-/service-worker-14.2.12.tgz", + "integrity": "sha512-7aAHb9XfToHQyHoPF9CmZSfsO5vFmKALDmTBWf8i3DCztrZvY+B8PCbfpJkpgFiF7LyF+hGaExI4fa6GmHZv+g==", "requires": { "tslib": "^2.3.0" } @@ -30698,23 +31029,45 @@ "dev": true }, "@commitlint/cli": { - "version": "17.1.2", - "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-17.1.2.tgz", - "integrity": "sha512-h/4Hlka3bvCLbnxf0Er2ri5A44VMlbMSkdTRp8Adv2tRiklSTRIoPGs7OEXDv3EoDs2AAzILiPookgM4Gi7LOw==", + "version": "17.3.0", + "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-17.3.0.tgz", + "integrity": "sha512-/H0md7TsKflKzVPz226VfXzVafJFO1f9+r2KcFvmBu08V0T56lZU1s8WL7/xlxqLMqBTVaBf7Ixtc4bskdEEZg==", "dev": true, "requires": { "@commitlint/format": "^17.0.0", - "@commitlint/lint": "^17.1.0", - "@commitlint/load": "^17.1.2", - "@commitlint/read": "^17.1.0", + "@commitlint/lint": "^17.3.0", + "@commitlint/load": "^17.3.0", + "@commitlint/read": "^17.2.0", "@commitlint/types": "^17.0.0", "execa": "^5.0.0", - "lodash": "^4.17.19", + "lodash.isfunction": "^3.0.9", "resolve-from": "5.0.0", "resolve-global": "1.0.0", "yargs": "^17.0.0" } }, + "@commitlint/config-conventional": { + "version": "17.3.0", + "resolved": "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-17.3.0.tgz", + "integrity": "sha512-hgI+fN5xF8nhS9uG/V06xyT0nlcyvHHMkq0kwRSr96vl5BFlRGaL2C0/YY4kQagfU087tmj01bJkG9Ek98Wllw==", + "dev": true, + "requires": { + "conventional-changelog-conventionalcommits": "^5.0.0" + }, + "dependencies": { + "conventional-changelog-conventionalcommits": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-5.0.0.tgz", + "integrity": "sha512-lCDbA+ZqVFQGUj7h9QBKoIpLhl8iihkO0nCTyRNzuXtcd7ubODpYB04IFy31JloiJgG0Uovu8ot8oxRzn7Nwtw==", + "dev": true, + "requires": { + "compare-func": "^2.0.0", + "lodash": "^4.17.15", + "q": "^1.5.1" + } + } + } + }, "@commitlint/config-validator": { "version": "17.1.0", "resolved": "https://registry.npmjs.org/@commitlint/config-validator/-/config-validator-17.1.0.tgz", @@ -30726,13 +31079,17 @@ } }, "@commitlint/ensure": { - "version": "17.0.0", - "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-17.0.0.tgz", - "integrity": "sha512-M2hkJnNXvEni59S0QPOnqCKIK52G1XyXBGw51mvh7OXDudCmZ9tZiIPpU882p475Mhx48Ien1MbWjCP1zlyC0A==", + "version": "17.3.0", + "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-17.3.0.tgz", + "integrity": "sha512-kWbrQHDoW5veIUQx30gXoLOCjWvwC6OOEofhPCLl5ytRPBDAQObMbxTha1Bt2aSyNE/IrJ0s0xkdZ1Gi3wJwQg==", "dev": true, "requires": { "@commitlint/types": "^17.0.0", - "lodash": "^4.17.19" + "lodash.camelcase": "^4.3.0", + "lodash.kebabcase": "^4.1.1", + "lodash.snakecase": "^4.1.1", + "lodash.startcase": "^4.4.0", + "lodash.upperfirst": "^4.3.1" } }, "@commitlint/execute-rule": { @@ -30803,9 +31160,9 @@ } }, "@commitlint/is-ignored": { - "version": "17.1.0", - "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-17.1.0.tgz", - "integrity": "sha512-JITWKDMHhIh8IpdIbcbuH9rEQJty1ZWelgjleTFrVRAcEwN/sPzk1aVUXRIZNXMJWbZj8vtXRJnFihrml8uECQ==", + "version": "17.2.0", + "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-17.2.0.tgz", + "integrity": "sha512-rgUPUQraHxoMLxiE8GK430HA7/R2vXyLcOT4fQooNrZq9ERutNrP6dw3gdKLkq22Nede3+gEHQYUzL4Wu75ndg==", "dev": true, "requires": { "@commitlint/types": "^17.0.0", @@ -30813,41 +31170,43 @@ } }, "@commitlint/lint": { - "version": "17.1.0", - "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-17.1.0.tgz", - "integrity": "sha512-ltpqM2ogt/+SDhUaScFo0MdscncEF96lvQTPMM/VTTWlw7sTGLLWkOOppsee2MN/uLNNWjQ7kqkd4h6JqoM9AQ==", + "version": "17.3.0", + "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-17.3.0.tgz", + "integrity": "sha512-VilOTPg0i9A7CCWM49E9bl5jytfTvfTxf9iwbWAWNjxJ/A5mhPKbm3sHuAdwJ87tDk1k4j8vomYfH23iaY+1Rw==", "dev": true, "requires": { - "@commitlint/is-ignored": "^17.1.0", - "@commitlint/parse": "^17.0.0", - "@commitlint/rules": "^17.0.0", + "@commitlint/is-ignored": "^17.2.0", + "@commitlint/parse": "^17.2.0", + "@commitlint/rules": "^17.3.0", "@commitlint/types": "^17.0.0" } }, "@commitlint/load": { - "version": "17.1.2", - "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-17.1.2.tgz", - "integrity": "sha512-sk2p/jFYAWLChIfOIp/MGSIn/WzZ0vkc3afw+l4X8hGEYkvDe4gQUUAVxjl/6xMRn0HgnSLMZ04xXh5pkTsmgg==", + "version": "17.3.0", + "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-17.3.0.tgz", + "integrity": "sha512-u/pV6rCAJrCUN+HylBHLzZ4qj1Ew3+eN9GBPhNi9otGxtOfA8b+8nJSxaNbcC23Ins/kcpjGf9zPSVW7628Umw==", "dev": true, "requires": { "@commitlint/config-validator": "^17.1.0", "@commitlint/execute-rule": "^17.0.0", - "@commitlint/resolve-extends": "^17.1.0", + "@commitlint/resolve-extends": "^17.3.0", "@commitlint/types": "^17.0.0", "@types/node": "^14.0.0", "chalk": "^4.1.0", "cosmiconfig": "^7.0.0", "cosmiconfig-typescript-loader": "^4.0.0", - "lodash": "^4.17.19", + "lodash.isplainobject": "^4.0.6", + "lodash.merge": "^4.6.2", + "lodash.uniq": "^4.5.0", "resolve-from": "^5.0.0", "ts-node": "^10.8.1", "typescript": "^4.6.4" }, "dependencies": { "@types/node": { - "version": "14.18.31", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.31.tgz", - "integrity": "sha512-vQAnaReSQkEDa8uwAyQby8bYGKu84R/deEc6mg5T8fX6gzCn8QW6rziSgsti1fNvsrswKUKPnVTi7uoB+u62Mw==", + "version": "14.18.34", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.34.tgz", + "integrity": "sha512-hcU9AIQVHmPnmjRK+XUUYlILlr9pQrsqSrwov/JK1pnf3GTQowVBhx54FbvM0AU/VXGH4i3+vgXS5EguR7fysA==", "dev": true }, "ansi-styles": { @@ -30902,15 +31261,15 @@ } }, "@commitlint/message": { - "version": "17.0.0", - "resolved": "https://registry.npmjs.org/@commitlint/message/-/message-17.0.0.tgz", - "integrity": "sha512-LpcwYtN+lBlfZijHUdVr8aNFTVpHjuHI52BnfoV01TF7iSLnia0jttzpLkrLmI8HNQz6Vhr9UrxDWtKZiMGsBw==", + "version": "17.2.0", + "resolved": "https://registry.npmjs.org/@commitlint/message/-/message-17.2.0.tgz", + "integrity": "sha512-/4l2KFKxBOuoEn1YAuuNNlAU05Zt7sNsC9H0mPdPm3chOrT4rcX0pOqrQcLtdMrMkJz0gC7b3SF80q2+LtdL9Q==", "dev": true }, "@commitlint/parse": { - "version": "17.0.0", - "resolved": "https://registry.npmjs.org/@commitlint/parse/-/parse-17.0.0.tgz", - "integrity": "sha512-cKcpfTIQYDG1ywTIr5AG0RAiLBr1gudqEsmAGCTtj8ffDChbBRxm6xXs2nv7GvmJN7msOt7vOKleLvcMmRa1+A==", + "version": "17.2.0", + "resolved": "https://registry.npmjs.org/@commitlint/parse/-/parse-17.2.0.tgz", + "integrity": "sha512-vLzLznK9Y21zQ6F9hf8D6kcIJRb2haAK5T/Vt1uW2CbHYOIfNsR/hJs0XnF/J9ctM20Tfsqv4zBitbYvVw7F6Q==", "dev": true, "requires": { "@commitlint/types": "^17.0.0", @@ -30919,9 +31278,9 @@ } }, "@commitlint/read": { - "version": "17.1.0", - "resolved": "https://registry.npmjs.org/@commitlint/read/-/read-17.1.0.tgz", - "integrity": "sha512-73BoFNBA/3Ozo2JQvGsE0J8SdrJAWGfZQRSHqvKaqgmY042Su4gXQLqvAzgr55S9DI1l9TiU/5WDuh8IE86d/g==", + "version": "17.2.0", + "resolved": "https://registry.npmjs.org/@commitlint/read/-/read-17.2.0.tgz", + "integrity": "sha512-bbblBhrHkjxra3ptJNm0abxu7yeAaxumQ8ZtD6GIVqzURCETCP7Dm0tlVvGRDyXBuqX6lIJxh3W7oyKqllDsHQ==", "dev": true, "requires": { "@commitlint/top-level": "^17.0.0", @@ -30932,27 +31291,27 @@ } }, "@commitlint/resolve-extends": { - "version": "17.1.0", - "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-17.1.0.tgz", - "integrity": "sha512-jqKm00LJ59T0O8O4bH4oMa4XyJVEOK4GzH8Qye9XKji+Q1FxhZznxMV/bDLyYkzbTodBt9sL0WLql8wMtRTbqQ==", + "version": "17.3.0", + "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-17.3.0.tgz", + "integrity": "sha512-Lf3JufJlc5yVEtJWC8o4IAZaB8FQAUaVlhlAHRACd0TTFizV2Lk2VH70et23KgvbQNf7kQzHs/2B4QZalBv6Cg==", "dev": true, "requires": { "@commitlint/config-validator": "^17.1.0", "@commitlint/types": "^17.0.0", "import-fresh": "^3.0.0", - "lodash": "^4.17.19", + "lodash.mergewith": "^4.6.2", "resolve-from": "^5.0.0", "resolve-global": "^1.0.0" } }, "@commitlint/rules": { - "version": "17.0.0", - "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-17.0.0.tgz", - "integrity": "sha512-45nIy3dERKXWpnwX9HeBzK5SepHwlDxdGBfmedXhL30fmFCkJOdxHyOJsh0+B0RaVsLGT01NELpfzJUmtpDwdQ==", + "version": "17.3.0", + "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-17.3.0.tgz", + "integrity": "sha512-s2UhDjC5yP2utx3WWqsnZRzjgzAX8BMwr1nltC0u0p8T/nzpkx4TojEfhlsOUj1t7efxzZRjUAV0NxNwdJyk+g==", "dev": true, "requires": { - "@commitlint/ensure": "^17.0.0", - "@commitlint/message": "^17.0.0", + "@commitlint/ensure": "^17.3.0", + "@commitlint/message": "^17.2.0", "@commitlint/to-lines": "^17.0.0", "@commitlint/types": "^17.0.0", "execa": "^5.0.0" @@ -31331,125 +31690,126 @@ } }, "@cspell/cspell-bundled-dicts": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/@cspell/cspell-bundled-dicts/-/cspell-bundled-dicts-6.12.0.tgz", - "integrity": "sha512-myfsDwSJcAMjKbztKBG424wIp/YV9/lvxsgHFKxBGPi+nNx1p7TbOjAAO9EWk0mZVHyGKZwCFJS2ohkoqxJWoQ==", - "dev": true, - "requires": { - "@cspell/dict-ada": "^2.0.1", - "@cspell/dict-aws": "^2.0.0", - "@cspell/dict-bash": "^2.0.4", - "@cspell/dict-companies": "^2.0.14", - "@cspell/dict-cpp": "^3.2.1", - "@cspell/dict-cryptocurrencies": "^2.0.0", - "@cspell/dict-csharp": "^3.0.1", - "@cspell/dict-css": "^2.1.0", - "@cspell/dict-dart": "^1.1.1", - "@cspell/dict-django": "^2.0.0", - "@cspell/dict-docker": "^1.1.1", - "@cspell/dict-dotnet": "^2.0.1", - "@cspell/dict-elixir": "^2.0.1", - "@cspell/dict-en_us": "^2.3.3", - "@cspell/dict-en-gb": "^1.1.33", - "@cspell/dict-filetypes": "^2.1.1", - "@cspell/dict-fonts": "^2.1.0", - "@cspell/dict-fullstack": "^2.0.6", - "@cspell/dict-git": "^1.0.1", - "@cspell/dict-golang": "^3.0.1", - "@cspell/dict-haskell": "^2.0.1", - "@cspell/dict-html": "^3.3.2", - "@cspell/dict-html-symbol-entities": "^3.0.0", - "@cspell/dict-java": "^3.0.7", - "@cspell/dict-latex": "^2.0.9", - "@cspell/dict-lorem-ipsum": "^2.0.1", - "@cspell/dict-lua": "^2.0.0", - "@cspell/dict-node": "^3.0.1", - "@cspell/dict-npm": "^3.1.2", - "@cspell/dict-php": "^2.0.0", - "@cspell/dict-powershell": "^2.0.0", - "@cspell/dict-public-licenses": "^1.0.6", - "@cspell/dict-python": "^3.0.6", - "@cspell/dict-r": "^1.0.3", - "@cspell/dict-ruby": "^2.0.2", - "@cspell/dict-rust": "^2.0.1", - "@cspell/dict-scala": "^2.0.0", - "@cspell/dict-software-terms": "^2.2.11", - "@cspell/dict-sql": "^1.0.4", - "@cspell/dict-swift": "^1.0.3", - "@cspell/dict-typescript": "^2.0.2", - "@cspell/dict-vue": "^2.0.2" + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/@cspell/cspell-bundled-dicts/-/cspell-bundled-dicts-6.17.0.tgz", + "integrity": "sha512-BA5cg2mfESbF3Fm/fIGXgbm0LhD8HKxCCiQDRN9FLaj4c69QUgFpQ9LpzGPZEtNn2Pjl2Jn/BEXX27hgaURG9g==", + "dev": true, + "requires": { + "@cspell/dict-ada": "^4.0.0", + "@cspell/dict-aws": "^3.0.0", + "@cspell/dict-bash": "^4.1.0", + "@cspell/dict-companies": "^3.0.3", + "@cspell/dict-cpp": "^4.0.0", + "@cspell/dict-cryptocurrencies": "^3.0.1", + "@cspell/dict-csharp": "^4.0.2", + "@cspell/dict-css": "^4.0.0", + "@cspell/dict-dart": "^2.0.0", + "@cspell/dict-django": "^4.0.0", + "@cspell/dict-docker": "^1.1.3", + "@cspell/dict-dotnet": "^4.0.0", + "@cspell/dict-elixir": "^4.0.0", + "@cspell/dict-en_us": "^4.1.0", + "@cspell/dict-en-gb": "1.1.33", + "@cspell/dict-filetypes": "^3.0.0", + "@cspell/dict-fonts": "^3.0.0", + "@cspell/dict-fullstack": "^3.0.0", + "@cspell/dict-git": "^2.0.0", + "@cspell/dict-golang": "^5.0.0", + "@cspell/dict-haskell": "^4.0.0", + "@cspell/dict-html": "^4.0.1", + "@cspell/dict-html-symbol-entities": "^4.0.0", + "@cspell/dict-java": "^5.0.2", + "@cspell/dict-latex": "^3.0.0", + "@cspell/dict-lorem-ipsum": "^3.0.0", + "@cspell/dict-lua": "^3.0.0", + "@cspell/dict-node": "^4.0.1", + "@cspell/dict-npm": "^5.0.0", + "@cspell/dict-php": "^3.0.3", + "@cspell/dict-powershell": "^3.0.0", + "@cspell/dict-public-licenses": "^2.0.0", + "@cspell/dict-python": "^4.0.0", + "@cspell/dict-r": "^2.0.0", + "@cspell/dict-ruby": "^3.0.0", + "@cspell/dict-rust": "^3.0.0", + "@cspell/dict-scala": "^3.0.0", + "@cspell/dict-software-terms": "^3.0.5", + "@cspell/dict-sql": "^2.0.0", + "@cspell/dict-svelte": "^1.0.0", + "@cspell/dict-swift": "^2.0.0", + "@cspell/dict-typescript": "^3.0.1", + "@cspell/dict-vue": "^3.0.0" } }, "@cspell/cspell-pipe": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/@cspell/cspell-pipe/-/cspell-pipe-6.12.0.tgz", - "integrity": "sha512-Nkm+tIJ5k+jZPovZCdmZhrWrwRFwnDq+7yCxhov0C7UX3hsSNtTJIpFuaCNEQJ+Whpvxdh1YKflvHiHYygEgTg==", + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/@cspell/cspell-pipe/-/cspell-pipe-6.17.0.tgz", + "integrity": "sha512-/VlX1cQtVBK9PFvSsaYVzV59i/2de9wrMSYDk+oGLXQzGBf5+5rPDZMJJ+QQkaexMdxoOXjCYTEXnNkPoVFyFA==", "dev": true }, "@cspell/cspell-service-bus": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/@cspell/cspell-service-bus/-/cspell-service-bus-6.12.0.tgz", - "integrity": "sha512-GgvciSeMUekl8z8vP8//cs5/qRQJSLz9IVREf6fxQW4upjw6zXZ1KonwPqOF5uLocIMAr8eCdrJzHKuKvigJIA==", + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/@cspell/cspell-service-bus/-/cspell-service-bus-6.17.0.tgz", + "integrity": "sha512-HrzR23aeC/ykSOJvUr+uX6Dv7JLc5meNABLxauiC9jexOXFB3DKmo+DvJFerRDOGz6eYSwM0VXAR62OCHrWK/Q==", "dev": true }, "@cspell/cspell-types": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/@cspell/cspell-types/-/cspell-types-6.12.0.tgz", - "integrity": "sha512-BcZTt05fNy9SGXfbPgUyxS4FfIaUpcVq8IOJ0noN+jsKsmlbssOUgJOB2ApN1h66FfWcKuFy/uNrjfcrQ7PTqg==", + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/@cspell/cspell-types/-/cspell-types-6.17.0.tgz", + "integrity": "sha512-4FStDRqZVEP6oYtXqj1wUlF02EC5PN7giJ5f4YPeChwXyQBdZWUPQgEIKn0K9GIgKDMlKRo9tloAHVgtaZ+zOA==", "dev": true }, "@cspell/dict-ada": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-ada/-/dict-ada-2.0.1.tgz", - "integrity": "sha512-vopTJ1oHrrFYV5GU55Sr+AzItR78Uj5YbCaspYABmYKlq4NRrcUAUsr4bWgymDcspMIHO7e7IFcj48OKs1fndA==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-ada/-/dict-ada-4.0.0.tgz", + "integrity": "sha512-M0n4ZYmpLOXbDD07Qb/Ekk0K5pX2C+mCuJ2ZxPgbTq9HGlrN43PmqrGJHWcgtVHE3fd1D4VxS85QcQP6r1Y+KQ==", "dev": true }, "@cspell/dict-aws": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-aws/-/dict-aws-2.0.0.tgz", - "integrity": "sha512-NKz7pDZ7pwj/b33i3f4WLpC1rOOUMmENwYgftxU+giU2YBeKM2wZbMTSEIzsrel56r0UlQYmdIVlP/B4nnVaoQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-aws/-/dict-aws-3.0.0.tgz", + "integrity": "sha512-O1W6nd5y3Z00AMXQMzfiYrIJ1sTd9fB1oLr+xf/UD7b3xeHeMeYE2OtcWbt9uyeHim4tk+vkSTcmYEBKJgS5bQ==", "dev": true }, "@cspell/dict-bash": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@cspell/dict-bash/-/dict-bash-2.0.4.tgz", - "integrity": "sha512-uK/ehmp5LYrmRH2Gv3nbvdPswpkybJUn34WYKLpeuYHQktmi+pOI1A9uPdBPnSbMDffSvwQlQohIyKawz+X8Ag==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-bash/-/dict-bash-4.1.0.tgz", + "integrity": "sha512-8pFL03ZKejynfbsa2UZ3iZ7BrT1TAGTD8ZlK822ioAb7aoDvQhYao2Bjz5cXU0uk7CyrlgsSnYX94sLfqDfTxQ==", "dev": true }, "@cspell/dict-companies": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/@cspell/dict-companies/-/dict-companies-2.0.14.tgz", - "integrity": "sha512-Sq1X29Z05OZ/UNqTwVhf3/WaqvJQy4/S6gS8qYI5AQRX45gVe8CPhNBLmZOTC6z8m716bfQCxa5rRT9YNSdTZg==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@cspell/dict-companies/-/dict-companies-3.0.3.tgz", + "integrity": "sha512-qBWdwA97HdnLbxPLOUTZ+/mg9eYhi14hM7PEUM1PZ004MEIxQHum0IQpypKAwP3teR1KEsyxEPHp8v24Dw45Zg==", "dev": true }, "@cspell/dict-cpp": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-cpp/-/dict-cpp-3.2.1.tgz", - "integrity": "sha512-XcmzrKIghqFfrYLLaHtWKOp9rupiuGdc5ODONk+emsq0W5CIc3Abn27IQHwUzxzF+Cm5IfKAIJ5Kpe6hkzm0HQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-cpp/-/dict-cpp-4.0.0.tgz", + "integrity": "sha512-NrCmer14tTSbPs1TwqyCjFEmWCBw0UFvAn4O3pdWuxktArHxRJ5vUQOoL2Gus2H9s3ihhOJZkcuJ47Kd21E7BQ==", "dev": true }, "@cspell/dict-cryptocurrencies": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-cryptocurrencies/-/dict-cryptocurrencies-2.0.0.tgz", - "integrity": "sha512-nREysmmfOp7L2YCRAUufQahwD5/Punzb5AZ6eyg4zUamdRWHgBFphb5/9h2flt1vgdUfhc6hZcML21Ci7iXjaA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-cryptocurrencies/-/dict-cryptocurrencies-3.0.1.tgz", + "integrity": "sha512-Tdlr0Ahpp5yxtwM0ukC13V6+uYCI0p9fCRGMGZt36rWv8JQZHIuHfehNl7FB/Qc09NCF7p5ep0GXbL+sVTd/+w==", "dev": true }, "@cspell/dict-csharp": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-csharp/-/dict-csharp-3.0.1.tgz", - "integrity": "sha512-xkfQu03F388w4sdVQSSjrVMkxAxpTYB2yW7nw0XYtTjl3L/jBgvTr/j1BTjdFbQhdNf10Lg0Ak1kXOjmHodVqA==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@cspell/dict-csharp/-/dict-csharp-4.0.2.tgz", + "integrity": "sha512-1JMofhLK+4p4KairF75D3A924m5ERMgd1GvzhwK2geuYgd2ZKuGW72gvXpIV7aGf52E3Uu1kDXxxGAiZ5uVG7g==", "dev": true }, "@cspell/dict-css": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-css/-/dict-css-2.1.0.tgz", - "integrity": "sha512-glASAELcGhh4Ru0rTQ4G9mTQxSyPwsZOON/5BYflB6Kks8YC8nUvKrtMCoo5W7CPKPfSEa8zUNctFQ1+IUYDHA==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-css/-/dict-css-4.0.0.tgz", + "integrity": "sha512-ieSeG9KAJGIr5eK0JRWqD5KXstPPUw6JUTmGWc7P/qiqj/sjmhWqWKEt7HhoSNcb8uQxAkAoxhrNpfbKzqnKAw==", "dev": true }, "@cspell/dict-dart": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-dart/-/dict-dart-1.1.1.tgz", - "integrity": "sha512-XBOCpezXrgFN18kGEwqMpTUGZdw4BjCoJrNOo6qBdcdZySCrEHLwELraLOkcSba2kM4stmTp0t59FkwtP8TKOA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-dart/-/dict-dart-2.0.0.tgz", + "integrity": "sha512-p7vHszsu2uJt+F04gvNy1e5okypFfVEYHBWgpOV/Jrvs0F5A+gUzFTG2Ix9b1jkCigAULYKQkIGue+qlhSoK5Q==", "dev": true }, "@cspell/dict-de-de": { @@ -31459,33 +31819,33 @@ "dev": true }, "@cspell/dict-django": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-django/-/dict-django-2.0.0.tgz", - "integrity": "sha512-GkJdJv6cmzrKcmq2/oxTXjKF5uv71r4eTqnFmgPbNBW1t+G4VYpzOf0QrVQrhx2RC4DdW5XfcTf+iS0FxHOTmw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-django/-/dict-django-4.0.0.tgz", + "integrity": "sha512-k0npSzQrPQSqjR2XtumV14sv9waTRMUzPx0UfOuJZcnCCZY8ofPeqFYoku+O+9Kc9etFOziOxnScshKVDzYWOQ==", "dev": true }, "@cspell/dict-docker": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-docker/-/dict-docker-1.1.1.tgz", - "integrity": "sha512-UEYoeRDm7oUN9yz1mYSozz6D4+2N14S/cd2Re9et6Xzq6yi62s4ky3knF92Of2weelADjnN41UA22VBhRAf7Sw==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@cspell/dict-docker/-/dict-docker-1.1.3.tgz", + "integrity": "sha512-Iz7EQGnLBgnnmzCC8iLQ7JssCCQlCjZLiCs0qhooETWLifob3nzsI9AVBh3gkYLhISLIIjBpfa4LTknskT7LzA==", "dev": true }, "@cspell/dict-dotnet": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-dotnet/-/dict-dotnet-2.0.1.tgz", - "integrity": "sha512-b1n4crJRW0WZVf9Gp/52j/tDtjYiZ3N81fIyfqPlBrjsh/5AivfA697DYwQ2mr8ngNX7RsqRtYNQjealA1rEnQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-dotnet/-/dict-dotnet-4.0.0.tgz", + "integrity": "sha512-biZiTWyDqwVV2m+c17lLIliPDXPjOR1VwwmyMxvb3nFS84aP9x52SAVCf0w7Io1CIpUiY7XnG6/xeI7esYU78w==", "dev": true }, "@cspell/dict-elixir": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-elixir/-/dict-elixir-2.0.1.tgz", - "integrity": "sha512-eTTTxZt1FqGkM780yFDxsGHvTbWqvlK8YISSccK8FyrB6ULW+uflQlNS5AnWg3uWKC48b7pQott+odYCsPJ+Ow==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-elixir/-/dict-elixir-4.0.0.tgz", + "integrity": "sha512-0TqqdQjg/zu3wAjk2FQkZ87pPIS9tA9kl6he5NJB729ysrWhND/7aSPC48QrP46VZ+oFrvFZK8DC8ZlYs16cjQ==", "dev": true }, "@cspell/dict-en_us": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/@cspell/dict-en_us/-/dict-en_us-2.3.3.tgz", - "integrity": "sha512-csyKeaNktfpvMkmE2GOPTwsrQm3wWhLKVaDRaGU0qTcIjDiCvqv/iYgrVrKRkoddA3kdNTZ8YNCcix7lb6VkOg==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-en_us/-/dict-en_us-4.1.0.tgz", + "integrity": "sha512-EnfxP/5U3kDhmTWcHV7Xs2Fxa9KAE5fbHm+4u8LGBOUZvSkZC5+ayjQ50CfEyTGuaI/946ITQYPRNxUZ7oqOiQ==", "dev": true }, "@cspell/dict-en-gb": { @@ -31495,15 +31855,15 @@ "dev": true }, "@cspell/dict-filetypes": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-filetypes/-/dict-filetypes-2.1.1.tgz", - "integrity": "sha512-Oo0/mUbFHzsaATqRLdkV1RMoYns3aGzeKFIpVJg415GYtJ8EABXtEArYTXeMwlboyGTPvEk+PR2hBSTSfQTqmg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-filetypes/-/dict-filetypes-3.0.0.tgz", + "integrity": "sha512-Fiyp0z5uWaK0d2TfR9GMUGDKmUMAsOhGD5A0kHoqnNGswL2iw0KB0mFBONEquxU65fEnQv4R+jdM2d9oucujuA==", "dev": true }, "@cspell/dict-fonts": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-fonts/-/dict-fonts-2.1.0.tgz", - "integrity": "sha512-hk7xsbfWEUhc136Xj7I2TD7ouKAfWwzCVAQaHBxcVXAsVxu7bDOGj4FvE2jBzlkSUY8A9Ww8qS0GOFvowJshVg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-fonts/-/dict-fonts-3.0.0.tgz", + "integrity": "sha512-zTZni0AbwBVG1MKA0WpwPyIJPVF+gp6neXDQzHcu4RUnuQ4uDu0PVEuZjGHCJWwwFoR5JmkqZxVSg1y3ufJODA==", "dev": true }, "@cspell/dict-fr-fr": { @@ -31513,153 +31873,165 @@ "dev": true }, "@cspell/dict-fullstack": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@cspell/dict-fullstack/-/dict-fullstack-2.0.6.tgz", - "integrity": "sha512-R2E2xvbHvvRwwurxfpBJDRIJjXBMfEPF5WNV3LTOEMRqkZtoYCeJK9aqc8LHlmJMtAbnN1cx//BCDIyTJ0rO0A==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-fullstack/-/dict-fullstack-3.0.0.tgz", + "integrity": "sha512-BMQRTaeReLufjMwgWqqwPdrXQ7jkVGTv7/YvOLsHFZvcAP3eM7WqX+rvdXckLhJmuuzbceFRDKs5F/9Ig2x/tQ==", "dev": true }, "@cspell/dict-git": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-git/-/dict-git-1.0.1.tgz", - "integrity": "sha512-Rk+eTof/9inF11lvxmkCRK+gODatA3qai8kSASv6OG/JfPvpj7fTHErx/rdgPw/LOTDUafnoTjTYmj7B2MOQXg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-git/-/dict-git-2.0.0.tgz", + "integrity": "sha512-n1AxyX5Kgxij/sZFkxFJlzn3K9y/sCcgVPg/vz4WNJ4K9YeTsUmyGLA2OQI7d10GJeiuAo2AP1iZf2A8j9aj2w==", "dev": true }, "@cspell/dict-golang": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-golang/-/dict-golang-3.0.1.tgz", - "integrity": "sha512-0KNfXTbxHW2l8iVjxeOf+KFv9Qrw3z5cyKnkuYJWlBTSB5KcUBfeKCb4fsds26VdANqiy6U91b4gDx5kNEmBjQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-golang/-/dict-golang-5.0.0.tgz", + "integrity": "sha512-Cbx4mVHsGbr5D+wlT0yU3n/0c5iLvciU48rSOQR7SCAzu5mTXyM1mqRu6nqnRiMv6G6mO50EL2LCTq6RZrlIOg==", "dev": true }, "@cspell/dict-haskell": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-haskell/-/dict-haskell-2.0.1.tgz", - "integrity": "sha512-ooA23qIG7InOOxlLm67CNH5O2J85QsPHEAzEU9KEqVfYG5ovFs5tx6n9pHekDVk3MpQULpqfNUYDR0KigPLg5g==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-haskell/-/dict-haskell-4.0.0.tgz", + "integrity": "sha512-U/DPpDoitGeUvduM9teDkDc1zs4Plgh0pNONDP3YbsEICErSlp1NfatD0i35Z6cR0C7I8uEe4gG2phG00zrSqw==", "dev": true }, "@cspell/dict-html": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/@cspell/dict-html/-/dict-html-3.3.2.tgz", - "integrity": "sha512-cM5pQSEiqjrdk6cRFLrlLdWNT/J8399f/A6DjwjfYhHrGy0e/Rsjv76HZT0GlE1OqMoq9eG9jdQsfoYYgWTIpQ==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-html/-/dict-html-4.0.1.tgz", + "integrity": "sha512-q5fCzkoOz+8BW79qLrnANEDnG+Jb2WS2fXERxg9xwgKBXwXUxH8ttGVNhfkLpNWe/UMm00U1IZMnVGyYLNTO5w==", "dev": true }, "@cspell/dict-html-symbol-entities": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-html-symbol-entities/-/dict-html-symbol-entities-3.0.0.tgz", - "integrity": "sha512-04K7cPTcbYXmHICfiob4gZA1yaj4hpfM+Nl5WIJ1EAZsSGHdqmGEF28GuCjyQ8ZeKiJAsPt/vXuLBbjxkHqZyQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-html-symbol-entities/-/dict-html-symbol-entities-4.0.0.tgz", + "integrity": "sha512-HGRu+48ErJjoweR5IbcixxETRewrBb0uxQBd6xFGcxbEYCX8CnQFTAmKI5xNaIt2PKaZiJH3ijodGSqbKdsxhw==", "dev": true }, "@cspell/dict-java": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@cspell/dict-java/-/dict-java-3.0.7.tgz", - "integrity": "sha512-IL7ubsRvKX6dZSx++TplJCfhiS7kkEGpbTPG0gMEP50DTNAVM4icZS8zmer2UBCU5PTwF85abJjdX7mRADWKVg==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@cspell/dict-java/-/dict-java-5.0.2.tgz", + "integrity": "sha512-HWgdp8plZOdYjOkndwmgHGVxoewylZcl886PqSL6TMcDshyI0+2nePft31nIuALRvt7HL8IX++DM1uk4UfY4kg==", "dev": true }, "@cspell/dict-latex": { - "version": "2.0.9", - "resolved": "https://registry.npmjs.org/@cspell/dict-latex/-/dict-latex-2.0.9.tgz", - "integrity": "sha512-d1kTK6dJb5z6UcfASQWjqQlsjZvnoVOvMWxYtLpGksYf6gM4IgqoPVNMLYYK6xBS4T/uAnLIj975A6YuAeyZpg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-latex/-/dict-latex-3.0.0.tgz", + "integrity": "sha512-QsRWj+Jll4ueVbce8ofKa743oQ2exmbVNZN70MaMbmu8PSbjW2+Rj3OdExVStesANMj7qc20inS/TgPr8DrInQ==", "dev": true }, "@cspell/dict-lorem-ipsum": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-lorem-ipsum/-/dict-lorem-ipsum-2.0.1.tgz", - "integrity": "sha512-s7Ft8UiloUJwgz4z8uLeFvCkeTcZ43HQl7mSAlZd76eW+keLSsdeGmLDx2zaciqo+MftPGyzygVCwaJjTGxiew==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-lorem-ipsum/-/dict-lorem-ipsum-3.0.0.tgz", + "integrity": "sha512-msEV24qEpzWZs2kcEicqYlhyBpR0amfDkJOs+iffC07si9ftqtQ+yP3lf1VFLpgqw3SQh1M1vtU7RD4sPrNlcQ==", "dev": true }, "@cspell/dict-lua": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-lua/-/dict-lua-2.0.0.tgz", - "integrity": "sha512-7WUEBEspSKtsq104WdIys1+DLqAxpJPzw74Py1TuE3fI5GvlzeSZkRFP2ya54GB2lCO4C3mq4M8EnitpibVDfw==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-lua/-/dict-lua-3.0.0.tgz", + "integrity": "sha512-WOhSCgS5wMxkGQJ8siB90iTB9ElquJB7FeqYSbJqqs6cUwH8G7MM/CEDPL6h7vCo0+v3GuxQ8yKWDSUcUhz9Lg==", "dev": true }, "@cspell/dict-node": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-node/-/dict-node-3.0.1.tgz", - "integrity": "sha512-sK2cpuV0EAc43Amd5xeQXkI9MeRTECMw+yjap06gKSModbgI7BqJUHeKZed+0Hii+LpaJ4TYpLGiRVsO+qSk0w==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-node/-/dict-node-4.0.1.tgz", + "integrity": "sha512-4EmT5yZFitdwnG0hYEd+Ek19zzD81Bp+n7w0kglZKldS5AvapwW6GM/SAps5YMQQc5zZMi+bMgV7NIzapREqUg==", "dev": true }, "@cspell/dict-npm": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/@cspell/dict-npm/-/dict-npm-3.1.3.tgz", - "integrity": "sha512-xnGp+TMpArdMLBUSG+ZrbEuhvY016rb76Yh35/OPDDEEz4ulENxLSZJxtN2/A0tZ9FJngDNSdFh7eJsOFmciZQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-npm/-/dict-npm-5.0.0.tgz", + "integrity": "sha512-eegoQrzfAl6yht+BgQu7YkqeKbVb3FsFIobW3pBE/c8TqEnfnxRHnS4/e80PA16rO9uJgSF5iKBxTbtEIGYvsg==", "dev": true }, "@cspell/dict-php": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-php/-/dict-php-2.0.0.tgz", - "integrity": "sha512-29WgU77eTO985LvMHwPi1pcpfopfCWfTdffDyqya0JIfOSaFUrlYKzGPkE4mRxcz2G3hXsaM0SRvBNdIRwEdUg==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@cspell/dict-php/-/dict-php-3.0.3.tgz", + "integrity": "sha512-7dvXdPTfbIF2xEob9w94/eV5SU8BkYoN0R7EQghXi0fcF7T1unK+JwDgfoEs6wqApB5aCVYwguiaj8HGX2IRIQ==", "dev": true }, "@cspell/dict-powershell": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-powershell/-/dict-powershell-2.0.0.tgz", - "integrity": "sha512-6uvEhLiGmG3u9TFkM1TYcky6aL9Yk7Sk3KJwoTYBaQJY2KqrprgyQtW6yxIw9oU52VRHlq3KKvSAA9Q26+SIkQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-powershell/-/dict-powershell-3.0.0.tgz", + "integrity": "sha512-pkztY9Ak4oc33q+Qxcn9/CTOKo4N8YIRRE6v67WwQOncA5QIJfcOPUrjfR3Z8SpzElXhu3s9qtWWSqbCy6qmcA==", "dev": true }, "@cspell/dict-public-licenses": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@cspell/dict-public-licenses/-/dict-public-licenses-1.0.6.tgz", - "integrity": "sha512-Z9IUFPkkOpOsEdgPUfQOJNQ+qU6+iBAZWS/CR5sUqTX+s5VkPNVwQyVC2kdmgmE2U5qwzAPewG6nVKr2MVogwg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-public-licenses/-/dict-public-licenses-2.0.0.tgz", + "integrity": "sha512-NdMHnS6xiYJKlzVoTV5CBhMiDpXMZ/PDcvXiOpxeR50xkjR18O/XFP4f4eDZpxGiBSUCMFRWf4JjILJ04Rpcfg==", "dev": true }, "@cspell/dict-python": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@cspell/dict-python/-/dict-python-3.0.6.tgz", - "integrity": "sha512-tzxJ4sd9ZGhAUKg/WJJpQGDNtoHvM8Wn+iS2+PnQj2/LTHBW4mnaCogsGsBtYu8C4b2+BEQs+tc5808AeEfLug==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-python/-/dict-python-4.0.0.tgz", + "integrity": "sha512-MC6CKbYOly3Ig25ZnhlCzPbE/QozqfQv4VYW6HcoMQ5IbHu33ddf2lzkZ89qTXlxsF5NT5qfZEkQYHYuhuL6AQ==", "dev": true }, "@cspell/dict-r": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@cspell/dict-r/-/dict-r-1.0.3.tgz", - "integrity": "sha512-u2qeXd4cx/TvTVcmkvA+sK6f4K1uMAMO6QPMSr1pSvqGElPRP1mIBXmuiSuBzLO3LbsJuUEHw5Cp3/bxIB6rNA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-r/-/dict-r-2.0.0.tgz", + "integrity": "sha512-rdt1cKc3VL2uXJ2X088gRhTFreN/MkJWK1jccW1EWdFHLzDwhKfrlAkoLCp0paD6HvmloLQ+eSR09D58DdsYfA==", "dev": true }, "@cspell/dict-ruby": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@cspell/dict-ruby/-/dict-ruby-2.0.2.tgz", - "integrity": "sha512-vVnUpSmGDbPjs7MHq741DsLHhQcoA4CnUCM9wsTorQ9AQRDAkDTbK/LcY8nM19MoXCb3eF8PFku5Jq+gqH0u7w==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-ruby/-/dict-ruby-3.0.0.tgz", + "integrity": "sha512-sA98T8Y1Pmq3RStVkO14E8vTWkq6JUn8c8PldiMyYgV0yfQgwhQfFAzlSfF3Gg2B0VkIdqt2et2SPN7f9wp7fQ==", "dev": true }, "@cspell/dict-rust": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-rust/-/dict-rust-2.0.1.tgz", - "integrity": "sha512-ATDpIh0VWpQdUIZa8zqqJY4wQz3q00BTXlQCodeOmObYSb23+L6KWWzJ8mKLgpbc1lqTkogWrqxiCxlrCmqNmg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-rust/-/dict-rust-3.0.0.tgz", + "integrity": "sha512-L1T1IBsYJZVDmfOGAbVLcpc6arWxRRCSJYvHSwEDBGrNuMyJ4jx/NvBEz5crcKf4vVKgwVlXgzQlJJZ8AVxU9w==", "dev": true }, "@cspell/dict-scala": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-scala/-/dict-scala-2.0.0.tgz", - "integrity": "sha512-MUwA2YKpqaQOSR4V1/CVGRNk8Ii5kf6I8Ch+4/BhRZRQXuwWbi21rDRYWPqdQWps7VNzAbbMA+PQDWsD5YY38g==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-scala/-/dict-scala-3.0.0.tgz", + "integrity": "sha512-sIiCQDIMMnNns/fzD61z5npbh5pypaKq07Orqe0+eRfdQpika8iRSGUGFHVbtdd1JzB1DyTCV2e8OwdaQiXqJQ==", "dev": true }, "@cspell/dict-software-terms": { - "version": "2.2.12", - "resolved": "https://registry.npmjs.org/@cspell/dict-software-terms/-/dict-software-terms-2.2.12.tgz", - "integrity": "sha512-wVVy4on8Uq5VAWm3cqrrhewTRRbpmNxtmTURGQ5rT6FqUtJvZ7W2Pj3QquzXsA9zSFZhGFQR3U7IdFesET9yAg==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@cspell/dict-software-terms/-/dict-software-terms-3.0.5.tgz", + "integrity": "sha512-xZVcX1zsIUbLvUc/RX+YgJRvbHaGMcdkRR+Vw8UoLjmhnT0yXWLds5uwRwAVjlQIrIcHylfDWuG70Cq5nmJHfA==", "dev": true }, "@cspell/dict-sql": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@cspell/dict-sql/-/dict-sql-1.0.4.tgz", - "integrity": "sha512-+9nMcwsCzdYH0tyv2LeuVvQ+DdecS2C1N+hw6sl0FTHWI5GwULHAGW840RBwcKw0s+dl7sc0WpZhS1EW7b0pXg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-sql/-/dict-sql-2.0.0.tgz", + "integrity": "sha512-J3X8VSgWpc/4McQEs138abtBw/SO3Z+vGaYi5X7XV1pKPBxjupHTTNQHSS/HWUDmVWj6fR3OV+ZGptcmvv3Clg==", + "dev": true + }, + "@cspell/dict-svelte": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-svelte/-/dict-svelte-1.0.0.tgz", + "integrity": "sha512-5mE1bPMv+0Zdv6fiaHw86kZ47FhqNy9waUyGOT/wSWf6M5lxCZ3ze15rDruit6/62DaYo7A4/1dgKxpRo6/ZBQ==", "dev": true }, "@cspell/dict-swift": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@cspell/dict-swift/-/dict-swift-1.0.3.tgz", - "integrity": "sha512-yOBLSaRD0AnkkkndJ8PuB82Evp6lA2xItf2AWsnPfCCgxp5Ojk6uUBC/WQBSkzkCAOGbXyHsu9D97tsOx2c6cw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-swift/-/dict-swift-2.0.0.tgz", + "integrity": "sha512-VStJ0fKPPNIXKmxJrbGH6vKNtJCwAnQatfSH0fVj+Unf3QHHlmuLKRG0cN0aVgEIolpRkxNXJcSB3CPbYr0Xhw==", "dev": true }, "@cspell/dict-typescript": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@cspell/dict-typescript/-/dict-typescript-2.0.2.tgz", - "integrity": "sha512-OIoSJsCw9WHX4eDikoF5/0QbptMPZjElOcMYdYCyV03nqV5n4ot72ysTexW95yW4+fQU6uDPNQvnrUnhXXEkTA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-typescript/-/dict-typescript-3.0.1.tgz", + "integrity": "sha512-nKEtOpj+rJNIUK268/mCFDCIv1MWFdK1efm9YL4q1q3NHT+qCKhkXoA0eG8k4AaDIpsvebB8CgNIYFPxY92r4A==", "dev": true }, "@cspell/dict-vue": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@cspell/dict-vue/-/dict-vue-2.0.2.tgz", - "integrity": "sha512-/MB0RS0Gn01s4pgmjy0FvsLfr3RRMrRphEuvTRserNcM8XVtoIVAtrjig/Gg0DPwDrN8Clm0L1j7iQay6S8D0g==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-vue/-/dict-vue-3.0.0.tgz", + "integrity": "sha512-niiEMPWPV9IeRBRzZ0TBZmNnkK3olkOPYxC1Ny2AX4TGlYRajcW0WUtoSHmvvjZNfWLSg2L6ruiBeuPSbjnG6A==", + "dev": true + }, + "@cspell/strong-weak-map": { + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/@cspell/strong-weak-map/-/strong-weak-map-6.17.0.tgz", + "integrity": "sha512-fRghm6eoUEH7Uz57t0SEKJNm4lqODF2/DRiLd2ek7QkzUHKrCetre/5UrvdE78GIUyl0+8GLx9iFwo/XFa6dDA==", "dev": true }, "@cspotcode/source-map-support": { @@ -31826,9 +32198,9 @@ "dev": true }, "@es-joy/jsdoccomment": { - "version": "0.31.0", - "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.31.0.tgz", - "integrity": "sha512-tc1/iuQcnaiSIUVad72PBierDFpsxdUHtEF/OrfqvM1CBAsIoMP51j52jTMb3dXriwhieTo289InzZj72jL3EQ==", + "version": "0.36.1", + "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.36.1.tgz", + "integrity": "sha512-922xqFsTpHs6D0BUiG4toiyPOMc8/jafnWKxz1KWgS4XzKPy2qXf1Pe6UFuNSCQqt6tOuhAWXBNuuyUhJmw9Vg==", "dev": true, "requires": { "comment-parser": "1.3.1", @@ -31843,10 +32215,19 @@ "dev": true, "optional": true }, + "@eslint-community/eslint-utils": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.1.2.tgz", + "integrity": "sha512-7qELuQWWjVDdVsFQ5+beUl+KPczrEDA7S3zM4QUd/bJl7oXgsmpXaEVqrRTnOBqenOV4rWf2kVZk2Ot085zPWA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^3.3.0" + } + }, "@eslint/eslintrc": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.2.tgz", - "integrity": "sha512-AXYd23w1S/bv3fTs3Lz0vjiYemS08jWkI3hYyS9I1ry+0f+Yjs1wm+sU0BS8qDOPrBIkp4qHYC16I8uVtpLajQ==", + "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", @@ -31883,9 +32264,9 @@ } }, "globals": { - "version": "13.17.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz", - "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==", + "version": "13.19.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz", + "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==", "dev": true, "requires": { "type-fest": "^0.20.2" @@ -31978,24 +32359,24 @@ } }, "@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==" + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.2.1.tgz", + "integrity": "sha512-Sz07mnQrTekFWLz5BMjOzHl/+NooTdW8F8kDQxjWwbpOJcnoSg4vUDng8d/WR1wOxM0O+CY9Zw0nR054riNYtQ==" }, "@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==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.2.1.tgz", + "integrity": "sha512-HELwwbCz6C1XEcjzyT1Jugmz2NNklMrSPjZOWMlc+ZsHIVk+XOvOXLGGQtFBwSyqfJDNgRq4xBCwWOaZ/d9DEA==", "requires": { - "@fortawesome/fontawesome-common-types": "6.2.0" + "@fortawesome/fontawesome-common-types": "6.2.1" } }, "@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==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.2.1.tgz", + "integrity": "sha512-oKuqrP5jbfEPJWTij4sM+/RvgX+RMFwx3QZCZcK9PrBDgxC35zuc7AOFsyMjMd/PIFPeB2JxyqDr5zs/DZFPPw==", "requires": { - "@fortawesome/fontawesome-common-types": "6.2.0" + "@fortawesome/fontawesome-common-types": "6.2.1" } }, "@gar/promisify": { @@ -32005,22 +32386,22 @@ "dev": true }, "@googlemaps/js-api-loader": { - "version": "1.14.3", - "resolved": "https://registry.npmjs.org/@googlemaps/js-api-loader/-/js-api-loader-1.14.3.tgz", - "integrity": "sha512-6iIb+qpGgQpgIHmIFO44WhE1rDUxPVHuezNFL30wRJnkvhwFm94tD291UvNg9L05hLDSoL16jd0lbqqmdy4C5g==", + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/@googlemaps/js-api-loader/-/js-api-loader-1.15.1.tgz", + "integrity": "sha512-AsnEgNsB7S/VdrHGEQUaUM2e5tmjFGKBAfzR/AqO8O7TPq/jQGvoRw5liPBw4EMF38RDsHmKDV89q/X+qiUREQ==", "requires": { "fast-deep-equal": "^3.1.3" } }, "@humanwhocodes/config-array": { - "version": "0.10.7", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.7.tgz", - "integrity": "sha512-MDl6D6sBsaV452/QSdX+4CXIjZhIcI0PELsxUjk4U828yd58vk3bTIvk/6w5FY+4hIy9sLW0sfrV7K7Kc++j/w==", + "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.4" + "minimatch": "^3.0.5" }, "dependencies": { "brace-expansion": { @@ -32044,12 +32425,6 @@ } } }, - "@humanwhocodes/gitignore-to-minimatch": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/gitignore-to-minimatch/-/gitignore-to-minimatch-1.0.2.tgz", - "integrity": "sha512-rSqmMJDdLFUsyxR6FMtD00nfQKKLFb1kv+qBbOVKqErvloEIJLo5bDTJTQNTYgeyp78JsA7u/NPi5jT1GR/MuA==", - "dev": true - }, "@humanwhocodes/module-importer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", @@ -32800,21 +33175,21 @@ } }, "@ngtools/webpack": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-14.2.5.tgz", - "integrity": "sha512-Thwq1WyOOq1PIWMcjAAqKI1hbvGC0ywxbNoDadOlWpEFm6k0dvXC6Zm9lnVkePjxlPfagvbnv55+Lv9Vmygc1g==", + "version": "14.2.10", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-14.2.10.tgz", + "integrity": "sha512-sLHapZLVub6mEz5b19tf1VfIV1w3tYfg7FNPLeni79aldxu1FbP1v2WmiFAnMzrswqyK0bhTtxrl+Z/CLKqyoQ==", "dev": true, "requires": {} }, "@nguniversal/builders": { - "version": "14.2.0", - "resolved": "https://registry.npmjs.org/@nguniversal/builders/-/builders-14.2.0.tgz", - "integrity": "sha512-7rElvsL1OdLtYmn1zNwijga21KhDtjkhuM2o2Mwqafiud3a4zfxzmdv/hOAvFapVTlpUYgb+m4pBwq7V4DYiUA==", + "version": "14.2.3", + "resolved": "https://registry.npmjs.org/@nguniversal/builders/-/builders-14.2.3.tgz", + "integrity": "sha512-4WpQ5zMfw4BIH/2ymWchFm2bbN8w0/sC0Rg3IracJ9ESsfTJMaIg8CzVer6NBqC+5As9iLZwau7nrfzt7sQf1A==", "dev": true, "requires": { "@angular-devkit/architect": "^0.1402.0", "@angular-devkit/core": "^14.2.0", - "@nguniversal/common": "14.2.0", + "@nguniversal/common": "14.2.3", "browser-sync": "^2.26.7", "express": "^4.17.1", "guess-parser": "^0.4.12", @@ -32843,9 +33218,9 @@ } }, "@nguniversal/common": { - "version": "14.2.0", - "resolved": "https://registry.npmjs.org/@nguniversal/common/-/common-14.2.0.tgz", - "integrity": "sha512-6dpPSpCo6Kz4OrFa0RRFu8kmR6QDAEhwgTjD2MNU+WVf5ngwBAcakxW5/3bIx6A17et+Zr1/EVyhpyXFYSUjhw==", + "version": "14.2.3", + "resolved": "https://registry.npmjs.org/@nguniversal/common/-/common-14.2.3.tgz", + "integrity": "sha512-FWoZY+DZCNw24tNnnWkgTpNAlshkfiaxiT7V+fx2WFpY0LNXLWk45+hWhl4+wFEknOXr/DT/oU1m/RjR6FgXZQ==", "requires": { "critters": "0.0.16", "jsdom": "20.0.0", @@ -32853,27 +33228,20 @@ } }, "@nguniversal/express-engine": { - "version": "14.2.0", - "resolved": "https://registry.npmjs.org/@nguniversal/express-engine/-/express-engine-14.2.0.tgz", - "integrity": "sha512-t6JlyjXuC4CAD2YIcO7uTiEQ88qgRauWivrpy0YqH37M3jw7OE10NmSxTxsorN8b+A6xcHEJ7mXFVHD03gxbeQ==", + "version": "14.2.3", + "resolved": "https://registry.npmjs.org/@nguniversal/express-engine/-/express-engine-14.2.3.tgz", + "integrity": "sha512-8G60LgQViz7caJbmL5f0Cw3mUtchVOiLUf9q1PKKhPVYMv9PVs1roKWuq1yAd4ZVMztBo93gyPt8vQGOo+C9WA==", "requires": { - "@nguniversal/common": "14.2.0", + "@nguniversal/common": "14.2.3", "tslib": "^2.3.0" } }, "@ngx-formly/core": { - "version": "5.12.7", - "resolved": "https://registry.npmjs.org/@ngx-formly/core/-/core-5.12.7.tgz", - "integrity": "sha512-WE4mVbIgWJ6zVf6WdQTUjQ17th/iZTW5pYlF43JdWxhwzmY6IX/NA2Qg7N4gtdlV3+Z+iSytcocBVx8G4kukZA==", + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@ngx-formly/core/-/core-6.0.4.tgz", + "integrity": "sha512-GH+uIwNivI7EmqIRcGwyWa+CXPBY3ihWi05foMsYV7ghADe2Ap6mHaYdKoejMItLoWz79CrV2pYfwrnjlE3KOQ==", "requires": { - "tslib": "^1.7.1" - }, - "dependencies": { - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - } + "tslib": "^2.0.0" } }, "@ngx-translate/core": { @@ -33231,24 +33599,24 @@ } }, "@schematics/angular": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-14.2.5.tgz", - "integrity": "sha512-oYtQJi68EcDK940fny9t12JGE6z/ZbLeCZs+cPh4XT7ytRdO4anypBtKx18+E+b6jUnox4FxIGOf2WpkSAosYA==", + "version": "14.2.10", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-14.2.10.tgz", + "integrity": "sha512-YFTc/9QJdx422XcApizEcVLKoyknu8b9zHIlAepZCu7WkV8GPT0hvVEHQ7KBWys5aQ7pPZMT0JpZLeAz0F2xYQ==", "dev": true, "requires": { - "@angular-devkit/core": "14.2.5", - "@angular-devkit/schematics": "14.2.5", + "@angular-devkit/core": "14.2.10", + "@angular-devkit/schematics": "14.2.10", "jsonc-parser": "3.1.0" } }, "@sentry/browser": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-7.14.1.tgz", - "integrity": "sha512-b9nW2+kT9Jl/tfzJmvzpnS6F8ziC62TDx04a7kZDtuaVA5rKKTTlLDg8ZamCRFjjnuwuFhLnzxO34N0KfeTqHg==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-7.25.0.tgz", + "integrity": "sha512-vBNWDv8SUtJqgw/Mg9hGxct7dzHucfxq1zfxOdFziZOA/N9l+K52roNLZjYOk1JxaBE4QsHgJJyXelHnPlzCbA==", "requires": { - "@sentry/core": "7.14.1", - "@sentry/types": "7.14.1", - "@sentry/utils": "7.14.1", + "@sentry/core": "7.25.0", + "@sentry/types": "7.25.0", + "@sentry/utils": "7.25.0", "tslib": "^1.9.3" }, "dependencies": { @@ -33260,30 +33628,12 @@ } }, "@sentry/core": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.14.1.tgz", - "integrity": "sha512-sjk60Gf5o9zynhWe1e0ro9uQO4OrKZ3H9xfgBf2ExgKXeMfKzYp5r2v2OKNevEde36Sr/DzlpiPj8EK67xrWPA==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.25.0.tgz", + "integrity": "sha512-4PMuf+MsLxtbesXFBdXfRQhdxHVMi4e6z52DEdtSN9V41lT/R78qIfVopHs5gAr9j4lxCaiKSnNQDKziWLeQ8w==", "requires": { - "@sentry/hub": "7.14.1", - "@sentry/types": "7.14.1", - "@sentry/utils": "7.14.1", - "tslib": "^1.9.3" - }, - "dependencies": { - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - } - } - }, - "@sentry/hub": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-7.14.1.tgz", - "integrity": "sha512-BWh5jUvGmzCsJtYy6EX3qA6gTOxwGhA64IEXHbzwIAnBoG+VWao3addaL77AGR9pIgAqn6ssfkX665OZa+GPGw==", - "requires": { - "@sentry/types": "7.14.1", - "@sentry/utils": "7.14.1", + "@sentry/types": "7.25.0", + "@sentry/utils": "7.25.0", "tslib": "^1.9.3" }, "dependencies": { @@ -33295,16 +33645,16 @@ } }, "@sentry/types": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.14.1.tgz", - "integrity": "sha512-PxAfrIwBci6ouHOuRsfVq1B16i92nQNV5IvlqfJIYciazVhDWJvbF52caJAPOFS1WnuQZ4zqBDMYvtnwld3JCA==" + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.25.0.tgz", + "integrity": "sha512-m/tVeuZpbYNQjp4BYOz7bBxZEWdTHdTgXg9YlztUOCf5JDDujpxYp2Pyp4+cDDulzFIixXzRH7FRiKsOJ0WF7w==" }, "@sentry/utils": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.14.1.tgz", - "integrity": "sha512-CErQFbJMuhnHFKGkfIazQj5ETKoS7hG8PkoQEBt19F5QMh4+sbrJgnpIrIW8fVGtp0qKWKuIxQwD3b+1cFBozA==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.25.0.tgz", + "integrity": "sha512-1Wct+LvDySYgXBYHjoTzccASK4Rk/88cCifSZF7pLrix3Rzk+8QnPt4vZ/ce62nTNBDs/OeFXO1eFwiz9nCoEg==", "requires": { - "@sentry/types": "7.14.1", + "@sentry/types": "7.25.0", "tslib": "^1.9.3" }, "dependencies": { @@ -33478,9 +33828,9 @@ "dev": true }, "@types/eslint": { - "version": "8.4.6", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.6.tgz", - "integrity": "sha512-/fqTbjxyFUaYNO7VcW5g+4npmqVACz1bB7RTHYuLj+PRjw9hrCwrUXVQFpChUS0JsyEFvMZ7U/PfmvWgxJhI9g==", + "version": "8.4.10", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.10.tgz", + "integrity": "sha512-Sl/HOqN8NKPmhWo2VBEPm0nvHnu2LL3v9vKo8MEq0EtbJ4eVzGPl41VNPvn5E1i5poMk4/XD8UriLHpJvEP/Nw==", "dev": true, "requires": { "@types/estree": "*", @@ -33537,9 +33887,9 @@ } }, "@types/google.maps": { - "version": "3.50.2", - "resolved": "https://registry.npmjs.org/@types/google.maps/-/google.maps-3.50.2.tgz", - "integrity": "sha512-F47YMR1sdAVYk6mWab1J9CyO8J5QnCl62QGx9i87cTB2VW5/j2V5b/qgpXTvtUCg91PffirYKiAXlff/XTp+Zw==", + "version": "3.51.0", + "resolved": "https://registry.npmjs.org/@types/google.maps/-/google.maps-3.51.0.tgz", + "integrity": "sha512-44/oQYjc5D6kxBcI3Qk9rk3IIOMwnlEMWDV7pwPJ2YI89s5Q1OzDrFvR7QJ3LFrpVXEhig+gyagFg54+foinFg==", "dev": true }, "@types/graceful-fs": { @@ -33654,9 +34004,9 @@ "dev": true }, "@types/node": { - "version": "16.11.64", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.64.tgz", - "integrity": "sha512-z5hPTlVFzNwtJ2LNozTpJcD1Cu44c4LNuzaq1mwxmiHWQh2ULdR6Vjwo1UGldzRpzL0yUEdZddnfqGW2G70z6Q==", + "version": "16.18.8", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.8.tgz", + "integrity": "sha512-TrpoNiaPvBH5h8rQQenMtVsJXtGsVBRJrcp2Ik6oEt99jHfGvDLh20VTTq3ixTbjYujukYz1IlY4N8a8yfY0jA==", "dev": true }, "@types/normalize-package-data": { @@ -33701,6 +34051,12 @@ "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", "dev": true }, + "@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 + }, "@types/serve-index": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.1.tgz", @@ -33742,9 +34098,9 @@ "dev": true }, "@types/uuid": { - "version": "8.3.4", - "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", - "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-kr90f+ERiQtKWMz5rP32ltJ/BtULDI5RVO0uavn1HQUOwjx0R1h0rnDYNL0CepF1zL5bSY6FISAfd9tOdDhU5Q==", "dev": true }, "@types/webpack": { @@ -33783,45 +34139,89 @@ "dev": true }, "@typescript-eslint/eslint-plugin": { - "version": "5.39.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.39.0.tgz", - "integrity": "sha512-xVfKOkBm5iWMNGKQ2fwX5GVgBuHmZBO1tCRwXmY5oAIsPscfwm2UADDuNB8ZVYCtpQvJK4xpjrK7jEhcJ0zY9A==", + "version": "5.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.46.1.tgz", + "integrity": "sha512-YpzNv3aayRBwjs4J3oz65eVLXc9xx0PDbIRisHj+dYhvBn02MjYOD96P8YGiWEIFBrojaUjxvkaUpakD82phsA==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "5.39.0", - "@typescript-eslint/type-utils": "5.39.0", - "@typescript-eslint/utils": "5.39.0", + "@typescript-eslint/scope-manager": "5.46.1", + "@typescript-eslint/type-utils": "5.46.1", + "@typescript-eslint/utils": "5.46.1", "debug": "^4.3.4", "ignore": "^5.2.0", + "natural-compare-lite": "^1.4.0", "regexpp": "^3.2.0", "semver": "^7.3.7", "tsutils": "^3.21.0" }, "dependencies": { + "@typescript-eslint/scope-manager": { + "version": "5.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.46.1.tgz", + "integrity": "sha512-iOChVivo4jpwUdrJZyXSMrEIM/PvsbbDOX1y3UCKjSgWn+W89skxWaYXACQfxmIGhPVpRWK/VWPYc+bad6smIA==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.46.1", + "@typescript-eslint/visitor-keys": "5.46.1" + } + }, "@typescript-eslint/type-utils": { - "version": "5.39.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.39.0.tgz", - "integrity": "sha512-KJHJkOothljQWzR3t/GunL0TPKY+fGJtnpl+pX+sJ0YiKTz3q2Zr87SGTmFqsCMFrLt5E0+o+S6eQY0FAXj9uA==", + "version": "5.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.46.1.tgz", + "integrity": "sha512-V/zMyfI+jDmL1ADxfDxjZ0EMbtiVqj8LUGPAGyBkXXStWmCUErMpW873zEHsyguWCuq2iN4BrlWUkmuVj84yng==", "dev": true, "requires": { - "@typescript-eslint/typescript-estree": "5.39.0", - "@typescript-eslint/utils": "5.39.0", + "@typescript-eslint/typescript-estree": "5.46.1", + "@typescript-eslint/utils": "5.46.1", "debug": "^4.3.4", "tsutils": "^3.21.0" } }, + "@typescript-eslint/types": { + "version": "5.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.46.1.tgz", + "integrity": "sha512-Z5pvlCaZgU+93ryiYUwGwLl9AQVB/PQ1TsJ9NZ/gHzZjN7g9IAn6RSDkpCV8hqTwAiaj6fmCcKSQeBPlIpW28w==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "5.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.46.1.tgz", + "integrity": "sha512-j9W4t67QiNp90kh5Nbr1w92wzt+toiIsaVPnEblB2Ih2U9fqBTyqV9T3pYWZBRt6QoMh/zVWP59EpuCjc4VRBg==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.46.1", + "@typescript-eslint/visitor-keys": "5.46.1", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + } + }, "@typescript-eslint/utils": { - "version": "5.39.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.39.0.tgz", - "integrity": "sha512-+DnY5jkpOpgj+EBtYPyHRjXampJfC0yUZZzfzLuUWVZvCuKqSdJVC8UhdWipIw7VKNTfwfAPiOWzYkAwuIhiAg==", + "version": "5.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.46.1.tgz", + "integrity": "sha512-RBdBAGv3oEpFojaCYT4Ghn4775pdjvwfDOfQ2P6qzNVgQOVrnSPe5/Pb88kv7xzYQjoio0eKHKB9GJ16ieSxvA==", "dev": true, "requires": { "@types/json-schema": "^7.0.9", - "@typescript-eslint/scope-manager": "5.39.0", - "@typescript-eslint/types": "5.39.0", - "@typescript-eslint/typescript-estree": "5.39.0", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.46.1", + "@typescript-eslint/types": "5.46.1", + "@typescript-eslint/typescript-estree": "5.46.1", "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0" + "eslint-utils": "^3.0.0", + "semver": "^7.3.7" + } + }, + "@typescript-eslint/visitor-keys": { + "version": "5.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.46.1.tgz", + "integrity": "sha512-jczZ9noovXwy59KjRTk1OftT78pwygdcmCuBf8yMoWt/8O8l+6x2LSEze0E4TeepXK4MezW3zGSyoDRZK7Y9cg==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.46.1", + "eslint-visitor-keys": "^3.3.0" } } } @@ -33852,15 +34252,58 @@ } }, "@typescript-eslint/parser": { - "version": "5.39.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.39.0.tgz", - "integrity": "sha512-PhxLjrZnHShe431sBAGHaNe6BDdxAASDySgsBCGxcBecVCi8NQWxQZMcizNA4g0pN51bBAn/FUfkWG3SDVcGlA==", + "version": "5.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.46.1.tgz", + "integrity": "sha512-RelQ5cGypPh4ySAtfIMBzBGyrNerQcmfA1oJvPj5f+H4jI59rl9xxpn4bonC0tQvUKOEN7eGBFWxFLK3Xepneg==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "5.39.0", - "@typescript-eslint/types": "5.39.0", - "@typescript-eslint/typescript-estree": "5.39.0", + "@typescript-eslint/scope-manager": "5.46.1", + "@typescript-eslint/types": "5.46.1", + "@typescript-eslint/typescript-estree": "5.46.1", "debug": "^4.3.4" + }, + "dependencies": { + "@typescript-eslint/scope-manager": { + "version": "5.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.46.1.tgz", + "integrity": "sha512-iOChVivo4jpwUdrJZyXSMrEIM/PvsbbDOX1y3UCKjSgWn+W89skxWaYXACQfxmIGhPVpRWK/VWPYc+bad6smIA==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.46.1", + "@typescript-eslint/visitor-keys": "5.46.1" + } + }, + "@typescript-eslint/types": { + "version": "5.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.46.1.tgz", + "integrity": "sha512-Z5pvlCaZgU+93ryiYUwGwLl9AQVB/PQ1TsJ9NZ/gHzZjN7g9IAn6RSDkpCV8hqTwAiaj6fmCcKSQeBPlIpW28w==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "5.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.46.1.tgz", + "integrity": "sha512-j9W4t67QiNp90kh5Nbr1w92wzt+toiIsaVPnEblB2Ih2U9fqBTyqV9T3pYWZBRt6QoMh/zVWP59EpuCjc4VRBg==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.46.1", + "@typescript-eslint/visitor-keys": "5.46.1", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/visitor-keys": { + "version": "5.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.46.1.tgz", + "integrity": "sha512-jczZ9noovXwy59KjRTk1OftT78pwygdcmCuBf8yMoWt/8O8l+6x2LSEze0E4TeepXK4MezW3zGSyoDRZK7Y9cg==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.46.1", + "eslint-visitor-keys": "^3.3.0" + } + } } }, "@typescript-eslint/scope-manager": { @@ -33874,31 +34317,31 @@ } }, "@typescript-eslint/type-utils": { - "version": "5.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.37.0.tgz", - "integrity": "sha512-BSx/O0Z0SXOF5tY0bNTBcDEKz2Ec20GVYvq/H/XNKiUorUFilH7NPbFUuiiyzWaSdN3PA8JV0OvYx0gH/5aFAQ==", + "version": "5.43.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.43.0.tgz", + "integrity": "sha512-K21f+KY2/VvYggLf5Pk4tgBOPs2otTaIHy2zjclo7UZGLyFH86VfUOm5iq+OtDtxq/Zwu2I3ujDBykVW4Xtmtg==", "dev": true, "requires": { - "@typescript-eslint/typescript-estree": "5.37.0", - "@typescript-eslint/utils": "5.37.0", + "@typescript-eslint/typescript-estree": "5.43.0", + "@typescript-eslint/utils": "5.43.0", "debug": "^4.3.4", "tsutils": "^3.21.0" }, "dependencies": { "@typescript-eslint/types": { - "version": "5.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.37.0.tgz", - "integrity": "sha512-3frIJiTa5+tCb2iqR/bf7XwU20lnU05r/sgPJnRpwvfZaqCJBrl8Q/mw9vr3NrNdB/XtVyMA0eppRMMBqdJ1bA==", + "version": "5.43.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.43.0.tgz", + "integrity": "sha512-jpsbcD0x6AUvV7tyOlyvon0aUsQpF8W+7TpJntfCUWU1qaIKu2K34pMwQKSzQH8ORgUrGYY6pVIh1Pi8TNeteg==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "5.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.37.0.tgz", - "integrity": "sha512-JkFoFIt/cx59iqEDSgIGnQpCTRv96MQnXCYvJi7QhBC24uyuzbD8wVbajMB1b9x4I0octYFJ3OwjAwNqk1AjDA==", + "version": "5.43.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.43.0.tgz", + "integrity": "sha512-BZ1WVe+QQ+igWal2tDbNg1j2HWUkAa+CVqdU79L4HP9izQY6CNhXfkNwd1SS4+sSZAP/EthI1uiCSY/+H0pROg==", "dev": true, "requires": { - "@typescript-eslint/types": "5.37.0", - "@typescript-eslint/visitor-keys": "5.37.0", + "@typescript-eslint/types": "5.43.0", + "@typescript-eslint/visitor-keys": "5.43.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -33907,12 +34350,12 @@ } }, "@typescript-eslint/visitor-keys": { - "version": "5.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.37.0.tgz", - "integrity": "sha512-Hp7rT4cENBPIzMwrlehLW/28EVCOcE9U1Z1BQTc8EA8v5qpr7GRGuG+U58V5tTY48zvUOA3KHvw3rA8tY9fbdA==", + "version": "5.43.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.43.0.tgz", + "integrity": "sha512-icl1jNH/d18OVHLfcwdL3bWUKsBeIiKYTGxMJCoGe7xFht+E4QgzOqoWYrU8XSLJWhVw8nTacbm03v23J/hFTg==", "dev": true, "requires": { - "@typescript-eslint/types": "5.37.0", + "@typescript-eslint/types": "5.43.0", "eslint-visitor-keys": "^3.3.0" } } @@ -33940,43 +34383,45 @@ } }, "@typescript-eslint/utils": { - "version": "5.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.37.0.tgz", - "integrity": "sha512-jUEJoQrWbZhmikbcWSMDuUSxEE7ID2W/QCV/uz10WtQqfOuKZUqFGjqLJ+qhDd17rjgp+QJPqTdPIBWwoob2NQ==", + "version": "5.43.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.43.0.tgz", + "integrity": "sha512-8nVpA6yX0sCjf7v/NDfeaOlyaIIqL7OaIGOWSPFqUKK59Gnumd3Wa+2l8oAaYO2lk0sO+SbWFWRSvhu8gLGv4A==", "dev": true, "requires": { "@types/json-schema": "^7.0.9", - "@typescript-eslint/scope-manager": "5.37.0", - "@typescript-eslint/types": "5.37.0", - "@typescript-eslint/typescript-estree": "5.37.0", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.43.0", + "@typescript-eslint/types": "5.43.0", + "@typescript-eslint/typescript-estree": "5.43.0", "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0" + "eslint-utils": "^3.0.0", + "semver": "^7.3.7" }, "dependencies": { "@typescript-eslint/scope-manager": { - "version": "5.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.37.0.tgz", - "integrity": "sha512-F67MqrmSXGd/eZnujjtkPgBQzgespu/iCZ+54Ok9X5tALb9L2v3G+QBSoWkXG0p3lcTJsL+iXz5eLUEdSiJU9Q==", + "version": "5.43.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.43.0.tgz", + "integrity": "sha512-XNWnGaqAtTJsUiZaoiGIrdJYHsUOd3BZ3Qj5zKp9w6km6HsrjPk/TGZv0qMTWyWj0+1QOqpHQ2gZOLXaGA9Ekw==", "dev": true, "requires": { - "@typescript-eslint/types": "5.37.0", - "@typescript-eslint/visitor-keys": "5.37.0" + "@typescript-eslint/types": "5.43.0", + "@typescript-eslint/visitor-keys": "5.43.0" } }, "@typescript-eslint/types": { - "version": "5.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.37.0.tgz", - "integrity": "sha512-3frIJiTa5+tCb2iqR/bf7XwU20lnU05r/sgPJnRpwvfZaqCJBrl8Q/mw9vr3NrNdB/XtVyMA0eppRMMBqdJ1bA==", + "version": "5.43.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.43.0.tgz", + "integrity": "sha512-jpsbcD0x6AUvV7tyOlyvon0aUsQpF8W+7TpJntfCUWU1qaIKu2K34pMwQKSzQH8ORgUrGYY6pVIh1Pi8TNeteg==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "5.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.37.0.tgz", - "integrity": "sha512-JkFoFIt/cx59iqEDSgIGnQpCTRv96MQnXCYvJi7QhBC24uyuzbD8wVbajMB1b9x4I0octYFJ3OwjAwNqk1AjDA==", + "version": "5.43.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.43.0.tgz", + "integrity": "sha512-BZ1WVe+QQ+igWal2tDbNg1j2HWUkAa+CVqdU79L4HP9izQY6CNhXfkNwd1SS4+sSZAP/EthI1uiCSY/+H0pROg==", "dev": true, "requires": { - "@typescript-eslint/types": "5.37.0", - "@typescript-eslint/visitor-keys": "5.37.0", + "@typescript-eslint/types": "5.43.0", + "@typescript-eslint/visitor-keys": "5.43.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -33985,12 +34430,12 @@ } }, "@typescript-eslint/visitor-keys": { - "version": "5.37.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.37.0.tgz", - "integrity": "sha512-Hp7rT4cENBPIzMwrlehLW/28EVCOcE9U1Z1BQTc8EA8v5qpr7GRGuG+U58V5tTY48zvUOA3KHvw3rA8tY9fbdA==", + "version": "5.43.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.43.0.tgz", + "integrity": "sha512-icl1jNH/d18OVHLfcwdL3bWUKsBeIiKYTGxMJCoGe7xFht+E4QgzOqoWYrU8XSLJWhVw8nTacbm03v23J/hFTg==", "dev": true, "requires": { - "@typescript-eslint/types": "5.37.0", + "@typescript-eslint/types": "5.43.0", "eslint-visitor-keys": "^3.3.0" } } @@ -34513,9 +34958,9 @@ }, "dependencies": { "loader-utils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz", - "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", "dev": true, "requires": { "big.js": "^5.2.2", @@ -34622,9 +35067,9 @@ } }, "angulartics2": { - "version": "12.1.0", - "resolved": "https://registry.npmjs.org/angulartics2/-/angulartics2-12.1.0.tgz", - "integrity": "sha512-Avmc2zIf6r8kn9eXpQQ3qzaeIlyYd4Uzjr5a5nOOQfHb8AcMsV1PfUVQ1OJmBdxjde+sIHmY3VvabNjWHh4BpQ==", + "version": "12.2.0", + "resolved": "https://registry.npmjs.org/angulartics2/-/angulartics2-12.2.0.tgz", + "integrity": "sha512-1wl/cPA4PGYj42z80VIR+A0Hy3+rt13POzfTfZ83NUDx2KKbHjtTKS0O7u3umi10cqvi5tn4NTSYIFFJ1fI2Tw==", "requires": { "tslib": "^2.3.0" } @@ -34708,12 +35153,6 @@ "integrity": "sha512-FCAJojipPn0bXjuEpjOOOMN8FZDkxfWWp4JGN9mifU2IhxvKyXZYqpzPHdnTSUpmPDy+tsslB6Z1g+Vg6nVbYA==", "dev": true }, - "app-root-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-3.0.0.tgz", - "integrity": "sha512-qMcx+Gy2UZynHjOHOIXPNvpf+9cjvk3cWrBBK7zg4gH9+clobJRb9NGzcT7mQTcV/6Gm/1WelUtqxVXnNlrwcw==", - "dev": true - }, "aproba": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", @@ -34742,10 +35181,44 @@ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, "aria-query": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.0.2.tgz", - "integrity": "sha512-eigU3vhqSO+Z8BKDnVLN/ompjhf3pYzecKXz8+whRy+9gZu8n1TCGfwzQUUPnqdHl9ax1Hr9031orZ+UOEYr7Q==", - "dev": true + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", + "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", + "dev": true, + "requires": { + "deep-equal": "^2.0.5" + }, + "dependencies": { + "deep-equal": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.1.0.tgz", + "integrity": "sha512-2pxgvWu3Alv1PoWEyVg7HS8YhGlUFUV7N5oOvfL6d+7xAmLSemMwv/c8Zv/i9KFzxV5Kt5CAvQc70fLwVuf4UA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "es-get-iterator": "^1.1.2", + "get-intrinsic": "^1.1.3", + "is-arguments": "^1.1.1", + "is-date-object": "^1.0.5", + "is-regex": "^1.1.4", + "isarray": "^2.0.5", + "object-is": "^1.1.5", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.4.3", + "side-channel": "^1.0.4", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.8" + } + }, + "isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + } + } }, "array-differ": { "version": "3.0.0", @@ -34893,19 +35366,25 @@ "dev": true }, "autoprefixer": { - "version": "10.4.12", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.12.tgz", - "integrity": "sha512-WrCGV9/b97Pa+jtwf5UGaRjgQIg7OK3D06GnoYoZNcG1Xb8Gt3EfuKjlhh9i/VtT16g6PYjZ69jdJ2g8FxSC4Q==", + "version": "10.4.13", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.13.tgz", + "integrity": "sha512-49vKpMqcZYsJjwotvt4+h/BCjJVnhGwcLpDt5xkcaOG3eLrG/HUYLagrihYsQ+qrIBgIzX1Rw7a6L8I/ZA1Atg==", "dev": true, "requires": { "browserslist": "^4.21.4", - "caniuse-lite": "^1.0.30001407", + "caniuse-lite": "^1.0.30001426", "fraction.js": "^4.2.0", "normalize-range": "^0.1.2", "picocolors": "^1.0.0", "postcss-value-parser": "^4.2.0" } }, + "available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "dev": true + }, "axios": { "version": "0.21.4", "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", @@ -34916,10 +35395,44 @@ } }, "axobject-query": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.0.1.tgz", - "integrity": "sha512-vy5JPSOibF9yAeC2PoemRdA1MuSXX7vX5osdoxKf/6OUeppAWekZ3JIJVNWFMH6wgj7uHYyqZUSqE/b/3JLV1A==", - "dev": true + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.1.1.tgz", + "integrity": "sha512-goKlv8DZrK9hUh975fnHzhNIO4jUnFCfv/dszV5VwUGDFjI6vQ2VwoyjYjYNEbBE8AH87TduWP5uyDR1D+Iteg==", + "dev": true, + "requires": { + "deep-equal": "^2.0.5" + }, + "dependencies": { + "deep-equal": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.1.0.tgz", + "integrity": "sha512-2pxgvWu3Alv1PoWEyVg7HS8YhGlUFUV7N5oOvfL6d+7xAmLSemMwv/c8Zv/i9KFzxV5Kt5CAvQc70fLwVuf4UA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "es-get-iterator": "^1.1.2", + "get-intrinsic": "^1.1.3", + "is-arguments": "^1.1.1", + "is-date-object": "^1.0.5", + "is-regex": "^1.1.4", + "isarray": "^2.0.5", + "object-is": "^1.1.5", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.4.3", + "side-channel": "^1.0.4", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.8" + } + }, + "isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + } + } }, "babel-jest": { "version": "28.1.3", @@ -35000,9 +35513,9 @@ }, "dependencies": { "loader-utils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz", - "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", "dev": true, "requires": { "big.js": "^5.2.2", @@ -35200,9 +35713,9 @@ "dev": true }, "body-parser": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz", - "integrity": "sha512-DfJ+q6EPcGKZD1QWUjSpqp+Q7bDQTsQIF4zfUAtZ6qk+H/3/QRhg9CEp39ss+/T2vw0+HaidC0ecJj/DRLIaKg==", + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", "requires": { "bytes": "3.1.2", "content-type": "~1.0.4", @@ -35212,7 +35725,7 @@ "http-errors": "2.0.0", "iconv-lite": "0.4.24", "on-finished": "2.4.1", - "qs": "6.10.3", + "qs": "6.11.0", "raw-body": "2.5.1", "type-is": "~1.6.18", "unpipe": "1.0.0" @@ -35232,9 +35745,9 @@ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, "qs": { - "version": "6.10.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", - "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", "requires": { "side-channel": "^1.0.4" } @@ -35738,12 +36251,6 @@ "unique-filename": "^1.1.1" } }, - "cachedir": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.3.0.tgz", - "integrity": "sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw==", - "dev": true - }, "call-bind": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", @@ -35789,9 +36296,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001416", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001416.tgz", - "integrity": "sha512-06wzzdAkCPZO+Qm4e/eNghZBDfVNDsCgw33T27OwBH9unE9S478OYw//Q2L7Npf/zBzs7rjZOszIFQkwQKAEqA==" + "version": "1.0.30001439", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001439.tgz", + "integrity": "sha512-1MgUzEkoMO6gKfXflStpYgZDlFM7M/ck/bgfVCACO5vnAf0fXoNVHdWtqGU+MYca+4bL9Z5bpOVmR33cWW9G2A==" }, "caseless": { "version": "0.12.0", @@ -35895,9 +36402,9 @@ "dev": true }, "ci-info": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.4.0.tgz", - "integrity": "sha512-t5QdPT5jq3o262DOQ8zA6E1tlH2upmUc4Hlvrbx1pGYJuiiHl7O7rvVNI+l8HTVhd/q3Qc9vqimkNk5yiXsAug==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.7.0.tgz", + "integrity": "sha512-2CpRNYmImPx+RXKLq6jko/L07phmS9I02TyqkcNU20GCF/GgaWvc58hPtjxDX8lPpkdwc9sNh72V9k00S7ezog==", "dev": true }, "cjs-module-lexer": { @@ -36192,85 +36699,6 @@ "integrity": "sha512-B52sN2VNghyq5ofvUsqZjmk6YkihBX5vMSChmSK9v4ShjKf3Vk5Xcmgpw4o+iIgtrnM/u5FiMpz9VKb8lpBveA==", "dev": true }, - "commitizen": { - "version": "4.2.5", - "resolved": "https://registry.npmjs.org/commitizen/-/commitizen-4.2.5.tgz", - "integrity": "sha512-9sXju8Qrz1B4Tw7kC5KhnvwYQN88qs2zbiB8oyMsnXZyJ24PPGiNM3nHr73d32dnE3i8VJEXddBFIbOgYSEXtQ==", - "dev": true, - "requires": { - "cachedir": "2.3.0", - "cz-conventional-changelog": "3.3.0", - "dedent": "0.7.0", - "detect-indent": "6.1.0", - "find-node-modules": "^2.1.2", - "find-root": "1.1.0", - "fs-extra": "9.1.0", - "glob": "7.2.3", - "inquirer": "8.2.4", - "is-utf8": "^0.2.1", - "lodash": "4.17.21", - "minimist": "1.2.6", - "strip-bom": "4.0.0", - "strip-json-comments": "3.1.1" - }, - "dependencies": { - "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" - } - }, - "fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "dev": true, - "requires": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - } - }, - "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" - } - }, - "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" - } - } - } - }, - "commitlint-config-cz": { - "version": "0.13.3", - "resolved": "https://registry.npmjs.org/commitlint-config-cz/-/commitlint-config-cz-0.13.3.tgz", - "integrity": "sha512-6LmCvGiFDTVSmLF0mzVVp1etMM8lAqLmPRlU7Oml1J8J9oOLadf+2g4uMTchdxOvvYLgll99SESFUHgmc6oATA==", - "dev": true, - "requires": { - "app-root-path": "~3.0.0", - "lodash.clonedeep": "~4.5.0" - } - }, "common-tags": { "version": "1.8.2", "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz", @@ -36638,12 +37066,6 @@ } } }, - "conventional-commit-types": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/conventional-commit-types/-/conventional-commit-types-3.0.0.tgz", - "integrity": "sha512-SmmCYnOniSsAa9GqWOeLqc179lfr5TRu5b4QFDkbsrJ5TZjPJx85wtOr3zn+1dbeNiXDKGPbZ72IKbPhLXh/Lg==", - "dev": true - }, "conventional-commits-filter": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-2.0.7.tgz", @@ -36777,9 +37199,9 @@ } }, "cosmiconfig": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", - "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", "dev": true, "requires": { "@types/parse-json": "^4.0.0", @@ -36790,9 +37212,9 @@ } }, "cosmiconfig-typescript-loader": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-4.1.1.tgz", - "integrity": "sha512-9DHpa379Gp0o0Zefii35fcmuuin6q92FnLDffzdZ0l9tVd3nEobG3O+MZ06+kuBvFTSVScvNb/oHA13Nd4iipg==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-4.3.0.tgz", + "integrity": "sha512-NTxV1MFfZDLPiBMjxbHRwSh5LaLcPMwNdCutmnHJCKoVnlvldPWlllonKwrsRJ5pYZBIBGRWWU2tfvzxgeSW5Q==", "dev": true, "requires": {} }, @@ -36948,24 +37370,24 @@ "dev": true }, "cspell": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/cspell/-/cspell-6.12.0.tgz", - "integrity": "sha512-ny4xVEPYFP2jVf5w71Mnk4HKj6RbPH+CMSzUrOMbYVVNnQUj3GLfzy5DrSFLG0zGa353ZRC4/s9MsEvnAL8mkA==", + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/cspell/-/cspell-6.17.0.tgz", + "integrity": "sha512-R1TXu1p2vON6rHXxZAUPbdf+v+ckPhWiEb3apq2PyxLSjzMiZDm2ThIwRcsQaMLLZyFOD+J3SHj0lZi1Qoaa8w==", "dev": true, "requires": { - "@cspell/cspell-pipe": "^6.12.0", + "@cspell/cspell-pipe": "6.17.0", "chalk": "^4.1.2", - "commander": "^9.4.0", - "cspell-gitignore": "^6.12.0", - "cspell-glob": "^6.12.0", - "cspell-lib": "^6.12.0", + "commander": "^9.4.1", + "cspell-gitignore": "6.17.0", + "cspell-glob": "6.17.0", + "cspell-lib": "6.17.0", "fast-json-stable-stringify": "^2.1.0", "file-entry-cache": "^6.0.1", "fs-extra": "^10.1.0", "get-stdin": "^8.0.0", "glob": "^8.0.3", "imurmurhash": "^0.1.4", - "semver": "^7.3.7", + "semver": "^7.3.8", "strip-ansi": "^6.0.1", "vscode-uri": "^3.0.6" }, @@ -37010,6 +37432,24 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "semver": { + "version": "7.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", @@ -37022,75 +37462,76 @@ } }, "cspell-dictionary": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/cspell-dictionary/-/cspell-dictionary-6.12.0.tgz", - "integrity": "sha512-I2cXSdXndt9H7yXmJzLTjgui/SAPGghXwxFeibTbvF68gyQYD5fUXvOygEIPrOEySKlAIb+aouV77SgoURxMHw==", + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/cspell-dictionary/-/cspell-dictionary-6.17.0.tgz", + "integrity": "sha512-jUb/kIR2glYliRem11kCu7gaXUcHKp8L2G73LmzIULx+UKRgTa/100FXqm5lZUWnCaIznMmaA2QtutP+xYy5AQ==", "dev": true, "requires": { - "@cspell/cspell-pipe": "^6.12.0", - "@cspell/cspell-types": "^6.12.0", - "cspell-trie-lib": "^6.12.0", + "@cspell/cspell-pipe": "6.17.0", + "@cspell/cspell-types": "6.17.0", + "cspell-trie-lib": "6.17.0", "fast-equals": "^4.0.3", "gensequence": "^4.0.2" } }, "cspell-gitignore": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/cspell-gitignore/-/cspell-gitignore-6.12.0.tgz", - "integrity": "sha512-gtsN2AAvqdE8CHVzpxsQcd/Wn5GAMTjzHpDXX71g/k8IJn743poGU06O0O1WSVAgK0fWTRsfg+V5OegA1TAo7A==", + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/cspell-gitignore/-/cspell-gitignore-6.17.0.tgz", + "integrity": "sha512-SDyPv6LqBebvoTKFP+ewh51gvmv1z8JDg7llumUFH2u1WoiMZBLLOL2pAa9UM0f6eEzBC1iS6nWQ+20VJx2yQA==", "dev": true, "requires": { - "cspell-glob": "^6.12.0", + "cspell-glob": "6.17.0", "find-up": "^5.0.0" } }, "cspell-glob": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/cspell-glob/-/cspell-glob-6.12.0.tgz", - "integrity": "sha512-Q0rMGTxDyFFPm1LmHYM0ziuxQt2aXgr8Oi1glA2s0dBs0hg1DexlAEoLwLiMDUwSTvibEKIidPzlrmZ1AUDWEg==", + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/cspell-glob/-/cspell-glob-6.17.0.tgz", + "integrity": "sha512-iKz2CvUU1HXuNJfxYRwSQFck3pCl9EhTx2qIR0lKf4gccCR89p44qxIR98nTbX1OF89lhfH6sUHtzkJ3nPWh+A==", "dev": true, "requires": { "micromatch": "^4.0.5" } }, "cspell-grammar": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/cspell-grammar/-/cspell-grammar-6.12.0.tgz", - "integrity": "sha512-WXcDiWJ2pTW0jHY0Bf0DW5s8A9S0a+2tsVZsNxE/0CR5P/8yDSnznE+59uok/JN+GXOKQ6VIaqAZA3/XjDZuuA==", + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/cspell-grammar/-/cspell-grammar-6.17.0.tgz", + "integrity": "sha512-3B9QmKWOjAPzLYqesLP2niIbo6Yvb4rodjIwFXUvL3vmMZF4c9HFU/JVTTerLxrwh3DH8u6Mac52RzUurOJ15Q==", "dev": true, "requires": { - "@cspell/cspell-pipe": "^6.12.0", - "@cspell/cspell-types": "^6.12.0" + "@cspell/cspell-pipe": "6.17.0", + "@cspell/cspell-types": "6.17.0" } }, "cspell-io": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/cspell-io/-/cspell-io-6.12.0.tgz", - "integrity": "sha512-1faxDj2OMgq61w7GaiXZD7ytks6PksJlG484LMl2USv58jDky4i2lujJs1C/+aP97Box9EcdwzydHX9GpnqqCw==", + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/cspell-io/-/cspell-io-6.17.0.tgz", + "integrity": "sha512-cofZlvKzXP3QytGM6OlREQIXLFcSdEKOFubSVHkRvAVX3IqeQnKo4oVF85C6McjwXTrJ1OH+SDP0vcpn6mKqTg==", "dev": true, "requires": { - "@cspell/cspell-service-bus": "^6.12.0", + "@cspell/cspell-service-bus": "6.17.0", "node-fetch": "^2.6.7" } }, "cspell-lib": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/cspell-lib/-/cspell-lib-6.12.0.tgz", - "integrity": "sha512-IKd2MzH/zoiXohc26Lqb1b8i+41Y2xGreyAe9ihv/7Z2dscGGVy7F/2taZvZK9kJIhaz33Yatxfx3htT6w0hqg==", + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/cspell-lib/-/cspell-lib-6.17.0.tgz", + "integrity": "sha512-oZNkm0UhRa4nkoYPij23z7cbVXFPVHs7SdGC6IAVc71uz44nLNeC3e8+UnTErOU7nlROvjp9k3G90DEwej1TqQ==", "dev": true, "requires": { - "@cspell/cspell-bundled-dicts": "^6.12.0", - "@cspell/cspell-pipe": "^6.12.0", - "@cspell/cspell-types": "^6.12.0", + "@cspell/cspell-bundled-dicts": "6.17.0", + "@cspell/cspell-pipe": "6.17.0", + "@cspell/cspell-types": "6.17.0", + "@cspell/strong-weak-map": "6.17.0", "clear-module": "^4.1.2", "comment-json": "^4.2.3", "configstore": "^5.0.1", - "cosmiconfig": "^7.0.1", - "cspell-dictionary": "^6.12.0", - "cspell-glob": "^6.12.0", - "cspell-grammar": "^6.12.0", - "cspell-io": "^6.12.0", - "cspell-trie-lib": "^6.12.0", + "cosmiconfig": "^8.0.0", + "cspell-dictionary": "6.17.0", + "cspell-glob": "6.17.0", + "cspell-grammar": "6.17.0", + "cspell-io": "6.17.0", + "cspell-trie-lib": "6.17.0", "fast-equals": "^4.0.3", "find-up": "^5.0.0", "fs-extra": "^10.1.0", @@ -37100,16 +37541,30 @@ "resolve-global": "^1.0.0", "vscode-languageserver-textdocument": "^1.0.7", "vscode-uri": "^3.0.6" + }, + "dependencies": { + "cosmiconfig": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.0.0.tgz", + "integrity": "sha512-da1EafcpH6b/TD8vDRaWV7xFINlHlF6zKsGwS1TsuVJTZRkquaS5HTMq7uq6h31619QjbsYl21gVDOm32KM1vQ==", + "dev": true, + "requires": { + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0" + } + } } }, "cspell-trie-lib": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/cspell-trie-lib/-/cspell-trie-lib-6.12.0.tgz", - "integrity": "sha512-SJOdb51Wy3ewaKfttZwc9NYOIXaKlhyr+ykYKBExj3qMfV1J4d4iDLE95FriaRcqnq6X/qEM9jUvZHlvadDk3A==", + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/cspell-trie-lib/-/cspell-trie-lib-6.17.0.tgz", + "integrity": "sha512-hmyZHhemWYLjjEDItAhgAF0tuL2iiQg+5PzUmELKIBSWEsmFdfxh1xWCmo1q0+vzVML+0Ms2cspiGyS9y/CF7A==", "dev": true, "requires": { - "@cspell/cspell-pipe": "^6.12.0", - "@cspell/cspell-types": "^6.12.0", + "@cspell/cspell-pipe": "6.17.0", + "@cspell/cspell-types": "6.17.0", "fs-extra": "^10.1.0", "gensequence": "^4.0.2" } @@ -37180,9 +37635,9 @@ "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==" }, "cssdb": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-7.0.1.tgz", - "integrity": "sha512-pT3nzyGM78poCKLAEy2zWIVX2hikq6dIrjuZzLV98MumBg+xMTNYfHx7paUlfiRTgg91O/vR889CIf+qiv79Rw==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-7.2.0.tgz", + "integrity": "sha512-JYlIsE7eKHSi0UNuCyo96YuIDFqvhGgHw4Ck6lsN+DP0Tp8M64UTDT2trGbkMDqnCoEjks7CkS0XcjU0rkvBdg==", "dev": true }, "cssesc": { @@ -37217,21 +37672,6 @@ "integrity": "sha512-yi1x3EAWKjQTreYWeSd98431AV+IEE0qoDyOoaHJ7KJ21gv6HtBXHVLX74opVSGqcR8/AbjJBHAHpcOy2bj5Gg==", "dev": true }, - "cz-conventional-changelog": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/cz-conventional-changelog/-/cz-conventional-changelog-3.3.0.tgz", - "integrity": "sha512-U466fIzU5U22eES5lTNiNbZ+d8dfcHcssH4o7QsdWaCcRs/feIPCxKYSWkYBNs5mny7MvEfwpTLWjvbm94hecw==", - "dev": true, - "requires": { - "@commitlint/load": ">6.1.1", - "chalk": "^2.4.1", - "commitizen": "^4.0.3", - "conventional-commit-types": "^3.0.0", - "lodash.map": "^4.5.1", - "longest": "^2.0.1", - "word-wrap": "^1.0.3" - } - }, "cz-customizable": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/cz-customizable/-/cz-customizable-7.0.0.tgz", @@ -37672,18 +38112,6 @@ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" }, - "detect-file": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", - "integrity": "sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==", - "dev": true - }, - "detect-indent": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", - "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", - "dev": true - }, "detect-newline": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", @@ -37980,9 +38408,9 @@ } }, "engine.io": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.2.0.tgz", - "integrity": "sha512-4KzwW3F3bk+KlzSOY57fj/Jx6LyRQ1nbcyIadehl+AnXjKT7gDO0ORdRi/84ixvMKTym6ZKuxvbzN62HDDU1Lg==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.2.1.tgz", + "integrity": "sha512-ECceEFcAaNRybd3lsGQKas3ZlMVjN3cyWwMP25D2i0zWfyiytVbTpRPa34qrr+FHddtpBVOmq4H/DCv1O0lZRA==", "dev": true, "requires": { "@types/cookie": "^0.4.1", @@ -38127,6 +38555,30 @@ "unbox-primitive": "^1.0.2" } }, + "es-get-iterator": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.2.tgz", + "integrity": "sha512-+DTO8GYwbMCwbywjimwZMHp8AuYXOS2JZFWoi2AlPOS3ebnII9w/NLpNZtA7A0YLaVDw+O7KFCeoIV7OPvM7hQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.0", + "has-symbols": "^1.0.1", + "is-arguments": "^1.1.0", + "is-map": "^2.0.2", + "is-set": "^2.0.2", + "is-string": "^1.0.5", + "isarray": "^2.0.5" + }, + "dependencies": { + "isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + } + } + }, "es-module-lexer": { "version": "0.9.3", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", @@ -38481,15 +38933,15 @@ } }, "eslint": { - "version": "8.24.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.24.0.tgz", - "integrity": "sha512-dWFaPhGhTAiPcCgm3f6LI2MBWbogMnTJzFBbhXVRQDJPkr9pGZvVjlVfXd+vyDcWPA2Ic9L2AXPIQM0+vk/cSQ==", + "version": "8.29.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.29.0.tgz", + "integrity": "sha512-isQ4EEiyUjZFbEKvEGJKKGBwXtvXX+zJbkVKCgTuB9t/+jUBcy8avhkEwWJecI15BkRkOYmvIM5ynbhRjEkoeg==", "dev": true, "requires": { - "@eslint/eslintrc": "^1.3.2", - "@humanwhocodes/config-array": "^0.10.5", - "@humanwhocodes/gitignore-to-minimatch": "^1.0.2", + "@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", @@ -38505,14 +38957,14 @@ "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", "find-up": "^5.0.0", - "glob-parent": "^6.0.1", + "glob-parent": "^6.0.2", "globals": "^13.15.0", - "globby": "^11.1.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", @@ -38717,26 +39169,26 @@ "version": "file:eslint-rules" }, "eslint-plugin-jest": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-27.1.1.tgz", - "integrity": "sha512-vuSuXGKHHi/UAffIM46QKm4g0tQP+6n52nRxUpMq6x6x9rhnv5WM7ktSu3h9cTnXE4b0Y0ODQTgRlCm9rdRLvg==", + "version": "27.1.6", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-27.1.6.tgz", + "integrity": "sha512-XA7RFLSrlQF9IGtAmhddkUkBuICCTuryfOTfCSWcZHiHb69OilIH05oozH2XA6CEOtztnOd0vgXyvxZodkxGjg==", "dev": true, "requires": { "@typescript-eslint/utils": "^5.10.0" } }, "eslint-plugin-jsdoc": { - "version": "39.3.6", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-39.3.6.tgz", - "integrity": "sha512-R6dZ4t83qPdMhIOGr7g2QII2pwCjYyKP+z0tPOfO1bbAbQyKC20Y2Rd6z1te86Lq3T7uM8bNo+VD9YFpE8HU/g==", + "version": "39.6.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-39.6.4.tgz", + "integrity": "sha512-fskvdLCfwmPjHb6e+xNGDtGgbF8X7cDwMtVLAP2WwSf9Htrx68OAx31BESBM1FAwsN2HTQyYQq7m4aW4Q4Nlag==", "dev": true, "requires": { - "@es-joy/jsdoccomment": "~0.31.0", + "@es-joy/jsdoccomment": "~0.36.1", "comment-parser": "1.3.1", "debug": "^4.3.4", "escape-string-regexp": "^4.0.0", "esquery": "^1.4.0", - "semver": "^7.3.7", + "semver": "^7.3.8", "spdx-expression-parse": "^3.0.1" }, "dependencies": { @@ -38745,6 +39197,24 @@ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "semver": { + "version": "7.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" + } } } }, @@ -38788,24 +39258,26 @@ } }, "eslint-plugin-unicorn": { - "version": "44.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-44.0.1.tgz", - "integrity": "sha512-ly6Ye9OfgYBCw/FfsdycCzAztcRd+pOA0F6xZwtUsUkgOBjtNR0684xC7u+0RmE3SKr3y7z8MaIWunw36tbZdg==", + "version": "45.0.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-45.0.2.tgz", + "integrity": "sha512-Y0WUDXRyGDMcKLiwgL3zSMpHrXI00xmdyixEGIg90gHnj0PcHY4moNv3Ppje/kDivdAy5vUeUr7z211ImPv2gw==", "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.19.1", - "ci-info": "^3.4.0", + "@eslint-community/eslint-utils": "^4.1.2", + "ci-info": "^3.6.1", "clean-regexp": "^1.0.0", - "eslint-utils": "^3.0.0", "esquery": "^1.4.0", "indent-string": "^4.0.0", "is-builtin-module": "^3.2.0", + "jsesc": "^3.0.2", "lodash": "^4.17.21", "pluralize": "^8.0.0", "read-pkg-up": "^7.0.1", "regexp-tree": "^0.1.24", + "regjsparser": "^0.9.1", "safe-regex": "^2.1.1", - "semver": "^7.3.7", + "semver": "^7.3.8", "strip-indent": "^3.0.0" }, "dependencies": { @@ -38825,6 +39297,12 @@ "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", "dev": true }, + "jsesc": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", + "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", + "dev": true + }, "locate-path": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", @@ -38834,6 +39312,15 @@ "p-locate": "^4.1.0" } }, + "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" + } + }, "normalize-package-data": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", @@ -38903,6 +39390,15 @@ "type-fest": "^0.8.1" } }, + "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" + } + }, "type-fest": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", @@ -38960,9 +39456,9 @@ "dev": true }, "espree": { - "version": "9.4.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.0.tgz", - "integrity": "sha512-DQmnRpLj7f6TgN/NYb0MTzJXL+vJF9h3pHy4JhCIs3zwcgez8xmGg3sXHcEO97BrmO2OSvCwMdfdlyl+E9KjOw==", + "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", @@ -39103,15 +39599,6 @@ "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", "dev": true }, - "expand-tilde": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", - "integrity": "sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==", - "dev": true, - "requires": { - "homedir-polyfill": "^1.0.1" - } - }, "expect": { "version": "28.1.3", "resolved": "https://registry.npmjs.org/expect/-/expect-28.1.3.tgz", @@ -39126,13 +39613,13 @@ } }, "express": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.1.tgz", - "integrity": "sha512-zZBcOX9TfehHQhtupq57OF8lFZ3UZi08Y97dwFCkD8p9d/d2Y3M+ykKcwaMDEL+4qyUolgBDX6AblpR3fL212Q==", + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", "requires": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.0", + "body-parser": "1.20.1", "content-disposition": "0.5.4", "content-type": "~1.0.4", "cookie": "0.5.0", @@ -39151,7 +39638,7 @@ "parseurl": "~1.3.3", "path-to-regexp": "0.1.7", "proxy-addr": "~2.0.7", - "qs": "6.10.3", + "qs": "6.11.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", "send": "0.18.0", @@ -39191,9 +39678,9 @@ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, "qs": { - "version": "6.10.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", - "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", "requires": { "side-channel": "^1.0.4" } @@ -39406,9 +39893,9 @@ }, "dependencies": { "loader-utils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz", - "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", "requires": { "big.js": "^5.2.2", "emojis-list": "^3.0.0", @@ -39498,22 +39985,6 @@ "user-home": "^2.0.0" } }, - "find-node-modules": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/find-node-modules/-/find-node-modules-2.1.3.tgz", - "integrity": "sha512-UC2I2+nx1ZuOBclWVNdcnbDR5dlrOdVb7xNjmT/lHE+LsgztWks3dG7boJ37yTS/venXw84B/mAW9uHVoC5QRg==", - "dev": true, - "requires": { - "findup-sync": "^4.0.0", - "merge": "^2.1.1" - } - }, - "find-root": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", - "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", - "dev": true - }, "find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -39530,18 +40001,6 @@ "integrity": "sha512-lg/Moejf4qXovVutL0Lz4IsaPoNYMuxt4PA0nGqFxnJ1CTTGGlEO2wKgoDpwknhvZ8k4Q2F+eesgkLbG2Mxfog==", "dev": true }, - "findup-sync": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-4.0.0.tgz", - "integrity": "sha512-6jvvn/12IC4quLBL1KNokxC7wWTvYncaVUYSoxWw7YykPLuRrnv4qdHcSOywOI5RpkOVGeQRtWM8/q+G6W6qfQ==", - "dev": true, - "requires": { - "detect-file": "^1.0.0", - "is-glob": "^4.0.0", - "micromatch": "^4.0.2", - "resolve-dir": "^1.0.1" - } - }, "flat-cache": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", @@ -39564,6 +40023,15 @@ "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", @@ -39709,9 +40177,9 @@ } }, "gensequence": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/gensequence/-/gensequence-4.0.2.tgz", - "integrity": "sha512-mQiFskYFPFDSUpBJ/n3ebAV2Ufu6DZGvUPXzyWYzFfJr6/DyOOZVnjx6VTWE4y0RLvYWnc5tZq5sCjzEWhRjqQ==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/gensequence/-/gensequence-4.0.3.tgz", + "integrity": "sha512-izr+MKqJKjexkvLiPGhW96elQX8TuUR/su/xzILxjqzU1RDz1n1ZbqwDUnNFaRcq0gFR3oQfNH2JOH4Je1x/QA==", "dev": true }, "gensync": { @@ -39992,47 +40460,6 @@ } } }, - "global-modules": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", - "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", - "dev": true, - "requires": { - "global-prefix": "^1.0.1", - "is-windows": "^1.0.1", - "resolve-dir": "^1.0.0" - } - }, - "global-prefix": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", - "integrity": "sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==", - "dev": true, - "requires": { - "expand-tilde": "^2.0.2", - "homedir-polyfill": "^1.0.1", - "ini": "^1.3.4", - "is-windows": "^1.0.1", - "which": "^1.2.14" - }, - "dependencies": { - "ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true - }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - } - } - }, "globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", @@ -40058,6 +40485,15 @@ "integrity": "sha512-xYfnw62CKG8nLkZBfWbhWwDw02CHty86jfPcc2cr3ZfeuK9ysoVPPEUxf21bAD/rWAgk52SuBrLJlefNy8mvFg==", "dev": true }, + "gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.3" + } + }, "graceful-fs": { "version": "4.2.10", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", @@ -40200,15 +40636,6 @@ "integrity": "sha512-7kIufnBqdsBGcSZLPJwqHT3yhk1QTsSlFsVD3kx5ixH/AlgBs9yM1q6DPhXZ8f8gtdqgh7N7/5btRLpQsS2gHw==", "dev": true }, - "homedir-polyfill": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", - "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", - "dev": true, - "requires": { - "parse-passwd": "^1.0.0" - } - }, "hosted-git-info": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", @@ -40412,9 +40839,9 @@ } }, "husky": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/husky/-/husky-8.0.1.tgz", - "integrity": "sha512-xs7/chUH/CKdOCs7Zy0Aev9e/dKOMZf3K1Az1nar3tzlv0jfqnYtu235bstsWTmXOR0EfINrPa97yy4Lz6RiKw==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/husky/-/husky-8.0.2.tgz", + "integrity": "sha512-Tkv80jtvbnkK3mYWxPZePGFpQ/tT3HNSs/sasF9P2YfkMezDl3ON37YN6jUUI4eTg5LcyVynlb6r4eyvOmspvg==", "dev": true }, "i18next": { @@ -40778,6 +41205,12 @@ "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", "dev": true }, + "is-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", + "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", + "dev": true + }, "is-negative-zero": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", @@ -40813,6 +41246,12 @@ "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", "dev": true }, + "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-obj": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", @@ -40846,6 +41285,12 @@ "has-tostringtag": "^1.0.0" } }, + "is-set": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", + "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", + "dev": true + }, "is-shared-array-buffer": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", @@ -40888,6 +41333,19 @@ "text-extensions": "^1.0.0" } }, + "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-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", @@ -40899,10 +41357,10 @@ "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==" }, - "is-utf8": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", - "integrity": "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==", + "is-weakmap": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", + "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", "dev": true }, "is-weakref": { @@ -40914,18 +41372,22 @@ "call-bind": "^1.0.2" } }, + "is-weakset": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", + "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + } + }, "is-what": { "version": "3.14.1", "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==", "dev": true }, - "is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true - }, "is-wsl": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", @@ -43050,9 +43512,9 @@ }, "dependencies": { "parse5": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.1.tgz", - "integrity": "sha512-kwpuwzB+px5WUg9pyK0IcK/shltJN5/OVhQagxhCQNtT9Y9QRZqNY2e1cmbu/paRh5LMnz/oVTVLBpjFmMZhSg==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", "requires": { "entities": "^4.4.0" } @@ -43223,9 +43685,9 @@ "dev": true }, "known-css-properties": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.25.0.tgz", - "integrity": "sha512-b0/9J1O9Jcyik1GC6KC42hJ41jKwdO/Mq8Mdo5sYN+IuRTXs2YFHZC3kZSx6ueusqa95x3wLYe/ytKjbAfGixA==", + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.26.0.tgz", + "integrity": "sha512-5FZRzrZzNTBruuurWpvZnvP9pum+fe0HcK8z/ooo+U+Hmp4vtbyp1/QDsqmufirXy4egGzbaH/y2uCZf+6W5Kg==", "dev": true }, "lazy": { @@ -43321,9 +43783,9 @@ } }, "lilconfig": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.5.tgz", - "integrity": "sha512-xaYmXZtTHPAw5m+xLN8ab9C+3a8YmV3asNSPOATITbtwrfbwaLJj8h66H1WMIpALCkqsIzK3h7oQ+PdX+LQ9Eg==", + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.6.tgz", + "integrity": "sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg==", "dev": true }, "limiter": { @@ -43339,24 +43801,24 @@ "dev": true }, "lint-staged": { - "version": "13.0.3", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-13.0.3.tgz", - "integrity": "sha512-9hmrwSCFroTSYLjflGI8Uk+GWAwMB4OlpU4bMJEAT5d/llQwtYKoim4bLOyLCuWFAhWEupE0vkIFqtw/WIsPug==", + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-13.1.0.tgz", + "integrity": "sha512-pn/sR8IrcF/T0vpWLilih8jmVouMlxqXxKuAojmbiGX5n/gDnz+abdPptlj0vYnbfE0SQNl3CY/HwtM0+yfOVQ==", "dev": true, "requires": { "cli-truncate": "^3.1.0", - "colorette": "^2.0.17", - "commander": "^9.3.0", + "colorette": "^2.0.19", + "commander": "^9.4.1", "debug": "^4.3.4", "execa": "^6.1.0", - "lilconfig": "2.0.5", - "listr2": "^4.0.5", + "lilconfig": "2.0.6", + "listr2": "^5.0.5", "micromatch": "^4.0.5", "normalize-path": "^3.0.0", "object-inspect": "^1.12.2", "pidtree": "^0.6.0", "string-argv": "^0.3.1", - "yaml": "^2.1.1" + "yaml": "^2.1.3" }, "dependencies": { "execa": { @@ -43433,17 +43895,17 @@ } }, "listr2": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-4.0.5.tgz", - "integrity": "sha512-juGHV1doQdpNT3GSTs9IUN43QJb7KHdF9uqg7Vufs/tG9VTzpFphqF4pm/ICdAABGQxsyNn9CiYA3StkI6jpwA==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-5.0.6.tgz", + "integrity": "sha512-u60KxKBy1BR2uLJNTWNptzWQ1ob/gjMzIJPZffAENzpZqbMZ/5PrXXOomDcevIS/+IB7s1mmCEtSlT2qHWMqag==", "dev": true, "requires": { "cli-truncate": "^2.1.0", - "colorette": "^2.0.16", + "colorette": "^2.0.19", "log-update": "^4.0.0", "p-map": "^4.0.0", "rfdc": "^1.3.0", - "rxjs": "^7.5.5", + "rxjs": "^7.5.7", "through": "^2.3.8", "wrap-ansi": "^7.0.0" }, @@ -43544,9 +44006,9 @@ "dev": true }, "loader-utils": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.0.tgz", - "integrity": "sha512-HVl9ZqccQihZ7JM85dco1MvO9G+ONvxoGa9rkhzFsneGLKSUg1gJf9bWzhRhcvm2qChhWpebQhP44qxjKIUCaQ==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.1.tgz", + "integrity": "sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw==", "dev": true }, "localtunnel": { @@ -43607,10 +44069,10 @@ "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" }, - "lodash.clonedeep": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==", + "lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", "dev": true }, "lodash.debounce": { @@ -43625,16 +44087,28 @@ "integrity": "sha512-7FGG40uhC8Mm633uKW1r58aElFlBlxCrg9JfSi3P6aYiWmfiWF0PgMd86ZUsxE5GwWPdHoS2+48bwTh2VPkIQA==", "dev": true }, + "lodash.isfunction": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz", + "integrity": "sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw==", + "dev": true + }, "lodash.ismatch": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz", "integrity": "sha512-fPMfXjGQEV9Xsq/8MTSgUf255gawYRbjwMyDbcvDhXgV7enSZA0hynz6vMPnpAb5iONEzBHBPsT+0zes5Z301g==", "dev": true }, - "lodash.map": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.map/-/lodash.map-4.6.0.tgz", - "integrity": "sha512-worNHGKLDetmcEYDvh2stPCrrQRkP20E4l0iIS7F8EvzMqBBi7ltvFN5m1HvTf1P7Jk1txKhvFcmYsCr8O2F1Q==", + "lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "dev": true + }, + "lodash.kebabcase": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz", + "integrity": "sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==", "dev": true }, "lodash.memoize": { @@ -43649,12 +44123,42 @@ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, + "lodash.mergewith": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz", + "integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==", + "dev": true + }, + "lodash.snakecase": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz", + "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==", + "dev": true + }, + "lodash.startcase": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.startcase/-/lodash.startcase-4.4.0.tgz", + "integrity": "sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==", + "dev": true + }, "lodash.truncate": { "version": "4.4.2", "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", "dev": true }, + "lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", + "dev": true + }, + "lodash.upperfirst": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/lodash.upperfirst/-/lodash.upperfirst-4.3.1.tgz", + "integrity": "sha512-sReKOYJIJf74dhJONhU4e0/shzi1trVbSWDOhKYE5XV2O+H7Sb2Dihwuc7xWxVl+DgFPyTqIN3zMfT9cq5iWDg==", + "dev": true + }, "log-driver": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/log-driver/-/log-driver-1.2.7.tgz", @@ -43793,12 +44297,6 @@ "integrity": "sha512-WpG9CcFAOjz/FtNht+QJeGpvVl/cdR6P0z6OcXSkr8wFJOsV2GRj2j10JLfjuA4aYkcKCNIEqRGCyTife9R8/g==", "dev": true }, - "longest": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/longest/-/longest-2.0.1.tgz", - "integrity": "sha512-Ajzxb8CM6WAnFjgiloPsI3bF+WCxcvhdIG3KNA2KN962+tdBsHcuQ4k4qX/EcS/2CRkcc0iAkR956Nib6aXU/Q==", - "dev": true - }, "lru-cache": { "version": "7.14.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.14.0.tgz", @@ -43920,9 +44418,9 @@ "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==" }, "memfs": { - "version": "3.4.7", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.4.7.tgz", - "integrity": "sha512-ygaiUSNalBX85388uskeCyhSAoOSgzBbtVCr9jA2RROssFL9Q19/ZXFqS+2Th2sr1ewNIWgFdLzLC3Yl1Zv+lw==", + "version": "3.4.12", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.4.12.tgz", + "integrity": "sha512-BcjuQn6vfqP+k100e0E9m61Hyqa//Brp+I3f0OBmN0ATHlFA8vx3Lt8z57R3u2bPqe3WGDBC+nF72fTH7isyEw==", "dev": true, "requires": { "fs-monkey": "^1.0.3" @@ -44077,12 +44575,6 @@ } } }, - "merge": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/merge/-/merge-2.1.1.tgz", - "integrity": "sha512-jz+Cfrg9GWOZbQAnDQ4hlVnQky+341Yk5ru8bZSe6sIDTCIg8n9i/u7hSQGSVOF3C7lH6mGtqjkiT9G4wFLL0w==", - "dev": true - }, "merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", @@ -44435,10 +44927,16 @@ "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 + }, "needle": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/needle/-/needle-3.1.0.tgz", - "integrity": "sha512-gCE9weDhjVGCRqS8dwDR/D3GTAeyXLXuqp7I8EzH6DllZGXSUyxuqqLh+YX9rMAWaaTFyVAg6rHGL25dqvczKw==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/needle/-/needle-3.2.0.tgz", + "integrity": "sha512-oUvzXnyLiVyVGoianLijF9O/RecZUf7TkBfimjGrLM4eQhXyeJwM6GeAWccwfQ9aa4gMCZKqhAOuLaMIcQxajQ==", "dev": true, "optional": true, "requires": { @@ -44493,9 +44991,9 @@ "dev": true }, "ng-mocks": { - "version": "14.2.3", - "resolved": "https://registry.npmjs.org/ng-mocks/-/ng-mocks-14.2.3.tgz", - "integrity": "sha512-WNNOtz8P05KJCvTGYUjqPJ/d1DdkVL1xtQFgUAoVIpa/SXxjCjq3LGGti9ZK4MWGrEZX6e1wUbAV+3mrywd93Q==", + "version": "14.5.0", + "resolved": "https://registry.npmjs.org/ng-mocks/-/ng-mocks-14.5.0.tgz", + "integrity": "sha512-bLevjrTxNmORUnEohOwy31NuvQxs62xoljWJTWjH/qaFdX9fuzg7nt+zcxUfqERFZumipvGraTdi+/J2PBUisg==", "dev": true, "requires": {} }, @@ -44569,17 +45067,17 @@ } }, "ngx-infinite-scroll": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/ngx-infinite-scroll/-/ngx-infinite-scroll-14.0.0.tgz", - "integrity": "sha512-YZB5PBPXSERNtCGQRZTVflbgkh5asp01NPfC8KPItemmQik1Ip8ZCCbcyHA77TDTdilmaiu8TbguA3geg/LMWw==", + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/ngx-infinite-scroll/-/ngx-infinite-scroll-14.0.1.tgz", + "integrity": "sha512-PlGL29d2PxNJTn6qdXs4Es0HlJTZ/ZqOVvFWECWm7mK2fN/q+q62s0iUQ7xRf76NuqoNovXvrjZ1zwLFT6c0Wg==", "requires": { "tslib": "^2.3.0" } }, "ngx-toastr": { - "version": "15.2.0", - "resolved": "https://registry.npmjs.org/ngx-toastr/-/ngx-toastr-15.2.0.tgz", - "integrity": "sha512-IrDWKYql3O5yPhmaWu78QilB/9j+J78tyfS/mMoX/yCdVc0zmLsv73OHvckG9XgEhVuQjuxz0yIGVaWff91m4A==", + "version": "15.2.2", + "resolved": "https://registry.npmjs.org/ngx-toastr/-/ngx-toastr-15.2.2.tgz", + "integrity": "sha512-srdxKKf1+B/7z11M4Ty7bnkme2xjdUcnP/t7mNG/2gRM1h0P/7Lbz71FIQHuKZOCdnGdXjsT6OXU0dRvNyrkyg==", "requires": { "tslib": "^2.3.0" } @@ -45386,12 +45884,6 @@ "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", "dev": true }, - "parse-passwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", - "integrity": "sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==", - "dev": true - }, "parse5": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", @@ -45653,9 +46145,9 @@ "dev": true }, "pm2": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/pm2/-/pm2-5.2.0.tgz", - "integrity": "sha512-PO5hMVhQ85cTszFM++6v07Me9hPJMkFbHjkFigtMMk+La8ty2wCi2dlBTeZYJDhPUSjK8Ccltpq2buNRcyMOTw==", + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/pm2/-/pm2-5.2.2.tgz", + "integrity": "sha512-mASxgh/MZhtVze/wijGf+tE6JKdA3lEq64FOfXVhhArkuk9Qxl4ePw9XgFJaArOXnU3bde+KbeAJHYxppVvYBQ==", "dev": true, "requires": { "@pm2/agent": "~2.0.0", @@ -45665,11 +46157,11 @@ "async": "~3.2.0", "blessed": "0.1.81", "chalk": "3.0.0", - "chokidar": "^3.5.1", + "chokidar": "^3.5.3", "cli-tableau": "^2.0.0", "commander": "2.15.1", "croner": "~4.1.92", - "dayjs": "~1.8.25", + "dayjs": "~1.11.5", "debug": "^4.3.1", "enquirer": "2.3.6", "eventemitter2": "5.0.1", @@ -45684,7 +46176,7 @@ "pm2-sysmonit": "^1.2.8", "promptly": "^2", "semver": "^7.2", - "source-map-support": "0.5.19", + "source-map-support": "0.5.21", "sprintf-js": "1.1.2", "vizion": "~2.2.1", "yamljs": "0.3.0" @@ -45730,6 +46222,12 @@ "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", "dev": true }, + "dayjs": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.6.tgz", + "integrity": "sha512-zZbY5giJAinCG+7AGaw0wIhNZ6J8AhWuSXKvuc1KAyMiRsvGQWqh4L+MomvhdAYjN+lqvVCMq1I41e3YHvXkyQ==", + "dev": true + }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -45758,22 +46256,6 @@ } } }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, - "source-map-support": { - "version": "0.5.19", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", - "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -45964,9 +46446,9 @@ } }, "postcss-custom-properties": { - "version": "12.1.9", - "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-12.1.9.tgz", - "integrity": "sha512-/E7PRvK8DAVljBbeWrcEQJPG72jaImxF3vvCNFwv9cC8CzigVoNIpeyfnJzphnN3Fd8/auBf5wvkw6W9MfmTyg==", + "version": "12.1.11", + "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-12.1.11.tgz", + "integrity": "sha512-0IDJYhgU8xDv1KY6+VgUwuQkVtmYzRwu+dMjnmdMafXYv86SWqfxkc7qdDvWS38vsjaEtv8e0vGOUQrAiMBLpQ==", "dev": true, "requires": { "postcss-value-parser": "^4.2.0" @@ -46289,9 +46771,9 @@ } }, "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==", + "version": "6.0.11", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.11.tgz", + "integrity": "sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g==", "dev": true, "requires": { "cssesc": "^3.0.0", @@ -47019,16 +47501,6 @@ "resolve-from": "^5.0.0" } }, - "resolve-dir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", - "integrity": "sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==", - "dev": true, - "requires": { - "expand-tilde": "^2.0.0", - "global-modules": "^1.0.0" - } - }, "resolve-from": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", @@ -47058,9 +47530,9 @@ }, "dependencies": { "loader-utils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz", - "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", "dev": true, "requires": { "big.js": "^5.2.2", @@ -48450,15 +48922,15 @@ "dev": true }, "stylelint": { - "version": "14.13.0", - "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-14.13.0.tgz", - "integrity": "sha512-NJSAdloiAB/jgVJKxMR90mWlctvmeBFGFVUvyKngi9+j/qPSJ5ZB+u8jOmGbLTnS7OHrII9NFGehPRyar8U5vg==", + "version": "14.16.0", + "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-14.16.0.tgz", + "integrity": "sha512-X6uTi9DcxjzLV8ZUAjit1vsRtSwcls0nl07c9rqOPzvpA8IvTX/xWEkBRowS0ffevRrqkHa/ThDEu86u73FQDg==", "dev": true, "requires": { "@csstools/selector-specificity": "^2.0.2", "balanced-match": "^2.0.0", "colord": "^2.9.3", - "cosmiconfig": "^7.0.1", + "cosmiconfig": "^7.1.0", "css-functions-list": "^3.1.0", "debug": "^4.3.4", "fast-glob": "^3.2.12", @@ -48468,21 +48940,21 @@ "globby": "^11.1.0", "globjoin": "^0.1.4", "html-tags": "^3.2.0", - "ignore": "^5.2.0", + "ignore": "^5.2.1", "import-lazy": "^4.0.0", "imurmurhash": "^0.1.4", "is-plain-object": "^5.0.0", - "known-css-properties": "^0.25.0", + "known-css-properties": "^0.26.0", "mathml-tag-names": "^2.1.3", "meow": "^9.0.0", "micromatch": "^4.0.5", "normalize-path": "^3.0.0", "picocolors": "^1.0.0", - "postcss": "^8.4.16", + "postcss": "^8.4.19", "postcss-media-query-parser": "^0.2.3", "postcss-resolve-nested-selector": "^0.1.1", "postcss-safe-parser": "^6.0.0", - "postcss-selector-parser": "^6.0.10", + "postcss-selector-parser": "^6.0.11", "postcss-value-parser": "^4.2.0", "resolve-from": "^5.0.0", "string-width": "^4.2.3", @@ -48490,7 +48962,7 @@ "style-search": "^0.1.0", "supports-hyperlinks": "^2.3.0", "svg-tags": "^1.0.0", - "table": "^6.8.0", + "table": "^6.8.1", "v8-compile-cache": "^2.3.0", "write-file-atomic": "^4.0.2" }, @@ -48543,6 +49015,12 @@ "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", "dev": true }, + "ignore": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.1.tgz", + "integrity": "sha512-d2qQLzTJ9WxQftPAuEQpSPmKqzxePjzVbpAVv62AQ64NTL+wR4JkrVqR/LqFsFEUsHDAiId52mJteHDFuDkElA==", + "dev": true + }, "ini": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", @@ -48596,6 +49074,17 @@ "p-limit": "^2.2.0" } }, + "postcss": { + "version": "8.4.20", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.20.tgz", + "integrity": "sha512-6Q04AXR1212bXr5fh03u8aAwbLxAQNGQ/Q1LNa0VfOI06ZAlhPHtQvE4OIdpj4kLThXilalPnmDSOD65DcHt+g==", + "dev": true, + "requires": { + "nanoid": "^3.3.4", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + } + }, "read-pkg": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", @@ -48681,9 +49170,9 @@ } }, "stylelint-config-prettier": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/stylelint-config-prettier/-/stylelint-config-prettier-9.0.3.tgz", - "integrity": "sha512-5n9gUDp/n5tTMCq1GLqSpA30w2sqWITSSEiAWQlpxkKGAUbjcemQ0nbkRvRUa0B1LgD3+hCvdL7B1eTxy1QHJg==", + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/stylelint-config-prettier/-/stylelint-config-prettier-9.0.4.tgz", + "integrity": "sha512-38nIGTGpFOiK5LjJ8Ma1yUgpKENxoKSOhbDNSemY7Ep0VsJoXIW9Iq/2hSt699oB9tReynfWicTAoIHiq8Rvbg==", "dev": true, "requires": {} }, @@ -48697,39 +49186,30 @@ } }, "stylelint-config-recommended": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-8.0.0.tgz", - "integrity": "sha512-IK6dWvE000+xBv9jbnHOnBq01gt6HGVB2ZTsot+QsMpe82doDQ9hvplxfv4YnpEuUwVGGd9y6nbaAnhrjcxhZQ==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-9.0.0.tgz", + "integrity": "sha512-9YQSrJq4NvvRuTbzDsWX3rrFOzOlYBmZP+o513BJN/yfEmGSr0AxdvrWs0P/ilSpVV/wisamAHu5XSk8Rcf4CQ==", "dev": true, "requires": {} }, "stylelint-config-recommended-scss": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/stylelint-config-recommended-scss/-/stylelint-config-recommended-scss-7.0.0.tgz", - "integrity": "sha512-rGz1J4rMAyJkvoJW4hZasuQBB7y9KIrShb20l9DVEKKZSEi1HAy0vuNlR8HyCKy/jveb/BdaQFcoiYnmx4HoiA==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/stylelint-config-recommended-scss/-/stylelint-config-recommended-scss-8.0.0.tgz", + "integrity": "sha512-BxjxEzRaZoQb7Iinc3p92GS6zRdRAkIuEu2ZFLTxJK2e1AIcCb5B5MXY9KOXdGTnYFZ+KKx6R4Fv9zU6CtMYPQ==", "dev": true, "requires": { "postcss-scss": "^4.0.2", - "stylelint-config-recommended": "^8.0.0", + "stylelint-config-recommended": "^9.0.0", "stylelint-scss": "^4.0.0" } }, "stylelint-config-standard": { - "version": "28.0.0", - "resolved": "https://registry.npmjs.org/stylelint-config-standard/-/stylelint-config-standard-28.0.0.tgz", - "integrity": "sha512-q/StuowDdDmFCravzGHAwgS9pjX0bdOQUEBBDIkIWsQuYGgYz/xsO8CM6eepmIQ1fc5bKdDVimlJZ6MoOUcJ5Q==", + "version": "29.0.0", + "resolved": "https://registry.npmjs.org/stylelint-config-standard/-/stylelint-config-standard-29.0.0.tgz", + "integrity": "sha512-uy8tZLbfq6ZrXy4JKu3W+7lYLgRQBxYTUUB88vPgQ+ZzAxdrvcaSUW9hOMNLYBnwH+9Kkj19M2DHdZ4gKwI7tg==", "dev": true, "requires": { "stylelint-config-recommended": "^9.0.0" - }, - "dependencies": { - "stylelint-config-recommended": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-9.0.0.tgz", - "integrity": "sha512-9YQSrJq4NvvRuTbzDsWX3rrFOzOlYBmZP+o513BJN/yfEmGSr0AxdvrWs0P/ilSpVV/wisamAHu5XSk8Rcf4CQ==", - "dev": true, - "requires": {} - } } }, "stylelint-order": { @@ -48871,9 +49351,9 @@ "dev": true }, "swiper": { - "version": "8.4.2", - "resolved": "https://registry.npmjs.org/swiper/-/swiper-8.4.2.tgz", - "integrity": "sha512-nMD/RHVYxJxrLqjWQX2n0B94ANwpnuUv/3PUDT8Aaf+mSteFvZGFng4ypAYq70zW4svryyV+8TRlbRZ+6cgv9A==", + "version": "8.4.5", + "resolved": "https://registry.npmjs.org/swiper/-/swiper-8.4.5.tgz", + "integrity": "sha512-zveyEFBBv4q1sVkbJHnuH4xCtarKieavJ4SxP0QEHvdpPLJRuD7j/Xg38IVVLbp7Db6qrPsLUePvxohYx39Agw==", "requires": { "dom7": "^4.0.4", "ssr-window": "^4.0.2" @@ -48898,9 +49378,9 @@ "optional": true }, "table": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/table/-/table-6.8.0.tgz", - "integrity": "sha512-s/fitrbVeEyHKFa7mFdkuQMWlH1Wgw/yEXMt5xACT4ZpzWFluehAxRtUUQKPuWhaLAWhFcVx6w3oC8VKaUfPGA==", + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/table/-/table-6.8.1.tgz", + "integrity": "sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==", "dev": true, "requires": { "ajv": "^8.0.1", @@ -49524,9 +50004,9 @@ } }, "tslib": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", + "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==" }, "tsutils": { "version": "3.21.0", @@ -49914,9 +50394,9 @@ } }, "vscode-languageserver-textdocument": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.7.tgz", - "integrity": "sha512-bFJH7UQxlXT8kKeyiyu41r22jCZXG8kuuVVA33OEJn1diWOZK5n8zBSPZFHVBOu8kXZ6h0LIRhf5UnCo61J4Hg==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.8.tgz", + "integrity": "sha512-1bonkGqQs5/fxGT5UchTgjGVnfysL0O8v1AYMBjqTbWQTFn721zaPGDYFkOKtfDgFiSgXM3KwaG3FMGfW4Ed9Q==", "dev": true }, "vscode-uri": { @@ -50250,6 +50730,32 @@ "is-symbol": "^1.0.3" } }, + "which-collection": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", + "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", + "dev": true, + "requires": { + "is-map": "^2.0.1", + "is-set": "^2.0.1", + "is-weakmap": "^2.0.1", + "is-weakset": "^2.0.1" + } + }, + "which-typed-array": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", + "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", + "dev": true, + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0", + "is-typed-array": "^1.1.10" + } + }, "wide-align": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", diff --git a/package.json b/package.json index e1abffabe7..5b8219d733 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "intershop-pwa", "description": "Intershop Progressive Web App", - "version": "3.1.0", + "version": "3.2.0", "license": "Intershop Standard Software End User License Agreement Intershop 7", "keywords": [ "intershop" @@ -58,104 +58,103 @@ "xliff": "node scripts/convert-to-xliff.js" }, "dependencies": { - "@angular-devkit/schematics": "^14.2.5", - "@angular/animations": "14.2.5", - "@angular/cdk": "14.2.4", - "@angular/common": "14.2.5", - "@angular/compiler": "14.2.5", - "@angular/core": "14.2.5", - "@angular/forms": "14.2.5", - "@angular/localize": "14.2.5", - "@angular/platform-browser": "14.2.5", - "@angular/platform-browser-dynamic": "14.2.5", - "@angular/platform-server": "14.2.5", - "@angular/router": "14.2.5", - "@angular/service-worker": "14.2.5", + "@angular-devkit/schematics": "^14.2.10", + "@angular/animations": "^14.2.12", + "@angular/cdk": "^14.2.7", + "@angular/common": "^14.2.12", + "@angular/compiler": "^14.2.12", + "@angular/core": "^14.2.12", + "@angular/forms": "^14.2.12", + "@angular/localize": "^14.2.12", + "@angular/platform-browser": "^14.2.12", + "@angular/platform-browser-dynamic": "^14.2.12", + "@angular/platform-server": "^14.2.12", + "@angular/router": "^14.2.12", + "@angular/service-worker": "^14.2.12", "@fortawesome/angular-fontawesome": "^0.11.1", - "@fortawesome/fontawesome-svg-core": "^6.2.0", - "@fortawesome/free-solid-svg-icons": "^6.2.0", - "@googlemaps/js-api-loader": "^1.14.3", + "@fortawesome/fontawesome-svg-core": "^6.2.1", + "@fortawesome/free-solid-svg-icons": "^6.2.1", + "@googlemaps/js-api-loader": "^1.15.1", "@ng-bootstrap/ng-bootstrap": "^11.0.1", - "@ngrx/effects": "14.3.2", - "@ngrx/entity": "14.3.2", - "@ngrx/router-store": "14.3.2", - "@ngrx/store": "14.3.2", - "@ngrx/store-devtools": "14.3.2", - "@nguniversal/express-engine": "14.2.0", - "@ngx-formly/core": "^5.12.7", + "@ngrx/effects": "^14.3.2", + "@ngrx/entity": "^14.3.2", + "@ngrx/router-store": "^14.3.2", + "@ngrx/store": "^14.3.2", + "@ngrx/store-devtools": "^14.3.2", + "@nguniversal/express-engine": "^14.2.3", + "@ngx-formly/core": "^6.0.4", "@ngx-translate/core": "^14.0.0", - "@rx-angular/state": "1.7.0", - "@sentry/browser": "^7.14.1", - "angular-oauth2-oidc": "13.0.1", - "angulartics2": "^12.1.0", + "@rx-angular/state": "^1.7.0", + "@sentry/browser": "^7.25.0", + "angular-oauth2-oidc": "^13.0.1", + "angulartics2": "^12.2.0", "bootstrap": "^4.6.2", "date-fns": "^2.29.3", - "express": "^4.18.1", + "express": "^4.18.2", "express-http-proxy": "^1.6.3", - "express-robots-txt": "1.0.0", + "express-robots-txt": "^1.0.0", "file-replace-loader": "^1.4.0", "js-yaml": "^4.1.0", "lodash-es": "^4.17.21", "morgan": "^1.10.0", "ng-recaptcha": "^10.0.0", - "ngx-infinite-scroll": "^14.0.0", - "ngx-toastr": "^15.2.0", + "ngx-infinite-scroll": "^14.0.1", + "ngx-toastr": "^15.2.2", "rxjs": "~7.5.7", - "swiper": "^8.4.2", - "tslib": "^2.4.0", - "typeface-roboto": "1.1.13", - "typeface-roboto-condensed": "1.1.13", + "swiper": "^8.4.5", + "tslib": "^2.4.1", + "typeface-roboto": "^1.1.13", + "typeface-roboto-condensed": "^1.1.13", "zone.js": "~0.11.8" }, "devDependencies": { - "@angular-builders/custom-webpack": "14.0.1", - "@angular-devkit/build-angular": "14.2.5", - "@angular-eslint/builder": "14.1.2", - "@angular-eslint/eslint-plugin": "14.1.2", - "@angular-eslint/eslint-plugin-template": "14.1.2", - "@angular-eslint/schematics": "14.1.2", - "@angular-eslint/template-parser": "14.1.2", - "@angular/cli": "^14.2.5", - "@angular/compiler-cli": "14.2.5", - "@angular/language-service": "14.2.5", - "@commitlint/cli": "^17.1.2", + "@angular-builders/custom-webpack": "^14.1.0", + "@angular-devkit/build-angular": "^14.2.10", + "@angular-eslint/builder": "^14.4.0", + "@angular-eslint/eslint-plugin": "^14.4.0", + "@angular-eslint/eslint-plugin-template": "^14.4.0", + "@angular-eslint/schematics": "^14.4.0", + "@angular-eslint/template-parser": "^14.4.0", + "@angular/cli": "^14.2.10", + "@angular/compiler-cli": "^14.2.12", + "@angular/language-service": "^14.2.12", + "@commitlint/cli": "^17.3.0", + "@commitlint/config-conventional": "^17.3.0", "@compodoc/compodoc": "^1.1.19", "@cspell/dict-de-de": "1.1.32", "@cspell/dict-fr-fr": "^2.1.1", "@ngrx/eslint-plugin": "^14.3.2", - "@nguniversal/builders": "14.2.0", + "@nguniversal/builders": "^14.2.3", "@phenomnomnominal/tsquery": "^5.0.0", - "@schematics/angular": "14.2.5", - "@types/eslint": "^8.4.6", - "@types/estree": "1.0.0", + "@schematics/angular": "^14.2.10", + "@types/eslint": "^8.4.10", + "@types/estree": "^1.0.0", "@types/express": "^4.17.14", - "@types/google.maps": "^3.50.2", + "@types/google.maps": "^3.51.0", "@types/jest": "^28.1.8", "@types/lodash-es": "^4.17.6", - "@types/node": "^16.11.64", - "@types/uuid": "^8.3.4", + "@types/node": "^16.18.8", + "@types/uuid": "^9.0.0", "@types/webpack": "^5.28.0", - "@typescript-eslint/eslint-plugin": "^5.39.0", - "@typescript-eslint/parser": "^5.39.0", + "@typescript-eslint/eslint-plugin": "^5.46.1", + "@typescript-eslint/parser": "^5.46.1", "comment-json": "^4.2.3", - "commitizen": "^4.2.5", - "commitlint-config-cz": "^0.13.3", - "conventional-changelog-cli": "2.2.2", - "cspell": "^6.12.0", + "conventional-changelog-cli": "^2.2.2", + "cspell": "^6.17.0", "cz-customizable": "^7.0.0", - "eslint": "^8.24.0", + "eslint": "^8.29.0", "eslint-config-prettier": "^8.5.0", - "eslint-plugin-ban": "1.6.0", - "eslint-plugin-etc": "2.0.2", + "eslint-plugin-ban": "^1.6.0", + "eslint-plugin-etc": "^2.0.2", "eslint-plugin-ish-custom-rules": "file:eslint-rules", - "eslint-plugin-jest": "^27.1.1", - "eslint-plugin-jsdoc": "39.3.6", + "eslint-plugin-jest": "^27.1.6", + "eslint-plugin-jsdoc": "^39.6.4", "eslint-plugin-prettier": "^4.2.1", - "eslint-plugin-rxjs": "5.0.2", + "eslint-plugin-rxjs": "^5.0.2", "eslint-plugin-rxjs-angular": "^2.0.0", - "eslint-plugin-unicorn": "44.0.1", + "eslint-plugin-unicorn": "^45.0.2", "eslint-plugin-unused-imports": "^2.0.0", - "husky": "^8.0.1", + "husky": "^8.0.2", "intershop-schematics": "file:schematics", "jasmine-marbles": "^0.9.2", "jest": "^28.1.3", @@ -163,24 +162,24 @@ "jest-jasmine2": "^29.1.2", "jest-preset-angular": "^12.2.2", "json-schema-to-typescript": "^11.0.2", - "lint-staged": "^13.0.3", - "ng-mocks": "^14.2.3", + "lint-staged": "^13.1.0", + "ng-mocks": "^14.5.0", "npm-run-all": "^4.1.5", - "pm2": "^5.2.0", + "pm2": "^5.2.2", "prettier": "^2.7.1", "prom-client": "^14.1.0", "purgecss-webpack-plugin": "^5.0.0", "sort-json": "^2.0.1", - "stylelint": "14.13.0", - "stylelint-config-prettier": "^9.0.3", + "stylelint": "^14.16.0", + "stylelint-config-prettier": "^9.0.4", "stylelint-config-recess-order": "^3.0.0", - "stylelint-config-recommended-scss": "^7.0.0", - "stylelint-config-standard": "^28.0.0", + "stylelint-config-recommended-scss": "^8.0.0", + "stylelint-config-standard": "^29.0.0", "stylelint-prettier": "^2.0.0", "stylelint-scss": "^4.3.0", "treeify": "^1.1.0", - "ts-mockito": "2.6.1", - "ts-morph": "16.0.0", + "ts-mockito": "^2.6.1", + "ts-morph": "^16.0.0", "ts-node": "~10.9.1", "typescript": "~4.8.4", "xliff": "^6.1.0" @@ -221,8 +220,34 @@ }, "commitlint": { "extends": [ - "cz" - ] + "@commitlint/config-conventional" + ], + "rules": { + "body-leading-blank": [2, "always"], + "body-max-line-length": [2, "always", 400], + "footer-leading-blank": [2, "always"], + "footer-max-line-length": [2, "always", 400], + "header-max-length": [2, "always", 200], + "type-enum": [ + 2, + "always", + [ + "feat", + "fix", + "perf", + "docs", + "style", + "i18n", + "refactor", + "test", + "build", + "deps", + "ci", + "chore", + "temp" + ] + ] + } }, "config": { "commitizen": { diff --git a/projects/requisition-management/src/app/pages/requisition-detail/budget-bar/budget-bar.component.scss b/projects/requisition-management/src/app/pages/requisition-detail/budget-bar/budget-bar.component.scss index a7e93abcda..d24196b61c 100644 --- a/projects/requisition-management/src/app/pages/requisition-detail/budget-bar/budget-bar.component.scss +++ b/projects/requisition-management/src/app/pages/requisition-detail/budget-bar/budget-bar.component.scss @@ -34,10 +34,22 @@ .overflow-indicator { position: absolute; - z-index: 2; + z-index: 1; height: 30px; - margin-top: -9px; - background: transparent (url('/assets/img/budget-bar-indicator.png')) 100% -8px no-repeat; + margin-top: -7px; + + &::before { + // small arrow budget bar indicator + position: absolute; + top: 0; + right: -3px; + width: 0; + height: 0; + content: ''; + border-top: 6px solid #2f2f2f; + border-right: 6px solid transparent; + border-left: 6px solid transparent; + } .overflow-display { float: right; diff --git a/projects/requisition-management/src/app/pages/requisition-detail/requisition-detail-page.component.html b/projects/requisition-management/src/app/pages/requisition-detail/requisition-detail-page.component.html index 2f8c02eec0..38e70bde9b 100644 --- a/projects/requisition-management/src/app/pages/requisition-detail/requisition-detail-page.component.html +++ b/projects/requisition-management/src/app/pages/requisition-detail/requisition-detail-page.component.html @@ -46,7 +46,7 @@

{{ 'approval.detailspage.order_details.heading' | translate }}

- + diff --git a/schematics/src/helpers/lazy-components/factory.ts b/schematics/src/helpers/lazy-components/factory.ts index b46e63dd38..a7b31e01d7 100644 --- a/schematics/src/helpers/lazy-components/factory.ts +++ b/schematics/src/helpers/lazy-components/factory.ts @@ -48,10 +48,10 @@ async function deleteOldComponents() { if (process.env.CI !== 'true') { let gitAvailable = false; try { - cp.execSync('git --version'); + cp.execSync('git status'); gitAvailable = true; } catch (error) { - console.warn('Git is not installed. Skipping deletion.'); + console.warn('Git is not installed or it is not a Git repository. Skipping deletion.'); } if (gitAvailable) { diff --git a/server.ts b/server.ts index b555348c17..535258d799 100644 --- a/server.ts +++ b/server.ts @@ -16,6 +16,27 @@ import { } from './src/main.server'; import { ngExpressEngine } from '@nguniversal/express-engine'; import { getDeployURLFromEnv, setDeployUrlInFile } from './src/ssr/deploy-url'; +import * as client from 'prom-client'; + +const collectDefaultMetrics = client.collectDefaultMetrics; + +const defaultLabels = + process.env.pm_id && process.env.name ? { theme: process.env.name, pm2_id: process.env.pm_id } : undefined; + +client.register.setDefaultLabels(defaultLabels); + +const requestCounts = new client.Gauge({ + name: 'pwa_http_request_counts', + help: 'counter for requests labeled with: method, status_code, theme, base_href, path', + labelNames: ['method', 'status_code', 'base_href', 'path'], +}); + +const requestDuration = new client.Histogram({ + name: 'pwa_http_request_duration_seconds', + help: 'duration histogram of http responses labeled with: status_code, theme', + buckets: [0.1, 0.3, 0.5, 0.7, 0.9, 1.1, 1.3, 1.5, 2, 3, 4, 5, 6, 7, 8, 9, 10, 20, 30], + labelNames: ['status_code', 'base_href', 'path'], +}); const PM2 = process.env.pm_id && process.env.name ? `${process.env.pm_id} ${process.env.name}` : undefined; @@ -71,6 +92,8 @@ export function app() { const ICM_BASE_URL = process.env.ICM_BASE_URL || environment.icmBaseURL; + const SSR_HYBRID_BACKEND = process.env.SSR_HYBRID_BACKEND || ICM_BASE_URL; + if (!ICM_BASE_URL) { console.error('ICM_BASE_URL not set'); process.exit(1); @@ -256,7 +279,7 @@ export function app() { server.use('*', hybridRedirect); } - const icmProxy = proxy(ICM_BASE_URL, { + const icmProxy = proxy(SSR_HYBRID_BACKEND, { // preserve original path proxyReqPathResolver: (req: express.Request) => req.originalUrl, // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -265,6 +288,10 @@ export function app() { // https://github.com/villadora/express-http-proxy#q-how-to-ignore-self-signed-certificates- options.rejectUnauthorized = false; } + if (process.env.SSR_HYBRID) { + // Force context proto to be https otherwise ICM WA is redirecting us to https + options.headers['X-Forwarded-Proto'] = 'https'; + } return options; }, // fool ICM so it thinks it's running here @@ -407,34 +434,19 @@ export function app() { }; if (/^(on|1|true|yes)$/i.test(process.env.PROMETHEUS)) { - const axios = require('axios'); const onFinished = require('on-finished'); server.use((req, res, next) => { const start = Date.now(); onFinished(res, () => { const duration = Date.now() - start; - axios - .post('http://localhost:9113/report', { - theme: THEME, - method: req.method, - status: res.statusCode, - duration, - url: req.originalUrl, - }) - .then((reportRes: { status: number; statusText: string; data: unknown }) => { - if (reportRes.status !== 204) { - console.error( - 'ERROR unexpected return from Prometheus:', - reportRes.status, - reportRes.statusText, - reportRes.data - ); - } - }) - .catch((error: Error) => { - console.error('ERROR reporting to Prometheus:', error.message); - }); + const matched = /;baseHref=([^;?]*)/.exec(req.originalUrl); + const base_href = matched?.[1] ? `${decodeURIComponent(decodeURIComponent(matched[1]))}/` : '/'; + const cleanUrl = req.originalUrl.replace(/[;?].*/g, ''); + const path = cleanUrl.replace(base_href, ''); + + requestCounts.inc({ method: req.method, status_code: res.statusCode, base_href, path }); + requestDuration.labels({ status_code: res.statusCode, base_href, path }).observe(duration / 1000); }); next(); }); @@ -448,11 +460,27 @@ export function app() { return server; } +if (/^(on|1|true|yes)$/i.test(process.env.PROMETHEUS)) { + type MetricsMessage = { topic: string }; + process.on('message', (msg: MetricsMessage) => { + if (msg.topic === 'getMetrics') { + client.register.getMetricsAsJSON().then((data: client.metric[]) => { + process.send({ + type: 'process:msg', + data: { + body: data, + topic: 'returnMetrics', + }, + }); + }); + } + }); +} + function run() { const http = require('http'); - http.createServer(app()).listen(PORT); - + collectDefaultMetrics({ prefix: 'pwa_' }); console.log(`Node Express server listening on http://${require('os').hostname()}:${PORT}`); console.log('serving static files from', BROWSER_FOLDER); } diff --git a/src/app/app.component.html b/src/app/app.component.html index b98b45fa71..8aa2b4dbb3 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -1,13 +1,13 @@ -
+
-
+
-
+
diff --git a/src/app/core/facades/account.facade.ts b/src/app/core/facades/account.facade.ts index 10d682d961..97844f1e59 100644 --- a/src/app/core/facades/account.facade.ts +++ b/src/app/core/facades/account.facade.ts @@ -19,6 +19,7 @@ import { getAddressesLoading, getAllAddresses, loadAddresses, + updateCustomerAddress, } from 'ish-core/store/customer/addresses'; import { getUserRoles } from 'ish-core/store/customer/authorization'; import { @@ -37,6 +38,7 @@ import { import { createUser, deleteUserPaymentInstrument, + fetchAnonymousUserToken, getCustomerApprovalEmail, getLoggedInCustomer, getLoggedInUser, @@ -52,6 +54,7 @@ import { loginUser, loginUserWithToken, logoutUser, + logoutUserSuccess, requestPasswordReminder, resetPasswordReminder, updateCustomer, @@ -91,8 +94,17 @@ export class AccountFacade { this.store.dispatch(loginUserWithToken({ token })); } - logoutUser() { - this.store.dispatch(logoutUser()); + /** + * Trigger logout action + * + * @param revokeToken option to revoke api token on server side before logout success action is dispatched + */ + logoutUser(options = { revokeApiToken: true }) { + options?.revokeApiToken ? this.store.dispatch(logoutUser()) : this.store.dispatch(logoutUserSuccess()); + } + + fetchAnonymousToken() { + this.store.dispatch(fetchAnonymousUserToken()); } createUser(body: CustomerRegistrationType) { @@ -240,6 +252,10 @@ export class AccountFacade { this.store.dispatch(deleteCustomerAddress({ addressId })); } + updateCustomerAddress(address: Address) { + this.store.dispatch(updateCustomerAddress({ address })); + } + // DATA REQUESTS dataRequestLoading$ = this.store.pipe(select(getDataRequestLoading)); diff --git a/src/app/core/facades/checkout.facade.ts b/src/app/core/facades/checkout.facade.ts index ad2fb630f7..ecd0f1f9e9 100644 --- a/src/app/core/facades/checkout.facade.ts +++ b/src/app/core/facades/checkout.facade.ts @@ -1,10 +1,12 @@ import { Injectable } from '@angular/core'; import { Store, createSelector, select } from '@ngrx/store'; +import { formatISO } from 'date-fns'; import { Subject, combineLatest, merge } from 'rxjs'; import { debounceTime, distinctUntilChanged, map, sample, switchMap, take, tap } from 'rxjs/operators'; import { Address } from 'ish-core/models/address/address.model'; import { Attribute } from 'ish-core/models/attribute/attribute.model'; +import { CheckoutStepType } from 'ish-core/models/checkout/checkout-step.type'; import { LineItemUpdate } from 'ish-core/models/line-item-update/line-item-update.model'; import { PaymentInstrument } from 'ish-core/models/payment-instrument/payment-instrument.model'; import { selectRouteData } from 'ish-core/store/core/router'; @@ -39,8 +41,10 @@ import { loadBasketWithId, removePromotionCodeFromBasket, setBasketAttribute, + setBasketDesiredDeliveryDate, setBasketPayment, startCheckout, + submitOrder, updateBasketAddress, updateBasketCostCenter, updateBasketItem, @@ -74,7 +78,11 @@ export class CheckoutFacade { this.store.dispatch(startCheckout()); } - continue(targetStep: number) { + submitOrder() { + this.store.dispatch(submitOrder()); + } + + continue(targetStep: CheckoutStepType) { this.store.dispatch(continueCheckout({ targetStep })); } @@ -159,6 +167,12 @@ export class CheckoutFacade { select(getServerConfigParameter('shipping.desiredDeliveryDaysMin')) ); + setDesiredDeliveryDate(date: Date) { + this.store.dispatch( + setBasketDesiredDeliveryDate({ desiredDeliveryDate: date ? formatISO(date, { representation: 'date' }) : '' }) + ); + } + eligibleShippingMethods$() { return this.basket$.pipe( whenTruthy(), diff --git a/src/app/core/guards/login.guard.ts b/src/app/core/guards/login.guard.ts index 1e6a3d31f7..fcdd2ec073 100644 --- a/src/app/core/guards/login.guard.ts +++ b/src/app/core/guards/login.guard.ts @@ -38,6 +38,7 @@ export class LoginGuard implements CanActivate { const loginModalComponent = this.currentDialog.componentInstance as LoginModalComponent; loginModalComponent.loginMessageKey = route.queryParamMap.get('messageKey'); + loginModalComponent.detectChanges(); // dialog closed loginModalComponent.closeModal.pipe(first()).subscribe(() => { diff --git a/src/app/core/identity-provider.module.ts b/src/app/core/identity-provider.module.ts index 1686259cb4..a5f9ebe2bd 100644 --- a/src/app/core/identity-provider.module.ts +++ b/src/app/core/identity-provider.module.ts @@ -1,7 +1,7 @@ import { HttpHandler, HttpRequest } from '@angular/common/http'; -import { ModuleWithProviders, NgModule } from '@angular/core'; +import { APP_INITIALIZER, ModuleWithProviders, NgModule } from '@angular/core'; import { OAuthModule, OAuthStorage } from 'angular-oauth2-oidc'; -import { noop } from 'rxjs'; +import { BehaviorSubject, noop, of, race, timer } from 'rxjs'; import { PunchoutIdentityProviderModule } from '../extensions/punchout/identity-provider/punchout-identity-provider.module'; @@ -9,6 +9,7 @@ import { Auth0IdentityProvider } from './identity-provider/auth0.identity-provid import { ICMIdentityProvider } from './identity-provider/icm.identity-provider'; import { IDENTITY_PROVIDER_IMPLEMENTOR, IdentityProviderFactory } from './identity-provider/identity-provider.factory'; import { IdentityProviderCapabilities } from './identity-provider/identity-provider.interface'; +import { OAuthConfigurationService } from './utils/oauth-configuration/oauth-configuration.service'; /** * provider factory for storage @@ -20,9 +21,23 @@ export function storageFactory(): OAuthStorage { } } +/** + * load configuration object for OAuth Service + * OAuth Service should be configured, when app is initialized + */ +function loadOAuthConfig(configService: OAuthConfigurationService) { + return () => race(configService.loadConfig$, timer(4000)); +} + @NgModule({ imports: [OAuthModule.forRoot({ resourceServer: { sendAccessToken: false } }), PunchoutIdentityProviderModule], providers: [ + { + provide: APP_INITIALIZER, + useFactory: loadOAuthConfig, + deps: [OAuthConfigurationService], + multi: true, + }, { provide: OAuthStorage, useFactory: storageFactory }, { provide: IDENTITY_PROVIDER_IMPLEMENTOR, @@ -63,6 +78,13 @@ export class IdentityProviderModule { getType: () => 'ICM', }, }, + { + provide: OAuthConfigurationService, + useValue: { + loadConfig$: of({}), + config$: new BehaviorSubject({}), + }, + }, ], }; } diff --git a/src/app/core/identity-provider/auth0.identity-provider.spec.ts b/src/app/core/identity-provider/auth0.identity-provider.spec.ts index 54a0290c5f..ad3dbc4c5e 100644 --- a/src/app/core/identity-provider/auth0.identity-provider.spec.ts +++ b/src/app/core/identity-provider/auth0.identity-provider.spec.ts @@ -4,7 +4,7 @@ import { Router } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; import { MockStore, provideMockStore } from '@ngrx/store/testing'; import { OAuthService } from 'angular-oauth2-oidc'; -import { of } from 'rxjs'; +import { BehaviorSubject, of } from 'rxjs'; import { anything, capture, instance, mock, resetCalls, spy, verify, when } from 'ts-mockito'; import { Customer } from 'ish-core/models/customer/customer.model'; @@ -13,6 +13,7 @@ import { ApiService } from 'ish-core/services/api/api.service'; import { getSsoRegistrationCancelled, getSsoRegistrationRegistered } from 'ish-core/store/customer/sso-registration'; import { getLoggedInCustomer, getUserAuthorized, getUserLoading } from 'ish-core/store/customer/user'; import { ApiTokenService } from 'ish-core/utils/api-token/api-token.service'; +import { OAuthConfigurationService } from 'ish-core/utils/oauth-configuration/oauth-configuration.service'; import { Auth0Config, Auth0IdentityProvider } from './auth0.identity-provider'; @@ -35,6 +36,7 @@ describe('Auth0 Identity Provider', () => { const oAuthService = mock(OAuthService); const apiService = mock(ApiService); const apiTokenService = mock(ApiTokenService); + const oAuthConfigurationService = mock(OAuthConfigurationService); let auth0IdentityProvider: Auth0IdentityProvider; let store$: MockStore; let storeSpy$: MockStore; @@ -55,6 +57,7 @@ describe('Auth0 Identity Provider', () => { { provide: ApiService, useFactory: () => instance(apiService) }, { provide: ApiTokenService, useFactory: () => instance(apiTokenService) }, { provide: APP_BASE_HREF, useValue: baseHref }, + { provide: OAuthConfigurationService, useFactory: () => instance(oAuthConfigurationService) }, { provide: OAuthService, useFactory: () => instance(oAuthService) }, provideMockStore(), ], @@ -67,7 +70,7 @@ describe('Auth0 Identity Provider', () => { }); beforeEach(() => { - when(apiTokenService.restore$(anything())).thenReturn(of(true)); + when(apiTokenService.restore$(anything(), anything())).thenReturn(of(true)); when(oAuthService.getIdToken()).thenReturn(idToken); when(oAuthService.loadDiscoveryDocumentAndTryLogin()).thenReturn( new Promise((res, _) => { @@ -75,6 +78,7 @@ describe('Auth0 Identity Provider', () => { }) ); when(oAuthService.state).thenReturn(undefined); + when(oAuthConfigurationService.config$).thenReturn(new BehaviorSubject({})); when(apiService.post(anything(), anything())).thenReturn(of(userData)); }); diff --git a/src/app/core/identity-provider/auth0.identity-provider.ts b/src/app/core/identity-provider/auth0.identity-provider.ts index ca5e392bd3..e668ab38a9 100644 --- a/src/app/core/identity-provider/auth0.identity-provider.ts +++ b/src/app/core/identity-provider/auth0.identity-provider.ts @@ -4,7 +4,7 @@ import { Inject, Injectable } from '@angular/core'; import { ActivatedRouteSnapshot, Router } from '@angular/router'; import { Store, select } from '@ngrx/store'; import { OAuthService } from 'angular-oauth2-oidc'; -import { Observable, combineLatest, from, of, race, timer } from 'rxjs'; +import { BehaviorSubject, Observable, combineLatest, from, of, race, timer } from 'rxjs'; import { catchError, filter, first, map, switchMap, take, tap } from 'rxjs/operators'; import { HttpError } from 'ish-core/models/http-error/http-error.model'; @@ -18,9 +18,10 @@ import { loadUserByAPIToken, } from 'ish-core/store/customer/user'; import { ApiTokenService } from 'ish-core/utils/api-token/api-token.service'; -import { whenTruthy } from 'ish-core/utils/operators'; +import { OAuthConfigurationService } from 'ish-core/utils/oauth-configuration/oauth-configuration.service'; +import { delayUntil, whenTruthy } from 'ish-core/utils/operators'; -import { IdentityProvider, TriggerReturnType } from './identity-provider.interface'; +import { IdentityProvider, IdentityProviderCapabilities, TriggerReturnType } from './identity-provider.interface'; export interface Auth0Config { type: 'auth0'; @@ -30,16 +31,21 @@ export interface Auth0Config { @Injectable({ providedIn: 'root' }) export class Auth0IdentityProvider implements IdentityProvider { + // emits true, when OAuth Service is successfully configured + // used as an additional condition to check that the OAuth Service is configured before OAuth Service actions are used + private oAuthServiceConfigured$ = new BehaviorSubject(false); + constructor( - private oauthService: OAuthService, private apiService: ApiService, private store: Store, private router: Router, private apiTokenService: ApiTokenService, + private oauthService: OAuthService, + private configService: OAuthConfigurationService, @Inject(APP_BASE_HREF) private baseHref: string ) {} - getCapabilities() { + getCapabilities(): IdentityProviderCapabilities { return { editPassword: false, editEmail: false, @@ -50,60 +56,78 @@ export class Auth0IdentityProvider implements IdentityProvider { init(config: Auth0Config) { const effectiveOrigin = this.baseHref === '/' ? window.location.origin : window.location.origin + this.baseHref; - this.oauthService.configure({ - // Your Auth0 app's domain - // Important: Don't forget to start with https:// AND the trailing slash! - issuer: `https://${config.domain}/`, + // use internal OAuth configuration service for tokenEndpoint configuration + this.configService.config$.pipe(whenTruthy(), take(1)).subscribe(serviceConf => { + this.oauthService.configure({ + // Your Auth0 app's domain + // Important: Don't forget to start with https:// AND the trailing slash! + issuer: `https://${config.domain}/`, - // The app's clientId configured in Auth0 - clientId: config.clientID, + // The app's clientId configured in Auth0 + clientId: config.clientID, - // The app's redirectUri configured in Auth0 - redirectUri: `${effectiveOrigin}/loading`, + // The app's redirectUri configured in Auth0 + redirectUri: `${effectiveOrigin}/loading`, - // logout redirect URL - postLogoutRedirectUri: effectiveOrigin, + // logout redirect URL + postLogoutRedirectUri: effectiveOrigin, - // Scopes ("rights") the Angular application wants get delegated - // https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims - scope: 'openid email profile offline_access', + // Scopes ("rights") the Angular application wants get delegated + // https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims + scope: 'openid email profile offline_access', - // Using Authorization Code Flow - // (PKCE is activated by default for authorization code flow) - responseType: 'code', + // Using Authorization Code Flow + // (PKCE is activated by default for authorization code flow) + responseType: 'code', - // Your Auth0 account's logout url - // Derive it from your application's domain - logoutUrl: `https://${config.domain}/v2/logout`, + // Your Auth0 account's logout url + // Derive it from your application's domain + logoutUrl: `https://${config.domain}/v2/logout`, - sessionChecksEnabled: true, + sessionChecksEnabled: true, + + // ICM token endpoint to retrieve a valid token for an anonymous user + tokenEndpoint: serviceConf?.tokenEndpoint, + + requireHttps: serviceConf?.requireHttps, + }); + this.oauthService.setupAutomaticSilentRefresh(); + this.oAuthServiceConfigured$.next(true); }); - this.oauthService.setupAutomaticSilentRefresh(); - this.apiTokenService - .restore$(['user', 'order']) + + // OAuth Service should be configured before apiToken informations are restored + this.oAuthServiceConfigured$ .pipe( - switchMap(() => from(this.oauthService.loadDiscoveryDocumentAndTryLogin())), + whenTruthy(), + take(1), switchMap(() => - timer(0, 200).pipe( - map(() => this.oauthService.getIdToken()), - take(100), + // anonymous user token should only be fetched when no user is logged in + this.apiTokenService.restore$(['user', 'order'], !this.oauthService.getIdToken()).pipe( + delayUntil(this.oAuthServiceConfigured$), + switchMap(() => from(this.oauthService.loadDiscoveryDocumentAndTryLogin())), + switchMap(() => + timer(0, 200).pipe( + map(() => this.oauthService.getIdToken()), + take(100), + whenTruthy(), + take(1) + ) + ), whenTruthy(), - take(1) + switchMap(idToken => { + const inviteUserId = window.sessionStorage.getItem('invite-userid'); + const inviteHash = window.sessionStorage.getItem('invite-hash'); + return inviteUserId && inviteHash + ? this.inviteRegistration(idToken, inviteUserId, inviteHash).pipe( + tap(() => { + window.sessionStorage.removeItem('invite-userid'); + window.sessionStorage.removeItem('invite-hash'); + }) + ) + : this.normalSignInRegistration(idToken); + }) ) - ), - whenTruthy(), - switchMap(idToken => { - const inviteUserId = window.sessionStorage.getItem('invite-userid'); - const inviteHash = window.sessionStorage.getItem('invite-hash'); - return inviteUserId && inviteHash - ? this.inviteRegistration(idToken, inviteUserId, inviteHash).pipe( - tap(() => { - window.sessionStorage.removeItem('invite-userid'); - window.sessionStorage.removeItem('invite-hash'); - }) - ) - : this.normalSignInRegistration(idToken); - }) + ) ) .subscribe(() => { this.apiTokenService.removeApiToken(); @@ -196,27 +220,45 @@ export class Auth0IdentityProvider implements IdentityProvider { if (route.queryParamMap.get('userid')) { return of(true); } else { - this.router.navigateByUrl('/loading'); - return this.oauthService.loadDiscoveryDocumentAndLogin({ - state: route.queryParams.returnUrl, - }); + return this.oAuthServiceConfigured$.pipe( + whenTruthy(), + take(1), + tap(() => { + this.router.navigateByUrl('/loading'); + this.oauthService.loadDiscoveryDocumentAndLogin({ + state: route.queryParams.returnUrl, + }); + }) + ); } } triggerLogin(route: ActivatedRouteSnapshot): TriggerReturnType { - this.router.navigateByUrl('/loading'); - return this.oauthService.loadDiscoveryDocumentAndLogin({ - state: route.queryParams.returnUrl, - }); + return this.oAuthServiceConfigured$.pipe( + whenTruthy(), + take(1), + tap(() => { + this.router.navigateByUrl('/loading'); + this.oauthService.loadDiscoveryDocumentAndLogin({ + state: route.queryParams.returnUrl, + }); + }) + ); } triggerInvite(route: ActivatedRouteSnapshot): TriggerReturnType { - this.router.navigateByUrl('/loading'); - window.sessionStorage.setItem('invite-userid', route.queryParams.uid); - window.sessionStorage.setItem('invite-hash', route.queryParams.Hash); - return this.oauthService.loadDiscoveryDocumentAndLogin({ - state: route.queryParams.returnUrl, - }); + return this.oAuthServiceConfigured$.pipe( + whenTruthy(), + take(1), + tap(() => { + this.router.navigateByUrl('/loading'); + window.sessionStorage.setItem('invite-userid', route.queryParams.uid); + window.sessionStorage.setItem('invite-hash', route.queryParams.Hash); + this.oauthService.loadDiscoveryDocumentAndLogin({ + state: route.queryParams.returnUrl, + }); + }) + ); } triggerLogout(): TriggerReturnType { diff --git a/src/app/core/identity-provider/icm.identity-provider.spec.ts b/src/app/core/identity-provider/icm.identity-provider.spec.ts new file mode 100644 index 0000000000..c15f38cbf5 --- /dev/null +++ b/src/app/core/identity-provider/icm.identity-provider.spec.ts @@ -0,0 +1,98 @@ +import { TestBed } from '@angular/core/testing'; +import { Router, UrlTree } from '@angular/router'; +import { MockStore, provideMockStore } from '@ngrx/store/testing'; +import { OAuthService } from 'angular-oauth2-oidc'; +import { BehaviorSubject, Observable, Subject, of } from 'rxjs'; +import { anything, instance, mock, resetCalls, spy, verify, when } from 'ts-mockito'; + +import { AccountFacade } from 'ish-core/facades/account.facade'; +import { selectQueryParam } from 'ish-core/store/core/router'; +import { ApiTokenService } from 'ish-core/utils/api-token/api-token.service'; +import { OAuthConfigurationService } from 'ish-core/utils/oauth-configuration/oauth-configuration.service'; + +import { ICMIdentityProvider } from './icm.identity-provider'; + +describe('Icm Identity Provider', () => { + const apiTokenService = mock(ApiTokenService); + const accountFacade = mock(AccountFacade); + const oAuthConfigurationService = mock(OAuthConfigurationService); + + let icmIdentityProvider: ICMIdentityProvider; + let store$: MockStore; + let router: Router; + + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [ + { provide: AccountFacade, useFactory: () => instance(accountFacade) }, + { provide: ApiTokenService, useFactory: () => instance(apiTokenService) }, + + { provide: OAuthConfigurationService, useFactory: () => instance(oAuthConfigurationService) }, + { provide: OAuthService, useFactory: () => instance(mock(OAuthService)) }, + + provideMockStore(), + ], + }).compileComponents(); + + icmIdentityProvider = TestBed.inject(ICMIdentityProvider); + router = TestBed.inject(Router); + store$ = TestBed.inject(MockStore); + }); + + beforeEach(() => { + when(apiTokenService.restore$()).thenReturn(of(true)); + when(apiTokenService.cookieVanishes$).thenReturn(new Subject()); + when(oAuthConfigurationService.config$).thenReturn(new BehaviorSubject({})); + + resetCalls(apiTokenService); + resetCalls(accountFacade); + + window.sessionStorage.clear(); + }); + + describe('init', () => { + it('should restore apiToken on startup', () => { + icmIdentityProvider.init(); + verify(apiTokenService.restore$()).once(); + verify(apiTokenService.removeApiToken()).never(); + }); + }); + + describe('triggerLogout', () => { + beforeEach(() => { + when(accountFacade.isLoggedIn$).thenReturn(of(false)); + store$.overrideSelector(selectQueryParam(anything()), undefined); + icmIdentityProvider.init(); + }); + + it('should remove api token on logout', done => { + const logoutTrigger$ = icmIdentityProvider.triggerLogout() as Observable; + + logoutTrigger$.subscribe(() => { + verify(accountFacade.logoutUser()).once(); + done(); + }); + }); + + it('should return to home page', done => { + const routerSpy = spy(router); + + const logoutTrigger$ = icmIdentityProvider.triggerLogout() as Observable; + + logoutTrigger$.subscribe(() => { + verify(routerSpy.parseUrl('/home')).once(); + done(); + }); + }); + }); + + describe('triggerLogin', () => { + beforeEach(() => { + icmIdentityProvider.init(); + }); + + it('should always return true without any further functionality', () => { + expect(icmIdentityProvider.triggerLogin()).toBeTrue(); + }); + }); +}); diff --git a/src/app/core/identity-provider/icm.identity-provider.ts b/src/app/core/identity-provider/icm.identity-provider.ts index c10c5922e4..f0c9862a73 100644 --- a/src/app/core/identity-provider/icm.identity-provider.ts +++ b/src/app/core/identity-provider/icm.identity-provider.ts @@ -2,18 +2,32 @@ import { HttpEvent, HttpHandler, HttpRequest } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { ActivatedRouteSnapshot, Router } from '@angular/router'; import { Store, select } from '@ngrx/store'; -import { Observable, noop } from 'rxjs'; -import { map } from 'rxjs/operators'; +import { OAuthService } from 'angular-oauth2-oidc'; +import { BehaviorSubject, Observable, merge, noop } from 'rxjs'; +import { filter, map, switchMap, take, tap, withLatestFrom } from 'rxjs/operators'; +import { AccountFacade } from 'ish-core/facades/account.facade'; import { selectQueryParam } from 'ish-core/store/core/router'; -import { logoutUser } from 'ish-core/store/customer/user'; import { ApiTokenService } from 'ish-core/utils/api-token/api-token.service'; +import { OAuthConfigurationService } from 'ish-core/utils/oauth-configuration/oauth-configuration.service'; +import { whenTruthy } from 'ish-core/utils/operators'; import { IdentityProvider, TriggerReturnType } from './identity-provider.interface'; @Injectable({ providedIn: 'root' }) export class ICMIdentityProvider implements IdentityProvider { - constructor(protected router: Router, protected store: Store, protected apiTokenService: ApiTokenService) {} + // emits true, when OAuth Service is successfully configured + // used as an additional condition to check that the OAuth Service is configured before OAuth Service actions are used + private oAuthServiceConfigured$ = new BehaviorSubject(false); + + constructor( + private router: Router, + private store: Store, + private apiTokenService: ApiTokenService, + private accountFacade: AccountFacade, + private oAuthService: OAuthService, + private configService: OAuthConfigurationService + ) {} getCapabilities() { return { @@ -24,16 +38,34 @@ export class ICMIdentityProvider implements IdentityProvider { } init() { - this.apiTokenService.restore$().subscribe(noop); - - this.apiTokenService.cookieVanishes$.subscribe(type => { - this.store.dispatch(logoutUser()); - if (type === 'user') { - this.router.navigate(['/login'], { - queryParams: { returnUrl: this.router.url, messageKey: 'session_timeout' }, - }); - } + // OAuth Service should be configured by internal OAuth configuration service + this.configService.config$.pipe(whenTruthy(), take(1)).subscribe(config => { + this.oAuthService.configure(config); + this.oAuthServiceConfigured$.next(true); }); + + this.apiTokenService.cookieVanishes$ + .pipe(withLatestFrom(this.apiTokenService.apiToken$)) + .subscribe(([type, apiToken]) => { + this.accountFacade.logoutUser({ revokeApiToken: false }); + if (!apiToken) { + this.accountFacade.fetchAnonymousToken(); + } + if (type === 'user') { + this.router.navigate(['/login'], { + queryParams: { returnUrl: this.router.url, messageKey: 'session_timeout' }, + }); + } + }); + + // OAuth Service should be configured before apiToken informations are restored and the refresh token mechanism is setup + this.oAuthServiceConfigured$ + .pipe( + whenTruthy(), + take(1), + switchMap(() => merge(this.apiTokenService.restore$(), this.configService.setupRefreshTokenMechanism$())) + ) + .subscribe(noop); } triggerLogin(): TriggerReturnType { @@ -41,12 +73,24 @@ export class ICMIdentityProvider implements IdentityProvider { } triggerLogout(): TriggerReturnType { - this.apiTokenService.removeApiToken(); - this.store.dispatch(logoutUser()); - return this.store.pipe( - select(selectQueryParam('returnUrl')), - map(returnUrl => returnUrl || '/home'), - map(returnUrl => this.router.parseUrl(returnUrl)) + return this.oAuthServiceConfigured$.pipe( + whenTruthy(), + take(1), + tap(() => this.accountFacade.logoutUser()), // user will be logged out and related refresh token is revoked on server + switchMap(() => + this.accountFacade.isLoggedIn$.pipe( + // wait until the user is logged out before you go to homepage to prevent unnecessary REST calls + filter(loggedIn => !loggedIn), + take(1), + switchMap(() => + this.store.pipe( + select(selectQueryParam('returnUrl')), + map(returnUrl => returnUrl || '/home'), + map(returnUrl => this.router.parseUrl(returnUrl)) + ) + ) + ) + ) ); } diff --git a/src/app/core/identity-provider/identity-provider.factory.ts b/src/app/core/identity-provider/identity-provider.factory.ts index 0a68d74d74..efc6098eca 100644 --- a/src/app/core/identity-provider/identity-provider.factory.ts +++ b/src/app/core/identity-provider/identity-provider.factory.ts @@ -1,5 +1,6 @@ import { Injectable, InjectionToken, Injector, Type } from '@angular/core'; import { Store, select } from '@ngrx/store'; +import { once } from 'lodash-es'; import { noop } from 'rxjs'; import { first } from 'rxjs/operators'; @@ -57,7 +58,14 @@ export class IdentityProviderFactory { } } + private logNoIdpError = once(() => + console.error('No identity provider instance exists. Please double-check your configuration:', this.config) + ); + getInstance() { + if (!this.instance) { + this.logNoIdpError(); + } return this.instance; } diff --git a/src/app/core/interceptors/identity-provider.interceptor.ts b/src/app/core/interceptors/identity-provider.interceptor.ts index 5fb4a72928..a01d019f0b 100644 --- a/src/app/core/interceptors/identity-provider.interceptor.ts +++ b/src/app/core/interceptors/identity-provider.interceptor.ts @@ -12,7 +12,7 @@ export class IdentityProviderInterceptor implements HttpInterceptor { intercept(req: HttpRequest, next: HttpHandler): Observable> { // TODO: check if this works with PROXY_ICM if (req.url.startsWith(this.appFacade.icmBaseUrl)) { - return this.identityProviderFactory.getInstance().intercept(req, next); + return this.identityProviderFactory.getInstance()?.intercept(req, next) ?? next.handle(req); } return next.handle(req); } diff --git a/src/app/core/models/category/category.mapper.ts b/src/app/core/models/category/category.mapper.ts index 30f7b72665..a96aeb73ed 100644 --- a/src/app/core/models/category/category.mapper.ts +++ b/src/app/core/models/category/category.mapper.ts @@ -30,7 +30,7 @@ export class CategoryMapper { * Creates Category stubs from the category path (excluding the last element) */ categoriesFromCategoryPath(path: CategoryPathElement[]): CategoryTree { - if (!path || !path.length) { + if (!path?.length) { return CategoryTreeHelper.empty(); } diff --git a/src/app/core/models/checkout/checkout-step.type.ts b/src/app/core/models/checkout/checkout-step.type.ts new file mode 100644 index 0000000000..09c5397ca7 --- /dev/null +++ b/src/app/core/models/checkout/checkout-step.type.ts @@ -0,0 +1,11 @@ +/** + * available, ordered checkout steps + */ +export enum CheckoutStepType { + BeforeCheckout, + Addresses, + Shipping, + Payment, + Review, + Receipt, +} diff --git a/src/app/core/models/content-page-tree/content-page-tree.mapper.ts b/src/app/core/models/content-page-tree/content-page-tree.mapper.ts index 9f0d8552c6..ba71327359 100644 --- a/src/app/core/models/content-page-tree/content-page-tree.mapper.ts +++ b/src/app/core/models/content-page-tree/content-page-tree.mapper.ts @@ -45,7 +45,7 @@ export class ContentPageTreeMapper { * Creates page tree stubs from the page tree path */ treeElementsFromTreeElementPath(path: Link[]): ContentPageTree { - if (!path || !path.length) { + if (!path?.length) { return ContentPageTreeHelper.empty(); } diff --git a/src/app/core/models/image/image.mapper.ts b/src/app/core/models/image/image.mapper.ts index c768644686..0e62405dea 100644 --- a/src/app/core/models/image/image.mapper.ts +++ b/src/app/core/models/image/image.mapper.ts @@ -53,7 +53,7 @@ export class ImageMapper { * @param url The relative or absolute image URL. * @returns The URL. */ - private fromEffectiveUrl(url: string): string { + fromEffectiveUrl(url: string): string { if (!url) { return; } diff --git a/src/app/core/models/line-item/line-item.interface.ts b/src/app/core/models/line-item/line-item.interface.ts index 80e96cdd56..d74687523f 100644 --- a/src/app/core/models/line-item/line-item.interface.ts +++ b/src/app/core/models/line-item/line-item.interface.ts @@ -34,4 +34,5 @@ export interface LineItemData { freeGift: boolean; quantityFixed?: boolean; quote?: string; + desiredDelivery?: string; } diff --git a/src/app/core/models/line-item/line-item.mapper.ts b/src/app/core/models/line-item/line-item.mapper.ts index 48632030d0..ae0474f2eb 100644 --- a/src/app/core/models/line-item/line-item.mapper.ts +++ b/src/app/core/models/line-item/line-item.mapper.ts @@ -49,6 +49,7 @@ export class LineItemMapper { productSKU: data.product, editable: !data.quantityFixed, quote: data.quote ? data.quote : undefined, + desiredDeliveryDate: data.desiredDelivery, }; } else { throw new Error(`'LineItemData' is required for the mapping`); diff --git a/src/app/core/models/line-item/line-item.model.ts b/src/app/core/models/line-item/line-item.model.ts index e3f74a173a..9cbfd4e908 100644 --- a/src/app/core/models/line-item/line-item.model.ts +++ b/src/app/core/models/line-item/line-item.model.ts @@ -35,6 +35,7 @@ export interface LineItem { editable: boolean; quote?: string; + desiredDeliveryDate?: string; } export interface LineItemView extends LineItem { diff --git a/src/app/core/models/payment-method/payment-method.mapper.ts b/src/app/core/models/payment-method/payment-method.mapper.ts index 5608c649b5..b13b031d08 100644 --- a/src/app/core/models/payment-method/payment-method.mapper.ts +++ b/src/app/core/models/payment-method/payment-method.mapper.ts @@ -13,7 +13,7 @@ import { PaymentMethod } from './payment-method.model'; export class PaymentMethodMapper { static fromData(body: PaymentMethodData): PaymentMethod[] { - if (!body || !body.data) { + if (!body?.data) { throw new Error(`'paymentMethodData' is required`); } @@ -58,7 +58,7 @@ export class PaymentMethodMapper { throw new Error(`'paymentMethodOptions' are required`); } - if (!options.methods || !options.methods.length) { + if (!options.methods?.length) { return []; } @@ -152,7 +152,7 @@ export class PaymentMethodMapper { const invalidCapabilities = ['LimitedTender', 'FastCheckout']; // without capabilities - if (!paymentData.capabilities || !paymentData.capabilities.length) { + if (!paymentData.capabilities?.length) { return true; } diff --git a/src/app/core/models/product-variation/product-variation.helper.spec.ts b/src/app/core/models/product-variation/product-variation.helper.spec.ts index d28c5aa228..eff3231a8e 100644 --- a/src/app/core/models/product-variation/product-variation.helper.spec.ts +++ b/src/app/core/models/product-variation/product-variation.helper.spec.ts @@ -9,8 +9,8 @@ const productVariations = [ sku: '222', productMasterSKU: 'M111', variableVariationAttributes: [ - { name: 'Attr 1', type: 'String', value: 'A', variationAttributeId: 'a1' }, - { name: 'Attr 2', type: 'String', value: 'A', variationAttributeId: 'a2' }, + { name: 'Attr 1', value: 'A', variationAttributeId: 'a1' }, + { name: 'Attr 2', value: 'A', variationAttributeId: 'a2' }, ], }, { @@ -18,32 +18,32 @@ const productVariations = [ productMasterSKU: 'M111', attributes: [{ name: 'defaultVariation', type: 'Boolean', value: true }], variableVariationAttributes: [ - { name: 'Attr 1', type: 'String', value: 'A', variationAttributeId: 'a1' }, - { name: 'Attr 2', type: 'String', value: 'B', variationAttributeId: 'a2' }, + { name: 'Attr 1', value: 'A', variationAttributeId: 'a1' }, + { name: 'Attr 2', value: 'B', variationAttributeId: 'a2' }, ], }, { sku: '444', productMasterSKU: 'M111', variableVariationAttributes: [ - { name: 'Attr 1', type: 'String', value: 'B', variationAttributeId: 'a1' }, - { name: 'Attr 2', type: 'String', value: 'A', variationAttributeId: 'a2' }, + { name: 'Attr 1', value: 'B', variationAttributeId: 'a1' }, + { name: 'Attr 2', value: 'A', variationAttributeId: 'a2' }, ], }, { sku: '555', productMasterSKU: 'M111', variableVariationAttributes: [ - { name: 'Attr 1', type: 'String', value: 'B', variationAttributeId: 'a1' }, - { name: 'Attr 2', type: 'String', value: 'B', variationAttributeId: 'a2' }, + { name: 'Attr 1', value: 'B', variationAttributeId: 'a1' }, + { name: 'Attr 2', value: 'B', variationAttributeId: 'a2' }, ], }, { sku: '666', productMasterSKU: 'M111', variableVariationAttributes: [ - { name: 'Attr 1', type: 'String', value: 'B', variationAttributeId: 'a1' }, - { name: 'Attr 2', type: 'String', value: 'C', variationAttributeId: 'a2' }, + { name: 'Attr 1', value: 'B', variationAttributeId: 'a1' }, + { name: 'Attr 2', value: 'C', variationAttributeId: 'a2' }, ], }, ] as VariationProduct[]; @@ -51,11 +51,11 @@ const productVariations = [ const productMaster = { sku: 'M111', variationAttributeValues: [ - { name: 'Attr 1', type: 'String', value: 'A', variationAttributeId: 'a1' }, - { name: 'Attr 1', type: 'String', value: 'B', variationAttributeId: 'a1' }, - { name: 'Attr 2', type: 'String', value: 'A', variationAttributeId: 'a2' }, - { name: 'Attr 2', type: 'String', value: 'B', variationAttributeId: 'a2' }, - { name: 'Attr 2', type: 'String', value: 'C', variationAttributeId: 'a2' }, + { name: 'Attr 1', value: 'A', variationAttributeId: 'a1' }, + { name: 'Attr 1', value: 'B', variationAttributeId: 'a1' }, + { name: 'Attr 2', value: 'A', variationAttributeId: 'a2' }, + { name: 'Attr 2', value: 'B', variationAttributeId: 'a2' }, + { name: 'Attr 2', value: 'C', variationAttributeId: 'a2' }, ], } as VariationProductMaster; diff --git a/src/app/core/models/product-variation/product-variation.helper.ts b/src/app/core/models/product-variation/product-variation.helper.ts index 36dca3ce99..d718bb503d 100644 --- a/src/app/core/models/product-variation/product-variation.helper.ts +++ b/src/app/core/models/product-variation/product-variation.helper.ts @@ -33,6 +33,7 @@ export class ProductVariationHelper { label: attr.value, value: attr.value, type: attr.variationAttributeId, + metaData: attr.metaData, active: currentSettings?.[attr.variationAttributeId]?.value === attr.value, })) .map(option => ({ @@ -50,6 +51,7 @@ export class ProductVariationHelper { return { id: attribute.variationAttributeId, label: attribute.name, + attributeType: attribute.attributeType, options: groupedOptions[attrId], }; }); diff --git a/src/app/core/models/product-variation/variation-attribute.interface.ts b/src/app/core/models/product-variation/variation-attribute.interface.ts new file mode 100644 index 0000000000..02a49ff411 --- /dev/null +++ b/src/app/core/models/product-variation/variation-attribute.interface.ts @@ -0,0 +1,23 @@ +import { VariationAttributeType } from './variation-attribute.model'; + +export interface VariationAttributeData { + variationAttributeId: string; + name: string; + value?: VariationAttributeValue; + values?: { + value: VariationAttributeValue; + metadata?: VariationAttributeMetaData; + }[]; + attributeType?: VariationAttributeType; + metadata?: VariationAttributeMetaData; +} + +interface VariationAttributeValue { + name: string; + value: string; +} + +export interface VariationAttributeMetaData { + colorCode?: string; + imagePath?: string; +} diff --git a/src/app/core/models/product-variation/variation-attribute.mapper.ts b/src/app/core/models/product-variation/variation-attribute.mapper.ts new file mode 100644 index 0000000000..8709815809 --- /dev/null +++ b/src/app/core/models/product-variation/variation-attribute.mapper.ts @@ -0,0 +1,52 @@ +/* eslint-disable ish-custom-rules/project-structure */ +import { Injectable } from '@angular/core'; + +import { ImageMapper } from 'ish-core/models/image/image.mapper'; + +import { VariationAttributeData, VariationAttributeMetaData } from './variation-attribute.interface'; +import { VariationAttribute, VariationAttributeType } from './variation-attribute.model'; + +/** + * Maps variation attributes data of HTTP requests to client side model instance. + */ +@Injectable({ providedIn: 'root' }) +export class VariationAttributeMapper { + constructor(private imageMapper: ImageMapper) {} + + fromData(data: VariationAttributeData[]): VariationAttribute[] { + return data?.map(varAttr => ({ + variationAttributeId: varAttr.variationAttributeId, + name: varAttr.name, + value: varAttr.value.value, + attributeType: varAttr.attributeType, + metaData: this.mapMetaData(varAttr.attributeType, varAttr.metadata), + })); + } + + fromMasterData(variationAttributes: VariationAttributeData[]): VariationAttribute[] { + return variationAttributes + ?.map(varAttr => + varAttr.values.map(value => ({ + variationAttributeId: varAttr.variationAttributeId, + name: varAttr.name, + value: value.value.value, + attributeType: varAttr.attributeType, + metaData: this.mapMetaData(varAttr.attributeType, value.metadata), + })) + ) + .flat(); + } + + private mapMetaData(attributeType: VariationAttributeType, metaData: VariationAttributeMetaData): string { + switch (attributeType) { + case 'colorCode': + case 'defaultAndColorCode': + return metaData?.colorCode; + case 'swatchImage': + case 'defaultAndSwatchImage': + return this.imageMapper.fromEffectiveUrl(metaData?.imagePath); + default: + return; + } + } +} diff --git a/src/app/core/models/product-variation/variation-attribute.model.ts b/src/app/core/models/product-variation/variation-attribute.model.ts index a2641d1667..e93dd8bc4e 100644 --- a/src/app/core/models/product-variation/variation-attribute.model.ts +++ b/src/app/core/models/product-variation/variation-attribute.model.ts @@ -1,5 +1,14 @@ -import { Attribute } from 'ish-core/models/attribute/attribute.model'; - -export interface VariationAttribute extends Attribute { +export interface VariationAttribute { variationAttributeId: string; + name: string; + value: string; + attributeType: VariationAttributeType; + metaData?: string; } + +export type VariationAttributeType = + | 'default' + | 'colorCode' + | 'defaultAndColorCode' + | 'swatchImage' + | 'defaultAndSwatchImage'; diff --git a/src/app/core/models/product-variation/variation-option-group.model.ts b/src/app/core/models/product-variation/variation-option-group.model.ts index 97a2d7db39..7aef3971e8 100644 --- a/src/app/core/models/product-variation/variation-option-group.model.ts +++ b/src/app/core/models/product-variation/variation-option-group.model.ts @@ -4,4 +4,5 @@ export interface VariationOptionGroup { options: VariationSelectOption[]; label: string; id: string; + attributeType?: string; } diff --git a/src/app/core/models/product-variation/variation-select-option.model.ts b/src/app/core/models/product-variation/variation-select-option.model.ts index f34715dba9..ce2dcef470 100644 --- a/src/app/core/models/product-variation/variation-select-option.model.ts +++ b/src/app/core/models/product-variation/variation-select-option.model.ts @@ -4,4 +4,5 @@ export interface VariationSelectOption { type: string; alternativeCombination?: boolean; active?: boolean; + metaData?: string; } diff --git a/src/app/core/models/product-view/product-view.model.ts b/src/app/core/models/product-view/product-view.model.ts index 34fe73aa1e..7565695a13 100644 --- a/src/app/core/models/product-view/product-view.model.ts +++ b/src/app/core/models/product-view/product-view.model.ts @@ -37,8 +37,7 @@ export function createVariationProductMasterView( defaultCategory?: CategoryView ): VariationProductMasterView { return ( - product && - variations?.length && { + product && { ...createProductView(product, defaultCategory), type: 'VariationProductMaster', defaultVariationSKU, @@ -54,9 +53,7 @@ export function createVariationProductView( defaultCategory?: CategoryView ): VariationProductView { return ( - product && - productMaster && - variations?.length && { + product && { ...createProductView(product, defaultCategory), type: 'VariationProduct', variations, diff --git a/src/app/core/models/product/product.helper.ts b/src/app/core/models/product/product.helper.ts index f239028ffd..353b144a9d 100644 --- a/src/app/core/models/product/product.helper.ts +++ b/src/app/core/models/product/product.helper.ts @@ -150,7 +150,7 @@ export class ProductHelper { * @returns A Product with specific attributes only compared to the common attributes */ static getProductWithoutCommonAttributes(product: ProductView, visibleProducts: ProductView[]): ProductView { - if (!product || !product.sku || !visibleProducts || !visibleProducts.length) { + if (!product?.sku || !visibleProducts?.length) { return; } const common = ProductHelper.getCommonAttributeNames(visibleProducts); diff --git a/src/app/core/models/product/product.interface.ts b/src/app/core/models/product/product.interface.ts index d9cd92c4d5..ffc80ba363 100644 --- a/src/app/core/models/product/product.interface.ts +++ b/src/app/core/models/product/product.interface.ts @@ -5,7 +5,7 @@ import { CategoryData } from 'ish-core/models/category/category.interface'; import { Image } from 'ish-core/models/image/image.model'; import { Link } from 'ish-core/models/link/link.model'; import { PriceData } from 'ish-core/models/price/price.interface'; -import { VariationAttribute } from 'ish-core/models/product-variation/variation-attribute.model'; +import { VariationAttributeData } from 'ish-core/models/product-variation/variation-attribute.interface'; import { SeoAttributesData } from 'ish-core/models/seo-attributes/seo-attributes.interface'; import { Warranty } from 'ish-core/models/warranty/warranty.model'; @@ -41,8 +41,7 @@ export interface ProductData { stepOrderQuantity?: number; packingUnit: string; - variationAttributeValues?: VariationAttribute[]; - variableVariationAttributes?: VariationAttribute[]; + variationAttributeValuesExtended?: VariationAttributeData[]; partOfRetailSet: boolean; attachments?: AttachmentData[]; @@ -74,5 +73,5 @@ export interface ProductDataStub { } export interface ProductVariationLink extends Link { - variableVariationAttributeValues: VariationAttribute[]; + variableVariationAttributeValuesExtended: VariationAttributeData[]; } diff --git a/src/app/core/models/product/product.mapper.spec.ts b/src/app/core/models/product/product.mapper.spec.ts index da6fe7e07f..e8d9b9f823 100644 --- a/src/app/core/models/product/product.mapper.spec.ts +++ b/src/app/core/models/product/product.mapper.spec.ts @@ -66,7 +66,7 @@ describe('Product Mapper', () => { const product: Product = productMapper.fromData({ sku: '1', productMaster: true, - variationAttributeValues: [], + variationAttributeValuesExtended: [], } as ProductData); expect(product).toBeTruthy(); expect(product.type).toEqual('VariationProductMaster'); @@ -78,7 +78,7 @@ describe('Product Mapper', () => { const product: Product = productMapper.fromData({ sku: '1', productMaster: false, - variableVariationAttributes: [], + variationAttributeValuesExtended: [], } as ProductData); expect(product).toBeTruthy(); expect(product.type).toEqual('Product'); diff --git a/src/app/core/models/product/product.mapper.ts b/src/app/core/models/product/product.mapper.ts index b1b97a161f..3f2e989b96 100644 --- a/src/app/core/models/product/product.mapper.ts +++ b/src/app/core/models/product/product.mapper.ts @@ -8,6 +8,7 @@ import { CategoryData } from 'ish-core/models/category/category.interface'; import { CategoryMapper } from 'ish-core/models/category/category.mapper'; import { ImageMapper } from 'ish-core/models/image/image.mapper'; import { Link } from 'ish-core/models/link/link.model'; +import { VariationAttributeMapper } from 'ish-core/models/product-variation/variation-attribute.mapper'; import { SeoAttributesMapper } from 'ish-core/models/seo-attributes/seo-attributes.mapper'; import { SkuQuantityType } from './product.helper'; @@ -43,7 +44,8 @@ export class ProductMapper { constructor( private imageMapper: ImageMapper, private attachmentMapper: AttachmentMapper, - private categoryMapper: CategoryMapper + private categoryMapper: CategoryMapper, + private variationAttributeMapper: VariationAttributeMapper ) {} static parseSkuFromURI(uri: string): string { @@ -91,7 +93,9 @@ export class ProductMapper { fromVariationLink(link: ProductVariationLink, productMasterSKU: string): Partial { return { ...this.fromLink(link), - variableVariationAttributes: link.variableVariationAttributeValues, + variableVariationAttributes: this.variationAttributeMapper.fromData( + link.variableVariationAttributeValuesExtended + ), productMasterSKU, type: 'VariationProduct', failed: false, @@ -227,14 +231,14 @@ export class ProductMapper { if (data.productMaster) { return { ...product, - variationAttributeValues: data.variationAttributeValues, + variationAttributeValues: this.variationAttributeMapper.fromMasterData(data.variationAttributeValuesExtended), type: 'VariationProductMaster', }; } else if (data.mastered) { return { ...product, productMasterSKU: data.productMasterSKU, - variableVariationAttributes: data.variableVariationAttributes, + variableVariationAttributes: this.variationAttributeMapper.fromData(data.variationAttributeValuesExtended), type: 'VariationProduct', }; } else if (data.productTypes?.includes('BUNDLE') || data.productBundle) { diff --git a/src/app/core/models/token/token.interface.ts b/src/app/core/models/token/token.interface.ts new file mode 100644 index 0000000000..195b688125 --- /dev/null +++ b/src/app/core/models/token/token.interface.ts @@ -0,0 +1,26 @@ +/** + * return correct token options for given grantType (NOTE: 'anonymous' grant type has no token options) + */ +export type FetchTokenOptions = T extends 'password' + ? FetchTokenPasswordOptions + : T extends 'client_credentials' + ? FetchTokenClientCredentialsOptions + : FetchTokenRefreshTokenOptions; + +interface FetchTokenPasswordOptions { + username: string; + password: string; + organization?: string; +} + +interface FetchTokenClientCredentialsOptions { + username: string; + password: string; + organization?: string; +} + +interface FetchTokenRefreshTokenOptions { + refresh_token: string; +} + +export type GrantType = 'anonymous' | 'password' | 'client_credentials' | 'refresh_token'; diff --git a/src/app/core/pipes/make-href.pipe.ts b/src/app/core/pipes/make-href.pipe.ts index 8a6c795751..689892d36e 100644 --- a/src/app/core/pipes/make-href.pipe.ts +++ b/src/app/core/pipes/make-href.pipe.ts @@ -10,7 +10,7 @@ import { MultiSiteService } from 'ish-core/utils/multi-site/multi-site.service'; export class MakeHrefPipe implements PipeTransform { constructor(private multiSiteService: MultiSiteService) {} transform(location: LocationStrategy, urlParams: Record): Observable { - if (!location || !location.path()) { + if (!location?.path()) { return of('undefined'); } diff --git a/src/app/core/routing/product/product.route.ts b/src/app/core/routing/product/product.route.ts index 230d75fcb0..736eb18be9 100644 --- a/src/app/core/routing/product/product.route.ts +++ b/src/app/core/routing/product/product.route.ts @@ -82,7 +82,7 @@ export function matchProductRoute(segments: UrlSegment[]): UrlMatchResult { * @returns localized product url */ export function generateProductUrl(product: ProductView, category?: CategoryView): string { - if (!product || !product.sku) { + if (!product?.sku) { return '/'; } diff --git a/src/app/core/services/api/api.service.ts b/src/app/core/services/api/api.service.ts index 3501500937..1237477ef8 100644 --- a/src/app/core/services/api/api.service.ts +++ b/src/app/core/services/api/api.service.ts @@ -126,30 +126,14 @@ export class ApiService { return httpCall$.pipe(this.handleErrors(!options?.skipApiErrorHandling)); } - private constructUrlForPath(path: string, options?: AvailableOptions): Observable { + constructUrlForPath(path: string, options?: AvailableOptions): Observable { if (path.startsWith('http://') || path.startsWith('https://')) { return of(path); } return combineLatest([ - // base url this.store.pipe(select(getRestEndpoint)), - // locale - options?.sendLocale === undefined || options.sendLocale - ? this.store.pipe( - select(getCurrentLocale), - whenTruthy(), - map(l => `;loc=${l}`) - ) - : of(''), - // currency - options?.sendCurrency === undefined || options.sendCurrency - ? this.store.pipe( - select(getCurrentCurrency), - whenTruthy(), - map(l => `;cur=${l}`) - ) - : of(''), - // first path segment + this.getLocale$(options), + this.getCurrency$(options), of('/'), of(path.includes('/') ? path.split('/')[0] : path), // pgid @@ -165,6 +149,26 @@ export class ApiService { ); } + private getLocale$(options: AvailableOptions): Observable { + return options?.sendLocale === undefined || options.sendLocale + ? this.store.pipe( + select(getCurrentLocale), + whenTruthy(), + map(l => `;loc=${l}`) + ) + : of(''); + } + + private getCurrency$(options: AvailableOptions): Observable { + return options?.sendCurrency === undefined || options.sendCurrency + ? this.store.pipe( + select(getCurrentCurrency), + whenTruthy(), + map(l => `;cur=${l}`) + ) + : of(''); + } + private constructHttpClientParams( path: string, options?: AvailableOptions diff --git a/src/app/core/services/basket/basket.service.spec.ts b/src/app/core/services/basket/basket.service.spec.ts index 2d089251ab..0125330244 100644 --- a/src/app/core/services/basket/basket.service.spec.ts +++ b/src/app/core/services/basket/basket.service.spec.ts @@ -7,6 +7,7 @@ import { anyString, anything, capture, instance, mock, verify, when } from 'ts-m import { Address } from 'ish-core/models/address/address.model'; import { BasketData } from 'ish-core/models/basket/basket.interface'; import { LineItemData } from 'ish-core/models/line-item/line-item.interface'; +import { LineItem } from 'ish-core/models/line-item/line-item.model'; import { ApiService } from 'ish-core/services/api/api.service'; import { OrderService } from 'ish-core/services/order/order.service'; import { getBasketIdOrCurrent } from 'ish-core/store/customer/basket'; @@ -271,6 +272,35 @@ describe('Basket Service', () => { }); }); + describe('Update Basket Items desired delivery date', () => { + const lineItems: LineItem[] = [ + ...BasketMockData.getBasket().lineItems, + { id: 'withdesiredDeliveryDate', desiredDeliveryDate: '2022-20-02' } as LineItem, + ]; + + it("should update the desired delivery date at all basket items when 'updateBasketItemsDesiredDeliveryDate' is called", done => { + when(apiService.patch(anyString(), anything(), anything())).thenReturn( + of({ data: { id: lineItemData.id, calculated: false } as LineItemData, infos: undefined }) + ); + + basketService.updateBasketItemsDesiredDeliveryDate('2022-22-02', lineItems).subscribe(() => { + verify(apiService.patch(anything(), anything(), anything())).twice(); + done(); + }); + }); + + it("should not update the desired delivery date at those basket items that have already the correct date when 'updateBasketItemsDesiredDeliveryDate' is called", done => { + when(apiService.patch(anyString(), anything(), anything())).thenReturn( + of({ data: { id: lineItemData.id, calculated: false } as LineItemData, infos: undefined }) + ); + + basketService.updateBasketItemsDesiredDeliveryDate('2022-20-02', lineItems).subscribe(() => { + verify(apiService.patch(anything(), anything(), anything())).once(); + done(); + }); + }); + }); + it("should create an attribute for a basket when 'createBasketAttribute' is called", done => { when(apiService.post(anything(), anything(), anything())).thenReturn(of({})); diff --git a/src/app/core/services/basket/basket.service.ts b/src/app/core/services/basket/basket.service.ts index e21ceb04b2..422db53256 100644 --- a/src/app/core/services/basket/basket.service.ts +++ b/src/app/core/services/basket/basket.service.ts @@ -1,7 +1,7 @@ import { HttpHeaders, HttpParams } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { Store, select } from '@ngrx/store'; -import { EMPTY, Observable, of, throwError } from 'rxjs'; +import { EMPTY, Observable, forkJoin, iif, of, throwError } from 'rxjs'; import { catchError, concatMap, map, take } from 'rxjs/operators'; import { AddressMapper } from 'ish-core/models/address/address.mapper'; @@ -20,7 +20,7 @@ import { Basket } from 'ish-core/models/basket/basket.model'; import { ErrorFeedback } from 'ish-core/models/http-error/http-error.model'; import { LineItemData } from 'ish-core/models/line-item/line-item.interface'; import { LineItemMapper } from 'ish-core/models/line-item/line-item.mapper'; -import { LineItem } from 'ish-core/models/line-item/line-item.model'; +import { LineItem, LineItemView } from 'ish-core/models/line-item/line-item.model'; import { SkuQuantityType } from 'ish-core/models/product/product.model'; import { ShippingMethodData } from 'ish-core/models/shipping-method/shipping-method.interface'; import { ShippingMethodMapper } from 'ish-core/models/shipping-method/shipping-method.mapper'; @@ -38,7 +38,9 @@ export type BasketUpdateType = export type BasketItemUpdateType = | { quantity?: { value: number; unit: string }; product?: string } - | { shippingMethod: { id: string } }; + | { shippingMethod?: { id: string } } + | { desiredDelivery?: string } + | { calculated: boolean }; type BasketIncludeType = | 'invoiceToAddress' @@ -513,6 +515,30 @@ export class BasketService { ); } + /** + * Updates the desired delivery date at all those line items of the current basket, whose desired delivery date differs from the given date. + * + * @param desiredDeliveryDate Desired delivery date in iso format, i.e. yyyy-mm-dd. + * @param lineItems Array of basket line items + * @returns Array of updated line items and basket + */ + updateBasketItemsDesiredDeliveryDate( + desiredDeliveryDate: string, + lineItems: LineItemView[] + ): Observable<{ lineItem: LineItem; info: BasketInfo[] }[]> { + if (desiredDeliveryDate && !new RegExp(/\d{4}-\d{2}-\d{2}/).test(desiredDeliveryDate)) { + return throwError( + () => new Error('updateBasketItemsDesiredDeliveryDate() called with an invalid desiredDeliveryDate') + ); + } + + const obsArray = lineItems + ?.filter(item => item.desiredDeliveryDate !== desiredDeliveryDate) + ?.map(item => this.updateBasketItem(item.id, { desiredDelivery: desiredDeliveryDate })); + + return iif(() => !!obsArray.length, forkJoin(obsArray), of([])); + } + /** * Creates a custom attribute on the currently used basket. Default attribute type is 'String'. * diff --git a/src/app/core/services/payment/payment.service.ts b/src/app/core/services/payment/payment.service.ts index dd5d89dd7b..883eefc39d 100644 --- a/src/app/core/services/payment/payment.service.ts +++ b/src/app/core/services/payment/payment.service.ts @@ -99,7 +99,7 @@ export class PaymentService { paymentInstrument: string, lang: string ): Observable { - if (!pm || !pm.capabilities || !pm.capabilities.some(data => ['RedirectBeforeCheckout'].includes(data))) { + if (!pm?.capabilities || !pm.capabilities.some(data => ['RedirectBeforeCheckout'].includes(data))) { return of(paymentInstrument); // send redirect urls if there is a redirect required } else { diff --git a/src/app/core/services/products/products.service.spec.ts b/src/app/core/services/products/products.service.spec.ts index 6310374dfb..4d364f8f03 100644 --- a/src/app/core/services/products/products.service.spec.ts +++ b/src/app/core/services/products/products.service.spec.ts @@ -129,21 +129,23 @@ describe('Products Service', () => { it("should get all product variations data when 'getProductVariations' is called and more than 50 variations exist", done => { const total = 156; when(apiServiceMock.get(`products/${productSku}/variations`, anything())).thenCall((_, opts) => - !opts.params ? of({ elements: [], amount: 40, total }) : of({ elements: [], total }) + !opts?.params.has('amount') ? of({ elements: [], amount: 40, total }) : of({ elements: [], total }) ); productsService.getProductVariations(productSku).subscribe(() => { verify(apiServiceMock.get(`products/${productSku}/variations`, anything())).times(4); - expect(capture(apiServiceMock.get).byCallIndex(0)?.[1]?.params).toBeUndefined(); + expect( + capture(apiServiceMock.get).byCallIndex(0)?.[1]?.params?.toString() + ).toMatchInlineSnapshot(`"extended=true"`); expect( capture(apiServiceMock.get).byCallIndex(1)?.[1]?.params?.toString() - ).toMatchInlineSnapshot(`"amount=40&offset=40"`); + ).toMatchInlineSnapshot(`"extended=true&amount=40&offset=40"`); expect( capture(apiServiceMock.get).byCallIndex(2)?.[1]?.params?.toString() - ).toMatchInlineSnapshot(`"amount=40&offset=80"`); + ).toMatchInlineSnapshot(`"extended=true&amount=40&offset=80"`); expect( capture(apiServiceMock.get).byCallIndex(3)?.[1]?.params?.toString() - ).toMatchInlineSnapshot(`"amount=36&offset=120"`); + ).toMatchInlineSnapshot(`"extended=true&amount=36&offset=120"`); done(); }); }); diff --git a/src/app/core/services/products/products.service.ts b/src/app/core/services/products/products.service.ts index 1d0f5b3818..4bb6278eda 100644 --- a/src/app/core/services/products/products.service.ts +++ b/src/app/core/services/products/products.service.ts @@ -44,7 +44,7 @@ export class ProductsService { return throwError(() => new Error('getProduct() called without a sku')); } - const params = new HttpParams().set('allImages', 'true'); + const params = new HttpParams().set('allImages', true).set('extended', true); return this.apiService .get(`products/${sku}`, { sendSPGID: true, params }) @@ -260,8 +260,13 @@ export class ProductsService { return throwError(() => new Error('getProductVariations() called without a sku')); } + const params = new HttpParams().set('extended', true); + return this.apiService - .get<{ elements: Link[]; total: number; amount: number }>(`products/${sku}/variations`, { sendSPGID: true }) + .get<{ elements: Link[]; total: number; amount: number }>(`products/${sku}/variations`, { + sendSPGID: true, + params, + }) .pipe( switchMap(resp => !resp.total @@ -277,7 +282,7 @@ export class ProductsService { this.apiService .get<{ elements: Link[] }>(`products/${sku}/variations`, { sendSPGID: true, - params: new HttpParams().set('amount', length).set('offset', offset), + params: params.set('amount', length).set('offset', offset), }) .pipe(mapToProperty('elements')) ) diff --git a/src/app/core/services/promotions/promotions.service.spec.ts b/src/app/core/services/promotions/promotions.service.spec.ts index f82a8b2da7..066ed12789 100644 --- a/src/app/core/services/promotions/promotions.service.spec.ts +++ b/src/app/core/services/promotions/promotions.service.spec.ts @@ -1,6 +1,6 @@ import { TestBed } from '@angular/core/testing'; import { of } from 'rxjs'; -import { instance, mock, verify, when } from 'ts-mockito'; +import { anything, instance, mock, verify, when } from 'ts-mockito'; import { Promotion } from 'ish-core/models/promotion/promotion.model'; import { ApiService } from 'ish-core/services/api/api.service'; @@ -39,10 +39,11 @@ describe('Promotions Service', () => { }); it("should get Promotion data when 'getPromotion' is called", done => { - when(apiServiceMock.get(`promotions/PROMO_UUID`)).thenReturn(of(promotionMockData)); + when(apiServiceMock.get(anything(), anything())).thenReturn(of(promotionMockData)); + promotionsService.getPromotion('PROMO_UUID').subscribe(data => { expect(data.id).toEqual('PROMO_UUID'); - verify(apiServiceMock.get(`promotions/PROMO_UUID`)).once(); + verify(apiServiceMock.get(`promotions/PROMO_UUID`, anything())).once(); done(); }); }); diff --git a/src/app/core/services/promotions/promotions.service.ts b/src/app/core/services/promotions/promotions.service.ts index 40bff51c4d..9a20aa0c1f 100644 --- a/src/app/core/services/promotions/promotions.service.ts +++ b/src/app/core/services/promotions/promotions.service.ts @@ -19,6 +19,8 @@ export class PromotionsService { return throwError(() => new Error('getPromotion() called without a id')); } - return this.apiService.get(`promotions/${id}`); + return this.apiService.get(`promotions/${id}`, { + sendSPGID: true, + }); } } diff --git a/src/app/core/services/user/user.service.spec.ts b/src/app/core/services/user/user.service.spec.ts index 19cd8562ca..d77b706b2d 100644 --- a/src/app/core/services/user/user.service.spec.ts +++ b/src/app/core/services/user/user.service.spec.ts @@ -1,6 +1,6 @@ -import { HttpHeaders } from '@angular/common/http'; import { TestBed } from '@angular/core/testing'; import { MockStore, provideMockStore } from '@ngrx/store/testing'; +import { OAuthService, TokenResponse } from 'angular-oauth2-oidc'; import { of, throwError } from 'rxjs'; import { anyString, anything, capture, instance, mock, verify, when } from 'ts-mockito'; @@ -13,51 +13,82 @@ import { User } from 'ish-core/models/user/user.model'; import { ApiService, AvailableOptions } from 'ish-core/services/api/api.service'; import { getUserPermissions } from 'ish-core/store/customer/authorization'; import { getLoggedInCustomer, getLoggedInUser } from 'ish-core/store/customer/user'; +import { ApiTokenService } from 'ish-core/utils/api-token/api-token.service'; import { encodeResourceID } from 'ish-core/utils/url-resource-ids'; import { UserService } from './user.service'; describe('User Service', () => { + const token = { + access_token: 'DEMO@access-token', + token_type: 'user', + expires_in: 3600, + refresh_token: 'DEMO@refresh-token', + id_token: 'DEMO@id-token', + } as TokenResponse; + let userService: UserService; let apiServiceMock: ApiService; + let apiTokenServiceMock: ApiTokenService; + let oAuthServiceMock: OAuthService; let appFacade: AppFacade; let store$: MockStore; beforeEach(() => { apiServiceMock = mock(ApiService); + apiTokenServiceMock = mock(ApiTokenService); appFacade = mock(AppFacade); + oAuthServiceMock = mock(OAuthService); + + when(oAuthServiceMock.fetchTokenUsingGrant(anyString(), anything(), anything())).thenResolve(token); + when(appFacade.isAppTypeREST$).thenReturn(of(true)); + when(appFacade.currentLocale$).thenReturn(of('en_US')); + when(appFacade.customerRestResource$).thenReturn(of('customers')); TestBed.configureTestingModule({ providers: [ { provide: ApiService, useFactory: () => instance(apiServiceMock) }, + { provide: ApiTokenService, useFactory: () => instance(apiTokenServiceMock) }, { provide: AppFacade, useFactory: () => instance(appFacade) }, + { provide: OAuthService, useFactory: () => instance(oAuthServiceMock) }, provideMockStore({ selectors: [{ selector: getLoggedInCustomer, value: undefined }] }), ], }); userService = TestBed.inject(UserService); - when(appFacade.isAppTypeREST$).thenReturn(of(true)); - when(appFacade.currentLocale$).thenReturn(of('en_US')); - when(appFacade.customerRestResource$).thenReturn(of('customers')); store$ = TestBed.inject(MockStore); }); describe('SignIn a user', () => { it('should login a user when correct credentials are entered', done => { const loginDetail = { login: 'patricia@test.intershop.de', password: '!InterShop00!' }; + when(apiServiceMock.get('customers/-', anything())).thenReturn( of({ customerNo: 'PC', customerType: 'PRIVATE' } as CustomerData) ); - when(apiServiceMock.get('privatecustomers/-')).thenReturn( + when(apiServiceMock.get('privatecustomers/-', anything())).thenReturn( of({ customerNo: 'PC', customerType: 'PRIVATE' } as CustomerData) ); - when(apiServiceMock.get('personalization')).thenReturn(of({ pgid: '6FGMJtFU2xuRpG9I3CpTS7fc0000' })); + when(apiServiceMock.get('personalization', anything())).thenReturn(of({ pgid: '6FGMJtFU2xuRpG9I3CpTS7fc0000' })); userService.signInUser(loginDetail).subscribe(data => { - const [, options] = capture<{}, { headers: HttpHeaders }>(apiServiceMock.get).first(); - const headers = options?.headers; - expect(headers).toBeTruthy(); - expect(headers.get('Authorization')).toEqual('BASIC cGF0cmljaWFAdGVzdC5pbnRlcnNob3AuZGU6IUludGVyU2hvcDAwIQ=='); + verify(oAuthServiceMock.fetchTokenUsingGrant(anyString(), anything(), anything())).once(); + expect(data).toHaveProperty('customer.customerNo', 'PC'); + expect(data).toHaveProperty('pgid', '6FGMJtFU2xuRpG9I3CpTS7fc0000'); + done(); + }); + }); + it('should not fetch a new token, when credentials are not entered', done => { + when(apiServiceMock.get('customers/-', anything())).thenReturn( + of({ customerNo: 'PC', customerType: 'PRIVATE' } as CustomerData) + ); + when(apiServiceMock.get('privatecustomers/-', anything())).thenReturn( + of({ customerNo: 'PC', customerType: 'PRIVATE' } as CustomerData) + ); + when(apiServiceMock.get('personalization', anything())).thenReturn(of({ pgid: '6FGMJtFU2xuRpG9I3CpTS7fc0000' })); + + userService.signInUser(undefined).subscribe(data => { + verify(oAuthServiceMock.fetchTokenUsingGrant(anyString(), anything(), anything())).never(); expect(data).toHaveProperty('customer.customerNo', 'PC'); expect(data).toHaveProperty('pgid', '6FGMJtFU2xuRpG9I3CpTS7fc0000'); done(); @@ -66,31 +97,34 @@ describe('User Service', () => { it('should login a private user when correct credentials are entered', done => { const loginDetail = { login: 'patricia@test.intershop.de', password: '!InterShop00!' }; + when(apiServiceMock.get('customers/-', anything())).thenReturn( of({ customerNo: 'PC', customerType: 'PRIVATE' } as CustomerData) ); - when(apiServiceMock.get('privatecustomers/-')).thenReturn(of({ customerNo: 'PC' } as CustomerData)); - when(apiServiceMock.get('personalization')).thenReturn(of({ pgid: '123' })); + when(apiServiceMock.get('privatecustomers/-', anything())).thenReturn(of({ customerNo: 'PC' } as CustomerData)); + when(apiServiceMock.get('personalization', anything())).thenReturn(of({ pgid: '123' })); userService.signInUser(loginDetail).subscribe(() => { verify(apiServiceMock.get(`customers/-`, anything())).once(); - verify(apiServiceMock.get(`privatecustomers/-`)).once(); - verify(apiServiceMock.get('personalization')).once(); + verify(apiServiceMock.get(`privatecustomers/-`, anything())).once(); + verify(apiServiceMock.get('personalization', anything())).once(); done(); }); }); it('should login a business user when correct credentials are entered', done => { const loginDetail = { login: 'patricia@test.intershop.de', password: '!InterShop00!' }; - when(apiServiceMock.get(anything(), anything())).thenReturn( + + when(apiServiceMock.get('customers/-', anything())).thenReturn( of({ customerNo: 'PC', customerType: 'SMBCustomer' } as CustomerData) ); - when(apiServiceMock.get('personalization')).thenReturn(of({ pgid: '123' })); + + when(apiServiceMock.get('personalization', anything())).thenReturn(of({ pgid: '123' })); userService.signInUser(loginDetail).subscribe(() => { verify(apiServiceMock.get(`customers/-`, anything())).once(); verify(apiServiceMock.get(`privatecustomers/-`, anything())).never(); - verify(apiServiceMock.get('personalization')).once(); + verify(apiServiceMock.get('personalization', anything())).once(); done(); }); }); @@ -113,12 +147,12 @@ describe('User Service', () => { when(apiServiceMock.get(anything(), anything())).thenReturn( of({ customerNo: '4711', type: 'SMBCustomer', customerType: 'SMBCustomer' } as CustomerData) ); - when(apiServiceMock.get('personalization')).thenReturn(of({ pgid: '1234' })); + when(apiServiceMock.get('personalization', anything())).thenReturn(of({ pgid: '1234' })); userService.signInUserByToken().subscribe(() => { verify(apiServiceMock.get('customers/-', anything())).once(); verify(apiServiceMock.get('privatecustomers/-', anything())).never(); - verify(apiServiceMock.get('personalization')).once(); + verify(apiServiceMock.get('personalization', anything())).once(); const [path] = capture(apiServiceMock.get).first(); expect(path).toEqual('customers/-'); done(); @@ -129,14 +163,13 @@ describe('User Service', () => { when(apiServiceMock.get(anything(), anything())).thenReturn( of({ customerNo: '4711', type: 'SMBCustomer', customerType: 'SMBCustomer' } as CustomerData) ); - when(apiServiceMock.get('personalization')).thenReturn(of({ pgid: '1234' })); + when(apiServiceMock.get('personalization', anything())).thenReturn(of({ pgid: '1234' })); userService.signInUserByToken('12345').subscribe(() => { verify(apiServiceMock.get('customers/-', anything())).once(); verify(apiServiceMock.get('privatecustomers/-', anything())).never(); - verify(apiServiceMock.get('personalization')).once(); - const [path, options] = capture(apiServiceMock.get).first(); - expect(options.headers.get(ApiService.TOKEN_HEADER_KEY)).toMatchInlineSnapshot(`"12345"`); + verify(apiServiceMock.get('personalization', anything())).once(); + const [path] = capture(apiServiceMock.get).first(); expect(path).toEqual('customers/-'); done(); }); @@ -267,6 +300,20 @@ describe('User Service', () => { }); }); + describe('Revoke Api Token', () => { + beforeEach(() => { + when(apiServiceMock.put(anyString())).thenReturn(of({})); + }); + + it("should revoke an existing api token when 'logoutUser' is called", done => { + userService.logoutUser().subscribe(() => { + verify(apiServiceMock.put('token/logout')).once(); + verify(apiTokenServiceMock.removeApiToken()).once(); + done(); + }); + }); + }); + describe('Updates a customer', () => { it('should return an error when called and the customer parameter is missing', done => { when(apiServiceMock.put(anything(), anything())).thenReturn(of({})); diff --git a/src/app/core/services/user/user.service.ts b/src/app/core/services/user/user.service.ts index 58c7a975c6..0ce951adef 100644 --- a/src/app/core/services/user/user.service.ts +++ b/src/app/core/services/user/user.service.ts @@ -1,9 +1,10 @@ import { HttpHeaders } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { Store, select } from '@ngrx/store'; +import { OAuthService, TokenResponse } from 'angular-oauth2-oidc'; import { pick } from 'lodash-es'; -import { Observable, combineLatest, forkJoin, of, throwError } from 'rxjs'; -import { concatMap, first, map, switchMap, take, withLatestFrom } from 'rxjs/operators'; +import { Observable, combineLatest, defer, forkJoin, from, of, throwError } from 'rxjs'; +import { concatMap, first, map, switchMap, take, tap, withLatestFrom } from 'rxjs/operators'; import { AppFacade } from 'ish-core/facades/app.facade'; import { Address } from 'ish-core/models/address/address.model'; @@ -19,12 +20,14 @@ import { } from 'ish-core/models/customer/customer.model'; import { PasswordReminderUpdate } from 'ish-core/models/password-reminder-update/password-reminder-update.model'; import { PasswordReminder } from 'ish-core/models/password-reminder/password-reminder.model'; +import { FetchTokenOptions, GrantType } from 'ish-core/models/token/token.interface'; import { UserCostCenter } from 'ish-core/models/user-cost-center/user-cost-center.model'; import { UserMapper } from 'ish-core/models/user/user.mapper'; import { User } from 'ish-core/models/user/user.model'; import { ApiService, AvailableOptions, unpackEnvelope } from 'ish-core/services/api/api.service'; import { getUserPermissions } from 'ish-core/store/customer/authorization'; import { getLoggedInCustomer, getLoggedInUser } from 'ish-core/store/customer/user'; +import { ApiTokenService } from 'ish-core/utils/api-token/api-token.service'; import { whenTruthy } from 'ish-core/utils/operators'; import { encodeResourceID } from 'ish-core/utils/url-resource-ids'; @@ -50,7 +53,13 @@ interface CreateBusinessCustomerType extends Customer { */ @Injectable({ providedIn: 'root' }) export class UserService { - constructor(private apiService: ApiService, private appFacade: AppFacade, private store: Store) {} + constructor( + private apiService: ApiService, + private apiTokenService: ApiTokenService, + private appFacade: AppFacade, + private store: Store, + private oauthService: OAuthService + ) {} /** * Sign in an existing user with the given login credentials (login, password). @@ -61,53 +70,73 @@ export class UserService { * For business customers user data are returned by a separate call (getCompanyUserData). */ signInUser(loginCredentials: Credentials): Observable { - const headers = new HttpHeaders().set( - ApiService.AUTHORIZATION_HEADER_KEY, - `BASIC ${window.btoa(`${loginCredentials.login}:${loginCredentials.password}`)}` + return defer(() => + loginCredentials + ? this.fetchToken('password', { username: loginCredentials.login, password: loginCredentials.password }).pipe( + switchMap(() => this.fetchCustomer()) + ) + : this.fetchCustomer() ); - - return this.fetchCustomer({ headers }); } + /** * Sign in an existing user with the given token or if no token is given, using token stored in cookie. * - * @param token The token that is used to login user. + * @param token The refresh token that is used to login user. * @returns The logged in customer data. * For private customers user data are also returned. * For business customers user data are returned by a separate call (getCompanyUserData). */ signInUserByToken(token?: string): Observable { if (token) { - return this.fetchCustomer({ - headers: new HttpHeaders().set(ApiService.TOKEN_HEADER_KEY, token), - }); + return this.fetchToken('refresh_token', { refresh_token: token }).pipe(switchMap(() => this.fetchCustomer())); } else { return this.fetchCustomer({ skipApiErrorHandling: true }); } } - private fetchCustomer(options?: AvailableOptions): Observable { + private fetchCustomer(options: AvailableOptions = {}): Observable { return this.apiService.get('customers/-', options).pipe( withLatestFrom(this.appFacade.isAppTypeREST$), concatMap(([data, isAppTypeRest]) => forkJoin([ isAppTypeRest && data.customerType === 'PRIVATE' - ? this.apiService.get('privatecustomers/-') + ? this.apiService.get('privatecustomers/-', options) : of(data), - this.apiService.get<{ pgid: string }>('personalization').pipe(map(data => data.pgid)), + this.apiService.get<{ pgid: string }>('personalization', options).pipe(map(data => data.pgid)), ]) ), map(([data, pgid]) => ({ ...CustomerMapper.mapLoginData(data), pgid })) ); } + /** + * Fetches a new user token. Based on the grantType the user has to apply certain token options to the method. + * + * @param grantType The given type ('anonymous', 'password', 'client_credentials', 'refresh_token') is used to specify, how the user token should be fetched. + */ + fetchToken(grantType: T): Observable; + fetchToken>(grantType: T, options: R): Observable; + fetchToken>( + grantType: T, + options?: R + ): Observable { + return from( + this.oauthService.fetchTokenUsingGrant( + grantType, + options ?? {}, + new HttpHeaders({ 'content-type': 'application/x-www-form-urlencoded' }) + ) + ); + } + /** * Creates a new user for the given data. * * @param body The user data (customer, user, credentials, address) to create a new user. The new user is not logged in after creation. */ createUser(body: CustomerRegistrationType): Observable { - if (!body || !body.customer || (!body.user && !body.userId) || !body.address) { + if (!body?.customer || (!body?.user && !body?.userId) || !body?.address) { return throwError(() => new Error('createUser() called without required body data')); } @@ -164,7 +193,7 @@ export class UserService { .post(AppFacade.getCustomerRestResource(body.customer.isBusinessCustomer, isAppTypeRest), newCustomer, { captcha: pick(body, ['captcha', 'captchaAction']), }) - .pipe(map(() => ({ customer: body.customer, user: body.user }))) + .pipe(map(() => ({ customer: body.customer, user: body.user }))) ) ); } @@ -175,7 +204,7 @@ export class UserService { * @param body The user data (customer, user ) to update the user. */ updateUser(body: CustomerUserType, credentials?: Credentials): Observable { - if (!body || !body.customer || !body.user) { + if (!body?.customer || !body?.user) { return throwError(() => new Error('updateUser() called without required body data')); } @@ -246,6 +275,14 @@ export class UserService { ); } + /** + * Logs out the current user associated with the specified authentication token. + * All (refresh) tokens issued for this user will expire and become invalid. + */ + logoutUser() { + return this.apiService.put('token/logout').pipe(tap(() => this.apiTokenService.removeApiToken())); + } + /** * Updates the customer data of the (currently logged in) b2b customer. * diff --git a/src/app/core/store/core/configuration/configuration.effects.ts b/src/app/core/store/core/configuration/configuration.effects.ts index 06a16d63a4..3a315fc280 100644 --- a/src/app/core/store/core/configuration/configuration.effects.ts +++ b/src/app/core/store/core/configuration/configuration.effects.ts @@ -16,8 +16,8 @@ import { distinctCompareWith, mapToPayload, whenTruthy } from 'ish-core/utils/op import { StatePropertiesService } from 'ish-core/utils/state-transfer/state-properties.service'; import { - applyConfiguration, ConfigurationType, + applyConfiguration, loadSingleServerTranslation, loadSingleServerTranslationSuccess, } from './configuration.actions'; diff --git a/src/app/core/store/customer/addresses/addresses.actions.ts b/src/app/core/store/customer/addresses/addresses.actions.ts index 2f9ff5aa8f..a72633552d 100644 --- a/src/app/core/store/customer/addresses/addresses.actions.ts +++ b/src/app/core/store/customer/addresses/addresses.actions.ts @@ -21,6 +21,8 @@ export const createCustomerAddressSuccess = createAction( payload<{ address: Address }>() ); +export const updateCustomerAddress = createAction('[Address] Update Customer Address', payload<{ address: Address }>()); + export const updateCustomerAddressFail = createAction('[Address API] Update Customer Address Fail', httpError()); export const updateCustomerAddressSuccess = createAction( diff --git a/src/app/core/store/customer/addresses/addresses.effects.spec.ts b/src/app/core/store/customer/addresses/addresses.effects.spec.ts index aae8de8be1..46597c97c0 100644 --- a/src/app/core/store/customer/addresses/addresses.effects.spec.ts +++ b/src/app/core/store/customer/addresses/addresses.effects.spec.ts @@ -23,6 +23,9 @@ import { deleteCustomerAddressSuccess, loadAddresses, loadAddressesSuccess, + updateCustomerAddress, + updateCustomerAddressFail, + updateCustomerAddressSuccess, } from './addresses.actions'; import { AddressesEffects } from './addresses.effects'; @@ -37,6 +40,7 @@ describe('Addresses Effects', () => { when(addressServiceMock.getCustomerAddresses()).thenReturn(of([{ urn: 'test' } as Address])); when(addressServiceMock.createCustomerAddress(anyString(), anything())).thenReturn(of({ urn: 'test' } as Address)); + when(addressServiceMock.updateCustomerAddress(anyString(), anything())).thenReturn(of({ urn: 'test' } as Address)); when(addressServiceMock.deleteCustomerAddress(anyString(), anything())).thenReturn(of('123')); TestBed.configureTestingModule({ @@ -155,4 +159,44 @@ describe('Addresses Effects', () => { expect(effects.deleteCustomerAddress$).toBeObservable(expected$); }); }); + + describe('updateCustomerAddress$', () => { + it('should call the addressService for updateCustomerAddress', done => { + const address = { urn: '123' } as Address; + const action = updateCustomerAddress({ address }); + actions$ = of(action); + + effects.updateCustomerAddress$.subscribe(() => { + verify(addressServiceMock.updateCustomerAddress('-', anything())).once(); + done(); + }); + }); + + it('should map to action of type updateCustomerSuccess', () => { + const address = { urn: '123' } as Address; + const action = updateCustomerAddress({ address }); + const completion = updateCustomerAddressSuccess({ address }); + const completion2 = displaySuccessMessage({ + message: 'account.addresses.address_updated.message', + }); + actions$ = hot('-a-', { a: action }); + const expected$ = cold('-(cd)', { c: completion, d: completion2 }); + + expect(effects.updateCustomerAddress$).toBeObservable(expected$); + }); + + it('should map invalid request to action of type updateCustomerFail', () => { + when(addressServiceMock.updateCustomerAddress('-', anything())).thenReturn( + throwError(() => makeHttpError({ message: 'invalid' })) + ); + const address = { urn: '123' } as Address; + const action = updateCustomerAddress({ address }); + const error = makeHttpError({ message: 'invalid' }); + const completion = updateCustomerAddressFail({ error }); + actions$ = hot('-a-a-a', { a: action }); + const expected$ = cold('-c-c-c', { c: completion }); + + expect(effects.updateCustomerAddress$).toBeObservable(expected$); + }); + }); }); diff --git a/src/app/core/store/customer/addresses/addresses.effects.ts b/src/app/core/store/customer/addresses/addresses.effects.ts index 48b4b50d58..e47fc4c30e 100644 --- a/src/app/core/store/customer/addresses/addresses.effects.ts +++ b/src/app/core/store/customer/addresses/addresses.effects.ts @@ -18,6 +18,9 @@ import { loadAddresses, loadAddressesFail, loadAddressesSuccess, + updateCustomerAddress, + updateCustomerAddressFail, + updateCustomerAddressSuccess, } from './addresses.actions'; @Injectable() @@ -59,6 +62,27 @@ export class AddressesEffects { ) ); + /** + * Updates a customer address. + */ + updateCustomerAddress$ = createEffect(() => + this.actions$.pipe( + ofType(updateCustomerAddress), + mapToPayloadProperty('address'), + withLatestFrom(this.store.pipe(select(getLoggedInCustomer))), + filter(([address, customer]) => !!address || !!customer), + mergeMap(([address]) => + this.addressService.updateCustomerAddress('-', address).pipe( + mergeMap(() => [ + updateCustomerAddressSuccess({ address }), + displaySuccessMessage({ message: 'account.addresses.address_updated.message' }), + ]), + mapErrorToAction(updateCustomerAddressFail) + ) + ) + ) + ); + /** * Deletes a customer address. */ diff --git a/src/app/core/store/customer/addresses/addresses.reducer.ts b/src/app/core/store/customer/addresses/addresses.reducer.ts index e6424c16bb..8bcbc60cbf 100644 --- a/src/app/core/store/customer/addresses/addresses.reducer.ts +++ b/src/app/core/store/customer/addresses/addresses.reducer.ts @@ -21,6 +21,7 @@ import { loadAddresses, loadAddressesFail, loadAddressesSuccess, + updateCustomerAddress, updateCustomerAddressFail, updateCustomerAddressSuccess, } from './addresses.actions'; @@ -43,6 +44,7 @@ export const addressesReducer = createReducer( loadAddresses, createCustomerAddress, createBasketAddress, + updateCustomerAddress, updateBasketAddress, deleteCustomerAddress, deleteBasketShippingAddress diff --git a/src/app/core/store/customer/basket/basket-items.effects.spec.ts b/src/app/core/store/customer/basket/basket-items.effects.spec.ts index 4477d42041..a0931347a7 100644 --- a/src/app/core/store/customer/basket/basket-items.effects.spec.ts +++ b/src/app/core/store/customer/basket/basket-items.effects.spec.ts @@ -31,10 +31,10 @@ import { loadBasketSuccess, updateBasketItem, updateBasketItemFail, + updateBasketItemSuccess, updateBasketItems, updateBasketItemsFail, updateBasketItemsSuccess, - updateBasketItemSuccess, validateBasket, } from './basket.actions'; diff --git a/src/app/core/store/customer/basket/basket-items.effects.ts b/src/app/core/store/customer/basket/basket-items.effects.ts index aeb3e45663..4b24d8304f 100644 --- a/src/app/core/store/customer/basket/basket-items.effects.ts +++ b/src/app/core/store/customer/basket/basket-items.effects.ts @@ -38,10 +38,10 @@ import { loadBasket, updateBasketItem, updateBasketItemFail, + updateBasketItemSuccess, updateBasketItems, updateBasketItemsFail, updateBasketItemsSuccess, - updateBasketItemSuccess, validateBasket, } from './basket.actions'; import { getCurrentBasket, getCurrentBasketId } from './basket.selectors'; diff --git a/src/app/core/store/customer/basket/basket-validation.effects.spec.ts b/src/app/core/store/customer/basket/basket-validation.effects.spec.ts index c5a0a5c39b..535bb6df7f 100644 --- a/src/app/core/store/customer/basket/basket-validation.effects.spec.ts +++ b/src/app/core/store/customer/basket/basket-validation.effects.spec.ts @@ -8,6 +8,7 @@ import { Observable, noop, of, throwError } from 'rxjs'; import { anything, instance, mock, verify, when } from 'ts-mockito'; import { BasketValidation } from 'ish-core/models/basket-validation/basket-validation.model'; +import { CheckoutStepType } from 'ish-core/models/checkout/checkout-step.type'; import { Product } from 'ish-core/models/product/product.model'; import { BasketService } from 'ish-core/services/basket/basket.service'; import { CoreStoreModule } from 'ish-core/store/core/core-store.module'; @@ -97,7 +98,7 @@ describe('Basket Validation Effects', () => { const action = startCheckout(); const completion = continueCheckout({ - targetStep: 1, + targetStep: CheckoutStepType.Addresses, }); actions$ = hot('-a', { a: action }); const expected$ = cold('-c', { c: completion }); @@ -298,7 +299,7 @@ describe('Basket Validation Effects', () => { }); it('should call the basketService for validateBasketAndContinueCheckout', done => { - const action = continueCheckout({ targetStep: 1 }); + const action = continueCheckout({ targetStep: CheckoutStepType.Addresses }); actions$ = of(action); effects.validateBasketAndContinueCheckout$.subscribe(() => { @@ -308,7 +309,7 @@ describe('Basket Validation Effects', () => { }); it('should map to action of type ContinueCheckoutSuccess if targetStep is not 5 (order creation)', () => { - const action = continueCheckout({ targetStep: 1 }); + const action = continueCheckout({ targetStep: CheckoutStepType.Addresses }); const completion = continueCheckoutSuccess({ targetRoute: '/checkout/address', basketValidation, @@ -320,7 +321,7 @@ describe('Basket Validation Effects', () => { }); it('should map to action of type CreateOrder if targetStep is 5 (order creation)', () => { - const action = continueCheckout({ targetStep: 5 }); + const action = continueCheckout({ targetStep: CheckoutStepType.Receipt }); const completion1 = continueCheckoutSuccess({ targetRoute: undefined, basketValidation }); const completion2 = createOrder(); actions$ = hot('-a----a----a', { a: action }); @@ -336,7 +337,7 @@ describe('Basket Validation Effects', () => { }) ); - const action = continueCheckout({ targetStep: 5 }); + const action = continueCheckout({ targetStep: CheckoutStepType.Receipt }); const completion1 = continueCheckoutSuccess({ targetRoute: undefined, basketValidation }); const completion2 = submitBasket(); actions$ = hot('-a----a----a', { a: action }); @@ -350,7 +351,7 @@ describe('Basket Validation Effects', () => { throwError(() => makeHttpError({ message: 'invalid' })) ); - const action = continueCheckout({ targetStep: 1 }); + const action = continueCheckout({ targetStep: CheckoutStepType.Addresses }); const completion = continueCheckoutFail({ error: makeHttpError({ message: 'invalid' }) }); actions$ = hot('-a', { a: action }); const expected$ = cold('-c', { c: completion }); @@ -392,7 +393,7 @@ describe('Basket Validation Effects', () => { })); it('should map to action of type ContinueCheckoutWithIssues if basket is not valid', () => { - const action = continueCheckout({ targetStep: 1 }); + const action = continueCheckout({ targetStep: CheckoutStepType.Addresses }); basketValidation.results.valid = false; const completion = continueCheckoutWithIssues({ targetRoute: '/checkout/address', diff --git a/src/app/core/store/customer/basket/basket-validation.effects.ts b/src/app/core/store/customer/basket/basket-validation.effects.ts index 8cee7683e9..e7a2c5a545 100644 --- a/src/app/core/store/customer/basket/basket-validation.effects.ts +++ b/src/app/core/store/customer/basket/basket-validation.effects.ts @@ -11,6 +11,7 @@ import { BasketValidationResultType, BasketValidationScopeType, } from 'ish-core/models/basket-validation/basket-validation.model'; +import { CheckoutStepType } from 'ish-core/models/checkout/checkout-step.type'; import { BasketService } from 'ish-core/services/basket/basket.service'; import { getServerConfigParameter } from 'ish-core/store/core/server-config'; import { createOrder } from 'ish-core/store/customer/orders'; @@ -41,14 +42,18 @@ export class BasketValidationEffects { private basketService: BasketService ) {} - private validationSteps: { scopes: BasketValidationScopeType[]; route: string }[] = [ - { scopes: ['Products', 'Value', 'CostCenter'], route: '/basket' }, - { scopes: ['InvoiceAddress', 'ShippingAddress', 'Addresses'], route: '/checkout/address' }, - { scopes: ['Shipping'], route: '/checkout/shipping' }, - { scopes: ['Payment'], route: '/checkout/payment' }, - { scopes: ['All', 'CostCenter'], route: '/checkout/review' }, // ToDo: has to be changed if the cost center approval has been implemented - { scopes: ['All'], route: 'auto' }, // targetRoute will be calculated in dependence of the validation result - ]; + // validation step for each checkout step type + private validationSteps: { [targetStep: string | number]: { scopes: BasketValidationScopeType[]; route: string } } = { + [CheckoutStepType.BeforeCheckout]: { scopes: ['Products', 'Promotion', 'Value', 'CostCenter'], route: '/basket' }, + [CheckoutStepType.Addresses]: { + scopes: ['InvoiceAddress', 'ShippingAddress', 'Addresses'], + route: '/checkout/address', + }, + [CheckoutStepType.Shipping]: { scopes: ['Shipping'], route: '/checkout/shipping' }, + [CheckoutStepType.Payment]: { scopes: ['Payment'], route: '/checkout/payment' }, + [CheckoutStepType.Review]: { scopes: ['All', 'CostCenter'], route: '/checkout/review' }, // ToDo: has to be changed if the cost center approval has been implemented + [CheckoutStepType.Receipt]: { scopes: ['All'], route: 'auto' }, // targetRoute will be calculated in dependence of the validation result + }; /** * Jumps to the first checkout step (no basket acceleration) @@ -58,7 +63,7 @@ export class BasketValidationEffects { ofType(startCheckout), withLatestFrom(this.store.pipe(select(getServerConfigParameter('basket.acceleration')))), filter(([, acc]) => !acc), - map(() => continueCheckout({ targetStep: 1 })) + map(() => continueCheckout({ targetStep: CheckoutStepType.Addresses })) ) ); @@ -71,7 +76,7 @@ export class BasketValidationEffects { withLatestFrom(this.store.pipe(select(getServerConfigParameter('basket.acceleration')))), filter(([, acc]) => acc), concatMap(() => - this.basketService.validateBasket(this.validationSteps[0].scopes).pipe( + this.basketService.validateBasket(this.validationSteps[CheckoutStepType.BeforeCheckout].scopes).pipe( map(basketValidation => startCheckoutSuccess({ basketValidation })), mapErrorToAction(startCheckoutFail) ) @@ -91,11 +96,11 @@ export class BasketValidationEffects { filter(results => results.valid && !results.adjusted), concatMap(() => this.basketService - .validateBasket(this.validationSteps[4].scopes) + .validateBasket(this.validationSteps[CheckoutStepType.Review].scopes) .pipe( concatMap(basketValidation => basketValidation?.results?.valid - ? from(this.router.navigate([this.validationSteps[4].route])) + ? from(this.router.navigate([this.validationSteps[CheckoutStepType.Review].route])) : this.jumpToTargetRoute('auto', basketValidation?.results) ) ) @@ -140,7 +145,7 @@ export class BasketValidationEffects { withLatestFrom(this.store.pipe(select(getCurrentBasket))), concatMap(([basketValidation, basket]) => basketValidation.results.valid - ? targetStep === 5 && !basketValidation.results.adjusted + ? targetStep === CheckoutStepType.Receipt && !basketValidation.results.adjusted ? basket.approval?.approvalRequired ? [continueCheckoutSuccess({ targetRoute: undefined, basketValidation }), submitBasket()] : [continueCheckoutSuccess({ targetRoute: undefined, basketValidation }), createOrder()] @@ -210,7 +215,12 @@ export class BasketValidationEffects { scopes = this.extractScopes(results.infos); } - const foundStep = this.validationSteps.find(step => intersection(step.scopes, scopes).length); + const foundKey = Object.keys(this.validationSteps).find( + key => intersection(this.validationSteps[key].scopes, scopes).length + ); + + const foundStep = this.validationSteps[foundKey]; + if (foundStep) { return from(this.router.navigate([foundStep.route], { queryParams: { error: true } })); } diff --git a/src/app/core/store/customer/basket/basket.actions.ts b/src/app/core/store/customer/basket/basket.actions.ts index a63da182e2..5947b17eff 100644 --- a/src/app/core/store/customer/basket/basket.actions.ts +++ b/src/app/core/store/customer/basket/basket.actions.ts @@ -6,6 +6,7 @@ import { Attribute } from 'ish-core/models/attribute/attribute.model'; import { BasketInfo } from 'ish-core/models/basket-info/basket-info.model'; import { BasketValidation, BasketValidationScopeType } from 'ish-core/models/basket-validation/basket-validation.model'; import { Basket } from 'ish-core/models/basket/basket.model'; +import { CheckoutStepType } from 'ish-core/models/checkout/checkout-step.type'; import { ErrorFeedback } from 'ish-core/models/http-error/http-error.model'; import { LineItemUpdate } from 'ish-core/models/line-item-update/line-item-update.model'; import { LineItem } from 'ish-core/models/line-item/line-item.model'; @@ -110,7 +111,7 @@ export const startCheckoutFail = createAction('[Basket API] Start the checkout p export const continueCheckout = createAction( '[Basket] Validate Basket and continue checkout', - payload<{ targetStep: number }>() + payload<{ targetStep: CheckoutStepType }>() ); export const continueCheckoutFail = createAction( @@ -283,3 +284,19 @@ export const updateConcardisCvcLastUpdatedSuccess = createAction( '[Basket API] Update CvcLastUpdated for Concardis Credit Card Success', payload<{ paymentInstrument: PaymentInstrument }>() ); + +export const submitOrder = createAction('[Basket] Basket Submit Order'); + +export const setBasketDesiredDeliveryDate = createAction( + '[Basket] Add or Update Basket Desired Delivery Date', + payload<{ desiredDeliveryDate: string }>() // international iso date format yyyy-mm-dd +); + +export const setBasketDesiredDeliveryDateFail = createAction( + '[Basket API] Add or Update Basket Desired Delivery Date Fail', + httpError() +); + +export const setBasketDesiredDeliveryDateSuccess = createAction( + '[Basket API] Add or Update Basket Desired Delivery Date Success' +); diff --git a/src/app/core/store/customer/basket/basket.effects.spec.ts b/src/app/core/store/customer/basket/basket.effects.spec.ts index 2dc72c32fc..a49ea6f60b 100644 --- a/src/app/core/store/customer/basket/basket.effects.spec.ts +++ b/src/app/core/store/customer/basket/basket.effects.spec.ts @@ -8,6 +8,7 @@ import { EMPTY, Observable, of, throwError } from 'rxjs'; import { anyString, anything, instance, mock, verify, when } from 'ts-mockito'; import { Basket } from 'ish-core/models/basket/basket.model'; +import { LineItem } from 'ish-core/models/line-item/line-item.model'; import { BasketService } from 'ish-core/services/basket/basket.service'; import { CoreStoreModule } from 'ish-core/store/core/core-store.module'; import { loadServerConfigSuccess } from 'ish-core/store/core/server-config'; @@ -37,8 +38,12 @@ import { setBasketAttribute, setBasketAttributeFail, setBasketAttributeSuccess, + setBasketDesiredDeliveryDate, + setBasketDesiredDeliveryDateFail, + setBasketDesiredDeliveryDateSuccess, submitBasket, submitBasketFail, + submitOrder, updateBasket, updateBasketCostCenter, updateBasketFail, @@ -63,7 +68,11 @@ describe('Basket Effects', () => { RouterTestingModule.withRoutes([{ path: '**', children: [] }]), ], providers: [ - { provide: ApiTokenService, useFactory: () => instance(mock(ApiTokenService)) }, + { + provide: ApiTokenService, + useFactory: () => instance(mock(ApiTokenService)), + useValue: { apiToken$: of({ apiToken: 'apiToken' }) }, + }, { provide: BasketService, useFactory: () => instance(basketServiceMock) }, BasketEffects, provideMockActions(() => actions$), @@ -213,9 +222,9 @@ describe('Basket Effects', () => { effects.recalculateBasketAfterCurrencyChange$.subscribe(action => { expect(action).toMatchInlineSnapshot(` - [Basket Internal] Update Basket: - update: {"calculated":true} - `); + [Basket Internal] Update Basket: + update: {"calculated":true} + `); done(); }); }); @@ -388,6 +397,58 @@ describe('Basket Effects', () => { }); }); + describe('setBasketDesiredDeliveryDate$', () => { + beforeEach(() => { + when(basketServiceMock.updateBasketItemsDesiredDeliveryDate(anything(), anything())).thenReturn(of([])); + store.dispatch( + loadBasketSuccess({ + basket: { + id: 'BID', + attributes: [{ name: 'desiredDeliveryDate', value: desiredDeliveryDate }], + lineItems, + } as Basket, + }) + ); + }); + const desiredDeliveryDate = '2022-02-20'; + const lineItems: LineItem[] = [{ id: '1', desiredDeliveryDate: undefined } as LineItem]; + + it('should call the basketService for setBasketDesiredDeliveryDate', done => { + const action = setBasketDesiredDeliveryDate({ desiredDeliveryDate }); + actions$ = of(action); + + effects.setBasketDesiredDeliveryDate$.subscribe(() => { + verify(basketServiceMock.updateBasketItemsDesiredDeliveryDate(desiredDeliveryDate, anything())).once(); + done(); + }); + }); + + it('should map to actions of type setBasketAttribute and setBasketDesiredDeliveryDate', () => { + const action = setBasketDesiredDeliveryDate({ desiredDeliveryDate }); + const completion1 = setBasketAttribute({ + attribute: { name: 'desiredDeliveryDate', value: desiredDeliveryDate }, + }); + const completion2 = setBasketDesiredDeliveryDateSuccess(); + actions$ = hot('-a', { a: action }); + const expected$ = cold('-(cd)', { c: completion1, d: completion2 }); + + expect(effects.setBasketDesiredDeliveryDate$).toBeObservable(expected$); + }); + + it('should map invalid request to action of type setBasketDesiredDeliveryDateFail', () => { + when(basketServiceMock.updateBasketItemsDesiredDeliveryDate(anything(), anything())).thenReturn( + throwError(() => makeHttpError({ message: 'invalid' })) + ); + + const action = setBasketDesiredDeliveryDate({ desiredDeliveryDate }); + const completion = setBasketDesiredDeliveryDateFail({ error: makeHttpError({ message: 'invalid' }) }); + actions$ = hot('-a-a-a', { a: action }); + const expected$ = cold('-c-c-c', { c: completion }); + + expect(effects.setBasketDesiredDeliveryDate$).toBeObservable(expected$); + }); + }); + describe('setCustomAttributeToBasket$', () => { beforeEach(() => { when(basketServiceMock.createBasketAttribute(anything())).thenReturn(of(undefined)); @@ -570,6 +631,34 @@ describe('Basket Effects', () => { }); }); + describe('loadBasketOnBasketPage$', () => { + it('should fire LoadBasket when route basket is navigated', () => { + router.navigateByUrl('/basket'); + + const action = routerTestNavigatedAction({ + routerState: { url: '/basket' }, + }); + actions$ = of(action); + + const completion = loadBasket(); + actions$ = hot('-a', { a: action }); + const expected$ = cold('-c', { c: completion }); + + expect(effects.loadBasketOnBasketPage$).toBeObservable(expected$); + }); + + it('should not fire LoadBasket when route /something is navigated', () => { + router.navigateByUrl('/something'); + + actions$ = of( + routerTestNavigatedAction({ + routerState: { url: '/something' }, + }) + ); + expect(effects.loadBasketOnBasketPage$).toBeObservable(cold('|')); + }); + }); + describe('createRequisition$', () => { beforeEach(() => { store.dispatch(loadBasketSuccess({ basket: { id: 'BID' } as Basket })); @@ -610,4 +699,74 @@ describe('Basket Effects', () => { expect(effects.createRequisition$).toBeObservable(expected$); }); }); + + describe('submitOrder$', () => { + beforeEach(() => { + when(basketServiceMock.updateBasketItemsDesiredDeliveryDate(anything(), anything())).thenReturn(of([])); + store.dispatch( + loadBasketSuccess({ + basket: { + id: 'BID', + attributes: [{ name: 'desiredDeliveryDate', value: desiredDeliveryDate }], + lineItems, + } as Basket, + }) + ); + }); + const desiredDeliveryDate = '2022-02-20'; + const lineItems: LineItem[] = [{ id: '1', desiredDeliveryDate: undefined } as LineItem]; + + it('should call the basketService for submitOrder if the basket has a desired delivery date', done => { + const action = submitOrder(); + actions$ = of(action); + + effects.submitOrder$.subscribe(() => { + verify(basketServiceMock.updateBasketItemsDesiredDeliveryDate(desiredDeliveryDate, anything())).once(); + done(); + }); + }); + + it('should not call the basketService for submitOrder if the basket has no desired delivery date', done => { + store.dispatch( + loadBasketSuccess({ + basket: { id: 'BID', attributes: [] } as Basket, + }) + ); + + const action = submitOrder(); + actions$ = of(action); + + effects.submitOrder$.subscribe({ + next: () => { + verify(basketServiceMock.updateBasketItemsDesiredDeliveryDate(anything(), anything())).never(); + }, + error: fail, + complete: done, + }); + }); + + it('should map a valid request to action of type continueCheckout', done => { + actions$ = of(submitOrder()); + + effects.submitOrder$.subscribe(action => { + expect(action).toMatchInlineSnapshot(` + [Basket] Validate Basket and continue checkout: + targetStep: 5 + `); + done(); + }); + }); + + it('should map an invalid request to action of type setBasketDesiredDeliveryDateFail', () => { + when(basketServiceMock.updateBasketItemsDesiredDeliveryDate(anything(), anything())).thenReturn( + throwError(() => makeHttpError({ message: 'invalid' })) + ); + const action = submitOrder(); + const completion = setBasketDesiredDeliveryDateFail({ error: makeHttpError({ message: 'invalid' }) }); + actions$ = hot('-a-a-a', { a: action }); + const expected$ = cold('-c-c-c', { c: completion }); + + expect(effects.submitOrder$).toBeObservable(expected$); + }); + }); }); diff --git a/src/app/core/store/customer/basket/basket.effects.ts b/src/app/core/store/customer/basket/basket.effects.ts index 07b946baf3..bdd11d0f20 100644 --- a/src/app/core/store/customer/basket/basket.effects.ts +++ b/src/app/core/store/customer/basket/basket.effects.ts @@ -16,7 +16,9 @@ import { withLatestFrom, } from 'rxjs/operators'; +import { AttributeHelper } from 'ish-core/models/attribute/attribute.helper'; import { Basket } from 'ish-core/models/basket/basket.model'; +import { CheckoutStepType } from 'ish-core/models/checkout/checkout-step.type'; import { BasketService } from 'ish-core/services/basket/basket.service'; import { getCurrentCurrency } from 'ish-core/store/core/configuration'; import { mapToRouterState } from 'ish-core/store/core/router'; @@ -26,6 +28,7 @@ import { ApiTokenService } from 'ish-core/utils/api-token/api-token.service'; import { mapErrorToAction, mapToPayloadProperty, mapToProperty } from 'ish-core/utils/operators'; import { + continueCheckout, createBasket, createBasketFail, createBasketSuccess, @@ -47,9 +50,13 @@ import { setBasketAttribute, setBasketAttributeFail, setBasketAttributeSuccess, + setBasketDesiredDeliveryDate, + setBasketDesiredDeliveryDateFail, + setBasketDesiredDeliveryDateSuccess, submitBasket, submitBasketFail, submitBasketSuccess, + submitOrder, updateBasket, updateBasketCostCenter, updateBasketFail, @@ -197,6 +204,31 @@ export class BasketEffects { ) ); + /** + * Sets a desired delivery date at the current basket and each line item. + */ + setBasketDesiredDeliveryDate$ = createEffect(() => + this.actions$.pipe( + ofType(setBasketDesiredDeliveryDate), + mapToPayloadProperty('desiredDeliveryDate'), + withLatestFrom(this.store.pipe(select(getCurrentBasket))), + mergeMap(([date, basket]) => + this.basketService.updateBasketItemsDesiredDeliveryDate(date, basket?.lineItems).pipe( + switchMap(() => [ + setBasketAttribute({ + attribute: { + name: 'desiredDeliveryDate', + value: date, + }, + }), + setBasketDesiredDeliveryDateSuccess(), + ]), + mapErrorToAction(setBasketDesiredDeliveryDateFail) + ) + ) + ) + ); + /** * Add or update an attribute at the basket. */ @@ -307,6 +339,18 @@ export class BasketEffects { ) ); + /** + * Trigger LoadBasket action after the user navigated to a basket route + */ + loadBasketOnBasketPage$ = createEffect(() => + this.actions$.pipe( + ofType(routerNavigatedAction), + mapToRouterState(), + filter(routerState => /^\/basket/.test(routerState.url)), + map(() => loadBasket()) + ) + ); + /** * Creates a requisition based on the given basket, if approval is required */ @@ -323,6 +367,32 @@ export class BasketEffects { ) ); + /** + * Before the basket is submitted the desired delivery date will be updated at the basket line items if necessary + * Afterwards the basket validation is triggered + */ + submitOrder$ = createEffect(() => + this.actions$.pipe( + ofType(submitOrder), + withLatestFrom(this.store.pipe(select(getCurrentBasket))), + concatMap(([, basket]) => { + const desiredDeliveryDate: string = AttributeHelper.getAttributeValueByAttributeName( + basket.attributes, + 'desiredDeliveryDate' + ); + + return ( + desiredDeliveryDate + ? this.basketService.updateBasketItemsDesiredDeliveryDate(desiredDeliveryDate, basket.lineItems) + : of([]) + ).pipe( + map(() => continueCheckout({ targetStep: CheckoutStepType.Receipt })), + mapErrorToAction(setBasketDesiredDeliveryDateFail) + ); + }) + ) + ); + /** check whether a specific custom attribute exists at basket. * * @param basket diff --git a/src/app/core/store/customer/basket/basket.reducer.ts b/src/app/core/store/customer/basket/basket.reducer.ts index 31a229cdc4..81133ee51a 100644 --- a/src/app/core/store/customer/basket/basket.reducer.ts +++ b/src/app/core/store/customer/basket/basket.reducer.ts @@ -57,6 +57,9 @@ import { setBasketAttribute, setBasketAttributeFail, setBasketAttributeSuccess, + setBasketDesiredDeliveryDate, + setBasketDesiredDeliveryDateFail, + setBasketDesiredDeliveryDateSuccess, setBasketPayment, setBasketPaymentFail, setBasketPaymentSuccess, @@ -70,10 +73,10 @@ import { updateBasketFail, updateBasketItem, updateBasketItemFail, + updateBasketItemSuccess, updateBasketItems, updateBasketItemsFail, updateBasketItemsSuccess, - updateBasketItemSuccess, updateBasketPayment, updateBasketPaymentFail, updateBasketPaymentSuccess, @@ -143,7 +146,8 @@ export const basketReducer = createReducer( submitBasket, updateConcardisCvcLastUpdated, startCheckout, - mergeBasketInProgress + mergeBasketInProgress, + setBasketDesiredDeliveryDate ), unsetLoadingOn(addPromotionCodeToBasketSuccess, addPromotionCodeToBasketFail, loadBasketSuccess), unsetLoadingAndErrorOn( @@ -163,7 +167,8 @@ export const basketReducer = createReducer( loadBasketEligiblePaymentMethodsSuccess, updateConcardisCvcLastUpdatedSuccess, submitBasketSuccess, - startCheckoutSuccess + startCheckoutSuccess, + setBasketDesiredDeliveryDateSuccess ), setErrorOn( mergeBasketFail, @@ -185,7 +190,8 @@ export const basketReducer = createReducer( deleteBasketPaymentFail, updateConcardisCvcLastUpdatedFail, submitBasketFail, - startCheckoutFail + startCheckoutFail, + setBasketDesiredDeliveryDateFail ), on(loadBasketSuccess, createBasketSuccess, mergeBasketSuccess, (state, action): BasketState => { diff --git a/src/app/core/store/customer/basket/basket.selectors.ts b/src/app/core/store/customer/basket/basket.selectors.ts index a006c76f04..a8e97f3305 100644 --- a/src/app/core/store/customer/basket/basket.selectors.ts +++ b/src/app/core/store/customer/basket/basket.selectors.ts @@ -17,7 +17,7 @@ const getInternalBasket = createSelector(getBasketState, basket => basket.basket export const getBasketValidationResults = createSelectorFactory(projector => resultMemoize(projector, isEqual) )(getBasketState, (basket: BasketState): BasketValidationResultType => { - if (!basket || !basket.validationResults) { + if (!basket?.validationResults) { return; } diff --git a/src/app/core/store/customer/customer-store.spec.ts b/src/app/core/store/customer/customer-store.spec.ts index 54d957ee63..bb98cf117c 100644 --- a/src/app/core/store/customer/customer-store.spec.ts +++ b/src/app/core/store/customer/customer-store.spec.ts @@ -1,8 +1,9 @@ import { TestBed } from '@angular/core/testing'; import { RouterTestingModule } from '@angular/router/testing'; import { TranslateModule } from '@ngx-translate/core'; +import { OAuthService, TokenResponse } from 'angular-oauth2-oidc'; import { EMPTY, of } from 'rxjs'; -import { anyNumber, anything, instance, mock, when } from 'ts-mockito'; +import { anyNumber, anyString, anything, instance, mock, when } from 'ts-mockito'; import { Basket } from 'ish-core/models/basket/basket.model'; import { Credentials } from 'ish-core/models/credentials/credentials.model'; @@ -106,6 +107,14 @@ describe('Customer Store', () => { useExternalUrl: false, } as Promotion; + const token = { + access_token: 'DEMO@access-token', + token_type: 'user', + expires_in: 3600, + refresh_token: 'DEMO@refresh-token', + id_token: 'DEMO@id-token', + } as TokenResponse; + beforeEach(() => { const categoriesServiceMock = mock(CategoriesService); when(categoriesServiceMock.getTopLevelCategories(anyNumber())).thenReturn(of(categoryTree())); @@ -140,6 +149,7 @@ describe('Customer Store', () => { const userServiceMock = mock(UserService); when(userServiceMock.signInUser(anything())).thenReturn(of({ customer, user, pgid })); + when(userServiceMock.fetchToken(anyString(), anything())).thenReturn(of(token)); const dataRequestsServiceMock = mock(DataRequestsService); const filterServiceMock = mock(FilterService); @@ -149,6 +159,9 @@ describe('Customer Store', () => { const productPriceServiceMock = mock(PricesService); when(productPriceServiceMock.getProductPrices(anything())).thenReturn(of([])); + const oAuthService = mock(OAuthService); + when(oAuthService.events).thenReturn(of()); + TestBed.configureTestingModule({ imports: [ CoreStoreModule.forTesting(['configuration', 'serverConfig'], true), @@ -174,6 +187,7 @@ describe('Customer Store', () => { { provide: CookiesService, useFactory: () => instance(mock(CookiesService)) }, { provide: DataRequestsService, useFactory: () => instance(dataRequestsServiceMock) }, { provide: FilterService, useFactory: () => instance(filterServiceMock) }, + { provide: OAuthService, useFactory: () => instance(oAuthService) }, { provide: OrderService, useFactory: () => instance(orderServiceMock) }, { provide: PaymentService, useFactory: () => instance(mock(PaymentService)) }, { provide: PricesService, useFactory: () => instance(productPriceServiceMock) }, diff --git a/src/app/core/store/customer/orders/orders.effects.ts b/src/app/core/store/customer/orders/orders.effects.ts index ac04ceec9b..91e06cdf2b 100644 --- a/src/app/core/store/customer/orders/orders.effects.ts +++ b/src/app/core/store/customer/orders/orders.effects.ts @@ -75,7 +75,7 @@ export class OrdersEffects { this.actions$.pipe( ofType(createOrderSuccess), mapToPayloadProperty('order'), - filter(order => !order || !order.orderCreation || order.orderCreation.status !== 'ROLLED_BACK'), + filter(order => !order?.orderCreation || order.orderCreation.status !== 'ROLLED_BACK'), concatMap(order => { if ( order.orderCreation && diff --git a/src/app/core/store/customer/user/user.actions.ts b/src/app/core/store/customer/user/user.actions.ts index d1fe8c0840..fa203d0512 100644 --- a/src/app/core/store/customer/user/user.actions.ts +++ b/src/app/core/store/customer/user/user.actions.ts @@ -25,6 +25,10 @@ export const loadCompanyUserSuccess = createAction('[User API] Load Company User export const logoutUser = createAction('[User] Logout User'); +export const logoutUserSuccess = createAction('[User API] Logout User Success'); + +export const logoutUserFail = createAction('[User API] Logout User Failed', httpError()); + export const createUser = createAction('[User] Create User', payload()); export const createUserSuccess = createAction('[User API] Create User Success', payload<{ email: string }>()); @@ -140,3 +144,5 @@ export const updateUserPasswordByPasswordReminderFail = createAction( '[Password Reminder] Update User Password Failed', httpError() ); + +export const fetchAnonymousUserToken = createAction('[Token API] Fetch Anonymous User Token'); diff --git a/src/app/core/store/customer/user/user.effects.spec.ts b/src/app/core/store/customer/user/user.effects.spec.ts index 1ed707702b..7230e00bea 100644 --- a/src/app/core/store/customer/user/user.effects.spec.ts +++ b/src/app/core/store/customer/user/user.effects.spec.ts @@ -4,6 +4,7 @@ import { Router } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; import { provideMockActions } from '@ngrx/effects/testing'; import { Action, Store } from '@ngrx/store'; +import { OAuthService, TokenResponse } from 'angular-oauth2-oidc'; import { cold, hot } from 'jasmine-marbles'; import { EMPTY, Observable, noop, of, throwError } from 'rxjs'; import { anyString, anything, instance, mock, verify, when } from 'ts-mockito'; @@ -30,6 +31,7 @@ import { deleteUserPaymentInstrument, deleteUserPaymentInstrumentFail, deleteUserPaymentInstrumentSuccess, + fetchAnonymousUserToken, loadCompanyUser, loadCompanyUserFail, loadCompanyUserSuccess, @@ -44,6 +46,9 @@ import { loginUserFail, loginUserSuccess, loginUserWithToken, + logoutUser, + logoutUserFail, + logoutUserSuccess, requestPasswordReminder, requestPasswordReminderFail, requestPasswordReminderSuccess, @@ -67,6 +72,7 @@ describe('User Effects', () => { let userServiceMock: UserService; let paymentServiceMock: PaymentService; let apiTokenServiceMock: ApiTokenService; + let oAuthServiceMock: OAuthService; let router: Router; let location: Location; @@ -83,12 +89,23 @@ describe('User Effects', () => { isBusinessCustomer: true, } as Customer; + const token = { + access_token: 'DEMO@access-token', + token_type: 'user', + expires_in: 3600, + refresh_token: 'DEMO@refresh-token', + id_token: 'DEMO@id-token', + } as TokenResponse; + beforeEach(() => { userServiceMock = mock(UserService); paymentServiceMock = mock(PaymentService); apiTokenServiceMock = mock(ApiTokenService); + oAuthServiceMock = mock(OAuthService); when(userServiceMock.signInUser(anything())).thenReturn(of(loginResponseData)); + when(userServiceMock.fetchToken(anyString(), anything())).thenReturn(of(token)); + when(userServiceMock.fetchToken(anyString())).thenReturn(of(token)); when(userServiceMock.signInUserByToken(anything())).thenReturn(of(loginResponseData)); when(userServiceMock.createUser(anything())).thenReturn(of(undefined)); when(userServiceMock.updateUser(anything(), anything())).thenReturn(of({ firstName: 'Patricia' } as User)); @@ -97,10 +114,12 @@ describe('User Effects', () => { when(userServiceMock.getCompanyUserData()).thenReturn(of({ firstName: 'Patricia' } as User)); when(userServiceMock.requestPasswordReminder(anything())).thenReturn(of({})); when(userServiceMock.getEligibleCostCenters()).thenReturn(of([])); + when(userServiceMock.logoutUser()).thenReturn(of(undefined)); when(paymentServiceMock.getUserPaymentMethods(anything())).thenReturn(of([])); when(paymentServiceMock.createUserPayment(anything(), anything())).thenReturn(of({ id: 'paymentInstrumentId' })); when(paymentServiceMock.deleteUserPaymentInstrument(anyString(), anyString())).thenReturn(of(undefined)); when(apiTokenServiceMock.hasUserApiTokenCookie()).thenReturn(false); + when(oAuthServiceMock.events).thenReturn(of()); TestBed.configureTestingModule({ imports: [ @@ -110,6 +129,7 @@ describe('User Effects', () => { ], providers: [ { provide: ApiTokenService, useFactory: () => instance(apiTokenServiceMock) }, + { provide: OAuthService, useFactory: () => instance(oAuthServiceMock) }, { provide: PaymentService, useFactory: () => instance(paymentServiceMock) }, { provide: UserService, useFactory: () => instance(userServiceMock) }, provideMockActions(() => actions$), @@ -170,6 +190,69 @@ describe('User Effects', () => { }); }); + describe('loginUserWithToken$', () => { + it('should call the api service when LoginUserWithToken event is called', done => { + const action = loginUserWithToken({ token: '12345' }); + + actions$ = of(action); + + effects.loginUserWithToken$.subscribe(() => { + verify(userServiceMock.signInUserByToken(anything())).once(); + done(); + }); + }); + }); + + describe('logoutUser$', () => { + it('should call the api service to revoke current token when logoutUser action is called', done => { + const action = logoutUser(); + + actions$ = of(action); + + effects.logoutUser$.subscribe(() => { + verify(userServiceMock.logoutUser()).once(); + done(); + }); + }); + + it('should dispatch a success action on a successful request and should fetch a new anonymous user token', () => { + const action = logoutUser(); + const completion1 = logoutUserSuccess(); + const completion2 = fetchAnonymousUserToken(); + + actions$ = hot('-a', { a: action }); + const expected$ = cold('-(bc)', { b: completion1, c: completion2 }); + + expect(effects.logoutUser$).toBeObservable(expected$); + }); + + it('should dispatch an error action on a failed request', () => { + const error = makeHttpError({ status: 401, code: 'error' }); + when(userServiceMock.logoutUser()).thenReturn(throwError(() => error)); + + const action = logoutUser(); + const completion = logoutUserFail({ error }); + + actions$ = hot('-a-a-a', { a: action }); + const expected$ = cold('-b-b-b', { b: completion }); + + expect(effects.logoutUser$).toBeObservable(expected$); + }); + }); + + describe('fetchAnonymousUserToken$', () => { + it('should call apiTokenService with token response', done => { + const action = fetchAnonymousUserToken(); + + actions$ = of(action); + + effects.fetchAnonymousUserToken$.subscribe(() => { + verify(userServiceMock.fetchToken('anonymous')).once(); + done(); + }); + }); + }); + describe('loadCompanyUser$', () => { it('should call the registration service for LoadCompanyUser', done => { const action = loadCompanyUser(); @@ -296,7 +379,7 @@ describe('User Effects', () => { const action = createUser({ customer, credentials } as CustomerRegistrationType); const completion1 = createUserSuccess({ email: customerLoginType.user.email }); - const completion2 = loginUserWithToken({ token: undefined }); + const completion2 = loginUser({ credentials }); actions$ = hot('-a', { a: action }); const expected$ = cold('-(bc)', { b: completion1, c: completion2 }); diff --git a/src/app/core/store/customer/user/user.effects.ts b/src/app/core/store/customer/user/user.effects.ts index 612b9498b3..093bda3204 100644 --- a/src/app/core/store/customer/user/user.effects.ts +++ b/src/app/core/store/customer/user/user.effects.ts @@ -3,8 +3,20 @@ import { Router } from '@angular/router'; import { Actions, createEffect, ofType } from '@ngrx/effects'; import { routerNavigatedAction } from '@ngrx/router-store'; import { Store, select } from '@ngrx/store'; +import { OAuthService, OAuthSuccessEvent } from 'angular-oauth2-oidc'; import { from } from 'rxjs'; -import { concatMap, delay, exhaustMap, filter, map, mergeMap, sample, takeWhile, withLatestFrom } from 'rxjs/operators'; +import { + concatMap, + delay, + exhaustMap, + filter, + map, + mergeMap, + sample, + switchMap, + takeWhile, + withLatestFrom, +} from 'rxjs/operators'; import { CustomerRegistrationType } from 'ish-core/models/customer/customer.model'; import { PaymentService } from 'ish-core/services/payment/payment.service'; @@ -24,6 +36,7 @@ import { deleteUserPaymentInstrument, deleteUserPaymentInstrumentFail, deleteUserPaymentInstrumentSuccess, + fetchAnonymousUserToken, loadCompanyUser, loadCompanyUserFail, loadCompanyUserSuccess, @@ -38,6 +51,9 @@ import { loginUserFail, loginUserSuccess, loginUserWithToken, + logoutUser, + logoutUserFail, + logoutUserSuccess, requestPasswordReminder, requestPasswordReminderFail, requestPasswordReminderSuccess, @@ -66,7 +82,8 @@ export class UserEffects { private userService: UserService, private paymentService: PaymentService, private router: Router, - private apiTokenService: ApiTokenService + private apiTokenService: ApiTokenService, + private oAuthService: OAuthService ) {} loginUser$ = createEffect(() => @@ -79,6 +96,43 @@ export class UserEffects { ) ); + /** + * Revoke token on server side + */ + logoutUser$ = createEffect(() => + this.actions$.pipe( + ofType(logoutUser), + switchMap(() => + this.userService.logoutUser().pipe( + concatMap(() => [logoutUserSuccess(), fetchAnonymousUserToken()]), + mapErrorToAction(logoutUserFail) + ) + ) + ) + ); + + fetchAnonymousUserToken$ = createEffect( + () => + this.actions$.pipe( + ofType(fetchAnonymousUserToken), + switchMap(() => this.userService.fetchToken('anonymous')) + ), + { dispatch: false } + ); + + setApiToken$ = createEffect( + () => + this.oAuthService.events.pipe( + filter(event => event instanceof OAuthSuccessEvent && event.type === 'token_received'), + map(() => + this.apiTokenService.setApiToken(this.oAuthService.getAccessToken(), { + expires: new Date(this.oAuthService.getAccessTokenExpiration()), + }) + ) + ), + { dispatch: false } + ); + loginUserWithToken$ = createEffect(() => this.actions$.pipe( ofType(loginUserWithToken), @@ -129,7 +183,7 @@ export class UserEffects { createUserSuccess({ email: createUserResponse.user.email }), customerTypeForLoginApproval?.includes(createUserResponse.customer.isBusinessCustomer ? 'SMB' : 'PRIVATE') ? createUserApprovalRequired({ email: createUserResponse.user.email }) - : loginUserWithToken({ token: undefined }), + : loginUser({ credentials: data.credentials }), ]), mapErrorToAction(createUserFail) ) diff --git a/src/app/core/store/customer/user/user.reducer.ts b/src/app/core/store/customer/user/user.reducer.ts index accf414714..75267cd532 100644 --- a/src/app/core/store/customer/user/user.reducer.ts +++ b/src/app/core/store/customer/user/user.reducer.ts @@ -10,7 +10,9 @@ import { setErrorOn, setLoadingOn, unsetLoadingAndErrorOn, unsetLoadingOn } from import { createUser, + createUserApprovalRequired, createUserFail, + createUserSuccess, deleteUserPaymentInstrument, deleteUserPaymentInstrumentFail, deleteUserPaymentInstrumentSuccess, @@ -26,6 +28,9 @@ import { loadUserPaymentMethodsSuccess, loginUserFail, loginUserSuccess, + logoutUser, + logoutUserFail, + logoutUserSuccess, requestPasswordReminder, requestPasswordReminderFail, requestPasswordReminderSuccess, @@ -43,8 +48,6 @@ import { updateUserPasswordSuccess, updateUserSuccess, userErrorReset, - createUserSuccess, - createUserApprovalRequired, } from './user.actions'; export interface UserState { @@ -95,7 +98,8 @@ export const userReducer = createReducer( loadUserPaymentMethods, deleteUserPaymentInstrument, updateUserPasswordByPasswordReminder, - requestPasswordReminder + requestPasswordReminder, + logoutUser ), unsetLoadingOn( loadUserCostCentersFail, @@ -113,7 +117,8 @@ export const userReducer = createReducer( updateCustomerSuccess, loadUserCostCentersSuccess, loadUserPaymentMethodsSuccess, - deleteUserPaymentInstrumentSuccess + deleteUserPaymentInstrumentSuccess, + logoutUserSuccess ), setErrorOn( updateUserFail, @@ -121,7 +126,8 @@ export const userReducer = createReducer( updateCustomerFail, loadUserPaymentMethodsFail, deleteUserPaymentInstrumentFail, - loadRolesAndPermissionsFail + loadRolesAndPermissionsFail, + logoutUserFail ), on(loginUserFail, loadCompanyUserFail, createUserFail, (_, action): UserState => { const error = action.payload.error; diff --git a/src/app/core/store/shopping/products/products.effects.ts b/src/app/core/store/shopping/products/products.effects.ts index 66dd6b7869..ebbad2d60d 100644 --- a/src/app/core/store/shopping/products/products.effects.ts +++ b/src/app/core/store/shopping/products/products.effects.ts @@ -48,14 +48,14 @@ import { loadProductLinksSuccess, loadProductParts, loadProductPartsSuccess, - loadProductsForCategory, - loadProductsForCategoryFail, - loadProductsForMaster, - loadProductsForMasterFail, loadProductSuccess, loadProductVariationsFail, loadProductVariationsIfNotLoaded, loadProductVariationsSuccess, + loadProductsForCategory, + loadProductsForCategoryFail, + loadProductsForMaster, + loadProductsForMasterFail, } from './products.actions'; import { getBreadcrumbForProductPage, diff --git a/src/app/core/store/shopping/search/search.effects.ts b/src/app/core/store/shopping/search/search.effects.ts index b56775436f..93257cf9b7 100644 --- a/src/app/core/store/shopping/search/search.effects.ts +++ b/src/app/core/store/shopping/search/search.effects.ts @@ -1,4 +1,5 @@ import { Injectable } from '@angular/core'; +import { Router } from '@angular/router'; import { Actions, createEffect, ofType } from '@ngrx/effects'; import { routerNavigatedAction } from '@ngrx/router-store'; import { Store, select } from '@ngrx/store'; @@ -17,6 +18,7 @@ import { } from 'rxjs/operators'; import { ProductListingMapper } from 'ish-core/models/product-listing/product-listing.mapper'; +import { generateProductUrl } from 'ish-core/routing/product/product.route'; import { ProductsService } from 'ish-core/services/products/products.service'; import { SuggestService } from 'ish-core/services/suggest/suggest.service'; import { ofUrl, selectRouteParam } from 'ish-core/store/core/router'; @@ -48,7 +50,8 @@ export class SearchEffects { private suggestService: SuggestService, private httpStatusCodeService: HttpStatusCodeService, private productListingMapper: ProductListingMapper, - private translateService: TranslateService + private translateService: TranslateService, + private router: Router ) {} /** @@ -81,23 +84,30 @@ export class SearchEffects { map(([payload, pageSize]) => ({ ...payload, amount: pageSize, offset: (payload.page - 1) * pageSize })), concatMap(({ searchTerm, amount, sorting, offset, page }) => this.productsService.searchProducts(searchTerm, amount, sorting, offset).pipe( - concatMap(({ total, products, sortableAttributes }) => [ - ...products.map(product => loadProductSuccess({ product })), - setProductListingPages( - this.productListingMapper.createPages( - products.map(p => p.sku), - 'search', - searchTerm, - amount, - { - startPage: page, - sorting, - sortableAttributes, - itemCount: total, - } - ) - ), - ]), + concatMap(({ total, products, sortableAttributes }) => { + // route to product detail page if only one product was found + if (total === 1) { + this.router.navigate([generateProductUrl(products[0])]); + } + // provide the data for the search result page + return [ + ...products.map(product => loadProductSuccess({ product })), + setProductListingPages( + this.productListingMapper.createPages( + products.map(p => p.sku), + 'search', + searchTerm, + amount, + { + startPage: page, + sorting, + sortableAttributes, + itemCount: total, + } + ) + ), + ]; + }), mapErrorToAction(searchProductsFail) ) ) diff --git a/src/app/core/store/shopping/shopping-store.spec.ts b/src/app/core/store/shopping/shopping-store.spec.ts index 0495c8aa54..70d6bd3492 100644 --- a/src/app/core/store/shopping/shopping-store.spec.ts +++ b/src/app/core/store/shopping/shopping-store.spec.ts @@ -125,7 +125,7 @@ describe('Shopping Store', () => { }) ); when(productsServiceMock.searchProducts('something', anyNumber(), anything(), anyNumber())).thenReturn( - of({ products: [{ sku: 'P2' } as Product], sortableAttributes: [], total: 1 }) + of({ products: [{ sku: 'P1' }, { sku: 'P2' }] as Product[], sortableAttributes: [], total: 2 }) ); promotionsServiceMock = mock(PromotionsService); @@ -281,8 +281,8 @@ describe('Shopping Store', () => { tick(5000); })); - it('should load the product for the search results', fakeAsync(() => { - expect(getProductIds(store.state)).toEqual(['P2']); + it('should load the products for the search results', fakeAsync(() => { + expect(getProductIds(store.state)).toEqual(['P1', 'P2']); })); it('should trigger required actions when searching', fakeAsync(() => { @@ -307,12 +307,14 @@ describe('Shopping Store', () => { sorting: undefined [Filter Internal] Load Filter for Search: searchTerm: "something" + [Products API] Load Product Success: + product: {"sku":"P1"} [Products API] Load Product Success: product: {"sku":"P2"} [Product Listing Internal] Set Product Listing Pages: - 1: ["P2"] + 1: ["P1","P2"] id: {"type":"search","value":"something"} - itemCount: 1 + itemCount: 2 sortableAttributes: [] [Filter API] Load Filter Success: filterNavigation: {} @@ -535,12 +537,14 @@ describe('Shopping Store', () => { sorting: undefined [Filter Internal] Load Filter for Search: searchTerm: "something" + [Products API] Load Product Success: + product: {"sku":"P1"} [Products API] Load Product Success: product: {"sku":"P2"} [Product Listing Internal] Set Product Listing Pages: - 1: ["P2"] + 1: ["P1","P2"] id: {"type":"search","value":"something"} - itemCount: 1 + itemCount: 2 sortableAttributes: [] [Filter API] Load Filter Success: filterNavigation: {} @@ -885,8 +889,8 @@ describe('Shopping Store', () => { tick(5000); })); - it('should load the product for the search results', fakeAsync(() => { - expect(getProductIds(store.state)).toEqual(['P2']); + it('should load the products for the search results', fakeAsync(() => { + expect(getProductIds(store.state)).toEqual(['P1', 'P2']); })); it('should trigger required actions when searching', fakeAsync(() => { @@ -910,12 +914,14 @@ describe('Shopping Store', () => { sorting: undefined [Filter Internal] Load Filter for Search: searchTerm: "something" + [Products API] Load Product Success: + product: {"sku":"P1"} [Products API] Load Product Success: product: {"sku":"P2"} [Product Listing Internal] Set Product Listing Pages: - 1: ["P2"] + 1: ["P1","P2"] id: {"type":"search","value":"something"} - itemCount: 1 + itemCount: 2 sortableAttributes: [] [Filter API] Load Filter Success: filterNavigation: {} diff --git a/src/app/core/utils/api-token/api-token.service.ts b/src/app/core/utils/api-token/api-token.service.ts index 2a9be22718..3aa7b2d4c4 100644 --- a/src/app/core/utils/api-token/api-token.service.ts +++ b/src/app/core/utils/api-token/api-token.service.ts @@ -1,9 +1,21 @@ -import { HttpErrorResponse, HttpEvent, HttpHandler, HttpRequest, HttpResponse } from '@angular/common/http'; +import { HttpErrorResponse, HttpEvent, HttpHandler, HttpParams, HttpRequest, HttpResponse } from '@angular/common/http'; import { ApplicationRef, Injectable } from '@angular/core'; import { Router } from '@angular/router'; import { Store, select } from '@ngrx/store'; +import { CookieOptions } from 'express'; import { isEqual } from 'lodash-es'; -import { Observable, ReplaySubject, Subject, combineLatest, interval, of, race, throwError, timer } from 'rxjs'; +import { + Observable, + OperatorFunction, + ReplaySubject, + Subject, + combineLatest, + interval, + of, + race, + throwError, + timer, +} from 'rxjs'; import { catchError, concatMap, @@ -14,20 +26,27 @@ import { mergeMap, pairwise, skip, + startWith, switchMap, take, - tap, withLatestFrom, } from 'rxjs/operators'; +import { BasketView } from 'ish-core/models/basket/basket.model'; +import { User } from 'ish-core/models/user/user.model'; import { ApiService } from 'ish-core/services/api/api.service'; import { getCurrentBasket, getCurrentBasketId, loadBasket, loadBasketByAPIToken } from 'ish-core/store/customer/basket'; import { getOrder, getSelectedOrderId, loadOrderByAPIToken } from 'ish-core/store/customer/orders'; -import { getLoggedInUser, getUserAuthorized, loadUserByAPIToken } from 'ish-core/store/customer/user'; +import { + fetchAnonymousUserToken, + getLoggedInUser, + getUserAuthorized, + loadUserByAPIToken, +} from 'ish-core/store/customer/user'; import { CookiesService } from 'ish-core/utils/cookies/cookies.service'; import { mapToProperty, whenTruthy } from 'ish-core/utils/operators'; -export type ApiTokenCookieType = 'user' | 'order'; +type ApiTokenCookieType = 'user' | 'order' | 'anonymous'; interface ApiTokenCookie { apiToken: string; @@ -37,11 +56,16 @@ interface ApiTokenCookie { creator?: string; } +// If no expiry date is supplied by the token endpoint, this value (in ms) is used +const DEFAULT_EXPIRY_TIME = 3600000; + @Injectable({ providedIn: 'root' }) export class ApiTokenService { apiToken$ = new ReplaySubject(1); cookieVanishes$ = new Subject(); + private cookieOptions: CookieOptions = {}; + private initialCookie$: Observable; constructor( @@ -50,6 +74,7 @@ export class ApiTokenService { private store: Store, appRef: ApplicationRef ) { + // setup initial values const initialCookie = this.parseCookie(); this.initialCookie$ = of(!SSR ? initialCookie : undefined); this.initialCookie$.pipe(mapToProperty('apiToken')).subscribe(token => { @@ -59,45 +84,27 @@ export class ApiTokenService { if (!SSR) { // save token routine combineLatest([ - store.pipe(select(getLoggedInUser)), + store.pipe(select(getLoggedInUser), startWith(undefined), pairwise()), store.pipe(select(getCurrentBasket)), store.pipe(select(getSelectedOrderId)), - this.apiToken$.pipe(skip(1)), + this.apiToken$, ]) - .pipe( - map(([user, basket, orderId, apiToken]): ApiTokenCookie => { - if (user) { - return { apiToken, type: 'user', isAnonymous: false, creator: 'pwa' }; - } else if (basket) { - return { apiToken, type: 'user', isAnonymous: true, creator: 'pwa' }; - } else if (orderId) { - return { apiToken, type: 'order', orderId, creator: 'pwa' }; - } else { - const apiTokenCookieString = this.cookiesService.get('apiToken'); - const apiTokenCookie: ApiTokenCookie = apiTokenCookieString - ? JSON.parse(apiTokenCookieString) - : undefined; - if (apiToken && apiTokenCookie) { - return { ...apiTokenCookie, apiToken }; - } - } - }), - distinctUntilChanged(isEqual) - ) + .pipe(skip(1), this.mapToApiTokenCookie(), distinctUntilChanged(isEqual)) .subscribe(apiToken => { const cookieContent = apiToken?.apiToken ? JSON.stringify(apiToken) : undefined; if (cookieContent) { cookiesService.put('apiToken', cookieContent, { - expires: new Date(Date.now() + 3600000), - secure: true, + expires: this.cookieOptions?.expires ?? new Date(Date.now() + DEFAULT_EXPIRY_TIME), + secure: this.cookieOptions?.secure ?? true, sameSite: 'Strict', + path: '/', }); } else { cookiesService.remove('apiToken'); } }); - // token vanishes routine + // access token vanishes routine appRef.isStable .pipe( whenTruthy(), @@ -118,6 +125,37 @@ export class ApiTokenService { this.cookieVanishes$.next(type); }); + // cookie vanishes routine when user is logged out in an another tab + appRef.isStable + .pipe( + whenTruthy(), + first(), + mergeMap(() => + interval(1000).pipe( + map(() => this.parseCookie()), + pairwise(), + filter(([previous, current]) => previous?.type === 'user' && current?.type === 'anonymous'), // user is logged out and got a new token as an anonymous user + switchMap(([previous, current]) => + combineLatest([ + store.pipe(select(getLoggedInUser), startWith(undefined), pairwise()), + store.pipe(select(getCurrentBasket)), + store.pipe(select(getSelectedOrderId)), + this.apiToken$, + ]).pipe( + take(1), + this.mapToApiTokenCookie(), + filter(calculated => calculated?.type === 'user'), // application calculated an user api token cookie although an anonymous cookie is stored + map(() => [previous.type, current.apiToken]) + ) + ) + ) + ) + ) + .subscribe(([type, apiToken]) => { + this.apiToken$.next(apiToken); + this.cookieVanishes$.next(type); + }); + // session keep alive appRef.isStable .pipe( @@ -137,19 +175,51 @@ export class ApiTokenService { } } + private mapToApiTokenCookie(): OperatorFunction<[[User, User], BasketView, string, string], ApiTokenCookie> { + return (source$: Observable<[[User, User], BasketView, string, string]>) => + source$.pipe( + map(([[prevUser, user], basket, orderId, apiToken]): ApiTokenCookie => { + if (user) { + return { apiToken, type: 'user', isAnonymous: false, creator: 'pwa' }; + } else if (basket) { + return { apiToken, type: 'user', isAnonymous: true, creator: 'pwa' }; + } else if (orderId) { + return { apiToken, type: 'order', orderId, creator: 'pwa' }; + } + // user is logged out and is now anonymous + else if (apiToken && !user && prevUser) { + return { apiToken, type: 'anonymous', creator: 'pwa', isAnonymous: true }; + } + + const apiTokenCookieString = this.cookiesService.get('apiToken'); + const apiTokenCookie: ApiTokenCookie = apiTokenCookieString ? JSON.parse(apiTokenCookieString) : undefined; + if (apiToken) { + if (apiTokenCookie) { + return { ...apiTokenCookie, apiToken }; // overwrite existing cookie informations with new apiToken + } + return { apiToken, type: 'anonymous', creator: 'pwa', isAnonymous: true }; // initial api token cookie + } + }) + ); + } + hasUserApiTokenCookie() { const apiTokenCookie = this.parseCookie(); return apiTokenCookie?.type === 'user' && !apiTokenCookie?.isAnonymous; } - restore$(types: ApiTokenCookieType[] = ['user', 'order']): Observable { + restore$(types: ApiTokenCookieType[] = ['user', 'order'], fetchAnonymousToken = true): Observable { if (SSR) { return of(true); } return this.router.events.pipe( first(), switchMap(() => this.initialCookie$), - switchMap(cookie => { + withLatestFrom(this.apiToken$), + switchMap(([cookie, apiToken]) => { + if (!apiToken && fetchAnonymousToken) { + this.store.dispatch(fetchAnonymousUserToken()); + } if (types.includes(cookie?.type)) { switch (cookie?.type) { case 'user': { @@ -191,7 +261,7 @@ export class ApiTokenService { ); } - private parseCookie() { + private parseCookie(): ApiTokenCookie { const cookieContent = this.cookiesService.get('apiToken'); if (cookieContent) { try { @@ -203,17 +273,18 @@ export class ApiTokenService { return; } - private setApiToken(apiToken: string) { - if (!apiToken) { - console.warn('do not use setApiToken to unset token, use remove or invalidate instead'); - } - this.apiToken$.next(apiToken); - } - + /** + * Should remove the actual apiToken cookie and fetch a new anonymous user token + */ removeApiToken() { this.apiToken$.next(undefined); } + setApiToken(apiToken: string, options?: CookieOptions) { + this.cookieOptions = options; + this.apiToken$.next(apiToken); + } + private invalidateApiToken() { const cookie = this.parseCookie(); @@ -230,23 +301,10 @@ export class ApiTokenService { ); } - private setTokenFromResponse(event: HttpEvent) { - if (event instanceof HttpResponse) { - const apiToken = event.headers.get(ApiService.TOKEN_HEADER_KEY); - if (apiToken) { - if (apiToken.startsWith('AuthenticationTokenOutdated') || apiToken.startsWith('AuthenticationTokenInvalid')) { - this.invalidateApiToken(); - } else if (!event.url.endsWith('/configurations') && !event.url.endsWith('/contact')) { - this.setApiToken(apiToken); - } - } - } - } - private appendAuthentication(req: HttpRequest): Observable> { return this.apiToken$.pipe( map(apiToken => - apiToken && !req.headers?.has(ApiService.AUTHORIZATION_HEADER_KEY) + apiToken && !req.headers?.has(ApiService.TOKEN_HEADER_KEY) ? req.clone({ headers: req.headers.set(ApiService.TOKEN_HEADER_KEY, apiToken) }) : req ), @@ -258,6 +316,17 @@ export class ApiTokenService { return this.appendAuthentication(req).pipe( concatMap(request => next.handle(request).pipe( + map(event => { + // remove id_token from /token response + // TODO: remove http request body adaptions if correct id_tokens are returned + if (event instanceof HttpResponse && event.url.endsWith('token') && request.body instanceof HttpParams) { + const { id_token: _, ...body } = event.body; + return event.clone({ + body, + }); + } + return event; + }), catchError(err => { if (this.isAuthTokenError(err)) { this.invalidateApiToken(); @@ -268,8 +337,7 @@ export class ApiTokenService { return timer(500).pipe(switchMap(() => next.handle(retryRequest))); } return throwError(() => err); - }), - tap(event => this.setTokenFromResponse(event)) + }) ) ) ); diff --git a/src/app/core/utils/http-error/login-user.error-handler.ts b/src/app/core/utils/http-error/login-user.error-handler.ts index 0f7665e60f..18c3c49bb3 100644 --- a/src/app/core/utils/http-error/login-user.error-handler.ts +++ b/src/app/core/utils/http-error/login-user.error-handler.ts @@ -1,10 +1,9 @@ -import { HttpErrorResponse, HttpRequest } from '@angular/common/http'; +import { HttpErrorResponse } from '@angular/common/http'; import { Inject, Injectable } from '@angular/core'; import { USER_REGISTRATION_LOGIN_TYPE } from 'ish-core/configurations/injection-keys'; import { SpecialHttpErrorHandler } from 'ish-core/interceptors/icm-error-mapper.interceptor'; import { HttpError } from 'ish-core/models/http-error/http-error.model'; -import { ApiService } from 'ish-core/services/api/api.service'; /* eslint-disable @typescript-eslint/ban-types */ @@ -12,12 +11,8 @@ import { ApiService } from 'ish-core/services/api/api.service'; export class LoginUserErrorHandler implements SpecialHttpErrorHandler { constructor(@Inject(USER_REGISTRATION_LOGIN_TYPE) public loginType: string) {} - test(error: HttpErrorResponse, request: HttpRequest): boolean { - return ( - request.headers.has(ApiService.AUTHORIZATION_HEADER_KEY) && - (error.status === 401 || error.status === 403) && - error.url.includes('customers/-') - ); + test(error: HttpErrorResponse): boolean { + return (error.status === 401 || error.status === 403) && error.url.includes('token'); } map(error: HttpErrorResponse): Partial { if (error.status === 403) { diff --git a/src/app/core/utils/meta-reducers.spec.ts b/src/app/core/utils/meta-reducers.spec.ts index ac1ee3a3b7..e593616379 100644 --- a/src/app/core/utils/meta-reducers.spec.ts +++ b/src/app/core/utils/meta-reducers.spec.ts @@ -5,7 +5,7 @@ import { identity } from 'rxjs'; import { applyConfiguration, getICMBaseURL } from 'ish-core/store/core/configuration'; import { CoreState } from 'ish-core/store/core/core-store'; import { CoreStoreModule } from 'ish-core/store/core/core-store.module'; -import { loginUser, logoutUser } from 'ish-core/store/customer/user'; +import { loginUser, logoutUserSuccess } from 'ish-core/store/customer/user'; import { StoreWithSnapshots, provideStoreSnapshots } from './dev/ngrx-testing'; import { resetOnLogoutMeta, resetSubStatesOnActionsMeta } from './meta-reducers'; @@ -19,7 +19,7 @@ describe('Meta Reducers', () => { TestBed.configureTestingModule({ imports: [ CoreStoreModule.forTesting(['configuration'], true, [ - resetSubStatesOnActionsMeta(['configuration'], [logoutUser]), + resetSubStatesOnActionsMeta(['configuration'], [logoutUserSuccess]), ]), ], providers: [provideStoreSnapshots()], @@ -36,7 +36,7 @@ describe('Meta Reducers', () => { it('should reset the configuration sub state', () => { expect(getICMBaseURL(store$.state)).toEqual(baseURL); - store$.dispatch(logoutUser()); + store$.dispatch(logoutUserSuccess()); expect(getICMBaseURL(store$.state)).toBeUndefined(); }); @@ -71,12 +71,12 @@ describe('Meta Reducers', () => { }); it('should reset state when reducing LogoutUser action', () => { - const result = resetOnLogoutMeta(identity)(state, logoutUser()); + const result = resetOnLogoutMeta(identity)(state, logoutUserSuccess()); expect(result).toBeUndefined(); }); it('should reset and delegate to reducer initial state when reducing LogoutUser action', () => { - const result = resetOnLogoutMeta(reducer)(state, logoutUser()); + const result = resetOnLogoutMeta(reducer)(state, logoutUserSuccess()); expect(result).toEqual({ a: 'initialA', b: 'initialB' }); }); diff --git a/src/app/core/utils/meta-reducers.ts b/src/app/core/utils/meta-reducers.ts index 484ca08568..94da024827 100644 --- a/src/app/core/utils/meta-reducers.ts +++ b/src/app/core/utils/meta-reducers.ts @@ -2,13 +2,13 @@ import { Action, ActionReducer, MetaReducer } from '@ngrx/store'; import { isEqual } from 'lodash-es'; import { identity } from 'rxjs'; -import { logoutUser } from 'ish-core/store/customer/user'; +import { logoutUserSuccess } from 'ish-core/store/customer/user'; import { omit } from './functions'; export function resetOnLogoutMeta(reducer: ActionReducer): ActionReducer { return (state: S, action: Action) => { - if (action.type === logoutUser.type) { + if (action.type === logoutUserSuccess.type) { return reducer(undefined, action); } return reducer(state, action); diff --git a/src/app/core/utils/oauth-configuration/oauth-configuration.service.spec.ts b/src/app/core/utils/oauth-configuration/oauth-configuration.service.spec.ts new file mode 100644 index 0000000000..1004b61869 --- /dev/null +++ b/src/app/core/utils/oauth-configuration/oauth-configuration.service.spec.ts @@ -0,0 +1,75 @@ +import { TestBed } from '@angular/core/testing'; +import { AuthConfig, OAuthInfoEvent, OAuthService, TokenResponse } from 'angular-oauth2-oidc'; +import { combineLatest, lastValueFrom, of } from 'rxjs'; +import { anything, instance, mock, verify, when } from 'ts-mockito'; + +import { ApiService } from 'ish-core/services/api/api.service'; + +import { OAuthConfigurationService } from './oauth-configuration.service'; + +describe('Oauth Configuration Service', () => { + const TOKEN_ENDPOINT = 'http://test-icm-url.de/token'; + + const config: AuthConfig = { + tokenEndpoint: TOKEN_ENDPOINT, + requireHttps: false, + }; + + const apiService = mock(ApiService); + const oAuthService = mock(OAuthService); + + let component: OAuthConfigurationService; + + beforeEach(() => { + when(apiService.constructUrlForPath('token', anything())).thenReturn(of(TOKEN_ENDPOINT)); + const infoEvent = Object.create(OAuthInfoEvent.prototype); + when(oAuthService.events).thenReturn( + // eslint-disable-next-line ban/ban + of(Object.assign(infoEvent, { type: 'token_expires', info: 'access_token' })) + ); + when(oAuthService.refreshToken()).thenReturn( + lastValueFrom(of({ access_token: 'access', expires_in: 10, refresh_token: 'refresh' } as TokenResponse)) + ); + + TestBed.configureTestingModule({ + providers: [ + { provide: ApiService, useFactory: () => instance(apiService) }, + { provide: OAuthService, useFactory: () => instance(oAuthService) }, + ], + }).compileComponents(); + + component = TestBed.inject(OAuthConfigurationService); + }); + + it('should be created', () => { + expect(component).toBeTruthy(); + }); + + describe('loadConfig$', () => { + it('should calculate correct configuration object', done => { + component.loadConfig$.subscribe(authConf => { + verify(apiService.constructUrlForPath('token', anything())).once(); + expect(authConf).toEqual(config); + done(); + }); + }); + }); + + describe('config$', () => { + it('should contain the calculated authConfig after successful loadConfig$ action', done => { + combineLatest([component.loadConfig$, component.config$]).subscribe(([, authConf]) => { + expect(authConf).toEqual(config); + done(); + }); + }); + }); + + describe('setupRefreshTokenMechanism$', () => { + it('should refresh access token, when access token is about to expire', done => { + component.setupRefreshTokenMechanism$().subscribe(() => { + verify(oAuthService.refreshToken()).once(); + done(); + }); + }); + }); +}); diff --git a/src/app/core/utils/oauth-configuration/oauth-configuration.service.ts b/src/app/core/utils/oauth-configuration/oauth-configuration.service.ts new file mode 100644 index 0000000000..bf58651fba --- /dev/null +++ b/src/app/core/utils/oauth-configuration/oauth-configuration.service.ts @@ -0,0 +1,50 @@ +import { Injectable } from '@angular/core'; +import { AuthConfig, OAuthInfoEvent, OAuthService, TokenResponse } from 'angular-oauth2-oidc'; +import { BehaviorSubject, Observable, filter, from, map, switchMap, take, tap } from 'rxjs'; + +import { ApiService } from 'ish-core/services/api/api.service'; +import { whenTruthy } from 'ish-core/utils/operators'; + +@Injectable({ + providedIn: 'root', +}) +export class OAuthConfigurationService { + config$ = new BehaviorSubject(undefined); + + constructor(private apiService: ApiService, private oAuthService: OAuthService) {} + + /** + * load an AuthConfig configuration object with specified tokenEndpoint + */ + get loadConfig$(): Observable { + return this.apiService + .constructUrlForPath('token', { + sendCurrency: true, + sendLocale: true, + }) + .pipe( + whenTruthy(), + filter(url => !url.startsWith('/')), // url should not be relative + take(1), + map(url => ({ + tokenEndpoint: url, + requireHttps: url.startsWith('https'), + })), + tap(config => this.config$.next(config)) + ); + } + + /** + * Refresh existing tokens, when token is about to expire + * + * @returns {TokenResponse} updated tokens + */ + setupRefreshTokenMechanism$(): Observable { + return this.oAuthService.events.pipe( + filter( + event => event instanceof OAuthInfoEvent && event.type === 'token_expires' && event.info === 'access_token' + ), + switchMap(() => from(this.oAuthService.refreshToken())) + ); + } +} diff --git a/src/app/core/utils/operators.ts b/src/app/core/utils/operators.ts index d410b3cbd2..9646f947ca 100644 --- a/src/app/core/utils/operators.ts +++ b/src/app/core/utils/operators.ts @@ -7,9 +7,9 @@ import { OperatorFunction, combineLatest, concat, + connect, of, throwError, - connect, } from 'rxjs'; import { buffer, catchError, distinctUntilChanged, filter, map, mergeAll, take, withLatestFrom } from 'rxjs/operators'; diff --git a/src/app/extensions/captcha/exports/lazy-captcha/lazy-captcha.component.ts b/src/app/extensions/captcha/exports/lazy-captcha/lazy-captcha.component.ts index bbc8f609c2..1ee594771a 100644 --- a/src/app/extensions/captcha/exports/lazy-captcha/lazy-captcha.component.ts +++ b/src/app/extensions/captcha/exports/lazy-captcha/lazy-captcha.component.ts @@ -2,13 +2,13 @@ import { AfterViewInit, ChangeDetectionStrategy, Component, - createNgModule, Injector, Input, OnDestroy, OnInit, ViewChild, ViewContainerRef, + createNgModule, } from '@angular/core'; import { AbstractControl, FormArray, FormGroup, Validators } from '@angular/forms'; import { Subject } from 'rxjs'; diff --git a/src/app/extensions/contact-us/pages/contact/contact-form/contact-form.component.spec.ts b/src/app/extensions/contact-us/pages/contact/contact-form/contact-form.component.spec.ts index 6d0a67373a..8cf6758b89 100644 --- a/src/app/extensions/contact-us/pages/contact/contact-form/contact-form.component.spec.ts +++ b/src/app/extensions/contact-us/pages/contact/contact-form/contact-form.component.spec.ts @@ -46,7 +46,7 @@ describe('Contact Form Component', () => { it('should always render formly form', () => { fixture.detectChanges(); - expect(element.querySelectorAll('formly-field')).toHaveLength(7); + expect(element.querySelectorAll('formly-group formly-field')).toHaveLength(7); }); it('should not emit contact request when invalid form is submitted', () => { diff --git a/src/app/extensions/punchout/identity-provider/punchout-identity-provider.spec.ts b/src/app/extensions/punchout/identity-provider/punchout-identity-provider.spec.ts index 2582add450..89e701c811 100644 --- a/src/app/extensions/punchout/identity-provider/punchout-identity-provider.spec.ts +++ b/src/app/extensions/punchout/identity-provider/punchout-identity-provider.spec.ts @@ -1,18 +1,20 @@ import { TestBed, fakeAsync, tick } from '@angular/core/testing'; import { ActivatedRouteSnapshot, Params, Router, UrlTree, convertToParamMap } from '@angular/router'; import { MockStore, provideMockStore } from '@ngrx/store/testing'; -import { EMPTY, Observable, Subject, noop, of, timer } from 'rxjs'; +import { OAuthService } from 'angular-oauth2-oidc'; +import { BehaviorSubject, EMPTY, Observable, Subject, noop, of, timer } from 'rxjs'; import { switchMap } from 'rxjs/operators'; -import { anyString, anything, capture, instance, mock, resetCalls, spy, verify, when } from 'ts-mockito'; +import { anyString, anything, instance, mock, resetCalls, spy, verify, when } from 'ts-mockito'; import { AccountFacade } from 'ish-core/facades/account.facade'; import { AppFacade } from 'ish-core/facades/app.facade'; import { CheckoutFacade } from 'ish-core/facades/checkout.facade'; import { selectQueryParam } from 'ish-core/store/core/router'; -import { ApiTokenCookieType, ApiTokenService } from 'ish-core/utils/api-token/api-token.service'; +import { ApiTokenService } from 'ish-core/utils/api-token/api-token.service'; import { CookiesService } from 'ish-core/utils/cookies/cookies.service'; import { makeHttpError } from 'ish-core/utils/dev/api-service-utils'; import { BasketMockData } from 'ish-core/utils/dev/basket-mock-data'; +import { OAuthConfigurationService } from 'ish-core/utils/oauth-configuration/oauth-configuration.service'; import { PunchoutSession } from '../models/punchout-session/punchout-session.model'; import { PunchoutService } from '../services/punchout/punchout.service'; @@ -32,12 +34,11 @@ describe('Punchout Identity Provider', () => { const accountFacade = mock(AccountFacade); const checkoutFacade = mock(CheckoutFacade); const cookiesService = mock(CookiesService); + const oAuthConfigurationService = mock(OAuthConfigurationService); let punchoutIdentityProvider: PunchoutIdentityProvider; let store$: MockStore; - let storeSpy$: MockStore; let router: Router; - let cookieVanishes$: Subject; beforeEach(() => { TestBed.configureTestingModule({ @@ -47,6 +48,8 @@ describe('Punchout Identity Provider', () => { { provide: AppFacade, useFactory: () => instance(appFacade) }, { provide: CheckoutFacade, useFactory: () => instance(checkoutFacade) }, { provide: CookiesService, useFactory: () => instance(cookiesService) }, + { provide: OAuthConfigurationService, useFactory: () => instance(oAuthConfigurationService) }, + { provide: OAuthService, useFactory: () => instance(mock(OAuthService)) }, { provide: PunchoutService, useFactory: () => instance(punchoutService) }, provideMockStore(), ], @@ -55,14 +58,13 @@ describe('Punchout Identity Provider', () => { punchoutIdentityProvider = TestBed.inject(PunchoutIdentityProvider); router = TestBed.inject(Router); store$ = TestBed.inject(MockStore); - storeSpy$ = spy(store$); }); beforeEach(() => { - cookieVanishes$ = new Subject(); when(apiTokenService.restore$(anything())).thenReturn(of(true)); + when(apiTokenService.cookieVanishes$).thenReturn(new Subject()); when(checkoutFacade.basket$).thenReturn(EMPTY); - when(apiTokenService.cookieVanishes$).thenReturn(cookieVanishes$); + when(oAuthConfigurationService.config$).thenReturn(new BehaviorSubject({})); resetCalls(apiTokenService); resetCalls(punchoutService); @@ -91,18 +93,21 @@ describe('Punchout Identity Provider', () => { describe('triggerLogout', () => { beforeEach(() => { when(checkoutFacade.basket$).thenReturn(of(BasketMockData.getBasket())); + when(accountFacade.isLoggedIn$).thenReturn(of(false)); store$.overrideSelector(selectQueryParam(anything()), undefined); punchoutIdentityProvider.init(); }); - it('should remove api token and basket-id on logout', () => { + it('should remove api token and basket-id on logout', done => { expect(window.sessionStorage.getItem('basket-id')).toEqual(BasketMockData.getBasket().id); - punchoutIdentityProvider.triggerLogout(); + const logoutTrigger$ = punchoutIdentityProvider.triggerLogout() as Observable; - expect(window.sessionStorage.getItem('basket-id')).toBeNull(); - expect(capture(storeSpy$.dispatch).first()).toMatchInlineSnapshot(`[User] Logout User`); - verify(apiTokenService.removeApiToken()).once(); + logoutTrigger$.subscribe(() => { + expect(window.sessionStorage.getItem('basket-id')).toBeNull(); + verify(accountFacade.logoutUser()).once(); + done(); + }); }); it('should return to home page per default on subscribe', done => { @@ -123,8 +128,8 @@ describe('Punchout Identity Provider', () => { beforeEach(() => { routerSpy = spy(router); punchoutIdentityProvider.init(); - when(accountFacade.userError$).thenReturn(EMPTY); - when(accountFacade.isLoggedIn$).thenReturn(EMPTY); + when(accountFacade.userError$).thenReturn(timer(Infinity).pipe(switchMap(() => EMPTY))); + when(accountFacade.isLoggedIn$).thenReturn(of(true)); }); it('should throw an business error without query params on login', () => { @@ -141,9 +146,13 @@ describe('Punchout Identity Provider', () => { queryParams = { sid: 'sid', 'access-token': accessToken }; }); - it('should trigger loginUserWithToken method on login', () => { - punchoutIdentityProvider.triggerLogin(getSnapshot(queryParams)); - verify(accountFacade.loginUserWithToken(accessToken)).once(); + it('should trigger loginUserWithToken method on login', done => { + const login$ = punchoutIdentityProvider.triggerLogin(getSnapshot(queryParams)) as Observable; + + login$.subscribe(() => { + verify(accountFacade.loginUserWithToken(accessToken)).once(); + done(); + }); }); }); @@ -155,9 +164,13 @@ describe('Punchout Identity Provider', () => { queryParams = { HOOK_URL: 'url', USERNAME: username, PASSWORD: password }; }); - it('should trigger loginUser method on login', () => { - punchoutIdentityProvider.triggerLogin(getSnapshot(queryParams)); - verify(accountFacade.loginUser(anything())).once(); + it('should trigger loginUser method on login', done => { + const login$ = punchoutIdentityProvider.triggerLogin(getSnapshot(queryParams)) as Observable; + + login$.subscribe(() => { + verify(accountFacade.loginUser(anything())).once(); + done(); + }); }); }); describe('race', () => { diff --git a/src/app/extensions/punchout/identity-provider/punchout-identity-provider.ts b/src/app/extensions/punchout/identity-provider/punchout-identity-provider.ts index 6124b6cdc6..1364a6fef2 100644 --- a/src/app/extensions/punchout/identity-provider/punchout-identity-provider.ts +++ b/src/app/extensions/punchout/identity-provider/punchout-identity-provider.ts @@ -2,23 +2,28 @@ import { HttpEvent, HttpHandler, HttpRequest } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { ActivatedRouteSnapshot, Router, UrlTree } from '@angular/router'; import { Store, select } from '@ngrx/store'; -import { Observable, noop, of, race, throwError } from 'rxjs'; -import { catchError, concatMap, delay, first, map, switchMap, take, tap } from 'rxjs/operators'; +import { OAuthService } from 'angular-oauth2-oidc'; +import { BehaviorSubject, Observable, merge, noop, of, race, throwError } from 'rxjs'; +import { catchError, concatMap, delay, filter, first, map, switchMap, take, tap, withLatestFrom } from 'rxjs/operators'; import { AccountFacade } from 'ish-core/facades/account.facade'; import { AppFacade } from 'ish-core/facades/app.facade'; import { CheckoutFacade } from 'ish-core/facades/checkout.facade'; import { IdentityProvider, TriggerReturnType } from 'ish-core/identity-provider/identity-provider.interface'; import { selectQueryParam } from 'ish-core/store/core/router'; -import { logoutUser } from 'ish-core/store/customer/user'; import { ApiTokenService } from 'ish-core/utils/api-token/api-token.service'; import { CookiesService } from 'ish-core/utils/cookies/cookies.service'; +import { OAuthConfigurationService } from 'ish-core/utils/oauth-configuration/oauth-configuration.service'; import { whenTruthy } from 'ish-core/utils/operators'; import { PunchoutService } from '../services/punchout/punchout.service'; @Injectable({ providedIn: 'root' }) export class PunchoutIdentityProvider implements IdentityProvider { + // emits true, when OAuth Service is successfully configured + // used as an additional condition to check that the OAuth Service is configured before OAuth Service actions are used + private oAuthServiceConfigured$ = new BehaviorSubject(false); + constructor( protected router: Router, protected store: Store, @@ -27,7 +32,9 @@ export class PunchoutIdentityProvider implements IdentityProvider { private accountFacade: AccountFacade, private punchoutService: PunchoutService, private cookiesService: CookiesService, - private checkoutFacade: CheckoutFacade + private checkoutFacade: CheckoutFacade, + private oAuthService: OAuthService, + private configService: OAuthConfigurationService ) {} getCapabilities() { @@ -39,13 +46,34 @@ export class PunchoutIdentityProvider implements IdentityProvider { } init() { - this.apiTokenService.restore$(['user', 'order']).subscribe(noop); - this.apiTokenService.cookieVanishes$.subscribe(type => { - if (type === 'user') { - this.store.dispatch(logoutUser()); - } + // OAuth Service should be configured by internal OAuth configuration service + this.configService.config$.pipe(whenTruthy(), take(1)).subscribe(config => { + this.oAuthService.configure(config); + this.oAuthServiceConfigured$.next(true); }); + this.apiTokenService.cookieVanishes$ + .pipe(withLatestFrom(this.apiTokenService.apiToken$)) + .subscribe(([type, apiToken]) => { + if (!apiToken) { + this.accountFacade.fetchAnonymousToken(); + } + if (type === 'user') { + this.accountFacade.logoutUser({ revokeApiToken: false }); + } + }); + + // OAuth Service should be configured before apiToken information are restored and the refresh token mechanism is setup + this.oAuthServiceConfigured$ + .pipe( + whenTruthy(), + take(1), + switchMap(() => + merge(this.apiTokenService.restore$(['user', 'order']), this.configService.setupRefreshTokenMechanism$()) + ) + ) + .subscribe(noop); + this.checkoutFacade.basket$.pipe(whenTruthy(), first()).subscribe(basketView => { window.sessionStorage.setItem('basket-id', basketView.id); }); @@ -66,67 +94,87 @@ export class PunchoutIdentityProvider implements IdentityProvider { return false; } - // initiate the punchout user login with the access-token (cXML) or the given credentials (OCI) - if (route.queryParamMap.has('access-token')) { - this.accountFacade.loginUserWithToken(route.queryParamMap.get('access-token')); - } else { - this.accountFacade.loginUser({ - login: route.queryParamMap.get('USERNAME'), - password: route.queryParamMap.get('PASSWORD'), - }); - } - return race( - // throw an error if a user login error occurs - this.accountFacade.userError$.pipe( - whenTruthy(), - take(1), - concatMap(userError => throwError(() => userError)) - ), - - // handle the punchout functions once the punchout user is logged in - this.accountFacade.isLoggedIn$.pipe( - whenTruthy(), - take(1), - switchMap(() => { - // handle cXML punchout with sid - if (route.queryParamMap.get('sid')) { - return this.handleCxmlPunchoutLogin(route); - // handle OCI punchout with HOOK_URL - } else if (route.queryParamMap.get('HOOK_URL')) { - return this.handleOciPunchoutLogin(route); - } - }), - // punchout error after successful authentication (needs to logout) - catchError(error => - this.accountFacade.userLoading$.pipe( - first(loading => !loading), - delay(0), + return this.oAuthServiceConfigured$.pipe( + whenTruthy(), + take(1), + tap(() => { + // initiate the punchout user login with the access-token (cXML) or the given credentials (OCI) + if (route.queryParamMap.has('access-token')) { + this.accountFacade.loginUserWithToken(route.queryParamMap.get('access-token')); + } else { + this.accountFacade.loginUser({ + login: route.queryParamMap.get('USERNAME'), + password: route.queryParamMap.get('PASSWORD'), + }); + } + }), + switchMap(() => + race( + // throw an error if a user login error occurs + this.accountFacade.userError$.pipe( + whenTruthy(), + take(1), + concatMap(userError => throwError(() => userError)) + ), + + // handle the punchout functions once the punchout user is logged in + this.accountFacade.isLoggedIn$.pipe( + whenTruthy(), + take(1), switchMap(() => { - this.accountFacade.logoutUser(); - this.apiTokenService.removeApiToken(); - this.appFacade.setBusinessError(error); - return of(this.router.parseUrl('/error')); - }) + // handle cXML punchout with sid + if (route.queryParamMap.get('sid')) { + return this.handleCxmlPunchoutLogin(route); + // handle OCI punchout with HOOK_URL + } else if (route.queryParamMap.get('HOOK_URL')) { + return this.handleOciPunchoutLogin(route); + } + }), + // punchout error after successful authentication (needs to logout) + catchError(error => + this.accountFacade.userLoading$.pipe( + first(loading => !loading), + delay(0), + switchMap(() => { + this.accountFacade.logoutUser(); + this.apiTokenService.removeApiToken(); + this.appFacade.setBusinessError(error); + return of(this.router.parseUrl('/error')); + }) + ) + ) ) + ).pipe( + // general punchout error handling (parameter missing, authentication error) + catchError(error => { + this.appFacade.setBusinessError(error); + return of(this.router.parseUrl('/error')); + }) ) ) - ).pipe( - // general punchout error handling (parameter missing, authentication error) - catchError(error => { - this.appFacade.setBusinessError(error); - return of(this.router.parseUrl('/error')); - }) ); } triggerLogout(): TriggerReturnType { window.sessionStorage.removeItem('basket-id'); - this.store.dispatch(logoutUser()); - this.apiTokenService.removeApiToken(); - return this.store.pipe( - select(selectQueryParam('returnUrl')), - map(returnUrl => returnUrl || '/home'), - map(returnUrl => this.router.parseUrl(returnUrl)) + return this.oAuthServiceConfigured$.pipe( + whenTruthy(), + take(1), + tap(() => this.accountFacade.logoutUser()), // user will be logged out and related refresh token is revoked on server + switchMap(() => + this.accountFacade.isLoggedIn$.pipe( + // wait until the user is logged out before you go to homepage to prevent unnecessary REST calls + filter(loggedIn => !loggedIn), + take(1), + switchMap(() => + this.store.pipe( + select(selectQueryParam('returnUrl')), + map(returnUrl => returnUrl || '/home'), + map(returnUrl => this.router.parseUrl(returnUrl)) + ) + ) + ) + ) ); } diff --git a/src/app/extensions/punchout/services/punchout/punchout.service.ts b/src/app/extensions/punchout/services/punchout/punchout.service.ts index 03ad6a0f19..a20e32b68d 100644 --- a/src/app/extensions/punchout/services/punchout/punchout.service.ts +++ b/src/app/extensions/punchout/services/punchout/punchout.service.ts @@ -366,7 +366,7 @@ export class PunchoutService { * @param submit Controls whether the HTML form is actually submitted (default) or not (only created in the document body). */ submitOciPunchoutData(data: Attribute[], submit = true) { - if (!data || !data.length) { + if (!data?.length) { return throwError(() => new Error('submitOciPunchoutData() of the punchout service called without data')); } const hookUrl = this.cookiesService.get('punchout_HookURL'); diff --git a/src/app/extensions/quickorder/shared/direct-order/direct-order.component.spec.ts b/src/app/extensions/quickorder/shared/direct-order/direct-order.component.spec.ts index 1ed87d9f3c..4dd96dbef9 100644 --- a/src/app/extensions/quickorder/shared/direct-order/direct-order.component.spec.ts +++ b/src/app/extensions/quickorder/shared/direct-order/direct-order.component.spec.ts @@ -51,13 +51,13 @@ describe('Direct Order Component', () => { it('should display form with direct order configuration', () => { fixture.detectChanges(); - expect(element.querySelectorAll('formly-field')).toMatchInlineSnapshot(` + expect(element.querySelectorAll('formly-group formly-field')).toMatchInlineSnapshot(` NodeList [ - TextInputFieldComponent: sku ish-text-input-field { "fieldClass": "col-12", "placeholder": "shopping_cart.direct_order.item_placeholder", "attributes": { "autocomplete": "on" }, "label": - "", "focus": false, "disabled": false}, ] diff --git a/src/app/extensions/quickorder/shared/quickorder-add-products-form/quickorder-add-products-form.component.spec.ts b/src/app/extensions/quickorder/shared/quickorder-add-products-form/quickorder-add-products-form.component.spec.ts index 31d8fd673e..0191505920 100644 --- a/src/app/extensions/quickorder/shared/quickorder-add-products-form/quickorder-add-products-form.component.spec.ts +++ b/src/app/extensions/quickorder/shared/quickorder-add-products-form/quickorder-add-products-form.component.spec.ts @@ -48,11 +48,9 @@ describe('Quickorder Add Products Form Component', () => { it('should display form with add products configuration', () => { fixture.detectChanges(); - expect(element.querySelectorAll('formly-field')).toMatchInlineSnapshot(` + expect(element.querySelectorAll('formly-group formly-field')).toMatchInlineSnapshot(` NodeList [ - , + , ] `); }); diff --git a/src/app/extensions/quoting/store/quoting/quoting.effects.ts b/src/app/extensions/quoting/store/quoting/quoting.effects.ts index 657b5fefd2..536afdc0f7 100644 --- a/src/app/extensions/quoting/store/quoting/quoting.effects.ts +++ b/src/app/extensions/quoting/store/quoting/quoting.effects.ts @@ -32,6 +32,9 @@ import { createQuoteRequestFromQuoteRequest, createQuoteRequestFromQuoteRequestSuccess, createQuoteRequestFromQuoteSuccess, + deleteQuoteFromBasket, + deleteQuoteFromBasketFail, + deleteQuoteFromBasketSuccess, deleteQuotingEntity, deleteQuotingEntityFail, deleteQuotingEntitySuccess, @@ -46,9 +49,6 @@ import { submitQuoteRequestSuccess, updateQuoteRequest, updateQuoteRequestSuccess, - deleteQuoteFromBasket, - deleteQuoteFromBasketSuccess, - deleteQuoteFromBasketFail, } from './quoting.actions'; import { getQuotingEntity } from './quoting.selectors'; diff --git a/src/app/extensions/store-locator/pages/store-locator/store-locator-page.component.html b/src/app/extensions/store-locator/pages/store-locator/store-locator-page.component.html index 84347aed49..2527834a82 100644 --- a/src/app/extensions/store-locator/pages/store-locator/store-locator-page.component.html +++ b/src/app/extensions/store-locator/pages/store-locator/store-locator-page.component.html @@ -1,7 +1,8 @@ -

{{ 'store_locator.title' | translate }}

+

{{ 'store_locator.title' | translate }}

{{ 'store_locator.description' | translate }}

{{ 'store_locator.howto' | translate }}

+
diff --git a/src/app/pages/account-addresses/account-addresses/account-addresses.component.html b/src/app/pages/account-addresses/account-addresses/account-addresses.component.html index fa600601e6..7ac61ededb 100644 --- a/src/app/pages/account-addresses/account-addresses/account-addresses.component.html +++ b/src/app/pages/account-addresses/account-addresses/account-addresses.component.html @@ -3,7 +3,7 @@

{{ 'account.addresses.saved_address.heading' | translate }}

{{ 'account.addresses.preferredinvoiceandshipping.heading' | translate }}

- - -
+ +
{{ 'account.addresses.preferredinvoiceandshipping.heading' | translate }}

{{ 'account.addresses.preferredinvoice.heading' | translate }}

- +

{{ 'account.addresses.no_preferred_invoice_address.text' | translate }}

-
+
@@ -74,12 +87,19 @@

{{ 'account.addresses.preferredinvoice.heading' | translate }}

{{ 'account.addresses.preferredshipping.heading' | translate }}

- +

{{ 'account.addresses.no_preferred_shipping_address.text' | translate }}

-
diff --git a/src/app/pages/account-addresses/account-addresses/account-addresses.component.spec.ts b/src/app/pages/account-addresses/account-addresses/account-addresses.component.spec.ts index 7c22517d66..884043e931 100644 --- a/src/app/pages/account-addresses/account-addresses/account-addresses.component.spec.ts +++ b/src/app/pages/account-addresses/account-addresses/account-addresses.component.spec.ts @@ -129,7 +129,7 @@ describe('Account Addresses Component', () => { expect(component.preferredAddressesEqual).toBeTruthy(); expect(element.querySelector('div[data-testing-id=preferred-invoice-and-shipping-address]')).toBeTruthy(); expect( - element.querySelectorAll('div[data-testing-id=preferred-invoice-and-shipping-address] formly-field') + element.querySelectorAll('div[data-testing-id=preferred-invoice-and-shipping-address] formly-group formly-field') ).toHaveLength(2); expect(element.querySelector('div[data-testing-id=preferred-invoice-address]')).toBeFalsy(); expect(element.querySelector('div[data-testing-id=preferred-shipping-address]')).toBeFalsy(); @@ -148,9 +148,13 @@ describe('Account Addresses Component', () => { expect(element.querySelector('div[data-testing-id=preferred-invoice-and-shipping-address]')).toBeFalsy(); expect(element.querySelector('div[data-testing-id=preferred-invoice-address]')).toBeTruthy(); - expect(element.querySelectorAll('div[data-testing-id=preferred-invoice-address] formly-field')).toHaveLength(1); + expect( + element.querySelectorAll('div[data-testing-id=preferred-invoice-address] formly-group formly-field') + ).toHaveLength(1); expect(element.querySelector('div[data-testing-id=preferred-shipping-address]')).toBeTruthy(); - expect(element.querySelectorAll('div[data-testing-id=preferred-shipping-address] formly-field')).toHaveLength(1); + expect( + element.querySelectorAll('div[data-testing-id=preferred-shipping-address] formly-group formly-field') + ).toHaveLength(1); }); it('should not display further addresses if only preferred invoice and shipping addresses are available', () => { @@ -271,6 +275,14 @@ describe('Account Addresses Component', () => { verify(accountFacade.createCustomerAddress(anything())).once(); }); + it('should emit updateAddress event when updateAddress is triggered', () => { + const address = { id: '123' } as Address; + + component.updateAddress(address); + + verify(accountFacade.updateCustomerAddress(anything())).once(); + }); + it('should emit deleteCustomerAddress event when deleteCustomerAddress is triggered', () => { const address = { id: '123' } as Address; diff --git a/src/app/pages/account-addresses/account-addresses/account-addresses.component.ts b/src/app/pages/account-addresses/account-addresses/account-addresses.component.ts index 306b4f5a8c..a0c152f4bc 100644 --- a/src/app/pages/account-addresses/account-addresses/account-addresses.component.ts +++ b/src/app/pages/account-addresses/account-addresses/account-addresses.component.ts @@ -36,6 +36,7 @@ export class AccountAddressesComponent implements OnInit, OnDestroy { selectShippingConfig: FormlyFieldConfig; isCreateAddressFormCollapsed = true; + updateFormExpandedAddressId: string; preferredAddressForm: FormGroup = new FormGroup({}); furtherAddresses: Address[] = []; @@ -150,15 +151,30 @@ export class AccountAddressesComponent implements OnInit, OnDestroy { showCreateAddressForm() { this.isCreateAddressFormCollapsed = false; } - hideCreateAddressForm() { this.isCreateAddressFormCollapsed = true; } + showUpdateAddressForm(address: Address) { + this.updateFormExpandedAddressId = address.id; + } + hideUpdateAddressForm() { + this.updateFormExpandedAddressId = undefined; + } + + isUpdateAddressFormCollapsed(address: Address) { + return address?.id !== this.updateFormExpandedAddressId; + } + createAddress(address: Address) { this.accountFacade.createCustomerAddress(address); } + updateAddress(address: Address): void { + this.accountFacade.updateCustomerAddress(address); + this.hideUpdateAddressForm(); + } + deleteAddress(address: Address) { this.accountFacade.deleteCustomerAddress(address.id); } diff --git a/src/app/pages/account-profile-company/account-profile-company/account-profile-company.component.spec.ts b/src/app/pages/account-profile-company/account-profile-company/account-profile-company.component.spec.ts index 951eab60e7..8fc470faa7 100644 --- a/src/app/pages/account-profile-company/account-profile-company/account-profile-company.component.spec.ts +++ b/src/app/pages/account-profile-company/account-profile-company/account-profile-company.component.spec.ts @@ -54,7 +54,7 @@ describe('Account Profile Company Component', () => { it('should display 3 input fields for companyName, companyName2 and taxationID', () => { fixture.detectChanges(); - expect(element.querySelectorAll('formly-field')).toHaveLength(3); + expect(element.querySelectorAll('formly-group formly-field')).toHaveLength(3); }); it('should emit updateCompanyProfile event if form is valid', () => { diff --git a/src/app/pages/account-profile-email/account-profile-email/account-profile-email.component.spec.ts b/src/app/pages/account-profile-email/account-profile-email/account-profile-email.component.spec.ts index 28eb48346a..4a920e0682 100644 --- a/src/app/pages/account-profile-email/account-profile-email/account-profile-email.component.spec.ts +++ b/src/app/pages/account-profile-email/account-profile-email/account-profile-email.component.spec.ts @@ -39,7 +39,7 @@ describe('Account Profile Email Component', () => { it('should display 3 input fields for email, emailConfirmation and password', () => { fixture.detectChanges(); - expect(element.querySelectorAll('formly-group formly-field')).toHaveLength(3); + expect(element.querySelectorAll('formly-group formly-group formly-field')).toHaveLength(3); }); it('should emit updateEmail event if form is valid', () => { diff --git a/src/app/pages/account-profile-password/account-profile-password/account-profile-password.component.spec.ts b/src/app/pages/account-profile-password/account-profile-password/account-profile-password.component.spec.ts index 3f1506ed63..98786aaa8c 100644 --- a/src/app/pages/account-profile-password/account-profile-password/account-profile-password.component.spec.ts +++ b/src/app/pages/account-profile-password/account-profile-password/account-profile-password.component.spec.ts @@ -35,7 +35,7 @@ describe('Account Profile Password Component', () => { it('should display 3 input fields for oldPassword, password and passwordConfirmation', () => { fixture.detectChanges(); - expect(element.querySelectorAll('formly-group formly-field')).toHaveLength(3); + expect(element.querySelectorAll('formly-group formly-group formly-field')).toHaveLength(3); }); it('should emit updatePassword event if form is valid', () => { diff --git a/src/app/pages/basket/shopping-basket-empty/shopping-basket-empty.component.html b/src/app/pages/basket/shopping-basket-empty/shopping-basket-empty.component.html index e75be827c0..310ea15775 100644 --- a/src/app/pages/basket/shopping-basket-empty/shopping-basket-empty.component.html +++ b/src/app/pages/basket/shopping-basket-empty/shopping-basket-empty.component.html @@ -8,7 +8,8 @@
- {{ 'shopping_cart.empty.alt.text' | translate }} + + {{ 'shopping_cart.empty.zero.text' | translate }}

{{ 'shopping_cart.empty.text' | translate }}

diff --git a/src/app/pages/basket/shopping-basket-empty/shopping-basket-empty.component.spec.ts b/src/app/pages/basket/shopping-basket-empty/shopping-basket-empty.component.spec.ts index bacabcd3af..1d7c2b9e84 100644 --- a/src/app/pages/basket/shopping-basket-empty/shopping-basket-empty.component.spec.ts +++ b/src/app/pages/basket/shopping-basket-empty/shopping-basket-empty.component.spec.ts @@ -1,4 +1,5 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { FaIconComponent } from '@fortawesome/angular-fontawesome'; import { TranslateModule } from '@ngx-translate/core'; import { MockComponent } from 'ng-mocks'; @@ -20,6 +21,7 @@ describe('Shopping Basket Empty Component', () => { MockComponent(BasketInfoComponent), MockComponent(BasketValidationResultsComponent), MockComponent(ErrorMessageComponent), + MockComponent(FaIconComponent), ShoppingBasketEmptyComponent, ], imports: [TranslateModule.forRoot()], diff --git a/src/app/pages/checkout-address/checkout-address-anonymous/checkout-address-anonymous.component.spec.ts b/src/app/pages/checkout-address/checkout-address-anonymous/checkout-address-anonymous.component.spec.ts index d2a81c1cc5..961540f03d 100644 --- a/src/app/pages/checkout-address/checkout-address-anonymous/checkout-address-anonymous.component.spec.ts +++ b/src/app/pages/checkout-address/checkout-address-anonymous/checkout-address-anonymous.component.spec.ts @@ -54,6 +54,8 @@ describe('Checkout Address Anonymous Component', () => { additionalAddressAttributes: fb.group({ email: new FormControl('', Validators.required), taxationID: new FormControl(''), + }), + shipOptions: fb.group({ shipOption: new FormControl('shipToInvoiceAddress'), }), invoiceAddress: fb.group({ @@ -125,9 +127,11 @@ describe('Checkout Address Anonymous Component', () => { it('should create address for valid invoice address form', () => { component.form.get('additionalAddressAttributes').setValue({ taxationID: '', - shipOption: 'shipToInvoiceAddress', email: 'test@intershop.de', }); + component.form.get('shipOptions').setValue({ + shipOption: 'shipToInvoiceAddress', + }); component.submitAddressForm(); fixture.detectChanges(); diff --git a/src/app/pages/checkout-address/checkout-address-anonymous/checkout-address-anonymous.component.ts b/src/app/pages/checkout-address/checkout-address-anonymous/checkout-address-anonymous.component.ts index 43bc07f993..7f1a65927e 100644 --- a/src/app/pages/checkout-address/checkout-address-anonymous/checkout-address-anonymous.component.ts +++ b/src/app/pages/checkout-address/checkout-address-anonymous/checkout-address-anonymous.component.ts @@ -64,10 +64,13 @@ export class CheckoutAddressAnonymousComponent implements OnChanges { this.addressForm.control.get('additionalAddressAttributes').setValue({ taxationID: '', - shipOption: 'shipToInvoiceAddress', email: '', }); + this.addressForm.control.get('shipOptions').setValue({ + shipOption: 'shipToInvoiceAddress', + }); + this.submitted = false; } @@ -88,7 +91,7 @@ export class CheckoutAddressAnonymousComponent implements OnChanges { }; const shippingAddress = - this.form.get('additionalAddressAttributes').value.shipOption === 'shipToInvoiceAddress' + this.form.get('shipOptions').value.shipOption === 'shipToInvoiceAddress' ? undefined : this.form.get('shippingAddress').value.address; @@ -114,6 +117,6 @@ export class CheckoutAddressAnonymousComponent implements OnChanges { } get isShippingAddressFormExpanded() { - return this.form && this.form.get('additionalAddressAttributes').value.shipOption === 'shipToDifferentAddress'; + return this.form && this.form.get('shipOptions').value.shipOption === 'shipToDifferentAddress'; } } diff --git a/src/app/pages/checkout-address/checkout-address-page.component.ts b/src/app/pages/checkout-address/checkout-address-page.component.ts index f71aadcfa8..ab51527b4d 100644 --- a/src/app/pages/checkout-address/checkout-address-page.component.ts +++ b/src/app/pages/checkout-address/checkout-address-page.component.ts @@ -6,6 +6,7 @@ import { filter, first, map, take, takeUntil } from 'rxjs/operators'; import { AccountFacade } from 'ish-core/facades/account.facade'; import { CheckoutFacade } from 'ish-core/facades/checkout.facade'; import { BasketView } from 'ish-core/models/basket/basket.model'; +import { CheckoutStepType } from 'ish-core/models/checkout/checkout-step.type'; import { HttpError } from 'ish-core/models/http-error/http-error.model'; import { User } from 'ish-core/models/user/user.model'; import { whenTruthy } from 'ish-core/utils/operators'; @@ -56,7 +57,7 @@ export class CheckoutAddressPageComponent implements OnInit, OnDestroy { this.basket$ .pipe( whenTruthy(), - filter(basket => !basket.lineItems || !basket.lineItems.length), + filter(basket => !basket.lineItems?.length), take(1), takeUntil(this.destroy$) ) @@ -69,7 +70,7 @@ export class CheckoutAddressPageComponent implements OnInit, OnDestroy { */ nextStep() { this.nextStepRequested = true; - this.checkoutFacade.continue(2); + this.checkoutFacade.continue(CheckoutStepType.Shipping); } ngOnDestroy() { diff --git a/src/app/pages/checkout-address/formly/components/checkout-address-anonymous-form/checkout-address-anonymous-form.component.html b/src/app/pages/checkout-address/formly/components/checkout-address-anonymous-form/checkout-address-anonymous-form.component.html index e0aea58658..f8c9648d3f 100644 --- a/src/app/pages/checkout-address/formly/components/checkout-address-anonymous-form/checkout-address-anonymous-form.component.html +++ b/src/app/pages/checkout-address/formly/components/checkout-address-anonymous-form/checkout-address-anonymous-form.component.html @@ -11,12 +11,15 @@

{{ 'checkout.addresses.billing_address.heading' | transla - +

{{ 'checkout.addresses.shipping_address.heading' | translate }}

- +
diff --git a/src/app/pages/checkout-address/formly/components/checkout-address-anonymous-form/checkout-address-anonymous-form.component.spec.ts b/src/app/pages/checkout-address/formly/components/checkout-address-anonymous-form/checkout-address-anonymous-form.component.spec.ts index aae4c8ac3b..833db14546 100644 --- a/src/app/pages/checkout-address/formly/components/checkout-address-anonymous-form/checkout-address-anonymous-form.component.spec.ts +++ b/src/app/pages/checkout-address/formly/components/checkout-address-anonymous-form/checkout-address-anonymous-form.component.spec.ts @@ -5,6 +5,7 @@ import { TranslateModule } from '@ngx-translate/core'; import { MockComponent } from 'ng-mocks'; import { FeatureToggleModule } from 'ish-core/feature-toggle.module'; +import { FormlyAddressExtensionFormComponent } from 'ish-shared/formly-address-forms/components/formly-address-extension-form/formly-address-extension-form.component'; import { FormlyAddressFormComponent } from 'ish-shared/formly-address-forms/components/formly-address-form/formly-address-form.component'; import { FormlyTestingModule } from 'ish-shared/formly/dev/testing/formly-testing.module'; @@ -18,7 +19,11 @@ describe('Checkout Address Anonymous Form Component', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [CheckoutAddressAnonymousFormComponent, MockComponent(FormlyAddressFormComponent)], + declarations: [ + CheckoutAddressAnonymousFormComponent, + MockComponent(FormlyAddressExtensionFormComponent), + MockComponent(FormlyAddressFormComponent), + ], imports: [ FeatureToggleModule.forTesting('businessCustomerRegistration'), FormlyTestingModule.withPresetMocks(['taxationID']), @@ -43,15 +48,10 @@ describe('Checkout Address Anonymous Form Component', () => { expect(() => fixture.detectChanges()).not.toThrow(); }); - it('should set input field for taxation-id, when businessCustomerRegistration feature is enabled', () => { - fixture.detectChanges(); - expect(component.parentForm.get('additionalAddressAttributes').value).toContainKey('taxationID'); - }); - it('should add shipping address form to parent form, when shipOption is set to shipToDifferentAddress', () => { fixture.detectChanges(); - component.form.get('shipOption').setValue('shipToDifferentAddress'); + component.shipOptionForm.get('shipOption').setValue('shipToDifferentAddress'); fixture.detectChanges(); diff --git a/src/app/pages/checkout-address/formly/components/checkout-address-anonymous-form/checkout-address-anonymous-form.component.ts b/src/app/pages/checkout-address/formly/components/checkout-address-anonymous-form/checkout-address-anonymous-form.component.ts index 61fd2e471c..ed411c2628 100644 --- a/src/app/pages/checkout-address/formly/components/checkout-address-anonymous-form/checkout-address-anonymous-form.component.ts +++ b/src/app/pages/checkout-address/formly/components/checkout-address-anonymous-form/checkout-address-anonymous-form.component.ts @@ -1,6 +1,6 @@ import { ChangeDetectionStrategy, Component, Input, OnDestroy, OnInit } from '@angular/core'; -import { FormControl, FormGroup } from '@angular/forms'; -import { FormlyFieldConfig, FormlyFormOptions } from '@ngx-formly/core'; +import { FormGroup } from '@angular/forms'; +import { FormlyFieldConfig } from '@ngx-formly/core'; import { Subject } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; @@ -13,14 +13,11 @@ import { FeatureToggleService } from 'ish-core/feature-toggle.module'; }) export class CheckoutAddressAnonymousFormComponent implements OnInit, OnDestroy { @Input() parentForm: FormGroup; - formControl: FormControl; invoiceAddressForm = new FormGroup({}); shippingAddressForm = new FormGroup({}); - form: FormGroup = new FormGroup({}); - - addressFields: FormlyFieldConfig[]; - addressOptions: FormlyFormOptions = {}; + attributesForm: FormGroup = new FormGroup({}); + shipOptionForm: FormGroup = new FormGroup({}); shipOptionFields: FormlyFieldConfig[]; @@ -29,35 +26,13 @@ export class CheckoutAddressAnonymousFormComponent implements OnInit, OnDestroy private destroy$ = new Subject(); get isShippingAddressFormExpanded() { - return this.form && this.form.get('shipOption').value === 'shipToDifferentAddress'; + return this.shipOptionForm && this.shipOptionForm.get('shipOption').value === 'shipToDifferentAddress'; } constructor(private featureToggleService: FeatureToggleService) {} ngOnInit() { - this.addressFields = [ - { - type: 'ish-fieldset-field', - fieldGroup: [ - { - key: 'email', - type: 'ish-email-field', - templateOptions: { - required: true, - label: 'checkout.addresses.email.label', - forceRequiredStar: true, - customDescription: { - key: 'account.address.email.hint', - }, - postWrappers: [{ wrapper: 'description', index: -1 }], - }, - }, - ], - }, - ]; - if (this.featureToggleService.enabled('businessCustomerRegistration')) { - this.addressFields = [this.createTaxationIDField(), ...this.addressFields]; this.isBusinessCustomer = true; } @@ -82,30 +57,20 @@ export class CheckoutAddressAnonymousFormComponent implements OnInit, OnDestroy }, ]; this.parentForm.setControl('invoiceAddress', this.invoiceAddressForm); - this.parentForm.setControl('additionalAddressAttributes', this.form); + this.parentForm.setControl('additionalAddressAttributes', this.attributesForm); + this.parentForm.setControl('shipOptions', this.shipOptionForm); // add / remove shipping form if shipTo address option changes this.parentForm - .get('additionalAddressAttributes') + .get('shipOptions') .valueChanges.pipe(takeUntil(this.destroy$)) - .subscribe(attributes => { - attributes.shipOption === 'shipToInvoiceAddress' + .subscribe(options => { + options.shipOption === 'shipToInvoiceAddress' ? this.parentForm.removeControl('shippingAddress') : this.parentForm.setControl('shippingAddress', this.shippingAddressForm); }); } - private createTaxationIDField(): FormlyFieldConfig { - return { - type: 'ish-fieldset-field', - fieldGroup: [ - { - type: '#taxationID', - }, - ], - }; - } - ngOnDestroy() { this.destroy$.next(); this.destroy$.complete(); diff --git a/src/app/pages/checkout-payment/checkout-payment-page.component.ts b/src/app/pages/checkout-payment/checkout-payment-page.component.ts index 6689cdce53..3dc97612af 100644 --- a/src/app/pages/checkout-payment/checkout-payment-page.component.ts +++ b/src/app/pages/checkout-payment/checkout-payment-page.component.ts @@ -4,6 +4,7 @@ import { filter, first, map, shareReplay, takeUntil, withLatestFrom } from 'rxjs import { CheckoutFacade } from 'ish-core/facades/checkout.facade'; import { BasketView } from 'ish-core/models/basket/basket.model'; +import { CheckoutStepType } from 'ish-core/models/checkout/checkout-step.type'; import { HttpError } from 'ish-core/models/http-error/http-error.model'; import { PaymentInstrument } from 'ish-core/models/payment-instrument/payment-instrument.model'; import { PaymentMethod } from 'ish-core/models/payment-method/payment-method.model'; @@ -54,7 +55,7 @@ export class CheckoutPaymentPageComponent implements OnInit, OnDestroy { } createPaymentInstrument(body: { paymentInstrument: PaymentInstrument; saveForLater: boolean }) { - if (!body || !body.paymentInstrument) { + if (!body?.paymentInstrument) { return; } this.checkoutFacade.createBasketPayment(body.paymentInstrument, body.saveForLater); @@ -68,7 +69,7 @@ export class CheckoutPaymentPageComponent implements OnInit, OnDestroy { * Validates the basket and jumps to the next checkout step (Review) */ nextStep() { - this.checkoutFacade.continue(4); + this.checkoutFacade.continue(CheckoutStepType.Review); } ngOnDestroy() { diff --git a/src/app/pages/checkout-payment/checkout-payment/checkout-payment.component.ts b/src/app/pages/checkout-payment/checkout-payment/checkout-payment.component.ts index f60bee1fef..826e2a6f23 100644 --- a/src/app/pages/checkout-payment/checkout-payment/checkout-payment.component.ts +++ b/src/app/pages/checkout-payment/checkout-payment/checkout-payment.component.ts @@ -246,7 +246,7 @@ export class CheckoutPaymentComponent implements OnInit, OnChanges, OnDestroy { } get nextDisabled() { - return (!this.basket || !this.basket.payment) && this.nextSubmitted; + return !this.basket?.payment && this.nextSubmitted; } get submitDisabled() { diff --git a/src/app/pages/checkout-payment/payment-concardis/payment-concardis.component.ts b/src/app/pages/checkout-payment/payment-concardis/payment-concardis.component.ts index bd8a86cfa2..3bd35d557f 100644 --- a/src/app/pages/checkout-payment/payment-concardis/payment-concardis.component.ts +++ b/src/app/pages/checkout-payment/payment-concardis/payment-concardis.component.ts @@ -114,7 +114,7 @@ export class PaymentConcardisComponent implements OnInit, OnChanges, OnDestroy { */ protected getParamValue(name: string, errorMessage: string): string { const parameter = this.paymentMethod.hostedPaymentPageParameters.find(param => param.name === name); - if (!parameter || !parameter.value) { + if (!parameter?.value) { this.errorMessage.general.message = errorMessage; return; } diff --git a/src/app/pages/checkout-payment/payment-cybersource-creditcard/payment-cybersource-creditcard.component.ts b/src/app/pages/checkout-payment/payment-cybersource-creditcard/payment-cybersource-creditcard.component.ts index 14cd9b4981..b819b96052 100644 --- a/src/app/pages/checkout-payment/payment-cybersource-creditcard/payment-cybersource-creditcard.component.ts +++ b/src/app/pages/checkout-payment/payment-cybersource-creditcard/payment-cybersource-creditcard.component.ts @@ -113,7 +113,7 @@ export class PaymentCybersourceCreditcardComponent implements OnChanges, OnDestr */ protected getParamValue(name: string, errorMessage: string): string { const parameter = this.paymentMethod.hostedPaymentPageParameters.find(param => param.name === name); - if (!parameter || !parameter.value) { + if (!parameter?.value) { this.errorMessage.general.message = errorMessage; return; } diff --git a/src/app/pages/checkout-payment/payment-payone-creditcard/payment-payone-creditcard.component.ts b/src/app/pages/checkout-payment/payment-payone-creditcard/payment-payone-creditcard.component.ts index 30696e3ef9..45941a8ccd 100644 --- a/src/app/pages/checkout-payment/payment-payone-creditcard/payment-payone-creditcard.component.ts +++ b/src/app/pages/checkout-payment/payment-payone-creditcard/payment-payone-creditcard.component.ts @@ -95,7 +95,7 @@ export class PaymentPayoneCreditcardComponent implements OnChanges, OnDestroy, O protected getParamValue(name: string, errorMessage: string): string { const parameter = this.paymentMethod.hostedPaymentPageParameters.find(param => param.name === name); - if (!parameter || !parameter.value) { + if (!parameter?.value) { this.generalErrorMessage = errorMessage; return; } diff --git a/src/app/pages/checkout-receipt/checkout-receipt/checkout-receipt.component.html b/src/app/pages/checkout-receipt/checkout-receipt/checkout-receipt.component.html index eebebac84e..ac01eff225 100644 --- a/src/app/pages/checkout-receipt/checkout-receipt/checkout-receipt.component.html +++ b/src/app/pages/checkout-receipt/checkout-receipt/checkout-receipt.component.html @@ -13,7 +13,7 @@
- + diff --git a/src/app/pages/checkout-review/checkout-review-page.component.ts b/src/app/pages/checkout-review/checkout-review-page.component.ts index b203fed5e6..ccea6749ac 100644 --- a/src/app/pages/checkout-review/checkout-review-page.component.ts +++ b/src/app/pages/checkout-review/checkout-review-page.component.ts @@ -27,9 +27,9 @@ export class CheckoutReviewPageComponent implements OnInit { } /** - * creates an order and routes to receipt page in case of success + * validates the basket, creates an order and routes to receipt page in case of success */ onCreateOrder() { - this.checkoutFacade.continue(5); + this.checkoutFacade.submitOrder(); } } diff --git a/src/app/pages/checkout-review/checkout-review/checkout-review.component.html b/src/app/pages/checkout-review/checkout-review/checkout-review.component.html index 52ac1c0de7..44d86ae664 100644 --- a/src/app/pages/checkout-review/checkout-review/checkout-review.component.html +++ b/src/app/pages/checkout-review/checkout-review/checkout-review.component.html @@ -48,7 +48,7 @@

editRouterLink="/checkout/address" class="infobox-wrapper col-md-6" > - + diff --git a/src/app/pages/checkout-shipping/checkout-shipping-page.component.ts b/src/app/pages/checkout-shipping/checkout-shipping-page.component.ts index 929769f756..8904019327 100644 --- a/src/app/pages/checkout-shipping/checkout-shipping-page.component.ts +++ b/src/app/pages/checkout-shipping/checkout-shipping-page.component.ts @@ -5,6 +5,7 @@ import { shareReplay, take, takeUntil } from 'rxjs/operators'; import { AccountFacade } from 'ish-core/facades/account.facade'; import { CheckoutFacade } from 'ish-core/facades/checkout.facade'; import { BasketView } from 'ish-core/models/basket/basket.model'; +import { CheckoutStepType } from 'ish-core/models/checkout/checkout-step.type'; import { HttpError } from 'ish-core/models/http-error/http-error.model'; import { ShippingMethod } from 'ish-core/models/shipping-method/shipping-method.model'; @@ -50,7 +51,7 @@ export class CheckoutShippingPageComponent implements OnInit, OnDestroy { this.nextDisabled = !basket || !shippingMethods || !shippingMethods.length || !basket.commonShippingMethod; this.cd.markForCheck(); if (!this.nextDisabled) { - this.checkoutFacade.continue(3); + this.checkoutFacade.continue(CheckoutStepType.Payment); } }); } diff --git a/src/app/pages/checkout-shipping/checkout-shipping/checkout-shipping.component.spec.ts b/src/app/pages/checkout-shipping/checkout-shipping/checkout-shipping.component.spec.ts index 15f8a716b4..da042482ab 100644 --- a/src/app/pages/checkout-shipping/checkout-shipping/checkout-shipping.component.spec.ts +++ b/src/app/pages/checkout-shipping/checkout-shipping/checkout-shipping.component.spec.ts @@ -48,7 +48,7 @@ describe('Checkout Shipping Component', () => { it('should render available shipping methods on page', () => { fixture.detectChanges(); - expect(element.querySelectorAll('formly-field')).toHaveLength(1); + expect(element.querySelectorAll('formly-group formly-field')).toHaveLength(1); }); it('should throw updateShippingMethod event when the user changes payment selection', () => { diff --git a/src/app/pages/registration/registration-page.component.spec.ts b/src/app/pages/registration/registration-page.component.spec.ts index acf629b622..78c8dc161d 100644 --- a/src/app/pages/registration/registration-page.component.spec.ts +++ b/src/app/pages/registration/registration-page.component.spec.ts @@ -63,12 +63,12 @@ describe('Registration Page Component', () => { it('should display form with registration configuration', () => { fixture.detectChanges(); - expect(element.querySelectorAll('formly-field')).toMatchInlineSnapshot(` + expect(element.querySelectorAll('formly-group formly-field')).toMatchInlineSnapshot(` NodeList [ - TextInputFieldComponent: test ish-text-input-field { "label": "", "placeholder": "", "focus": - false, "disabled": false}TextInputFieldComponent: test ish-text-input-field { "label": "", "placeholder": "", + "disabled": false}, ] diff --git a/src/app/shared/components/basket/basket-address-summary/basket-address-summary.component.html b/src/app/shared/components/basket/basket-address-summary/basket-address-summary.component.html index 78a8666224..d819a54191 100644 --- a/src/app/shared/components/basket/basket-address-summary/basket-address-summary.component.html +++ b/src/app/shared/components/basket/basket-address-summary/basket-address-summary.component.html @@ -7,7 +7,7 @@

{{ 'checkout.address.billing.label' | translate }}
- +
diff --git a/src/app/shared/components/basket/basket-cost-center-selection/basket-cost-center-selection.component.spec.ts b/src/app/shared/components/basket/basket-cost-center-selection/basket-cost-center-selection.component.spec.ts index caabaf17c8..3e69e6d73b 100644 --- a/src/app/shared/components/basket/basket-cost-center-selection/basket-cost-center-selection.component.spec.ts +++ b/src/app/shared/components/basket/basket-cost-center-selection/basket-cost-center-selection.component.spec.ts @@ -71,8 +71,8 @@ describe('Basket Cost Center Selection Component', () => { when(checkoutFacade.eligibleCostCenterSelectOptions$()).thenReturn(of([mockCostCenterOptions[0]])); fixture.detectChanges(); - expect(element.querySelectorAll('formly-field')).toHaveLength(1); - expect(element.querySelector('formly-field').textContent).toMatchInlineSnapshot(` + expect(element.querySelectorAll('formly-group formly-field')).toHaveLength(1); + expect(element.querySelector('formly-group formly-field').textContent).toMatchInlineSnapshot(` "SelectFieldComponent: costCenter ish-select-field { \\"label\\": \\"checkout.cost_center.select.label\\", \\"required\\": true, @@ -84,7 +84,6 @@ describe('Basket Cost Center Selection Component', () => { } ], \\"placeholder\\": \\"\\", - \\"focus\\": false, \\"disabled\\": false }" `); @@ -93,8 +92,8 @@ describe('Basket Cost Center Selection Component', () => { it('should be rendered with correct options and placeholder for multiple cost center options', () => { when(checkoutFacade.eligibleCostCenterSelectOptions$()).thenReturn(of(mockCostCenterOptions)); fixture.detectChanges(); - expect(element.querySelectorAll('formly-field')).toHaveLength(1); - expect(element.querySelector('formly-field').textContent).toMatchInlineSnapshot(` + expect(element.querySelectorAll('formly-group formly-field')).toHaveLength(1); + expect(element.querySelector('formly-group formly-field').textContent).toMatchInlineSnapshot(` "SelectFieldComponent: costCenter ish-select-field { \\"label\\": \\"checkout.cost_center.select.label\\", \\"required\\": true, @@ -110,7 +109,6 @@ describe('Basket Cost Center Selection Component', () => { } ], \\"placeholder\\": \\"account.option.select.text\\", - \\"focus\\": false, \\"disabled\\": false }" `); @@ -125,8 +123,8 @@ describe('Basket Cost Center Selection Component', () => { subject$.next({ ...BasketMockData.getBasket(), costCenter: '2' }); fixture.detectChanges(); - expect(element.querySelectorAll('formly-field')).toHaveLength(1); - expect(element.querySelector('formly-field').textContent).toMatchInlineSnapshot(` + expect(element.querySelectorAll('formly-group formly-field')).toHaveLength(1); + expect(element.querySelector('formly-group formly-field').textContent).toMatchInlineSnapshot(` "SelectFieldComponent: costCenter ish-select-field { \\"label\\": \\"checkout.cost_center.select.label\\", \\"required\\": true, @@ -142,7 +140,6 @@ describe('Basket Cost Center Selection Component', () => { } ], \\"placeholder\\": \\"\\", - \\"focus\\": false, \\"disabled\\": false }" `); diff --git a/src/app/shared/components/basket/basket-desired-delivery-date/basket-desired-delivery-date.component.spec.ts b/src/app/shared/components/basket/basket-desired-delivery-date/basket-desired-delivery-date.component.spec.ts index 465a941b2e..0e35cdf26e 100644 --- a/src/app/shared/components/basket/basket-desired-delivery-date/basket-desired-delivery-date.component.spec.ts +++ b/src/app/shared/components/basket/basket-desired-delivery-date/basket-desired-delivery-date.component.spec.ts @@ -1,12 +1,10 @@ import { SimpleChange } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { TranslateModule } from '@ngx-translate/core'; -import { MockComponent } from 'ng-mocks'; -import { anything, instance, mock, when } from 'ts-mockito'; +import { anything, instance, mock, verify, when } from 'ts-mockito'; import { CheckoutFacade } from 'ish-core/facades/checkout.facade'; import { Basket } from 'ish-core/models/basket/basket.model'; -import { SuccessMessageComponent } from 'ish-shared/components/common/success-message/success-message.component'; import { FormlyTestingModule } from 'ish-shared/formly/dev/testing/formly-testing.module'; import { BasketDesiredDeliveryDateComponent } from './basket-desired-delivery-date.component'; @@ -22,7 +20,7 @@ describe('Basket Desired Delivery Date Component', () => { await TestBed.configureTestingModule({ imports: [FormlyTestingModule, TranslateModule.forRoot()], - declarations: [BasketDesiredDeliveryDateComponent, MockComponent(SuccessMessageComponent)], + declarations: [BasketDesiredDeliveryDateComponent], providers: [{ provide: CheckoutFacade, useFactory: () => instance(checkoutFacade) }], }).compileComponents(); }); @@ -32,7 +30,7 @@ describe('Basket Desired Delivery Date Component', () => { component = fixture.componentInstance; element = fixture.nativeElement; - when(checkoutFacade.setBasketCustomAttribute(anything())).thenReturn(); + when(checkoutFacade.setDesiredDeliveryDate(anything())).thenReturn(); }); it('should be created', () => { @@ -58,16 +56,14 @@ describe('Basket Desired Delivery Date Component', () => { expect(component.model.desiredDeliveryDate?.toISOString()).toMatch(/^2022-03-17/); }); - it('should show success message after successful delivery date change', () => { - const prev = { - attributes: [{ name: 'desiredDeliveryDate', value: '2022-3-17' }], - } as Basket; - const post = { - attributes: [{ name: 'desiredDeliveryDate', value: '2022-3-18' }], + it('should call setDesiredDeliveryDate if submit form is called', () => { + component.basket = { + attributes: [{ name: 'desiredDeliveryDate', value: '2022-03-17' }], } as Basket; - component.basket = prev; - component.ngOnChanges({ basket: new SimpleChange(prev, post, false) }); + fixture.detectChanges(); - expect(element.querySelector('ish-success-message')).toBeTruthy(); + + component.submitForm(); + verify(checkoutFacade.setDesiredDeliveryDate(anything())).once(); }); }); diff --git a/src/app/shared/components/basket/basket-desired-delivery-date/basket-desired-delivery-date.component.ts b/src/app/shared/components/basket/basket-desired-delivery-date/basket-desired-delivery-date.component.ts index f5d2c78850..d3e15f7e51 100644 --- a/src/app/shared/components/basket/basket-desired-delivery-date/basket-desired-delivery-date.component.ts +++ b/src/app/shared/components/basket/basket-desired-delivery-date/basket-desired-delivery-date.component.ts @@ -9,7 +9,7 @@ import { } from '@angular/core'; import { FormControl, FormGroup } from '@angular/forms'; import { FormlyFieldConfig } from '@ngx-formly/core'; -import { formatISO, isEqual, parseISO } from 'date-fns'; +import { isEqual, parseISO } from 'date-fns'; import { CheckoutFacade } from 'ish-core/facades/checkout.facade'; import { AttributeHelper } from 'ish-core/models/attribute/attribute.helper'; @@ -128,16 +128,7 @@ export class BasketDesiredDeliveryDateComponent implements OnInit, OnChanges { if (this.disabled) { return; } - const value = this.form.get('desiredDeliveryDate').value; - let desiredDeliveryDate; - if (value) { - desiredDeliveryDate = formatISO(this.form.get('desiredDeliveryDate').value, { representation: 'date' }); - } - - this.checkoutFacade.setBasketCustomAttribute({ - name: 'desiredDeliveryDate', - value: desiredDeliveryDate ? desiredDeliveryDate : '', - }); + this.checkoutFacade.setDesiredDeliveryDate(this.form.get('desiredDeliveryDate').value); } } diff --git a/src/app/shared/components/basket/basket-promotion-code/basket-promotion-code.component.ts b/src/app/shared/components/basket/basket-promotion-code/basket-promotion-code.component.ts index 537cfbf4e4..fff8fcd4d3 100644 --- a/src/app/shared/components/basket/basket-promotion-code/basket-promotion-code.component.ts +++ b/src/app/shared/components/basket/basket-promotion-code/basket-promotion-code.component.ts @@ -58,7 +58,7 @@ export class BasketPromotionCodeComponent implements OnInit, OnDestroy { */ submitPromotionCode() { // prevent success message if the user enters the same promo code twice - if (!this.basketPromoCodes || !this.basketPromoCodes.includes(this.codeInput.value)) { + if (!this.basketPromoCodes?.includes(this.codeInput.value)) { this.lastEnteredPromoCode = this.codeInput.value; } this.checkoutFacade.addPromotionCodeToBasket(this.codeInput.value); diff --git a/src/app/shared/components/checkout/basket-invoice-address-widget/basket-invoice-address-widget.component.html b/src/app/shared/components/checkout/basket-invoice-address-widget/basket-invoice-address-widget.component.html index 250d64c4ae..8d0ad35d71 100644 --- a/src/app/shared/components/checkout/basket-invoice-address-widget/basket-invoice-address-widget.component.html +++ b/src/app/shared/components/checkout/basket-invoice-address-widget/basket-invoice-address-widget.component.html @@ -13,7 +13,7 @@

{{ 'checkout.address.billing.label' | translate }}

- +

{{ 'checkout.addresses.no_Selection.invoice.error' | translate }} @@ -28,7 +28,7 @@

{{ 'checkout.address.billing.label' | translate }}

-
+

diff --git a/src/app/shared/components/checkout/basket-invoice-address-widget/basket-invoice-address-widget.component.spec.ts b/src/app/shared/components/checkout/basket-invoice-address-widget/basket-invoice-address-widget.component.spec.ts index 683be5da2a..e6b1fba96b 100644 --- a/src/app/shared/components/checkout/basket-invoice-address-widget/basket-invoice-address-widget.component.spec.ts +++ b/src/app/shared/components/checkout/basket-invoice-address-widget/basket-invoice-address-widget.component.spec.ts @@ -31,6 +31,7 @@ describe('Basket Invoice Address Widget Component', () => { accountFacade = mock(AccountFacade); when(accountFacade.addresses$()).thenReturn(EMPTY); + when(accountFacade.isLoggedIn$).thenReturn(of(true)); await TestBed.configureTestingModule({ imports: [FormlyTestingModule, TranslateModule.forRoot()], @@ -160,11 +161,11 @@ describe('Basket Invoice Address Widget Component', () => { component.addresses$.subscribe(addrs => { expect(addrs.map(add => add.id)).toMatchInlineSnapshot(` - Array [ - "3", - "4", - ] - `); + Array [ + "3", + "4", + ] + `); done(); }); }); diff --git a/src/app/shared/components/checkout/basket-invoice-address-widget/basket-invoice-address-widget.component.ts b/src/app/shared/components/checkout/basket-invoice-address-widget/basket-invoice-address-widget.component.ts index 1801a52fa5..73e3543558 100644 --- a/src/app/shared/components/checkout/basket-invoice-address-widget/basket-invoice-address-widget.component.ts +++ b/src/app/shared/components/checkout/basket-invoice-address-widget/basket-invoice-address-widget.component.ts @@ -33,6 +33,7 @@ export class BasketInvoiceAddressWidgetComponent implements OnInit, OnDestroy { invoiceAddress$: Observable
; addresses$: Observable; customerAddresses$: Observable; + isLoggedIn$: Observable; form = new UntypedFormGroup({}); fields: FormlyFieldConfig[]; @@ -64,6 +65,7 @@ export class BasketInvoiceAddressWidgetComponent implements OnInit, OnDestroy { addresses?.filter(address => address.invoiceToAddress).filter(address => address.id !== invoiceAddress?.id) ) ); + this.isLoggedIn$ = this.accountFacade.isLoggedIn$; this.fields = [ { diff --git a/src/app/shared/components/checkout/basket-shipping-address-widget/basket-shipping-address-widget.component.html b/src/app/shared/components/checkout/basket-shipping-address-widget/basket-shipping-address-widget.component.html index f086a07e26..d0d8079ed7 100644 --- a/src/app/shared/components/checkout/basket-shipping-address-widget/basket-shipping-address-widget.component.html +++ b/src/app/shared/components/checkout/basket-shipping-address-widget/basket-shipping-address-widget.component.html @@ -62,7 +62,7 @@

{{ 'checkout.address.shipping.label' | translate }}

-
+
diff --git a/src/app/shared/components/login/login-modal/login-modal.component.ts b/src/app/shared/components/login/login-modal/login-modal.component.ts index a0030c2e1a..0f9cd4bb53 100644 --- a/src/app/shared/components/login/login-modal/login-modal.component.ts +++ b/src/app/shared/components/login/login-modal/login-modal.component.ts @@ -1,4 +1,4 @@ -import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core'; +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, Output } from '@angular/core'; @Component({ selector: 'ish-login-modal', @@ -9,6 +9,12 @@ export class LoginModalComponent { @Input() loginMessageKey: string; @Output() closeModal = new EventEmitter(); + constructor(private cdRef: ChangeDetectorRef) {} + + detectChanges() { + this.cdRef.detectChanges(); + } + hide() { this.closeModal.emit(); } diff --git a/src/app/shared/components/product/product-attributes/product-attributes.component.html b/src/app/shared/components/product/product-attributes/product-attributes.component.html index f53ae5529e..07e36fc3e8 100644 --- a/src/app/shared/components/product/product-attributes/product-attributes.component.html +++ b/src/app/shared/components/product/product-attributes/product-attributes.component.html @@ -2,6 +2,5 @@
{{ attribute.name }}:
-
diff --git a/src/app/shared/components/product/product-label/product-label.component.html b/src/app/shared/components/product/product-label/product-label.component.html index a01c3f40bd..379dc5f534 100644 --- a/src/app/shared/components/product/product-label/product-label.component.html +++ b/src/app/shared/components/product/product-label/product-label.component.html @@ -1,5 +1,14 @@ - + + + + + {{ 'product.label.new.text' | translate }} + + + {{ 'product.label.sale.text' | translate }} + + + {{ 'product.label.topseller.text' | translate }} + + + diff --git a/src/app/shared/components/product/product-label/product-label.component.spec.ts b/src/app/shared/components/product/product-label/product-label.component.spec.ts index 3727c7f763..93d6ecf816 100644 --- a/src/app/shared/components/product/product-label/product-label.component.spec.ts +++ b/src/app/shared/components/product/product-label/product-label.component.spec.ts @@ -1,4 +1,5 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { TranslateModule } from '@ngx-translate/core'; import { of } from 'rxjs'; import { instance, mock, when } from 'ts-mockito'; @@ -17,6 +18,7 @@ describe('Product Label Component', () => { await TestBed.configureTestingModule({ declarations: [ProductLabelComponent], providers: [{ provide: ProductContextFacade, useFactory: () => instance(context) }], + imports: [TranslateModule.forRoot()], }).compileComponents(); }); diff --git a/src/app/shared/components/product/product-variation-select-default/product-variation-select-default.component.html b/src/app/shared/components/product/product-variation-select-default/product-variation-select-default.component.html new file mode 100644 index 0000000000..75ece50bb9 --- /dev/null +++ b/src/app/shared/components/product/product-variation-select-default/product-variation-select-default.component.html @@ -0,0 +1,20 @@ + diff --git a/src/app/shared/components/product/product-variation-select-default/product-variation-select-default.component.spec.ts b/src/app/shared/components/product/product-variation-select-default/product-variation-select-default.component.spec.ts new file mode 100644 index 0000000000..58c50be128 --- /dev/null +++ b/src/app/shared/components/product/product-variation-select-default/product-variation-select-default.component.spec.ts @@ -0,0 +1,72 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { By } from '@angular/platform-browser'; +import { anything, capture, spy, verify } from 'ts-mockito'; + +import { VariationOptionGroup } from 'ish-core/models/product-variation/variation-option-group.model'; +import { findAllDataTestingIDs } from 'ish-core/utils/dev/html-query-utils'; + +import { ProductVariationSelectDefaultComponent } from './product-variation-select-default.component'; + +describe('Product Variation Select Default Component', () => { + let component: ProductVariationSelectDefaultComponent; + let fixture: ComponentFixture; + let element: HTMLElement; + + const group = { id: 'a', options: [{ value: 'B' }, { value: 'C' }] } as VariationOptionGroup; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ProductVariationSelectDefaultComponent], + }).compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(ProductVariationSelectDefaultComponent); + component = fixture.componentInstance; + element = fixture.nativeElement; + component.group = group; + }); + + it('should be created', () => { + expect(component).toBeTruthy(); + expect(element).toBeTruthy(); + expect(() => fixture.detectChanges()).not.toThrow(); + }); + + it('should initialize form of option group', () => { + fixture.detectChanges(); + + expect(findAllDataTestingIDs(fixture)).toMatchInlineSnapshot(` + Array [ + "a", + "a-B", + "a-C", + ] + `); + }); + + it('should set active values for form', () => { + fixture.detectChanges(); + + expect(fixture.debugElement.query(By.css('select[data-testing-id=a]')).nativeElement.value).toMatchInlineSnapshot( + `"B"` + ); + }); + + it('should trigger changeOption output handler if select value changes', () => { + fixture.detectChanges(); + const emitter = spy(component.changeOption); + const select = fixture.debugElement.query(By.css('select')).nativeElement; + select.value = 'C'; + select.dispatchEvent(new Event('change')); + + verify(emitter.emit(anything())).once(); + const [arg] = capture(emitter.emit).last(); + expect(arg).toMatchInlineSnapshot(` + Object { + "group": "a", + "value": "C", + } + `); + }); +}); diff --git a/src/app/shared/components/product/product-variation-select-default/product-variation-select-default.component.ts b/src/app/shared/components/product/product-variation-select-default/product-variation-select-default.component.ts new file mode 100644 index 0000000000..df15509942 --- /dev/null +++ b/src/app/shared/components/product/product-variation-select-default/product-variation-select-default.component.ts @@ -0,0 +1,20 @@ +import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core'; + +import { VariationOptionGroup } from 'ish-core/models/product-variation/variation-option-group.model'; + +@Component({ + selector: 'ish-product-variation-select-default', + templateUrl: './product-variation-select-default.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class ProductVariationSelectDefaultComponent { + @Input() group: VariationOptionGroup; + @Input() uuid: string; + @Input() multipleOptions: boolean; + + @Output() changeOption = new EventEmitter<{ group: string; value: string }>(); + + optionChange(group: string, target: EventTarget) { + this.changeOption.emit({ group, value: (target as HTMLDataElement).value }); + } +} diff --git a/src/app/shared/components/product/product-variation-select-enhanced/product-variation-select-enhanced.component.html b/src/app/shared/components/product/product-variation-select-enhanced/product-variation-select-enhanced.component.html new file mode 100644 index 0000000000..3e14d835da --- /dev/null +++ b/src/app/shared/components/product/product-variation-select-enhanced/product-variation-select-enhanced.component.html @@ -0,0 +1,58 @@ + + +
+ +
+ + + +
+
+
+ + + +
+
+ + + +
+
+
+ + + + + {{ option.label }} + {{ option.label }} + + - {{ 'product.available_in_different_configuration' | translate }} + + + diff --git a/src/app/shared/components/product/product-variation-select-enhanced/product-variation-select-enhanced.component.scss b/src/app/shared/components/product/product-variation-select-enhanced/product-variation-select-enhanced.component.scss new file mode 100644 index 0000000000..19b1663aff --- /dev/null +++ b/src/app/shared/components/product/product-variation-select-enhanced/product-variation-select-enhanced.component.scss @@ -0,0 +1,66 @@ +@import 'variables'; + +.variation-select { + width: 100%; + padding-right: 12px; + padding-left: 12px; + overflow: hidden; + text-align: left; + border: 1px solid $gray-400; + + &.dropdown-toggle::after { + position: absolute; + top: 17px; + right: 10px; + } + + .label.selected { + font-family: $font-family-regular; + } +} + +.variation-options { + width: 100%; + + .dropdown-item { + padding-right: 12px; + padding-left: 12px; + } +} + +.mobile-variation-select { + margin: $space-default * 0.5 0 $space-default 0; + font-family: $font-family-regular; + + .mobile-variation-option { + margin-bottom: $space-default * 0.5; + } +} + +span.color-code, +img.image-swatch { + display: inline-block; + width: 24px; + height: 24px; + margin-right: $space-default * 0.5; + vertical-align: middle; +} + +span.color-code { + border: 1px solid transparent; + border-radius: 50%; + + &.light-color { + border: 1px solid $border-color-light; + } +} + +span.label { + font-family: $font-family-regular; + color: $text-color-primary; + text-transform: none; + + &.selected { + font-family: $font-family-bold; + } +} diff --git a/src/app/shared/components/product/product-variation-select-enhanced/product-variation-select-enhanced.component.spec.ts b/src/app/shared/components/product/product-variation-select-enhanced/product-variation-select-enhanced.component.spec.ts new file mode 100644 index 0000000000..1198f369c2 --- /dev/null +++ b/src/app/shared/components/product/product-variation-select-enhanced/product-variation-select-enhanced.component.spec.ts @@ -0,0 +1,134 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { By } from '@angular/platform-browser'; +import { of } from 'rxjs'; +import { anything, capture, instance, mock, spy, verify, when } from 'ts-mockito'; + +import { AppFacade } from 'ish-core/facades/app.facade'; +import { VariationOptionGroup } from 'ish-core/models/product-variation/variation-option-group.model'; + +import { ProductVariationSelectEnhancedComponent } from './product-variation-select-enhanced.component'; + +describe('Product Variation Select Enhanced Component', () => { + let component: ProductVariationSelectEnhancedComponent; + let fixture: ComponentFixture; + let element: HTMLElement; + let appFacade: AppFacade; + + const group_colorCode = { + id: 'color', + attributeType: 'defaultAndColorCode', + options: [ + { value: 'black', label: 'Black', metaData: '000000', active: true }, + { value: 'white', label: 'White', metaData: 'FFFFFF' }, + ], + } as VariationOptionGroup; + + const group_swatchImage = { + id: 'swatch', + attributeType: 'defaultAndSwatchImage', + options: [ + { value: 'Y', label: 'yyy', metaData: 'imageY.png' }, + { value: 'Z', label: 'zzz', metaData: 'imageZ.png', active: true }, + ], + } as VariationOptionGroup; + + beforeEach(async () => { + appFacade = mock(AppFacade); + await TestBed.configureTestingModule({ + declarations: [ProductVariationSelectEnhancedComponent], + providers: [{ provide: AppFacade, useFactory: () => instance(appFacade) }], + }).compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(ProductVariationSelectEnhancedComponent); + component = fixture.componentInstance; + element = fixture.nativeElement; + component.group = group_colorCode; + component.uuid = 'uuid'; + }); + + it('should be created', () => { + expect(component).toBeTruthy(); + expect(element).toBeTruthy(); + expect(() => fixture.detectChanges()).not.toThrow(); + }); + + it('should render a color code select when the attribute type is "defaultAndColorCode" for mobile', () => { + component.group = group_colorCode; + fixture.detectChanges(); + expect(element).toMatchInlineSnapshot(` +
+
+ Black +
+
+ White +
+
+ `); + }); + + it('should render a swatch image select when the attribute type is "defaultAndColorCode" for desktop', () => { + when(appFacade.deviceType$).thenReturn(of('desktop')); + component.group = group_swatchImage; + fixture.detectChanges(); + expect(element).toMatchInlineSnapshot(` +
+ +
+ +
+
+ `); + }); + + it('should trigger changeOption output handler if color code element is clicked (mobile)', () => { + component.group = group_colorCode; + fixture.detectChanges(); + const emitter = spy(component.changeOption); + const link = fixture.debugElement.query(By.css('.label.selected')).parent.nativeElement; + link.dispatchEvent(new Event('click')); + + verify(emitter.emit(anything())).once(); + const [arg] = capture(emitter.emit).last(); + expect(arg).toMatchInlineSnapshot(` + Object { + "group": "color", + "value": "black", + } + `); + }); + + it('should trigger changeOption output handler if swatch image element is clicked (desktop)', () => { + when(appFacade.deviceType$).thenReturn(of('desktop')); + component.group = group_swatchImage; + fixture.detectChanges(); + const emitter = spy(component.changeOption); + const link = fixture.debugElement.queryAll(By.css('.label.selected')).pop().parent.nativeElement; + link.dispatchEvent(new Event('click')); + + verify(emitter.emit(anything())).once(); + const [arg] = capture(emitter.emit).last(); + expect(arg).toMatchInlineSnapshot(` + Object { + "group": "swatch", + "value": "Z", + } + `); + }); +}); diff --git a/src/app/shared/components/product/product-variation-select-enhanced/product-variation-select-enhanced.component.ts b/src/app/shared/components/product/product-variation-select-enhanced/product-variation-select-enhanced.component.ts new file mode 100644 index 0000000000..ece21caa84 --- /dev/null +++ b/src/app/shared/components/product/product-variation-select-enhanced/product-variation-select-enhanced.component.ts @@ -0,0 +1,32 @@ +import { ChangeDetectionStrategy, Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; +import { Observable } from 'rxjs'; + +import { AppFacade } from 'ish-core/facades/app.facade'; +import { VariationOptionGroup } from 'ish-core/models/product-variation/variation-option-group.model'; +import { DeviceType } from 'ish-core/models/viewtype/viewtype.types'; + +@Component({ + selector: 'ish-product-variation-select-enhanced', + templateUrl: './product-variation-select-enhanced.component.html', + styleUrls: ['./product-variation-select-enhanced.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class ProductVariationSelectEnhancedComponent implements OnInit { + @Input() group: VariationOptionGroup; + @Input() uuid: string; + @Input() multipleOptions: boolean; + + @Output() changeOption = new EventEmitter<{ group: string; value: string }>(); + + deviceType$: Observable; + + constructor(private appFacade: AppFacade) {} + + ngOnInit() { + this.deviceType$ = this.appFacade.deviceType$; + } + + optionChange(group: string, value: string) { + this.changeOption.emit({ group, value }); + } +} diff --git a/src/app/shared/components/product/product-variation-select-swatch/product-variation-select-swatch.component.html b/src/app/shared/components/product/product-variation-select-swatch/product-variation-select-swatch.component.html new file mode 100644 index 0000000000..4fba65af2e --- /dev/null +++ b/src/app/shared/components/product/product-variation-select-swatch/product-variation-select-swatch.component.html @@ -0,0 +1,12 @@ + diff --git a/src/app/shared/components/product/product-variation-select-swatch/product-variation-select-swatch.component.scss b/src/app/shared/components/product/product-variation-select-swatch/product-variation-select-swatch.component.scss new file mode 100644 index 0000000000..9c1cf2f785 --- /dev/null +++ b/src/app/shared/components/product/product-variation-select-swatch/product-variation-select-swatch.component.scss @@ -0,0 +1,36 @@ +@import 'variables'; + +ul { + padding: 0; + margin: 10px 0; + + li { + display: inline-block; + margin-right: 5px; + border: 1px solid transparent; + border-radius: 50%; + + &.selected { + border: 1px solid $border-color-light; + } + + a { + display: block; + border: 1px solid transparent; + border-radius: 50%; + + span, + img { + display: block; + width: 32px; + height: 32px; + border: 1px solid transparent; + border-radius: 50%; + + &.light-color { + border: 1px solid $border-color-light; + } + } + } + } +} diff --git a/src/app/shared/components/product/product-variation-select-swatch/product-variation-select-swatch.component.spec.ts b/src/app/shared/components/product/product-variation-select-swatch/product-variation-select-swatch.component.spec.ts new file mode 100644 index 0000000000..3944981abc --- /dev/null +++ b/src/app/shared/components/product/product-variation-select-swatch/product-variation-select-swatch.component.spec.ts @@ -0,0 +1,116 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { By } from '@angular/platform-browser'; +import { anything, capture, spy, verify } from 'ts-mockito'; + +import { VariationOptionGroup } from 'ish-core/models/product-variation/variation-option-group.model'; + +import { ProductVariationSelectSwatchComponent } from './product-variation-select-swatch.component'; + +describe('Product Variation Select Swatch Component', () => { + let component: ProductVariationSelectSwatchComponent; + let fixture: ComponentFixture; + let element: HTMLElement; + + const group_colorCode = { + id: 'color', + attributeType: 'colorCode', + options: [ + { value: 'black', label: 'Black', metaData: '000000', active: true }, + { value: 'white', label: 'White', metaData: 'FFFFFF' }, + ], + } as VariationOptionGroup; + + const group_swatchImage = { + id: 'swatch', + attributeType: 'swatchImage', + options: [ + { value: 'Y', label: 'yyy', metaData: 'imageY.png' }, + { value: 'Z', label: 'zzz', metaData: 'imageZ.png', active: true }, + ], + } as VariationOptionGroup; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ProductVariationSelectSwatchComponent], + }).compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(ProductVariationSelectSwatchComponent); + component = fixture.componentInstance; + element = fixture.nativeElement; + component.group = group_colorCode; + }); + + it('should be created', () => { + expect(component).toBeTruthy(); + expect(element).toBeTruthy(); + expect(() => fixture.detectChanges()).not.toThrow(); + }); + + it('should render a color code when the attribute type is "colorCode"', () => { + component.group = group_colorCode; + fixture.detectChanges(); + expect(element).toMatchInlineSnapshot(` +
    +
  • + +
  • +
  • + +
  • +
+ `); + }); + + it('should render a swatch image when the attribute type is "swatchImage"', () => { + component.group = group_swatchImage; + fixture.detectChanges(); + expect(element).toMatchInlineSnapshot(` +
    +
  • + yyy +
  • +
  • + zzz +
  • +
+ `); + }); + + it('should trigger changeOption output handler if color code element is clicked', () => { + component.group = group_colorCode; + fixture.detectChanges(); + const emitter = spy(component.changeOption); + const link = fixture.debugElement.query(By.css('li.selected a')).nativeElement; + link.dispatchEvent(new Event('click')); + + verify(emitter.emit(anything())).once(); + const [arg] = capture(emitter.emit).last(); + expect(arg).toMatchInlineSnapshot(` + Object { + "group": "color", + "value": "black", + } + `); + }); + + it('should trigger changeOption output handler if swatch image element is clicked', () => { + component.group = group_swatchImage; + fixture.detectChanges(); + const emitter = spy(component.changeOption); + const link = fixture.debugElement.query(By.css('li.selected a')).nativeElement; + link.dispatchEvent(new Event('click')); + + verify(emitter.emit(anything())).once(); + const [arg] = capture(emitter.emit).last(); + expect(arg).toMatchInlineSnapshot(` + Object { + "group": "swatch", + "value": "Z", + } + `); + }); +}); diff --git a/src/app/shared/components/product/product-variation-select-swatch/product-variation-select-swatch.component.ts b/src/app/shared/components/product/product-variation-select-swatch/product-variation-select-swatch.component.ts new file mode 100644 index 0000000000..799c2381c1 --- /dev/null +++ b/src/app/shared/components/product/product-variation-select-swatch/product-variation-select-swatch.component.ts @@ -0,0 +1,19 @@ +import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core'; + +import { VariationOptionGroup } from 'ish-core/models/product-variation/variation-option-group.model'; + +@Component({ + selector: 'ish-product-variation-select-swatch', + templateUrl: './product-variation-select-swatch.component.html', + styleUrls: ['./product-variation-select-swatch.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class ProductVariationSelectSwatchComponent { + @Input() group: VariationOptionGroup; + + @Output() changeOption = new EventEmitter<{ group: string; value: string }>(); + + optionChange(group: string, value: string) { + this.changeOption.emit({ group, value }); + } +} diff --git a/src/app/shared/components/product/product-variation-select/product-variation-select.component.html b/src/app/shared/components/product/product-variation-select/product-variation-select.component.html index f5246033b9..b651096143 100644 --- a/src/app/shared/components/product/product-variation-select/product-variation-select.component.html +++ b/src/app/shared/components/product/product-variation-select/product-variation-select.component.html @@ -2,27 +2,37 @@
- - + + + + + + +
diff --git a/src/app/shared/components/product/product-variation-select/product-variation-select.component.spec.ts b/src/app/shared/components/product/product-variation-select/product-variation-select.component.spec.ts index e1750c6661..0cd27ba792 100644 --- a/src/app/shared/components/product/product-variation-select/product-variation-select.component.spec.ts +++ b/src/app/shared/components/product/product-variation-select/product-variation-select.component.spec.ts @@ -1,13 +1,15 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { By } from '@angular/platform-browser'; -import { TranslateModule } from '@ngx-translate/core'; +import { MockComponent } from 'ng-mocks'; import { of } from 'rxjs'; import { anything, capture, instance, mock, verify, when } from 'ts-mockito'; import { ProductContextFacade } from 'ish-core/facades/product-context.facade'; import { ProductView } from 'ish-core/models/product-view/product-view.model'; import { VariationProduct, VariationProductMaster } from 'ish-core/models/product/product.model'; -import { findAllDataTestingIDs } from 'ish-core/utils/dev/html-query-utils'; +import { findAllCustomElements } from 'ish-core/utils/dev/html-query-utils'; +import { ProductVariationSelectDefaultComponent } from 'ish-shared/components/product/product-variation-select-default/product-variation-select-default.component'; +import { ProductVariationSelectEnhancedComponent } from 'ish-shared/components/product/product-variation-select-enhanced/product-variation-select-enhanced.component'; +import { ProductVariationSelectSwatchComponent } from 'ish-shared/components/product/product-variation-select-swatch/product-variation-select-swatch.component'; import { ProductVariationSelectComponent } from './product-variation-select.component'; @@ -19,17 +21,26 @@ describe('Product Variation Select Component', () => { const productMaster = { variationAttributeValues: [ - { variationAttributeId: 'a1', value: 'A' }, - { variationAttributeId: 'a1', value: 'B' }, - { variationAttributeId: 'a2', value: 'C' }, - { variationAttributeId: 'a2', value: 'D' }, + { variationAttributeId: 'a1', value: 'A', attributeType: 'colorCode' }, + { variationAttributeId: 'a1', value: 'B', attributeType: 'colorCode' }, + { variationAttributeId: 'a2', value: 'C', attributeType: 'defaultAndColorCode' }, + { variationAttributeId: 'a2', value: 'D', attributeType: 'defaultAndColorCode' }, + { variationAttributeId: 'a3', value: 'E', attributeType: 'swatchImage' }, + { variationAttributeId: 'a3', value: 'F', attributeType: 'swatchImage' }, + { variationAttributeId: 'a4', value: 'G', attributeType: 'defaultAndSwatchImage' }, + { variationAttributeId: 'a4', value: 'H', attributeType: 'defaultAndSwatchImage' }, + { variationAttributeId: 'a5', value: 'I', attributeType: 'default' }, + { variationAttributeId: 'a5', value: 'J', attributeType: 'default' }, ], } as VariationProductMaster; const variationProduct = { variableVariationAttributes: [ - { variationAttributeId: 'a1', value: 'B' }, - { variationAttributeId: 'a2', value: 'D' }, + { variationAttributeId: 'a1', value: 'B', attributeType: 'colorCode' }, + { variationAttributeId: 'a2', value: 'D', attributeType: 'defaultAndColorCode' }, + { variationAttributeId: 'a3', value: 'F', attributeType: 'swatchImage' }, + { variationAttributeId: 'a4', value: 'H', attributeType: 'defaultAndSwatchImage' }, + { variationAttributeId: 'a5', value: 'J', attributeType: 'default' }, ], } as VariationProduct; @@ -42,8 +53,12 @@ describe('Product Variation Select Component', () => { beforeEach(async () => { context = mock(ProductContextFacade); await TestBed.configureTestingModule({ - imports: [TranslateModule.forRoot()], - declarations: [ProductVariationSelectComponent], + declarations: [ + MockComponent(ProductVariationSelectDefaultComponent), + MockComponent(ProductVariationSelectEnhancedComponent), + MockComponent(ProductVariationSelectSwatchComponent), + ProductVariationSelectComponent, + ], providers: [{ provide: ProductContextFacade, useFactory: () => instance(context) }], }).compileComponents(); }); @@ -63,45 +78,30 @@ describe('Product Variation Select Component', () => { expect(() => fixture.detectChanges()).not.toThrow(); }); - it('should initialize form of option groups', () => { + it('should render the different attribute types with the fitting product variation select components', () => { fixture.detectChanges(); - expect(findAllDataTestingIDs(fixture)).toMatchInlineSnapshot(` + expect(findAllCustomElements(element)).toMatchInlineSnapshot(` Array [ - "a1", - "a1-A", - "a1-B", - "a2", - "a2-C", - "a2-D", + "ish-product-variation-select-swatch", + "ish-product-variation-select-enhanced", + "ish-product-variation-select-swatch", + "ish-product-variation-select-enhanced", + "ish-product-variation-select-default", ] `); }); - it('should set active values for form', () => { + it('should trigger a contex value change if value changes', () => { fixture.detectChanges(); - expect(fixture.debugElement.query(By.css('select[data-testing-id=a1]')).nativeElement.value).toMatchInlineSnapshot( - `"B"` - ); - - expect(fixture.debugElement.query(By.css('select[data-testing-id=a2]')).nativeElement.value).toMatchInlineSnapshot( - `"D"` - ); - }); - - it('should trigger value change if value changes', () => { - fixture.detectChanges(); - - const select = fixture.debugElement.query(By.css('select')).nativeElement; - select.value = 'A'; - select.dispatchEvent(new Event('change')); + component.optionChange({ group: 'a2', value: 'C' }); verify(context.changeVariationOption(anything(), anything())).once(); expect(capture(context.changeVariationOption).last()).toMatchInlineSnapshot(` Array [ - "a1", - "A", + "a2", + "C", ] `); }); diff --git a/src/app/shared/components/product/product-variation-select/product-variation-select.component.ts b/src/app/shared/components/product/product-variation-select/product-variation-select.component.ts index e183dd0464..6714e7f261 100644 --- a/src/app/shared/components/product/product-variation-select/product-variation-select.component.ts +++ b/src/app/shared/components/product/product-variation-select/product-variation-select.component.ts @@ -26,7 +26,7 @@ export class ProductVariationSelectComponent implements OnInit { this.visible$ = this.context.select('displayProperties', 'variations'); } - optionChange(group: string, target: EventTarget) { - this.context.changeVariationOption(group, (target as HTMLDataElement).value); + optionChange(event: { group: string; value: string }) { + this.context.changeVariationOption(event.group, event.value); } } diff --git a/src/app/shared/components/search/search-box/search-box.component.ts b/src/app/shared/components/search/search-box/search-box.component.ts index ddd836fab0..3d232e48fa 100644 --- a/src/app/shared/components/search/search-box/search-box.component.ts +++ b/src/app/shared/components/search/search-box/search-box.component.ts @@ -87,6 +87,7 @@ export class SearchBoxComponent implements OnInit, OnDestroy { // something was selected via keyboard this.searchResults$.pipe(take(1), takeUntil(this.destroy$)).subscribe(results => { this.router.navigate(['/search', results[this.activeIndex].term]); + this.activeIndex = -1; }); } else { this.router.navigate(['/search', suggestedTerm]); diff --git a/src/app/shared/formly-address-forms/components/formly-address-extension-form/formly-address-extension-form.component.html b/src/app/shared/formly-address-forms/components/formly-address-extension-form/formly-address-extension-form.component.html new file mode 100644 index 0000000000..a073edf36c --- /dev/null +++ b/src/app/shared/formly-address-forms/components/formly-address-extension-form/formly-address-extension-form.component.html @@ -0,0 +1 @@ + diff --git a/src/app/shared/formly-address-forms/components/formly-address-extension-form/formly-address-extension-form.component.spec.ts b/src/app/shared/formly-address-forms/components/formly-address-extension-form/formly-address-extension-form.component.spec.ts new file mode 100644 index 0000000000..9887f58b9b --- /dev/null +++ b/src/app/shared/formly-address-forms/components/formly-address-extension-form/formly-address-extension-form.component.spec.ts @@ -0,0 +1,53 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { FormBuilder } from '@angular/forms'; + +import { FormlyTestingModule } from 'ish-shared/formly/dev/testing/formly-testing.module'; + +import { FormlyAddressExtensionFormComponent } from './formly-address-extension-form.component'; + +describe('Formly Address Extension Form Component', () => { + let component: FormlyAddressExtensionFormComponent; + let fixture: ComponentFixture; + let element: HTMLElement; + let fb: FormBuilder; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [FormlyAddressExtensionFormComponent], + imports: [FormlyTestingModule.withPresetMocks(['taxationID'])], + }).compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(FormlyAddressExtensionFormComponent); + component = fixture.componentInstance; + element = fixture.nativeElement; + + fb = TestBed.inject(FormBuilder); + + component.form = fb.group({}); + }); + + it('should be created', () => { + expect(component).toBeTruthy(); + expect(element).toBeTruthy(); + expect(() => fixture.detectChanges()).not.toThrow(); + }); + + it('should always set input field for email', () => { + fixture.detectChanges(); + expect(component.form.value).toContainKey('email'); + }); + + it('should set input field for taxation-id, when businessCustomerRegistration feature is enabled', () => { + component.businessCustomer = true; + fixture.detectChanges(); + expect(component.form.value).toContainKey('taxationID'); + }); + + it('should not set input field for taxation-id, when businessCustomerRegistration feature is disabled', () => { + component.businessCustomer = false; + fixture.detectChanges(); + expect(component.form.value).not.toContainKey('taxationID'); + }); +}); diff --git a/src/app/shared/formly-address-forms/components/formly-address-extension-form/formly-address-extension-form.component.ts b/src/app/shared/formly-address-forms/components/formly-address-extension-form/formly-address-extension-form.component.ts new file mode 100644 index 0000000000..aeb7248e80 --- /dev/null +++ b/src/app/shared/formly-address-forms/components/formly-address-extension-form/formly-address-extension-form.component.ts @@ -0,0 +1,55 @@ +import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core'; +import { FormGroup } from '@angular/forms'; +import { FormlyFieldConfig } from '@ngx-formly/core'; + +/** + * Sub form with additional fields like email address and taxation id to extend the anonymous invoice address form. + */ +@Component({ + selector: 'ish-formly-address-extension-form', + templateUrl: './formly-address-extension-form.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class FormlyAddressExtensionFormComponent implements OnInit { + @Input() form: FormGroup; + @Input() businessCustomer: boolean; + @Input() model: Partial<{ email: string; taxationId: string }> = {}; // model with data for the update mode. + + fields: FormlyFieldConfig[]; + + ngOnInit() { + this.fields = [ + { + type: 'ish-fieldset-field', + fieldGroup: [ + { + key: 'email', + type: 'ish-email-field', + templateOptions: { + required: true, + label: 'checkout.addresses.email.label', + customDescription: { + key: 'account.address.email.hint', + }, + postWrappers: [{ wrapper: 'description', index: -1 }], + }, + }, + ], + }, + ]; + if (this.businessCustomer) { + this.fields = [this.createTaxationIDField(), ...this.fields]; + } + } + + private createTaxationIDField(): FormlyFieldConfig { + return { + type: 'ish-fieldset-field', + fieldGroup: [ + { + type: '#taxationID', + }, + ], + }; + } +} diff --git a/src/app/shared/formly-address-forms/components/formly-address-form/formly-address-form.component.ts b/src/app/shared/formly-address-forms/components/formly-address-form/formly-address-form.component.ts index 8c03d9b4f4..6fe7745d10 100644 --- a/src/app/shared/formly-address-forms/components/formly-address-form/formly-address-form.component.ts +++ b/src/app/shared/formly-address-forms/components/formly-address-form/formly-address-form.component.ts @@ -83,7 +83,9 @@ export class FormlyAddressFormComponent implements OnInit, OnChanges { this.addressModel.countryCode = model.countryCode; this.addressForm.updateValueAndValidity(); - this.addressForm.get('countryCode').markAsDirty(); + if (model.countryCode) { + this.addressForm.get('countryCode').markAsDirty(); + } this.parentForm?.setControl('address', this.addressForm); } @@ -125,9 +127,10 @@ export class FormlyAddressFormComponent implements OnInit, OnChanges { } private fillForm(prefilledAddress: Partial
= {}) { - if (Object.keys(prefilledAddress).length === 0) { + if (!this.addressForm || Object.keys(prefilledAddress).length === 0) { return; } + this.addressModel.countryCode = prefilledAddress.countryCode; this.handleCountryChange(this.addressModel); this.addressModel = { diff --git a/src/app/shared/formly-address-forms/components/formly-customer-address-form/formly-customer-address-form.component.html b/src/app/shared/formly-address-forms/components/formly-customer-address-form/formly-customer-address-form.component.html index 30e42cebf1..0d12c29fd1 100644 --- a/src/app/shared/formly-address-forms/components/formly-customer-address-form/formly-customer-address-form.component.html +++ b/src/app/shared/formly-address-forms/components/formly-customer-address-form/formly-customer-address-form.component.html @@ -12,6 +12,12 @@ [prefilledAddress]="address" > + +