diff --git a/.eslintrc.cjs b/.eslintrc.cjs deleted file mode 100644 index 968c0320f..000000000 --- a/.eslintrc.cjs +++ /dev/null @@ -1,18 +0,0 @@ -module.exports = { - extends: [__dirname+'/config/defaultEslintConfig.cjs'], - parserOptions: { - project: './tsconfig.eslint.json', - tsconfigRootDir: __dirname, - }, - rules: { - '@typescript-eslint/naming-convention': [ - 'error', - { - 'selector': 'variable', - 'types': ['boolean'], - 'format': ['PascalCase'], - 'prefix': ['is', 'with', 'should', 'has', 'can', 'did', 'will'] - } - ] - } - } \ No newline at end of file diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 3c6510cc1..334e5b309 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -6,6 +6,6 @@ updates: directory: '/' # Check the npm registry for updates every day (weekdays) schedule: - interval: 'daily' + interval: 'monthly' commit-message: prefix: 'build(npm): ' diff --git a/.github/workflows/azure-static-web-apps-black-rock-0dc6b0d03.yml b/.github/workflows/azure-static-web-apps-black-rock-0dc6b0d03.yml index 1d00995a0..0e0c6d22e 100644 --- a/.github/workflows/azure-static-web-apps-black-rock-0dc6b0d03.yml +++ b/.github/workflows/azure-static-web-apps-black-rock-0dc6b0d03.yml @@ -9,6 +9,9 @@ on: branches: - main +env: + PNPM_VERSION: 8.6.11 + NODE_VERSION: 18 jobs: skip_ci: runs-on: ubuntu-latest @@ -22,18 +25,25 @@ jobs: runs-on: ubuntu-latest name: Build and Deploy Job steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: submodules: true - - uses: actions/setup-node@v2 + - uses: actions/setup-node@v4 with: - node-version: 18 + node-version: ${{ env.NODE_VERSION }} + - uses: pnpm/action-setup@v4 + name: Install pnpm + with: + version: ${{ env.PNPM_VERSION }} + run_install: false + - name: pnpm install + run: pnpm i --frozen-lockfile - name: pnpm install run: pnpm i --frozen-lockfile - working-directory: ./packages/react-oidc + working-directory: ./examples/react-oidc-demo - name: pnpm run build run: pnpm run build - working-directory: ./packages/react-oidc + working-directory: ./examples/react-oidc-demo - name: Build And Deploy id: builddeploy uses: Azure/static-web-apps-deploy@v1 @@ -44,9 +54,9 @@ jobs: skip_app_build: true ###### Repository/Build Configurations - These values can be configured to match your app requirements. ###### # For more information regarding Static Web App workflow configurations, please visit: https://aka.ms/swaworkflowconfig - app_location: "/packages/react-oidc/build" # App source code path + app_location: "/examples/react-oidc-demo/dist" # App source code path api_location: "" # Api source code path - optional - output_location: "build" # Built app content directory - optional + #output_location: "dist" # Built app content directory - optional ###### End of Repository/Build Configurations ###### close_pull_request_job: diff --git a/.github/workflows/azure-static-web-apps-icy-glacier-004ab4303.yml b/.github/workflows/azure-static-web-apps-icy-glacier-004ab4303.yml index 33e3657df..f7bf9eb68 100644 --- a/.github/workflows/azure-static-web-apps-icy-glacier-004ab4303.yml +++ b/.github/workflows/azure-static-web-apps-icy-glacier-004ab4303.yml @@ -9,6 +9,9 @@ on: branches: - main +env: + PNPM_VERSION: 8.6.11 + NODE_VERSION: 18 jobs: skip_ci: runs-on: ubuntu-latest @@ -22,15 +25,25 @@ jobs: runs-on: ubuntu-latest name: Build and Deploy Job steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: submodules: true - - uses: actions/setup-node@v2 + - uses: actions/setup-node@v4 with: - node-version: 18 + node-version: ${{ env.NODE_VERSION }} + - uses: pnpm/action-setup@v4 + name: Install pnpm + with: + version: ${{ env.PNPM_VERSION }} + run_install: false + - name: pnpm install root + run: pnpm i --frozen-lockfile - name: pnpm install run: pnpm i --frozen-lockfile - working-directory: ./examples/react-oidc-demo + working-directory: ./examples/oidc-client-demo + - name: pnpm run build + run: pnpm run build + working-directory: ./examples/oidc-client-demo - name: Build And Deploy id: builddeploy uses: Azure/static-web-apps-deploy@v1 @@ -38,11 +51,12 @@ jobs: azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_ICY_GLACIER_004AB4303 }} repo_token: ${{ secrets.GITHUB_TOKEN }} # Used for Github integrations (i.e. PR comments) action: "upload" + skip_app_build: true ###### Repository/Build Configurations - These values can be configured to match your app requirements. ###### # For more information regarding Static Web App workflow configurations, please visit: https://aka.ms/swaworkflowconfig - app_location: "/examples/react-oidc-demo" # App source code path + app_location: "/examples/oidc-client-demo/dist" # App source code path api_location: "" # Api source code path - optional - output_location: "build" # Built app content directory - optional + #output_location: "dist" # Built app content directory - optional ###### End of Repository/Build Configurations ###### close_pull_request_job: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e939c8e61..b47788da8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,7 +9,7 @@ on: # branches: [ main ] env: - PNPM_VERSION: 8.5.1 + PNPM_VERSION: 8.6.11 NODE_VERSION: 18 jobs: @@ -17,14 +17,14 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install node.js - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ env.NODE_VERSION }} - - uses: pnpm/action-setup@v2 + - uses: pnpm/action-setup@v4 name: Install pnpm with: version: ${{ env.PNPM_VERSION }} diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 000000000..869d47247 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,50 @@ +name: Lint + +on: + # Trigger the workflow on push or pull request, + # but only for the main branch + push: + # branches: + # - main + pull_request: + # branches: + # - main + +env: + PNPM_VERSION: 8.6.11 + NODE_VERSION: 18 + +jobs: + run-linters: + name: Run linters + runs-on: ubuntu-latest + + steps: + - name: Check out Git repository + uses: actions/checkout@v4 + + - name: Install node.js + uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} + + - uses: pnpm/action-setup@v4 + name: Install pnpm + with: + version: ${{ env.PNPM_VERSION }} + run_install: false + + # ESLint and Prettier must be in `package.json` + - name: Install dependencies + run: pnpm i + + - name: Run lint + run: pnpm run lint + + # Currently incompatible with ESlint 9 (https://github.com/wearerequired/lint-action/pull/799) + # - name: Run linters + # uses: wearerequired/lint-action@v2 + # with: + # eslint: true + # prettier: false #runs part of eslint + # autofix: false #does not work well with pull requests https://github.com/wearerequired/lint-action?tab=readme-ov-file#limitations \ No newline at end of file diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml index bce42b6f2..09a8bd259 100644 --- a/.github/workflows/npm-publish.yml +++ b/.github/workflows/npm-publish.yml @@ -10,7 +10,7 @@ on: branches: [ main ] env: - PNPM_VERSION: 8.5.1 + PNPM_VERSION: 8.6.11 NODE_VERSION: 18 jobs: skip_ci: @@ -24,12 +24,12 @@ jobs: runs-on: ubuntu-latest if: needs.skip_ci.outputs.canSkip != 'true' && github.event.pull_request.head.repo.fork steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 with: node-version: ${{ env.NODE_VERSION }} - - uses: pnpm/action-setup@v2 + - uses: pnpm/action-setup@v4 name: Install pnpm with: version: ${{ env.PNPM_VERSION }} @@ -56,19 +56,22 @@ jobs: working-directory: ./packages/oidc-client build: + permissions: + contents: write environment: react-oidc runs-on: ubuntu-latest if: needs.skip_ci.outputs.canSkip != 'true' && !github.event.pull_request.head.repo.fork steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: token: ${{ secrets.GIT_TOKEN }} + fetch-depth: 0 - name: Determine Alpha, Beta or Release id: which_tag run: | if [[ ${{ github.ref }} == refs/pull* ]]; then - last_commit_message=$(curl -s "https://api.github.com/repos/AxaFrance/react-oidc/pulls/${{ github.event.number }}/commits" | jq -r '.[-1].commit.message') + last_commit_message=$(curl -s "https://api.github.com/repos/${GITHUB_REPOSITORY}/pulls/${{ github.event.number }}/commits" | jq -r '.[-1].commit.message') else last_commit_message=$(git log --format=%B -n 1) fi @@ -111,51 +114,62 @@ jobs: echo "new_version=$version" >> $GITHUB_OUTPUT fi if [[ '${{ steps.which_tag.outputs.tag }}' = 'alpha' ]]; then - echo "new_version=$version-alpha${{ github.run_number }}" >> $GITHUB_OUTPUT + echo "new_version=$version-alpha.${{ github.run_number }}" >> $GITHUB_OUTPUT fi if [[ '${{ steps.which_tag.outputs.tag }}' = 'beta' ]]; then - echo "new_version=$version-beta${{ github.run_number }}" >> $GITHUB_OUTPUT + echo "new_version=$version-beta.${{ github.run_number }}" >> $GITHUB_OUTPUT fi - - uses: actions/setup-node@v2 + - uses: actions/setup-node@v4 with: node-version: ${{ env.NODE_VERSION }} - - uses: pnpm/action-setup@v2 + - uses: pnpm/action-setup@v4 name: Install pnpm with: version: ${{ env.PNPM_VERSION }} run_install: false - - - name: npm version ${{ steps.tag.outputs.new_version }} - if: (github.ref == 'refs/heads/main' && steps.which_tag.outputs.tag == 'release') || steps.which_tag.outputs.tag == 'alpha' || steps.which_tag.outputs.tag == 'beta' - run: npm version ${{ steps.tag.outputs.new_version }} - working-directory: ./packages/react-oidc - - name: pnpm i + # oidc-client-service-worker + - name: pnpm version ${{ steps.tag.outputs.new_version }} + if: (github.ref == 'refs/heads/main' && steps.which_tag.outputs.tag == 'release') || steps.which_tag.outputs.tag == 'alpha' || steps.which_tag.outputs.tag == 'beta' + run: pnpm version ${{ steps.tag.outputs.new_version }} + working-directory: ./packages/oidc-client-service-worker + + - name: update version.ts ${{ steps.tag.outputs.new_version }} + if: (github.ref == 'refs/heads/main' && steps.which_tag.outputs.tag == 'release') || steps.which_tag.outputs.tag == 'alpha' || steps.which_tag.outputs.tag == 'beta' + run: | + echo "export default '${{ steps.tag.outputs.new_version }}';" > version.ts + working-directory: ./packages/oidc-client-service-worker/src + + + - name: pnpm ci run: pnpm i --frozen-lockfile - working-directory: ./packages/react-oidc + working-directory: ./packages/oidc-client-service-worker - name: pnpm prepare run: pnpm run prepare - working-directory: ./packages/react-oidc + working-directory: ./packages/oidc-client-service-worker - name: pnpm test run: pnpm test -- --run - working-directory: ./packages/react-oidc + working-directory: ./packages/oidc-client-service-worker - - id: publish-react - uses: JS-DevTools/npm-publish@v1 - if: (github.ref == 'refs/heads/main' && steps.which_tag.outputs.tag == 'release') || steps.which_tag.outputs.tag == 'alpha' || steps.which_tag.outputs.tag == 'beta' - with: - token: ${{ secrets.NPM_TOKEN }} - package: ./packages/react-oidc/package.json - + # oidc-client - name: pnpm version ${{ steps.tag.outputs.new_version }} if: (github.ref == 'refs/heads/main' && steps.which_tag.outputs.tag == 'release') || steps.which_tag.outputs.tag == 'alpha' || steps.which_tag.outputs.tag == 'beta' - run: pnpm version ${{ steps.tag.outputs.new_version }} + run: | + set -e + pnpm version ${{ steps.tag.outputs.new_version }} || true + cat package.json working-directory: ./packages/oidc-client - + + - name: update version.ts ${{ steps.tag.outputs.new_version }} + if: (github.ref == 'refs/heads/main' && steps.which_tag.outputs.tag == 'release') || steps.which_tag.outputs.tag == 'alpha' || steps.which_tag.outputs.tag == 'beta' + run: | + echo "export default '${{ steps.tag.outputs.new_version }}';" > version.ts + working-directory: ./packages/oidc-client/src + - name: pnpm ci run: pnpm i --frozen-lockfile working-directory: ./packages/oidc-client @@ -163,7 +177,44 @@ jobs: - name: pnpm prepare run: pnpm run prepare working-directory: ./packages/oidc-client + + # React-oidc + - name: pnpm version ${{ steps.tag.outputs.new_version }} + if: (github.ref == 'refs/heads/main' && steps.which_tag.outputs.tag == 'release') || steps.which_tag.outputs.tag == 'alpha' || steps.which_tag.outputs.tag == 'beta' + run: | + set -e + pnpm version ${{ steps.tag.outputs.new_version }} || true + cat package.json + working-directory: ./packages/react-oidc + + - name: pnpm i + run: pnpm i --frozen-lockfile + working-directory: ./packages/react-oidc + - name: pnpm prepare + run: pnpm run prepare + working-directory: ./packages/react-oidc + + - name: pnpm test + run: pnpm test -- --run + working-directory: ./packages/react-oidc + + # oidc-client-service-worker + - id: publish-oidc-client-service-worker + uses: JS-DevTools/npm-publish@v1 + if: (github.ref == 'refs/heads/main' && steps.which_tag.outputs.tag == 'release') || steps.which_tag.outputs.tag == 'alpha' || steps.which_tag.outputs.tag == 'beta' + with: + token: ${{ secrets.NPM_TOKEN }} + package: ./packages/oidc-client-service-worker/package.json + + # oidc-client + - name: replace workspace:* by ${{ steps.tag.outputs.new_version }} + if: (github.ref == 'refs/heads/main' && steps.which_tag.outputs.tag == 'release') || steps.which_tag.outputs.tag == 'alpha' || steps.which_tag.outputs.tag == 'beta' + run: | + sed -i 's/workspace:\*/${{ steps.tag.outputs.new_version }}/g' package.json + cat package.json + working-directory: ./packages/oidc-client + - id: publish-oidc-client uses: JS-DevTools/npm-publish@v1 if: (github.ref == 'refs/heads/main' && steps.which_tag.outputs.tag == 'release') || steps.which_tag.outputs.tag == 'alpha' || steps.which_tag.outputs.tag == 'beta' @@ -171,33 +222,69 @@ jobs: token: ${{ secrets.NPM_TOKEN }} package: ./packages/oidc-client/package.json - - name: SonarCloud Scan - uses: sonarsource/sonarcloud-github-action@master - if: github.event.pull_request.head.repo.full_name == github.repository && !github.event.pull_request.head.repo.fork - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - with: - args: > - -Dsonar.organization=axaguildev - -Dsonar.projectKey=AxaGuilDEv_react-oidc - -Dsonar.exclusions=**/*.spec.js,**/*.stories.js,Scripts/**,**/*.scss,**/__snapshots__/**,**/*[Tt]ests.cs,**/node_modules/**,**/ClientApp/build/**,**/ClientApp/.storybook/**,**/ClientApp/storybook-static/**,**/obj/**,**/__mocks__/**,**/ClientApp/src/serviceWorker.ts - -Dsonar.javascript.lcov.reportPaths=**/coverage/lcov.info - - - name: Commit updates package.json - uses: stefanzweifel/git-auto-commit-action@v4 - if: github.ref == 'refs/heads/main' + - name: replace ${{ steps.tag.outputs.new_version }} by workspace:* + if: (github.ref == 'refs/heads/main' && steps.which_tag.outputs.tag == 'release') || steps.which_tag.outputs.tag == 'alpha' || steps.which_tag.outputs.tag == 'beta' + run: | + sed -i 's/"@axa-fr\/oidc-client-service-worker": "[^"]*"/"@axa-fr\/oidc-client-service-worker": "workspace:*"/g' package.json + cat package.json + working-directory: ./packages/oidc-client + + # react-oidc + - name: replace workspace:* by ${{ steps.tag.outputs.new_version }} + if: (github.ref == 'refs/heads/main' && steps.which_tag.outputs.tag == 'release') || steps.which_tag.outputs.tag == 'alpha' || steps.which_tag.outputs.tag == 'beta' + run: | + sed -i 's/workspace:\*/${{ steps.tag.outputs.new_version }}/g' package.json + cat package.json + working-directory: ./packages/react-oidc + + - id: publish-react + uses: JS-DevTools/npm-publish@v1 + if: (github.ref == 'refs/heads/main' && steps.which_tag.outputs.tag == 'release') || steps.which_tag.outputs.tag == 'alpha' || steps.which_tag.outputs.tag == 'beta' with: - commit_message: "[skip ci] Update version package.json" - commit_user_name: GitHub - commit_user_email: github-action@bot.com - commit_author: GitHub - push_options: '--force' + token: ${{ secrets.NPM_TOKEN }} + package: ./packages/react-oidc/package.json + + - name: replace ${{ steps.tag.outputs.new_version }} by workspace:* + if: (github.ref == 'refs/heads/main' && steps.which_tag.outputs.tag == 'release') || steps.which_tag.outputs.tag == 'alpha' || steps.which_tag.outputs.tag == 'beta' + run: | + sed -i 's/"@axa-fr\/oidc-client-service-worker": "[^"]*"/"@axa-fr\/oidc-client-service-worker": "workspace:*"/g' package.json + sed -i 's/"@axa-fr\/oidc-client": "[^"]*"/"@axa-fr\/oidc-client": "workspace:*"/g' package.json + cat package.json + working-directory: ./packages/react-oidc + + - name: Commit and push + if: github.ref == 'refs/heads/main' && steps.which_tag.outputs.tag == 'release' + run: | + git config --global user.name "GitHub" + git config --global user.email "github-action@bot.com" + git add . + git commit -m "[skip ci] Update to version ${{ steps.tag.outputs.new_version }} in package.json" + git tag ${{ steps.tag.outputs.new_version }} + git push --set-upstream origin "HEAD:main" --follow-tags -f + chmod +x ./bin/generate-changelog.sh + ./bin/generate-changelog.sh + git add . + git commit -m "[skip ci] Generate changelog to version ${{ steps.tag.outputs.new_version }}" + git push --set-upstream origin "HEAD:main" --follow-tags -f + + # - name: SonarCloud Scan + # uses: sonarsource/sonarcloud-github-action@master + # if: github.event.pull_request.head.repo.full_name == github.repository && !github.event.pull_request.head.repo.fork + # env: + # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + # SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + # with: + # args: > + # -Dsonar.organization=axaguildev + # -Dsonar.projectKey=AxaGuilDEv_react-oidc + # -Dsonar.exclusions=**/*.spec.js,**/*.stories.js,Scripts/**,**/*.scss,**/__snapshots__/**,**/*[Tt]ests.cs,**/node_modules/**,**/ClientApp/build/**,**/ClientApp/.storybook/**,**/ClientApp/storybook-static/**,**/obj/**,**/__mocks__/**,**/ClientApp/src/serviceWorker.ts + # -Dsonar.javascript.lcov.reportPaths=**/coverage/lcov.info + # - name: Create a GitHub release uses: ncipollo/release-action@v1 - if: github.ref == 'refs/heads/main' + if: github.ref == 'refs/heads/main' && steps.which_tag.outputs.tag == 'release' with: - tag: ${{ steps.tag_version.outputs.new_tag }} - name: Release ${{ steps.tag_version.outputs.new_tag }} - body: ${{ steps.tag_version.outputs.changelog }} + tag: ${{ steps.tag_release.outputs.new_tag }} + name: Release ${{ steps.tag_release.outputs.new_tag }} + body: ${{ steps.tag_release.outputs.changelog }} diff --git a/.gitignore b/.gitignore index 10d5cede9..204bffd0b 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,4 @@ examples/**/build/ **/public/*.d.ts /public/* +/Folder.DotSettings.user diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 000000000..88b151d4f --- /dev/null +++ b/.prettierignore @@ -0,0 +1,11 @@ +# deep dirs +**/dist +**/node_modules +**/fixtures + +# directories +.github +.changeset + +# files +pnpm-lock.yaml \ No newline at end of file diff --git a/.prettierrc.cjs b/.prettierrc.cjs new file mode 100644 index 000000000..6fb26d080 --- /dev/null +++ b/.prettierrc.cjs @@ -0,0 +1,20 @@ +module.exports = { + printWidth: 100, + tabWidth: 2, + trailingComma: 'all', + arrowParens: 'avoid', + endOfLine: 'auto', + bracketSameLine: false, + bracketSpacing: true, + singleQuote: true, + useTabs: false, + semi: true, + overrides: [ + { + files: ['.*', '*.json', '*.md', '*.toml', '*.yml'], + options: { + useTabs: false, + }, + }, + ], +}; diff --git a/.prettierrc.json b/.prettierrc.json deleted file mode 100644 index 8de7f847e..000000000 --- a/.prettierrc.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "jsxSingleQuote": true, - "singleQuote": true -} \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 1374bc538..d4fde1892 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,489 +1,329 @@ -### Changelog -All notable changes to this project will be documented in this file. - -#### [v3.1.7](https://github.com/AxaGuilDEv/react-oidc/compare/v3.1.6...v3.1.7) -> 17 June 2021 -- feat: add signinSilent to useReactOidc and AuthenticationContext [`#578`](https://github.com/AxaGuilDEv/react-oidc/pull/578) by Olivier YOUF -- ci: add dependabot config file and change prefix to `build(npm)` [`#561`](https://github.com/AxaGuilDEv/react-oidc/pull/561) by Olivier YOUF -- feat:unload userManager when unnmount oidc provider [`#547`](https://github.com/AxaGuilDEv/react-oidc/pull/547) by Olivier YOUF -- feat(context-fetch/fetch-core): removing recompose [`#530`](https://github.com/AxaGuilDEv/react-oidc/pull/530) by Olivier YOUF -- chore(deps): bump example dependencies [`80ccc10`](https://github.com/AxaGuilDEv/react-oidc/commit/80ccc10c5cb33df891365c896b81b8eb1d5e46c5) by Julien Foratier -- fix: create usermanager before rendering + some refacto [`16cb26d`](https://github.com/AxaGuilDEv/react-oidc/commit/16cb26d057e50037b7ee04f32319f02a92ae72cd) by Amine JELTI -- chore(release): publish v3.1.7 ***NO_CI*** [`8b5cb40`](https://github.com/AxaGuilDEv/react-oidc/commit/8b5cb405d5735bacd24318c9fe0de1736b98712e) by Build-CI -- chore(deps): [security] bump handlebars from 4.4.2 to 4.7.6 [`c785f2d`](https://github.com/AxaGuilDEv/react-oidc/commit/c785f2d6cd92d9380c0c3ec99e01bb61f7ec2fcd) by dependabot-preview[bot] -- chore(deps): [security] bump ini from 1.3.5 to 1.3.8 [`c978517`](https://github.com/AxaGuilDEv/react-oidc/commit/c9785176ccd4c1cd3777f8e6e12e3535a37e7aa6) by dependabot-preview[bot] -- fix(examples): replace https://demo.identityserver.io deprecated configuration [`ebe9e79`](https://github.com/AxaGuilDEv/react-oidc/commit/ebe9e79465f52323626b2ac94b333e8d51987999) by Julien Foratier -- docs(changelog) update to new 3.1.6 [`8cfbc7c`](https://github.com/AxaGuilDEv/react-oidc/commit/8cfbc7c6111444a156c5bddcad253c0366e6f38c) by Build-CI -- chore(deps): [security] bump lodash from 4.17.15 to 4.17.20 [`124a9ca`](https://github.com/AxaGuilDEv/react-oidc/commit/124a9ca777135382695f2873253f076bf4f7434a) by dependabot-preview[bot] - -#### [v3.1.6](https://github.com/AxaGuilDEv/react-oidc/compare/v3.1.5...v3.1.6) -> 13 October 2020 -- feat(context): Allowing hooking into the oidc-client events in the AuthenticationProvider [`#415`](https://github.com/AxaGuilDEv/react-oidc/issues/415) by Michael Wolfenden -- chore(release): publish v3.1.6 ***NO_CI*** [`9c1a618`](https://github.com/AxaGuilDEv/react-oidc/commit/9c1a6186d4f804d6ddcf50819602653d50f05df3) by Build-CI -- docs(changelog) update to new 3.1.5 [`02ad255`](https://github.com/AxaGuilDEv/react-oidc/commit/02ad25574978464cb67123d4b695a62a15704960) by Build-CI -- feat(logger): remove debug overriddenConfiguration [`f23bebd`](https://github.com/AxaGuilDEv/react-oidc/commit/f23bebdd64de6082d183bead17553174919d515a) by Arnaud Foraison -- fix(example): add hook dependency [`b491c02`](https://github.com/AxaGuilDEv/react-oidc/commit/b491c02757775052d1605b2922fa13e25acf7128) by Arnaud Foraison - -#### [v3.1.5](https://github.com/AxaGuilDEv/react-oidc/compare/v3.1.4...v3.1.5) -> 8 September 2020 -- Add prop-types as dependency [`#507`](https://github.com/AxaGuilDEv/react-oidc/pull/507) by Olivier YOUF -- fix(core): keep location.hash in the url used to redirect after login [`#515`](https://github.com/AxaGuilDEv/react-oidc/pull/515) by jreimbold-t1 -- fix: move prop-types from peer to dependencies [`a53a189`](https://github.com/AxaGuilDEv/react-oidc/commit/a53a189b08b70ee705bb06fd0d8eee4184a2558b) by Arnaud Foraison -- chore(release): publish v3.1.5 ***NO_CI*** [`0a24a04`](https://github.com/AxaGuilDEv/react-oidc/commit/0a24a04741b5d6ac28d0cd4d6346beeda01e79a8) by Build-CI -- docs(changelog) update to new 3.1.4 [`b43b45d`](https://github.com/AxaGuilDEv/react-oidc/commit/b43b45dab5b2ae6f46cce62e3061e23ab388b61e) by Build-CI - -#### [v3.1.4](https://github.com/AxaGuilDEv/react-oidc/compare/v3.1.3...v3.1.4) -> 14 July 2020 -- fix(context): made type for AuthenticationProviderProps partial [`#473`](https://github.com/AxaGuilDEv/react-oidc/pull/473) by Olivier YOUF -- chore(release): publish v3.1.4 ***NO_CI*** [`aea9407`](https://github.com/AxaGuilDEv/react-oidc/commit/aea940793fbb9ecf4cc87a0d870e4b9e7d2e5156) by Build-CI -- docs(changelog) update to new 3.1.3 [`c3043c4`](https://github.com/AxaGuilDEv/react-oidc/commit/c3043c4078b24906e35b4a15062a1995e79683af) by Build-CI - -#### [v3.1.3](https://github.com/AxaGuilDEv/react-oidc/compare/v3.1.2...v3.1.3) -> 16 June 2020 -- style: remove overwritten property jsx-filename-extension [`#468`](https://github.com/AxaGuilDEv/react-oidc/pull/468) by Olivier YOUF -- fix(Vanilla): return type callback with signinSilent [`#469`](https://github.com/AxaGuilDEv/react-oidc/pull/469) by Olivier YOUF -- feat(react-oidc-redux): Adding Redux Authenticating component [`#463`](https://github.com/AxaGuilDEv/react-oidc/pull/463) by Olivier YOUF -- Fix types for AuthenticationProvider and withOidcUser [`#457`](https://github.com/AxaGuilDEv/react-oidc/pull/457) by Olivier YOUF -- chore(release): publish v3.1.3 ***NO_CI*** [`5b4db53`](https://github.com/AxaGuilDEv/react-oidc/commit/5b4db533b3edaa60b273dd05dd822b6687793165) by Build-CI -- Replace Pick with Omit [`7f160b7`](https://github.com/AxaGuilDEv/react-oidc/commit/7f160b708bb51dd43389571fd6f0d8e66b5cd2f8) by Vincent Ricard -- docs(changelog) update to new 3.1.2 [`faa73a7`](https://github.com/AxaGuilDEv/react-oidc/commit/faa73a7c9cc015ac4dd10289819d06d071ef7ca7) by Build-CI - -#### [v3.1.2](https://github.com/AxaGuilDEv/react-oidc/compare/v3.1.1...v3.1.2) -> 11 June 2020 -- fix(context): Renrender children aftersilent signin [`#464`](https://github.com/AxaGuilDEv/react-oidc/pull/464) by Olivier YOUF -- chore(release): publish v3.1.2 ***NO_CI*** [`6dbcbc8`](https://github.com/AxaGuilDEv/react-oidc/commit/6dbcbc860df7ee6697983d1024950312a2c8eea4) by Build-CI -- Add usage example to demo [`e3bb8b0`](https://github.com/AxaGuilDEv/react-oidc/commit/e3bb8b03e13048f99672050946bb2379dde417a4) by Viet VO -- Fix types for AuthenticationProvider and withOidcUser [`5004289`](https://github.com/AxaGuilDEv/react-oidc/commit/50042890bc070bd87a99c0c730acfc47678e0d8a) by Vincent Ricard -- Add readme [`be2bb57`](https://github.com/AxaGuilDEv/react-oidc/commit/be2bb5783ae702d65dbc90b38cf41bcf55002415) by Viet VO -- Add config option to OidcSecure [`7881742`](https://github.com/AxaGuilDEv/react-oidc/commit/7881742d81fda72571d88642da13a5fd6d188139) by Viet VO -- PR: change to authenticating [`bf06f9e`](https://github.com/AxaGuilDEv/react-oidc/commit/bf06f9e5f25e8d6343849f176ed5e1ecfb54b158) by Viet VO -- fix(Vanilla): return type callback with signinSilent [`3d4f8af`](https://github.com/AxaGuilDEv/react-oidc/commit/3d4f8af68901a39d6a9e4c958cf6c6e24c5c5ab5) by Hamza HAMIDI -- style: remove overwritten property jsx-filename-extension [`5dee604`](https://github.com/AxaGuilDEv/react-oidc/commit/5dee604e9bb16edad8a0c87c3c29d2fa98fc870f) by Hamza Hamidi -- docs(changelog) update to new 3.1.1 [`dd8b685`](https://github.com/AxaGuilDEv/react-oidc/commit/dd8b685650d08c2d2a480e7406b5d2f09c0ddc50) by Build-CI -- remove useMemo [`4cbf8f2`](https://github.com/AxaGuilDEv/react-oidc/commit/4cbf8f2df93271544f09f28008b199bfea07b391) by Viet VO - -#### [v3.1.1](https://github.com/AxaGuilDEv/react-oidc/compare/v3.1.1-alpha.0...v3.1.1) -> 25 May 2020 -- chore(release): publish v3.1.1 ***NO_CI*** [`1500b7e`](https://github.com/AxaGuilDEv/react-oidc/commit/1500b7e28914afb913ea4fc3e6b87ee707999fc3) by Build-CI -- docs(changelog) update to new 3.1.1-alpha.0 [`90ea0c9`](https://github.com/AxaGuilDEv/react-oidc/commit/90ea0c954531093f6f7a5cd221cf4d986468fd7c) by Build-CI - -#### [v3.1.1-alpha.0](https://github.com/AxaGuilDEv/react-oidc/compare/v3.1.0-alpha.0...v3.1.1-alpha.0) -> 20 May 2020 -- fix(context): Memoize the child component [`#451`](https://github.com/AxaGuilDEv/react-oidc/pull/451) by Olivier YOUF -- chore(release): publish v3.1.1-alpha.0 ***NO_CI*** [`dc8ee89`](https://github.com/AxaGuilDEv/react-oidc/commit/dc8ee8944258e33430be309cb09d5c55f71fc13b) by Build-CI -- docs(changelog) update to new 3.1.0-alpha.0 [`6a33c46`](https://github.com/AxaGuilDEv/react-oidc/commit/6a33c46beaa3f32c56c516811d6961362e761b20) by Build-CI - -#### [v3.1.0-alpha.0](https://github.com/AxaGuilDEv/react-oidc/compare/v3.0.8...v3.1.0-alpha.0) -> 12 May 2020 -- fix: add logout action [`#439`](https://github.com/AxaGuilDEv/react-oidc/pull/439) by Olivier YOUF -- refactor(context): Refactor/containers providers [`#432`](https://github.com/AxaGuilDEv/react-oidc/pull/432) by Olivier YOUF -- Typescript migration [`#410`](https://github.com/AxaGuilDEv/react-oidc/pull/410) by Olivier YOUF -- Remove all occurences of 'triggerAuthFlow' [`#425`](https://github.com/AxaGuilDEv/react-oidc/pull/425) by Olivier YOUF -- Overrides the react-redux dependency [`#424`](https://github.com/AxaGuilDEv/react-oidc/pull/424) by Olivier YOUF -- Fix minor typos in docs [`#414`](https://github.com/AxaGuilDEv/react-oidc/pull/414) by Tommi Laukkanen -- Remove all occurences of 'triggerAuthFlow' [`#392`](https://github.com/AxaGuilDEv/react-oidc/issues/392) by Vincent Ricard -- Upgrade Jest [`7281ee1`](https://github.com/AxaGuilDEv/react-oidc/commit/7281ee1e5a7d3f19f6381a427ce5bfa4332829ef) by Vincent Ricard -- Migration of packages/core [`9f518a5`](https://github.com/AxaGuilDEv/react-oidc/commit/9f518a50f7867a702d4174e764d169de9b21a5c6) by Vincent Ricard -- Format code with prettier and fix lint errors [`52ae362`](https://github.com/AxaGuilDEv/react-oidc/commit/52ae362769572e29155403695d8bb5de26ea4c26) by Vincent Ricard -- WIP [`b123a42`](https://github.com/AxaGuilDEv/react-oidc/commit/b123a4206ec4b7b134714d8f9e70434682a01c99) by Vincent Ricard -- WIP context package [`0fa40e9`](https://github.com/AxaGuilDEv/react-oidc/commit/0fa40e99a3d42ebdcf472bbd6d0ba7cca55c25c7) by Vincent Ricard -- WIP redux package [`b251bcc`](https://github.com/AxaGuilDEv/react-oidc/commit/b251bcc452a1362e54463d3f4c86b9f883c973f2) by Vincent Ricard -- Rename OidcHistory into ReactOidcHistory [`760c77f`](https://github.com/AxaGuilDEv/react-oidc/commit/760c77f511536eaf49f7e1e3b702a741c0723d36) by Vincent Ricard -- chore(release): publish v3.1.0-alpha.0 ***NO_CI*** [`892f3cb`](https://github.com/AxaGuilDEv/react-oidc/commit/892f3cb98ab452f11823af8ed44fb16897f14ecb) by Build-CI -- chore(release): publish v3.0.9-alpha.0 ***NO_CI*** [`61c8884`](https://github.com/AxaGuilDEv/react-oidc/commit/61c8884393c0df5ae37b0c8b113cb92a942602aa) by Build-CI -- WIP [`0282c3c`](https://github.com/AxaGuilDEv/react-oidc/commit/0282c3c81cfb1ecc4be57408f3dd6e7a2bc72fe7) by Vincent Ricard -- Fix some tests [`6a7b09c`](https://github.com/AxaGuilDEv/react-oidc/commit/6a7b09c90d47203eb5cfe5bafb71e3371def176f) by Vincent Ricard -- docs(changelog) update to new 3.0.9-alpha.0 [`08a6938`](https://github.com/AxaGuilDEv/react-oidc/commit/08a69388c8177bc87335cb741330811db6d2aca2) by Build-CI -- Add specific type ofr UserStore [`1b44db5`](https://github.com/AxaGuilDEv/react-oidc/commit/1b44db5d9a9c433b27571e73335bfc18fec4f97f) by Vincent Ricard -- WIP redux-fetch package [`a8bed40`](https://github.com/AxaGuilDEv/react-oidc/commit/a8bed40cead711a707ae1dfdb5ca36e77a43935d) by Vincent Ricard -- WIP context-fetch package [`fd6f8f2`](https://github.com/AxaGuilDEv/react-oidc/commit/fd6f8f2872c12f6d4abdec36f0915524b64cab17) by Vincent Ricard -- docs(changelog) update to new 3.0.8 [`f28c0ed`](https://github.com/AxaGuilDEv/react-oidc/commit/f28c0ede0d3bba884085b1269b94eee3a223e50e) by Build-CI -- Revert a useless modification in fetch-core/package.json [`fa101b8`](https://github.com/AxaGuilDEv/react-oidc/commit/fa101b865ba386cdef4ebf1479ab357ce8e0288c) by Vincent Ricard - -#### [v3.0.8](https://github.com/AxaGuilDEv/react-oidc/compare/v3.0.7...v3.0.8) -> 14 February 2020 -- fix(options): options can be overrided [`#399`](https://github.com/AxaGuilDEv/react-oidc/pull/399) by Guillaume Chervet -- fix(fetchToken): options override [`#398`](https://github.com/AxaGuilDEv/react-oidc/pull/398) by Guillaume Chervet -- chore(release): publish v3.0.8 ***NO_CI*** [`ecccc47`](https://github.com/AxaGuilDEv/react-oidc/commit/ecccc47cb9ee65cccbb23aac53e215ced26d4914) by Build-CI -- docs(changelog) update to new 3.0.7 [`1c2e599`](https://github.com/AxaGuilDEv/react-oidc/commit/1c2e599cc9eeffc287b05b6c2671b270c28ad91e) by Build-CI - -#### [v3.0.7](https://github.com/AxaGuilDEv/react-oidc/compare/v3.0.6...v3.0.7) -> 7 February 2020 -- chore(deps-dev): bump concurrently from 4.1.2 to 5.1.0 [`#393`](https://github.com/AxaGuilDEv/react-oidc/pull/393) by dependabot-preview[bot] -- refactor(log): Replace console.log by oidcLog [`#386`](https://github.com/AxaGuilDEv/react-oidc/pull/386) by Cockedey Sébastien -- chore(release): publish v3.0.7 ***NO_CI*** [`9bdbb89`](https://github.com/AxaGuilDEv/react-oidc/commit/9bdbb8976b173d1fbc8da12e1a623aca61c39d6c) by Build-CI -- docs(changelog) update to new 3.0.6 [`46055a6`](https://github.com/AxaGuilDEv/react-oidc/commit/46055a654246bb678e745abb5b57717049850d82) by Build-CI - -#### [v3.0.6](https://github.com/AxaGuilDEv/react-oidc/compare/v3.0.6-alpha.0...v3.0.6) -> 7 January 2020 -- feat(components): add bem to default components [`#384`](https://github.com/AxaGuilDEv/react-oidc/pull/384) by Guillaume Chervet -- chore(release): publish v3.0.6 ***NO_CI*** [`db79cce`](https://github.com/AxaGuilDEv/react-oidc/commit/db79ccec24ddca89f7eb55a84a9684e409c8e548) by Build-CI -- docs(changelog) update to new 3.0.6-alpha.0 [`c55f2ed`](https://github.com/AxaGuilDEv/react-oidc/commit/c55f2ed5538e1dd4bd9f9f0ae0d25fdeb1421984) by Build-CI - -#### [v3.0.6-alpha.0](https://github.com/AxaGuilDEv/react-oidc/compare/v3.0.5-alpha.0...v3.0.6-alpha.0) -> 5 January 2020 -- fix(SessionLost): complete re-auth automaticaly first time display [`#373`](https://github.com/AxaGuilDEv/react-oidc/pull/373) by Guillaume Chervet -- chore(deps-dev): bump eslint-plugin-react-hooks from 1.7.0 to 2.3.0 [`#363`](https://github.com/AxaGuilDEv/react-oidc/pull/363) by dependabot-preview[bot] -- chore(deps-dev): bump redux from 4.0.4 to 4.0.5 [`#372`](https://github.com/AxaGuilDEv/react-oidc/pull/372) by dependabot-preview[bot] -- chore(deps-dev): bump @babel/cli from 7.7.4 to 7.7.7 [`#369`](https://github.com/AxaGuilDEv/react-oidc/pull/369) by dependabot-preview[bot] -- chore(deps-dev): bump oidc-client from 1.9.1 to 1.10.1 [`#366`](https://github.com/AxaGuilDEv/react-oidc/pull/366) by dependabot-preview[bot] -- chore(deps-dev): bump auto-changelog from 1.16.1 to 1.16.2 [`#367`](https://github.com/AxaGuilDEv/react-oidc/pull/367) by dependabot-preview[bot] -- chore(deps-dev): bump eslint-plugin-import from 2.18.2 to 2.19.1 [`#364`](https://github.com/AxaGuilDEv/react-oidc/pull/364) by dependabot-preview[bot] -- chore(deps-dev): bump @testing-library/jest-dom from 4.1.0 to 4.2.4 [`#368`](https://github.com/AxaGuilDEv/react-oidc/pull/368) by dependabot-preview[bot] -- chore(deps): bump @typescript-eslint/parser from 2.3.2 to 2.14.0 [`#371`](https://github.com/AxaGuilDEv/react-oidc/pull/371) by dependabot-preview[bot] -- chore(deps-dev): bump inquirer from 6.5.2 to 7.0.1 [`#365`](https://github.com/AxaGuilDEv/react-oidc/pull/365) by dependabot-preview[bot] -- chore(release): publish v3.0.6-alpha.0 ***NO_CI*** [`c871a60`](https://github.com/AxaGuilDEv/react-oidc/commit/c871a60adc3a6a8bbe816e5298e6056563e5b531) by Build-CI -- docs(changelog) update to new 3.0.5-alpha.0 [`96a24a9`](https://github.com/AxaGuilDEv/react-oidc/commit/96a24a95d62b1b829958c5769ac0617ccab18cca) by Build-CI - -#### [v3.0.5-alpha.0](https://github.com/AxaGuilDEv/react-oidc/compare/v3.0.4-alpha.0...v3.0.5-alpha.0) -> 3 January 2020 -- chore(deps-dev): bump @testing-library/react from 8.0.9 to 9.4.0 [`#358`](https://github.com/AxaGuilDEv/react-oidc/pull/358) by dependabot-preview[bot] -- chore(deps): [security] bump lodash.template from 4.4.0 to 4.5.0 [`#230`](https://github.com/AxaGuilDEv/react-oidc/pull/230) by dependabot-preview[bot] -- Can set the JWT in memory [`#354`](https://github.com/AxaGuilDEv/react-oidc/pull/354) by Olivier YOUF -- fix(all): F5 always re-auth and manage session lost [`#319`](https://github.com/AxaGuilDEv/react-oidc/pull/319) by Olivier YOUF -- chore(deps): bump enzyme-adapter-react-16 from 1.14.0 to 1.15.2 [`#359`](https://github.com/AxaGuilDEv/react-oidc/pull/359) by dependabot-preview[bot] -- chore(deps-dev): bump eslint-plugin-prettier from 3.1.1 to 3.1.2 [`#357`](https://github.com/AxaGuilDEv/react-oidc/pull/357) by dependabot-preview[bot] -- chore(deps-dev): bump redux-oidc from 3.1.5 to 3.1.7 [`#336`](https://github.com/AxaGuilDEv/react-oidc/pull/336) by dependabot-preview[bot] -- chore(deps-dev): bump typescript from 3.6.3 to 3.7.4 [`#361`](https://github.com/AxaGuilDEv/react-oidc/pull/361) by dependabot-preview[bot] -- chore(deps-dev): bump @babel/preset-react from 7.0.0 to 7.7.4 [`#347`](https://github.com/AxaGuilDEv/react-oidc/pull/347) by dependabot-preview[bot] -- chore(deps): [security] bump https-proxy-agent from 2.2.2 to 2.2.4 [`#345`](https://github.com/AxaGuilDEv/react-oidc/pull/345) by dependabot-preview[bot] -- chore(deps-dev): bump lint-staged from 8.2.1 to 9.5.0 [`#348`](https://github.com/AxaGuilDEv/react-oidc/pull/348) by dependabot-preview[bot] -- chore(deps-dev): bump react-redux from 5.1.1 to 7.1.3 [`#334`](https://github.com/AxaGuilDEv/react-oidc/pull/334) by dependabot-preview[bot] -- chore(deps-dev): bump eslint-plugin-jest from 22.17.0 to 23.2.0 [`#362`](https://github.com/AxaGuilDEv/react-oidc/pull/362) by dependabot-preview[bot] -- feat(context): Add events in useReactOidc hook [`#343`](https://github.com/AxaGuilDEv/react-oidc/pull/343) by Olivier YOUF -- chore(release): publish v3.0.5-alpha.0 ***NO_CI*** [`6fa041a`](https://github.com/AxaGuilDEv/react-oidc/commit/6fa041af0e1f1fcb9216fd6ed7a287e7fdc73ed6) by Build-CI -- fix(sessionlost) typo [`dd69fe6`](https://github.com/AxaGuilDEv/react-oidc/commit/dd69fe67acda1d6f2b7b1933cafa67f3c6133839) by guillaume chervet -- fix(sessionlost) typo [`2d8427f`](https://github.com/AxaGuilDEv/react-oidc/commit/2d8427ffd81f39dc65f9ecf26bc65b4244013607) by guillaume chervet -- refactor(auth) refresh branch and clean things [`59dedc1`](https://github.com/AxaGuilDEv/react-oidc/commit/59dedc11c7fc10a246ff8c915fa0583be981ab52) by guillaume chervet -- docs(changelog) update to new 3.0.4-alpha.0 [`b201e35`](https://github.com/AxaGuilDEv/react-oidc/commit/b201e3563ff1caf9bf940dde2210ef2bfc39ace0) by Build-CI - -#### [v3.0.4-alpha.0](https://github.com/AxaGuilDEv/react-oidc/compare/v3.0.3-alpha.0...v3.0.4-alpha.0) -> 18 November 2019 -- fix(context): avoid errors on console with custom callback [`#341`](https://github.com/AxaGuilDEv/react-oidc/pull/341) by Olivier YOUF -- fix(context): Fix silent crash [`#340`](https://github.com/AxaGuilDEv/react-oidc/pull/340) by Olivier YOUF -- doc(oidc-metadata): add document about metadata [`#330`](https://github.com/AxaGuilDEv/react-oidc/pull/330) by Guillaume Chervet -- chore(release): publish v3.0.4-alpha.0 ***NO_CI*** [`f8d7557`](https://github.com/AxaGuilDEv/react-oidc/commit/f8d755783d2b4cfbee0cdaabe6f27178d3200080) by Build-CI -- docs(changelog) update to new 3.0.3-alpha.0 [`6b0fc09`](https://github.com/AxaGuilDEv/react-oidc/commit/6b0fc0961c90ec3200e3995482fe748d1fbe5e1d) by Build-CI - -#### [v3.0.3-alpha.0](https://github.com/AxaGuilDEv/react-oidc/compare/v3.0.2-alpha.0...v3.0.3-alpha.0) -> 5 November 2019 -- fix(redux) oidcSecure hoc was not working [`#331`](https://github.com/AxaGuilDEv/react-oidc/pull/331) by Guillaume Chervet -- wip [`e5d41f8`](https://github.com/AxaGuilDEv/react-oidc/commit/e5d41f82a1b7d7e1608e84aad4482a5f4ac5fefc) by guillaume chervet -- wip [`d03101d`](https://github.com/AxaGuilDEv/react-oidc/commit/d03101d730d6cbecc3a4ee191bfde97137060cdf) by guillaume chervet -- chore(release): publish v3.0.3-alpha.0 ***NO_CI*** [`9b8de3b`](https://github.com/AxaGuilDEv/react-oidc/commit/9b8de3bf60b0d5d58caf12513be1bd742d2936df) by Build-CI -- maj [`b2d63e8`](https://github.com/AxaGuilDEv/react-oidc/commit/b2d63e8c92e0526abe1ba242759c1716f56bdac6) by guillaume chervet -- wip [`5613367`](https://github.com/AxaGuilDEv/react-oidc/commit/5613367e95de9aa5399b9ccdacd268e5d0ef4516) by guillaume chervet -- docs(changelog) update to new 3.0.2-alpha.0 [`5f22a9f`](https://github.com/AxaGuilDEv/react-oidc/commit/5f22a9fe09da0b803abd0c7698638acdfe6620f9) by Build-CI - -#### [v3.0.2-alpha.0](https://github.com/AxaGuilDEv/react-oidc/compare/v3.0.1-alpha.0...v3.0.2-alpha.0) -> 15 October 2019 -- Fix component prop type validation to use elementType [`#321`](https://github.com/AxaGuilDEv/react-oidc/pull/321) by Henri Koskenranta -- fix(router) : Add some polyfills for IE [`#314`](https://github.com/AxaGuilDEv/react-oidc/pull/314) by Olivier YOUF -- chore(mergify) add sonar rules [`#313`](https://github.com/AxaGuilDEv/react-oidc/pull/313) by Guillaume Chervet -- refactor(context) : remove callback OR in core [`#310`](https://github.com/AxaGuilDEv/react-oidc/pull/310) by Olivier YOUF -- chore(deps-dev): bump cross-env from 5.2.0 to 6.0.0 [`#306`](https://github.com/AxaGuilDEv/react-oidc/pull/306) by dependabot-preview[bot] -- chore(deps-dev): bump redux from 4.0.1 to 4.0.4 [`#243`](https://github.com/AxaGuilDEv/react-oidc/pull/243) by dependabot-preview[bot] -- fix(all) F5 always re-auth and manage session lost [`ee0c13f`](https://github.com/AxaGuilDEv/react-oidc/commit/ee0c13f437244fad58fa352da9a1a35f8e3eb3f7) by guillaume chervet -- wip [`b2a7185`](https://github.com/AxaGuilDEv/react-oidc/commit/b2a71851d0cb91653e1d77e2fe037aa2114e9037) by guillaume chervet -- chore(release): publish v3.0.2-alpha.0 ***NO_CI*** [`1e74a2c`](https://github.com/AxaGuilDEv/react-oidc/commit/1e74a2cdf751debd3e5fe6bb84c55d0850b27ba8) by Build-CI -- docs(changelog) update to new 3.0.1-alpha.0 [`75b21af`](https://github.com/AxaGuilDEv/react-oidc/commit/75b21af75f890f3b08c46847dcb7ab7fd52df1ef) by Build-CI -- wip [`e20c897`](https://github.com/AxaGuilDEv/react-oidc/commit/e20c8975f80f71ac7a6b4eaebf44025744359d93) by guillaume chervet - -#### [v3.0.1-alpha.0](https://github.com/AxaGuilDEv/react-oidc/compare/v3.0.0-alpha.0...v3.0.1-alpha.0) -> 25 September 2019 -- feat(all) Add callback component [`#303`](https://github.com/AxaGuilDEv/react-oidc/pull/303) by Madebymaurice -- doc(package) add better keword and update licence [`#304`](https://github.com/AxaGuilDEv/react-oidc/pull/304) by Guillaume Chervet -- docs: fixed a typo on AuthenticationProvider [`#295`](https://github.com/AxaGuilDEv/react-oidc/pull/295) by Jean-Lou Piermé -- fix(sample:redux) typo to get the condition working [`#292`](https://github.com/AxaGuilDEv/react-oidc/pull/292) by Markus Lasermann -- chore(release): publish v3.0.1-alpha.0 ***NO_CI*** [`3a6de2e`](https://github.com/AxaGuilDEv/react-oidc/commit/3a6de2ef2af3a7a51ee191a0c003907ba7fbcd7e) by Build-CI -- docs(changelog) update to new 3.0.0-alpha.0 [`1953c47`](https://github.com/AxaGuilDEv/react-oidc/commit/1953c479773b6181a3e0acf308e63bdc4d12cf8b) by Build-CI - -#### [v3.0.0-alpha.0](https://github.com/AxaGuilDEv/react-oidc/compare/v2.0.8...v3.0.0-alpha.0) -> 2 September 2019 -- feat(router) Agnostic router [`#290`](https://github.com/AxaGuilDEv/react-oidc/pull/290) by Arnaud Foraison -- fix(licence)set correct entity name [`#285`](https://github.com/AxaGuilDEv/react-oidc/pull/285) by Guillaume Chervet -- chore(release): publish v3.0.0-alpha.0 ***NO_CI*** [`6192d98`](https://github.com/AxaGuilDEv/react-oidc/commit/6192d98c63cd30ee2b69561bd78c4c313353dff7) by Build-CI -- docs(changelog) update to new 2.0.8 [`db610e3`](https://github.com/AxaGuilDEv/react-oidc/commit/db610e36a5874fc05ee3130eb116223b8122aa29) by Build-CI - -#### [v2.0.8](https://github.com/AxaGuilDEv/react-oidc/compare/v2.0.7...v2.0.8) -> 20 August 2019 -- fix(redux) F5 always re-auth [`#278`](https://github.com/AxaGuilDEv/react-oidc/pull/278) by Guillaume Chervet -- fix(redux) sample react route problem [`#277`](https://github.com/AxaGuilDEv/react-oidc/pull/277) by Guillaume Chervet -- chore(release): publish v2.0.8 ***NO_CI*** [`ebe2d7d`](https://github.com/AxaGuilDEv/react-oidc/commit/ebe2d7de2a76557b0bd95110afdf7b63192ead46) by Build-CI -- docs(changelog) update to new 2.0.7 [`5264289`](https://github.com/AxaGuilDEv/react-oidc/commit/5264289a48a6c0fd863757cf57b3e4bec89a6fe1) by Build-CI - -#### [v2.0.7](https://github.com/AxaGuilDEv/react-oidc/compare/v2.0.6...v2.0.7) -> 13 August 2019 -- fix(redux) workflow [`#271`](https://github.com/AxaGuilDEv/react-oidc/pull/271) by Guillaume Chervet -- chore(release): publish v2.0.7 ***NO_CI*** [`a45f630`](https://github.com/AxaGuilDEv/react-oidc/commit/a45f6300cac5f37efc9fdbdf76f7c97107a49b2f) by Build-CI -- docs(changelog) update to new 2.0.6 [`356afab`](https://github.com/AxaGuilDEv/react-oidc/commit/356afab343cd06f9535feb3a64fdf9675a84b8f2) by Build-CI - -#### [v2.0.6](https://github.com/AxaGuilDEv/react-oidc/compare/v2.0.5...v2.0.6) -> 9 August 2019 -- fix(redux) workflow [`#266`](https://github.com/AxaGuilDEv/react-oidc/pull/266) by Guillaume Chervet -- chore(release): publish v2.0.6 ***NO_CI*** [`a55b16e`](https://github.com/AxaGuilDEv/react-oidc/commit/a55b16edadb67903e51db9e359d7f260107c4a39) by Build-CI -- docs(changelog) update to new 2.0.5 [`44cc13b`](https://github.com/AxaGuilDEv/react-oidc/commit/44cc13b9b33de9184fd87cb3beae48aea33837a7) by Build-CI - -#### [v2.0.5](https://github.com/AxaGuilDEv/react-oidc/compare/v2.0.4...v2.0.5) -> 5 August 2019 -- fix(redux) incorrect properties [`#262`](https://github.com/AxaGuilDEv/react-oidc/pull/262) by Guillaume Chervet -- chore(release): publish v2.0.5 ***NO_CI*** [`fff2d20`](https://github.com/AxaGuilDEv/react-oidc/commit/fff2d20ae08b5a0f5af84452db2376280df70f55) by Build-CI -- docs(changelog) update to new 2.0.4 [`a43242b`](https://github.com/AxaGuilDEv/react-oidc/commit/a43242b6cc33d096e9c85303f8d63c8d6be7ad07) by Build-CI - -#### [v2.0.4](https://github.com/AxaGuilDEv/react-oidc/compare/v2.0.3...v2.0.4) -> 5 August 2019 -- fix(redux) upgrade react router version [`#261`](https://github.com/AxaGuilDEv/react-oidc/pull/261) by Guillaume Chervet -- chore(release): publish v2.0.4 ***NO_CI*** [`2b63d3e`](https://github.com/AxaGuilDEv/react-oidc/commit/2b63d3ee4a925b045c1a711b2a92cace4448d3b0) by Build-CI -- docs(changelog) update to new 2.0.3 [`dba7b1d`](https://github.com/AxaGuilDEv/react-oidc/commit/dba7b1d899ab58c7351ffe065e0ad4b01fb3ef21) by Build-CI - -#### [v2.0.3](https://github.com/AxaGuilDEv/react-oidc/compare/v2.0.2...v2.0.3) -> 2 August 2019 -- fix(redux) token renew [`#260`](https://github.com/AxaGuilDEv/react-oidc/pull/260) by Guillaume Chervet -- fix(redux) token renew [`#260`](https://github.com/AxaGuilDEv/react-oidc/pull/260) by Guillaume Chervet -- chore(build) add and regenerate package.lock [`ef392f1`](https://github.com/AxaGuilDEv/react-oidc/commit/ef392f1c2294a150444dc370531ba17f46d30701) by guillaume chervet -- chore(package) fix package version [`0a2a2bf`](https://github.com/AxaGuilDEv/react-oidc/commit/0a2a2bf84740fac0586cdd137ae5cf47102957ac) by guillaume chervet -- chore(release): publish v2.0.3 ***NO_CI*** [`bcac2f4`](https://github.com/AxaGuilDEv/react-oidc/commit/bcac2f4e37e6bc280fed9e6690224d552f8ee229) by Build-CI -- docs(changelog) update to new 2.0.2 [`ff075a4`](https://github.com/AxaGuilDEv/react-oidc/commit/ff075a4b400a074d376a4c07f4a751e6914f6cb4) by Build-CI - -#### [v2.0.2](https://github.com/AxaGuilDEv/react-oidc/compare/v2.0.2-alpha.0...v2.0.2) -> 30 July 2019 -- fix(redux) token renew [`#258`](https://github.com/AxaGuilDEv/react-oidc/pull/258) by Guillaume Chervet -- chore(release): publish v2.0.2 ***NO_CI*** [`8e50a29`](https://github.com/AxaGuilDEv/react-oidc/commit/8e50a29d6302b3c0487dd5102fe115458760705a) by Build-CI -- docs(changelog) update to new 2.0.2-alpha.0 [`df80867`](https://github.com/AxaGuilDEv/react-oidc/commit/df808675ee9d524f15d2c1f493d8cfe5a36d926e) by Build-CI - -#### [v2.0.2-alpha.0](https://github.com/AxaGuilDEv/react-oidc/compare/v2.0.1-alpha.0...v2.0.2-alpha.0) -> 25 July 2019 -- doc : add optionnal parameter for post logout uri redirect [`#253`](https://github.com/AxaGuilDEv/react-oidc/pull/253) by Olivier YOUF -- chore(release): publish v2.0.2-alpha.0 ***NO_CI*** [`3c1230a`](https://github.com/AxaGuilDEv/react-oidc/commit/3c1230ab6b950a100ba58190f4f9781ed06af82f) by Build-CI -- docs(changelog) update to new 2.0.1-alpha.0 [`c7c32a2`](https://github.com/AxaGuilDEv/react-oidc/commit/c7c32a21992e8f907671788f4d49a3af7a76fcd6) by Build-CI - -#### [v2.0.1-alpha.0](https://github.com/AxaGuilDEv/react-oidc/compare/v2.0.0-alpha.0...v2.0.1-alpha.0) -> 15 July 2019 -- Fix/infiniteloop [`#238`](https://github.com/AxaGuilDEv/react-oidc/pull/238) by Olivier YOUF -- fix(infiniteLoop) : package upgrade [`e98e7d6`](https://github.com/AxaGuilDEv/react-oidc/commit/e98e7d6febdc820dc66122db43d443a8eb3d7d26) by Olivier YOUF -- fix(infiniteLoop) : change hooks to avoid infinite loop [`2168254`](https://github.com/AxaGuilDEv/react-oidc/commit/21682540fdf9a71e178942ee31b711a1f2c1575d) by Olivier YOUF -- chore(release): publish v2.0.1-alpha.0 ***NO_CI*** [`d906ddf`](https://github.com/AxaGuilDEv/react-oidc/commit/d906ddf3b2d269a362604e0a1418699bd4d10371) by Build-CI -- docs(changelog) update to new 2.0.0-alpha.0 [`2b07917`](https://github.com/AxaGuilDEv/react-oidc/commit/2b0791737eaf7c42b96ba77900d1bf10aa6a1e09) by Build-CI - -#### [v2.0.0-alpha.0](https://github.com/AxaGuilDEv/react-oidc/compare/v1.3.3...v2.0.0-alpha.0) -> 11 July 2019 -- fix(packages) : rebuild packages for package lock [`#229`](https://github.com/AxaGuilDEv/react-oidc/pull/229) by Olivier YOUF -- Feature/hooks [`#225`](https://github.com/AxaGuilDEv/react-oidc/pull/225) by Olivier YOUF -- fix(packages) : resolves missing scripts [`043a66e`](https://github.com/AxaGuilDEv/react-oidc/commit/043a66eee2f3862e1a0ab5b4155fd2475206fa35) by Olivier YOUF -- upgrading React Context + Hooks [`dafe353`](https://github.com/AxaGuilDEv/react-oidc/commit/dafe353e93456cbb2d4feba5f20cbc563029e50c) by Olivier YOUF -- babel 7 migration [`d4a8b09`](https://github.com/AxaGuilDEv/react-oidc/commit/d4a8b099fb5f1cf47a57f418b93f12f9afd04efb) by Olivier YOUF -- refacto : Package managament & dependency [`d8e8d39`](https://github.com/AxaGuilDEv/react-oidc/commit/d8e8d394cfcad14bc2bec0b58a13d440aa9a6702) by Olivier YOUF -- fix(lint) : fix lint return and deps [`c275ea3`](https://github.com/AxaGuilDEv/react-oidc/commit/c275ea3daaff745b691f083788c0155f6c89bb3c) by Olivier YOUF -- fix : fix isEnabled flag [`fe5779c`](https://github.com/AxaGuilDEv/react-oidc/commit/fe5779c5d47986223cafab81ca09bfb3f5b7a83b) by Olivier YOUF -- PR remarks [`8b6ed4d`](https://github.com/AxaGuilDEv/react-oidc/commit/8b6ed4d3e3a1a0600d9d7011a551c07c500f82cf) by Olivier YOUF -- feat : new hooks function to get oidc props [`e7c4530`](https://github.com/AxaGuilDEv/react-oidc/commit/e7c45303167c37b5322955f1274e6cf90bd698cf) by Olivier YOUF -- chore(release): publish v2.0.0-alpha.0 ***NO_CI*** [`06e5a77`](https://github.com/AxaGuilDEv/react-oidc/commit/06e5a7743225a652142defc6dd658fa9c45f8d26) by Build-CI -- refacto(packags) : bump babel [`fcf3169`](https://github.com/AxaGuilDEv/react-oidc/commit/fcf31694c9235da8c9d0b6d5d11f226efb65af43) by Olivier YOUF -- docs(changelog) update to new 1.3.3 [`eea8716`](https://github.com/AxaGuilDEv/react-oidc/commit/eea8716a1b2e8ac098c0f388682f1e1f166f22ca) by Build-CI -- override conf for example [`c6342f5`](https://github.com/AxaGuilDEv/react-oidc/commit/c6342f57d2952676d96b0990099c2741c63ac736) by Olivier YOUF - -#### [v1.3.3](https://github.com/AxaGuilDEv/react-oidc/compare/v1.3.3-alpha.0...v1.3.3) -> 4 April 2019 -- chore(release): publish v1.3.3 ***NO_CI*** [`3e011c2`](https://github.com/AxaGuilDEv/react-oidc/commit/3e011c2ca20c48a0b3e308c8e42ba96fd30b4ef8) by Build-CI -- docs(changelog) update to new 1.3.3-alpha.0 [`e8b9de0`](https://github.com/AxaGuilDEv/react-oidc/commit/e8b9de0754c9c1df227f70912fd5b5acf67a4134) by Build-CI - -#### [v1.3.3-alpha.0](https://github.com/AxaGuilDEv/react-oidc/compare/v1.3.2-alpha.0...v1.3.3-alpha.0) -> 1 April 2019 -- Fetch Core : Fix for header props [`#182`](https://github.com/AxaGuilDEv/react-oidc/pull/182) by Olivier YOUF -- chore(release): publish v1.3.3-alpha.0 ***NO_CI*** [`1d9d9e3`](https://github.com/AxaGuilDEv/react-oidc/commit/1d9d9e3ecf855f56e961743d04533c1408bbbeb5) by Build-CI -- docs(changelog) update to new 1.3.2-alpha.0 [`100e4be`](https://github.com/AxaGuilDEv/react-oidc/commit/100e4be4321359fdb628bf52c93adae612576564) by Build-CI -- fix headers [`01dd579`](https://github.com/AxaGuilDEv/react-oidc/commit/01dd579c63401c99b097726b73658bfa84db7767) by Olivier YOUF - -#### [v1.3.2-alpha.0](https://github.com/AxaGuilDEv/react-oidc/compare/v1.3.1-alpha.0...v1.3.2-alpha.0) -> 27 March 2019 -- Few changes for multiple Auth requests and callbacks issue [`#180`](https://github.com/AxaGuilDEv/react-oidc/pull/180) by Olivier YOUF -- fix callback double tap [`35f5609`](https://github.com/AxaGuilDEv/react-oidc/commit/35f56093d6e0aedca493aabde779bef58f49d59d) by Olivier YOUF -- fix : flag for waiting auth [`89b32c0`](https://github.com/AxaGuilDEv/react-oidc/commit/89b32c0a411957d1e514602d72b52ddb25b5de97) by Olivier YOUF -- Fix : package changes [`b8692f2`](https://github.com/AxaGuilDEv/react-oidc/commit/b8692f29f4fae45fb64e74d1d89fa7cf10f2fc05) by Olivier YOUF -- chore(release): publish v1.3.2-alpha.0 ***NO_CI*** [`d814ada`](https://github.com/AxaGuilDEv/react-oidc/commit/d814ada43b9e826d3a5aa9317e4b8f7dcff0671f) by Build-CI -- wip : callback [`01af436`](https://github.com/AxaGuilDEv/react-oidc/commit/01af43636e2fc5cb99a08aa154b415857493956b) by Olivier YOUF -- docs(changelog) update to new 1.3.1-alpha.0 [`17c8683`](https://github.com/AxaGuilDEv/react-oidc/commit/17c86839884e63cf8c05459839f869f0ef55e019) by Build-CI - -#### [v1.3.1-alpha.0](https://github.com/AxaGuilDEv/react-oidc/compare/v1.3.0...v1.3.1-alpha.0) -> 14 March 2019 -- Fix(context) component should wait user loading [`#170`](https://github.com/AxaGuilDEv/react-oidc/pull/170) by Guillaume Chervet -- fix(tweet) set up good changelog link [`#169`](https://github.com/AxaGuilDEv/react-oidc/pull/169) by Guillaume Chervet -- docs(changelog) update to new 1.3.0 [`02de519`](https://github.com/AxaGuilDEv/react-oidc/commit/02de5196b3e7907acfeb631ee27fdea7ed15968a) by Build-CI -- chore(release): publish v1.3.1-alpha.0 ***NO_CI*** [`32d880f`](https://github.com/AxaGuilDEv/react-oidc/commit/32d880fb06a6b916d87e90d8f4c6b1d338969d06) by Build-CI - -#### [v1.3.0](https://github.com/AxaGuilDEv/react-oidc/compare/v1.2.1...v1.3.0) -> 12 March 2019 -- fix(context) no state found in storage [`#168`](https://github.com/AxaGuilDEv/react-oidc/pull/168) by Guillaume Chervet -- docs(changelog) update to new 1.2.1 [`4eed1e9`](https://github.com/AxaGuilDEv/react-oidc/commit/4eed1e91ad3ed5dce05827444334a598f747844c) by Guillaume Chervet -- chore(release): publish v1.3.0 ***NO_CI*** [`517804b`](https://github.com/AxaGuilDEv/react-oidc/commit/517804b569c31e2e6a43f32f0aac2ff960291988) by Build-CI - -#### [v1.2.1](https://github.com/AxaGuilDEv/react-oidc/compare/v1.2.0...v1.2.1) -> 8 March 2019 -- feature(context/routes) allow to configure callbacks [`#164`](https://github.com/AxaGuilDEv/react-oidc/pull/164) by Guillaume Chervet -- feature(vanilla) vanilla lib usefull for demo or debug or migration of old js application [`#160`](https://github.com/AxaGuilDEv/react-oidc/pull/160) by Guillaume Chervet -- chore(changelog) set up auto changelog and auto tweet [`#153`](https://github.com/AxaGuilDEv/react-oidc/pull/153) by Guillaume Chervet -- chore(release): publish v1.2.1 ***NO_CI*** [`fbb0339`](https://github.com/AxaGuilDEv/react-oidc/commit/fbb0339dad91dda54d2828c7d5a4ffa5cd071a6e) by Build-CI - -#### [v1.2.0](https://github.com/AxaGuilDEv/react-oidc/compare/v1.1.6...v1.2.0) -> 24 February 2019 -- English - change all instances of "authentified" to be "authenticated" [`#151`](https://github.com/AxaGuilDEv/react-oidc/pull/151) by Paul Hammond -- chore(release): publish v1.2.0 ***NO_CI*** [`5f491b7`](https://github.com/AxaGuilDEv/react-oidc/commit/5f491b75962664904720b3404ce80a27ed9967a6) by Build-CI - -#### [v1.1.6](https://github.com/AxaGuilDEv/react-oidc/compare/v1.1.5...v1.1.6) -> 24 February 2019 -- Customise authenticating component [context] [`#150`](https://github.com/AxaGuilDEv/react-oidc/pull/150) by Paul Hammond -- lock down version of jest [`#149`](https://github.com/AxaGuilDEv/react-oidc/pull/149) by Paul Hammond -- chore(deps-dev): bump enzyme from 3.7.0 to 3.8.0 [`#112`](https://github.com/AxaGuilDEv/react-oidc/pull/112) by dependabot[bot] -- chore(deps-dev): bump eslint-plugin-jsx-a11y from 6.1.2 to 6.2.0 [`#113`](https://github.com/AxaGuilDEv/react-oidc/pull/113) by dependabot[bot] -- chore(deps-dev): bump codacy-coverage from 3.3.0 to 3.4.0 [`#116`](https://github.com/AxaGuilDEv/react-oidc/pull/116) by dependabot[bot] -- chore(deps-dev): bump eslint-plugin-import from 2.14.0 to 2.16.0 [`#117`](https://github.com/AxaGuilDEv/react-oidc/pull/117) by dependabot[bot] -- chore(deps-dev): bump prettier from 1.16.1 to 1.16.4 [`#122`](https://github.com/AxaGuilDEv/react-oidc/pull/122) by dependabot[bot] -- chore(deps-dev): bump eslint-plugin-jest from 22.1.2 to 22.2.2 [`#126`](https://github.com/AxaGuilDEv/react-oidc/pull/126) by dependabot[bot] -- feat : adding enable prop in Provider [`#125`](https://github.com/AxaGuilDEv/react-oidc/pull/125) by Olivier YOUF -- chore(release): publish v1.1.6 ***NO_CI*** [`6f573cd`](https://github.com/AxaGuilDEv/react-oidc/commit/6f573cd08e1e39143c661553645fdc62adebd3d8) by Build-CI - -#### [v1.1.5](https://github.com/AxaGuilDEv/react-oidc/compare/v1.1.5-alpha.0...v1.1.5) -> 1 February 2019 -- chore(deps-dev): bump eslint-config-prettier from 3.3.0 to 4.0.0 [`#111`](https://github.com/AxaGuilDEv/react-oidc/pull/111) by dependabot[bot] -- chore(deps-dev): bump prettier from 1.16.0 to 1.16.1 [`#110`](https://github.com/AxaGuilDEv/react-oidc/pull/110) by dependabot[bot] -- chore(deps-dev): bump jest from 23.6.0 to 24.0.0 [`#118`](https://github.com/AxaGuilDEv/react-oidc/pull/118) by dependabot[bot] -- Fix: Add react-router to dependencies [`#120`](https://github.com/AxaGuilDEv/react-oidc/pull/120) by Hamza Hamidi -- chore: remove react-redux dependency [`#119`](https://github.com/AxaGuilDEv/react-oidc/pull/119) by rpetigny -- chore(deps-dev): bump expect from 23.6.0 to 24.0.0 [`#106`](https://github.com/AxaGuilDEv/react-oidc/pull/106) by dependabot[bot] -- chore(deps-dev): bump lerna from 3.5.0 to 3.10.7 [`#107`](https://github.com/AxaGuilDEv/react-oidc/pull/107) by dependabot[bot] -- chore(deps-dev): bump eslint-plugin-jest from 22.1.2 to 22.1.3 [`#108`](https://github.com/AxaGuilDEv/react-oidc/pull/108) by dependabot[bot] -- chore(deps-dev): bump enzyme-adapter-react-16 from 1.7.1 to 1.8.0 [`#109`](https://github.com/AxaGuilDEv/react-oidc/pull/109) by dependabot[bot] -- chore(deps): bump react-dom from 16.6.3 to 16.7.0 [`#95`](https://github.com/AxaGuilDEv/react-oidc/pull/95) by dependabot[bot] -- chore(deps): bump oidc-client from 1.5.4 to 1.6.1 [`#96`](https://github.com/AxaGuilDEv/react-oidc/pull/96) by dependabot[bot] -- chore(deps): bump react from 16.6.3 to 16.7.0 [`#97`](https://github.com/AxaGuilDEv/react-oidc/pull/97) by dependabot[bot] -- chore(deps-dev): bump tslint from 5.11.0 to 5.12.1 [`#99`](https://github.com/AxaGuilDEv/react-oidc/pull/99) by dependabot[bot] -- chore(deps-dev): bump eslint from 5.11.1 to 5.12.1 [`#100`](https://github.com/AxaGuilDEv/react-oidc/pull/100) by dependabot[bot] -- chore(deps-dev): bump prettier from 1.15.3 to 1.16.0 [`#101`](https://github.com/AxaGuilDEv/react-oidc/pull/101) by dependabot[bot] -- chore(deps-dev): bump babel-plugin-macros from 2.4.4 to 2.4.5 [`#93`](https://github.com/AxaGuilDEv/react-oidc/pull/93) by dependabot[bot] -- chore(deps-dev): bump typescript from 3.2.2 to 3.2.4 [`#102`](https://github.com/AxaGuilDEv/react-oidc/pull/102) by dependabot[bot] -- chore(deps-dev): bump eslint-plugin-react from 7.12.3 to 7.12.4 [`#103`](https://github.com/AxaGuilDEv/react-oidc/pull/103) by dependabot[bot] -- chore(deps-dev): bump eslint-plugin-prettier from 3.0.0 to 3.0.1 [`#88`](https://github.com/AxaGuilDEv/react-oidc/pull/88) by dependabot[bot] -- chore(deps-dev): bump react-scripts from 2.1.1 to 2.1.3 [`#90`](https://github.com/AxaGuilDEv/react-oidc/pull/90) by dependabot[bot] -- chore(deps-dev): bump babel-plugin-macros from 2.4.2 to 2.4.4 [`#85`](https://github.com/AxaGuilDEv/react-oidc/pull/85) by mergify[bot] -- chore(deps-dev): bump chalk from 2.4.1 to 2.4.2 [`#86`](https://github.com/AxaGuilDEv/react-oidc/pull/86) by mergify[bot] -- chore(deps-dev): bump eslint-plugin-react from 7.11.1 to 7.12.3 [`#87`](https://github.com/AxaGuilDEv/react-oidc/pull/87) by mergify[bot] -- Fix example link [`#89`](https://github.com/AxaGuilDEv/react-oidc/pull/89) by Seth -- fix(redux) oidc default props [`#84`](https://github.com/AxaGuilDEv/react-oidc/pull/84) by julienbirgand -- chore(release): publish v1.1.5 ***NO_CI*** [`e21bbbc`](https://github.com/AxaGuilDEv/react-oidc/commit/e21bbbcadfec1fe70cc64d0b33c84910a9e8add1) by Build-CI - -#### [v1.1.5-alpha.0](https://github.com/AxaGuilDEv/react-oidc/compare/v1.1.0...v1.1.5-alpha.0) -> 4 January 2019 -- chore(pipeline-azure) branch variable was a bad one [`#83`](https://github.com/AxaGuilDEv/react-oidc/pull/83) by mergify[bot] -- fix : Context Fetch>oidcUser transmission [`#80`](https://github.com/AxaGuilDEv/react-oidc/pull/80) by Olivier YOUF -- fix token expired event [`#81`](https://github.com/AxaGuilDEv/react-oidc/pull/81) by mergify[bot] -- chore(deps-dev): bump eslint from 5.9.0 to 5.11.1 [`#82`](https://github.com/AxaGuilDEv/react-oidc/pull/82) by mergify[bot] -- chore(deps-dev): bump @angular/compiler from 7.1.0 to 7.1.4 [`#75`](https://github.com/AxaGuilDEv/react-oidc/pull/75) by mergify[bot] -- chore(deps-dev): bump typescript from 3.2.1 to 3.2.2 [`#63`](https://github.com/AxaGuilDEv/react-oidc/pull/63) by dependabot[bot] -- chore(deps-dev): bump @angular/core from 7.1.0 to 7.1.3 [`#65`](https://github.com/AxaGuilDEv/react-oidc/pull/65) by mergify[bot] -- chore(deps-dev): bump tslint-config-prettier from 1.16.0 to 1.17.0 [`#64`](https://github.com/AxaGuilDEv/react-oidc/pull/64) by mergify[bot] -- chore(deps-dev): bump regenerator-runtime from 0.12.1 to 0.13.1 [`#67`](https://github.com/AxaGuilDEv/react-oidc/pull/67) by mergify[bot] -- chore(deps-dev): bump babel-eslint from 8.2.6 to 10.0.1 [`#69`](https://github.com/AxaGuilDEv/react-oidc/pull/69) by mergify[bot] -- chore(deps-dev): bump inquirer from 6.2.0 to 6.2.1 [`#68`](https://github.com/AxaGuilDEv/react-oidc/pull/68) by mergify[bot] -- chore(deps-dev): bump react-test-renderer from 16.6.3 to 16.7.0 [`#70`](https://github.com/AxaGuilDEv/react-oidc/pull/70) by mergify[bot] -- chore(deps-dev): bump enzyme-adapter-react-16 from 1.7.0 to 1.7.1 [`#71`](https://github.com/AxaGuilDEv/react-oidc/pull/71) by mergify[bot] -- chore(deps-dev): bump eslint-plugin-jest from 22.0.1 to 22.1.2 [`#76`](https://github.com/AxaGuilDEv/react-oidc/pull/76) by mergify[bot] -- docs(readme) add keyword [`#79`](https://github.com/AxaGuilDEv/react-oidc/pull/79) by Guillaume Chervet -- chore(ci) remove travis and codeclimate [`#73`](https://github.com/AxaGuilDEv/react-oidc/pull/73) by Guillaume Chervet -- chore(deps-dev): bump lint-staged from 7.3.0 to 8.1.0 [`#74`](https://github.com/AxaGuilDEv/react-oidc/pull/74) by dependabot[bot] -- chore(ci) add azureDevops build + sonar [`#72`](https://github.com/AxaGuilDEv/react-oidc/pull/72) by Guillaume Chervet -- chore(deps-dev): bump react-scripts from 1.1.5 to 2.1.1 [`#57`](https://github.com/AxaGuilDEv/react-oidc/pull/57) by dependabot[bot] -- chore(deps-dev): bump typescript from 3.1.6 to 3.2.1 [`#59`](https://github.com/AxaGuilDEv/react-oidc/pull/59) by dependabot[bot] -- chore(deps-dev): bump react-test-renderer from 16.6.1 to 16.6.3 [`#60`](https://github.com/AxaGuilDEv/react-oidc/pull/60) by dependabot[bot] -- chore(deps-dev): bump prettier from 1.15.1 to 1.15.3 [`#61`](https://github.com/AxaGuilDEv/react-oidc/pull/61) by dependabot[bot] -- doc(readme) small fix for demo to internship [`#62`](https://github.com/AxaGuilDEv/react-oidc/pull/62) by Guillaume Chervet -- chore(azurepipeline) configure lerna to publish [`#58`](https://github.com/AxaGuilDEv/react-oidc/pull/58) by Guillaume Chervet -- chore(deps-dev): bump lerna from 3.4.3 to 3.5.0 [`#55`](https://github.com/AxaGuilDEv/react-oidc/pull/55) by dependabot[bot] -- chore(deps-dev): bump eslint-plugin-json from 1.2.1 to 1.3.2 [`#54`](https://github.com/AxaGuilDEv/react-oidc/pull/54) by dependabot[bot] -- chore(deps-dev): bump eslint-plugin-prettier from 2.7.0 to 3.0.0 [`#56`](https://github.com/AxaGuilDEv/react-oidc/pull/56) by dependabot[bot] -- chore(deps-dev): bump @angular/compiler from 7.0.4 to 7.1.0 [`#52`](https://github.com/AxaGuilDEv/react-oidc/pull/52) by dependabot[bot] -- chore(deps-dev): bump codacy-coverage from 3.2.0 to 3.3.0 [`#53`](https://github.com/AxaGuilDEv/react-oidc/pull/53) by dependabot[bot] -- chore(deps-dev): bump @angular/core from 7.0.3 to 7.1.0 [`#46`](https://github.com/AxaGuilDEv/react-oidc/pull/46) by dependabot[bot] -- chore(deps-dev): bump eslint from 5.8.0 to 5.9.0 [`#48`](https://github.com/AxaGuilDEv/react-oidc/pull/48) by dependabot[bot] -- chore(deps-dev): bump shelljs from 0.8.2 to 0.8.3 [`#49`](https://github.com/AxaGuilDEv/react-oidc/pull/49) by dependabot[bot] -- chore(deps-dev): bump eslint-plugin-jest from 22.0.0 to 22.0.1 [`#50`](https://github.com/AxaGuilDEv/react-oidc/pull/50) by dependabot[bot] -- chore(deps-dev): bump eslint-config-prettier from 3.1.0 to 3.3.0 [`#47`](https://github.com/AxaGuilDEv/react-oidc/pull/47) by dependabot[bot] -- chore(deps): bump react-dom from 16.6.1 to 16.6.3 [`#44`](https://github.com/AxaGuilDEv/react-oidc/pull/44) by dependabot[bot] -- chore(deps): bump rxjs from 6.3.2 to 6.3.3 [`#45`](https://github.com/AxaGuilDEv/react-oidc/pull/45) by dependabot[bot] -- chore(deps): bump react from 16.6.1 to 16.6.3 [`#43`](https://github.com/AxaGuilDEv/react-oidc/pull/43) by dependabot[bot] -- chore(deps): bump react-redux from 5.0.7 to 5.1.1 [`#38`](https://github.com/AxaGuilDEv/react-oidc/pull/38) by dependabot[bot] -- chore(deps-dev): bump @angular/compiler from 7.0.3 to 7.0.4 [`#42`](https://github.com/AxaGuilDEv/react-oidc/pull/42) by dependabot[bot] -- chore(deps-dev): bump tslint-config-prettier from 1.15.0 to 1.16.0 [`#40`](https://github.com/AxaGuilDEv/react-oidc/pull/40) by dependabot[bot] -- doc(redux): update code example and add more informations [`#41`](https://github.com/AxaGuilDEv/react-oidc/pull/41) by Benoit Fontaine -- doc(context) add more explanation [`#37`](https://github.com/AxaGuilDEv/react-oidc/pull/37) by Guillaume Chervet -- chore(deps): [security] bump merge from 1.2.0 to 1.2.1 [`#39`](https://github.com/AxaGuilDEv/react-oidc/pull/39) by dependabot[bot] -- Set up CI with Azure Pipelines [`#31`](https://github.com/AxaGuilDEv/react-oidc/pull/31) by Cyril Lakech -- chore(deps-dev): bump tslint-plugin-prettier from 1.3.0 to 2.0.1 [`#34`](https://github.com/AxaGuilDEv/react-oidc/pull/34) by dependabot[bot] -- chore(deps-dev): bump eslint-config-prettier from 2.10.0 to 3.1.0 [`#36`](https://github.com/AxaGuilDEv/react-oidc/pull/36) by dependabot[bot] -- chore(deps-dev): bump eslint-plugin-jest from 21.27.2 to 22.0.0 [`#35`](https://github.com/AxaGuilDEv/react-oidc/pull/35) by dependabot[bot] -- fix oidcUser transmission [`0ae83e1`](https://github.com/AxaGuilDEv/react-oidc/commit/0ae83e1e9e4d71683c190a32fb87a91b307539cc) by Olivier YOUF -- chore(release): publish v1.1.5-alpha.0 ***NO_CI*** [`41536de`](https://github.com/AxaGuilDEv/react-oidc/commit/41536de22955b5f7f6b5b0dc758554a7f1deff20) by Build-CI -- WIP [`b866401`](https://github.com/AxaGuilDEv/react-oidc/commit/b86640100253030ccc1386d198f9910f86c052a4) by Guillaume Chervet -- WIP [`cad214b`](https://github.com/AxaGuilDEv/react-oidc/commit/cad214b48575a759f9245bcf2651d78dba4435e6) by Guillaume Chervet -- WIP [`d36dd3d`](https://github.com/AxaGuilDEv/react-oidc/commit/d36dd3d1463b0a4f6c9b6f8f6be74707552b139f) by Guillaume Chervet -- it works! [`b58a355`](https://github.com/AxaGuilDEv/react-oidc/commit/b58a355821a53cb0229acc1a1a69d724655e9f77) by Guillaume Chervet -- WIP [`fd2c87a`](https://github.com/AxaGuilDEv/react-oidc/commit/fd2c87a4b8b67914526bdef213719c08d49cbd54) by Guillaume Chervet -- chore(pipeline-azure) bug during publish [`0f0935a`](https://github.com/AxaGuilDEv/react-oidc/commit/0f0935a84f5065c1b3beabbb0b4acdc04346bf1d) by Guillaume Chervet -- WIP [`7c238f5`](https://github.com/AxaGuilDEv/react-oidc/commit/7c238f59ed3221910ced2631bed5092a9a56d71d) by Guillaume Chervet -- WIP [`4d04233`](https://github.com/AxaGuilDEv/react-oidc/commit/4d04233963fe77e803626ed0752dfe66474f8e71) by Guillaume Chervet -- WIP [`1a2fdbd`](https://github.com/AxaGuilDEv/react-oidc/commit/1a2fdbd0b2fc8f9d611248c02987fc524c77ea94) by Guillaume Chervet -- it works! [`adb3ecf`](https://github.com/AxaGuilDEv/react-oidc/commit/adb3ecf6f64e626209dd18bc6b0949c321af3347) by Guillaume Chervet -- WIP [`0836ecd`](https://github.com/AxaGuilDEv/react-oidc/commit/0836ecdfe1a0ff9846621a78e44b3cacb9184436) by Guillaume Chervet - -#### [v1.1.0](https://github.com/AxaGuilDEv/react-oidc/compare/v1.0.2...v1.1.0) -> 9 November 2018 -- fix(publish) missing attribute to publish to npm [`36a05fa`](https://github.com/AxaGuilDEv/react-oidc/commit/36a05faf92e6f09a2fec01756ad9b15cb44253ac) by Guillaume Chervet -- chore(release): publish v1.1.0 [ci skip] [`cc39e30`](https://github.com/AxaGuilDEv/react-oidc/commit/cc39e30840195b6d00591f72bef879e671a6a0f6) by Travis CI User - -#### [v1.0.2](https://github.com/AxaGuilDEv/react-oidc/compare/v1.0.1...v1.0.2) -> 31 October 2018 -- feat: add fetch observable hoc [`7ef055c`](https://github.com/AxaGuilDEv/react-oidc/commit/7ef055cb555d2937c2fcac175ab6294ef0fe9662) by Thierno Barry -- chore(release): publish v1.0.2 [ci skip] [`689b36c`](https://github.com/AxaGuilDEv/react-oidc/commit/689b36c1820e07ab1bc4b8542c4914f3081fed54) by Travis CI User -- chore: remove codacy that return 404 errors [`52724bb`](https://github.com/AxaGuilDEv/react-oidc/commit/52724bb7171a1e117f893580a6df54bcacf6d584) by Cyril Lakech - -#### [v1.0.1](https://github.com/AxaGuilDEv/react-oidc/compare/v1.0.0...v1.0.1) -> 4 October 2018 -- replacing includes by indexof [`#25`](https://github.com/AxaGuilDEv/react-oidc/pull/25) by mergify[bot] -- chore(release): publish v1.0.1 [ci skip] [`7cfb06c`](https://github.com/AxaGuilDEv/react-oidc/commit/7cfb06ce706187d79fccf9fbcebf28e5f1c28e9b) by Travis CI User - -### [v1.0.0](https://github.com/AxaGuilDEv/react-oidc/compare/v0.0.1...v1.0.0) -> 3 October 2018 -- doc: add npm version badge [`#23`](https://github.com/AxaGuilDEv/react-oidc/pull/23) by mergify[bot] -- chore(release): publish v1.0.0 [ci skip] [`728051b`](https://github.com/AxaGuilDEv/react-oidc/commit/728051b8b5db2eba1c7d2f922d9c466c7eba62ea) by Travis CI User - -#### [v0.0.1](https://github.com/AxaGuilDEv/react-oidc/compare/v0.0.1-alpha.11...v0.0.1) -> 3 October 2018 -- Mergify initial configuration [`#22`](https://github.com/AxaGuilDEv/react-oidc/pull/22) by mergify[bot] -- chore(release): publish v0.0.1 [ci skip] [`94cbf05`](https://github.com/AxaGuilDEv/react-oidc/commit/94cbf05bf38ad190f0025d3ddee3bb584d42cc01) by Travis CI User - -#### [v0.0.1-alpha.11](https://github.com/AxaGuilDEv/react-oidc/compare/v0.0.1-alpha.10...v0.0.1-alpha.11) -> 3 October 2018 -- chore: exclude tests from codeclimate analysis [`#14`](https://github.com/AxaGuilDEv/react-oidc/pull/14) by Cyril Lakech -- chore(build) add user variable for releasing a specific version to npm [`#20`](https://github.com/AxaGuilDEv/react-oidc/pull/20) by Guillaume Chervet -- fix : recompose branch test in the consumer and add doc about dev [`#21`](https://github.com/AxaGuilDEv/react-oidc/pull/21) by youf-olivier -- chore(release): publish v0.0.1-alpha.11 [ci skip] [`82d326a`](https://github.com/AxaGuilDEv/react-oidc/commit/82d326a0abc8c89516c010e731f911cc27da29c6) by Travis CI User - -#### [v0.0.1-alpha.10](https://github.com/AxaGuilDEv/react-oidc/compare/v0.0.1-alpha.9...v0.0.1-alpha.10) -> 1 October 2018 -- chore: setup test coverage with codacy [`#17`](https://github.com/AxaGuilDEv/react-oidc/pull/17) by Cyril Lakech -- chore(release): publish v0.0.1-alpha.10 [ci skip] [`612031e`](https://github.com/AxaGuilDEv/react-oidc/commit/612031ea55e145672dd5c2d8fd078479cff5f706) by Travis CI User - -#### v0.0.1-alpha.9 -> 1 October 2018 -- wip chore: setup publishing to npm [`#19`](https://github.com/AxaGuilDEv/react-oidc/pull/19) by Cyril Lakech -- chore: do not share codeclimate token [`#16`](https://github.com/AxaGuilDEv/react-oidc/pull/16) by Guillaume Chervet -- Add a Codacy badge to readme.md [`#15`](https://github.com/AxaGuilDEv/react-oidc/pull/15) by Guillaume Chervet -- chore: setup coverage with codeclimate [`#13`](https://github.com/AxaGuilDEv/react-oidc/pull/13) by youf-olivier -- chore: add coverage badge [`#12`](https://github.com/AxaGuilDEv/react-oidc/pull/12) by Guillaume Chervet -- chore(packages) add require attributes to publish inside npm in publi… [`#11`](https://github.com/AxaGuilDEv/react-oidc/pull/11) by Cyril Lakech -- refactor: simplify oidc service authenticateUser [`#10`](https://github.com/AxaGuilDEv/react-oidc/pull/10) by Guillaume Chervet -- chore: add codeclimate badge [`#8`](https://github.com/AxaGuilDEv/react-oidc/pull/8) by Guillaume Chervet -- init [`8d1518e`](https://github.com/AxaGuilDEv/react-oidc/commit/8d1518edc28882b83f207e8dc19d3c805f5ce96d) by Olivier Youf -- chore(release): publish v0.0.1-alpha.9 [ci skip] [`df4adb5`](https://github.com/AxaGuilDEv/react-oidc/commit/df4adb51f25be9f6b49f46ad9c7620e6b91fc259) by Travis CI User -- chore(packages) add require attributes to publish inside npm in public with a scope [`bb6f22f`](https://github.com/AxaGuilDEv/react-oidc/commit/bb6f22fe4a2c93156ad5848e1e9e221f5d7f2e57) by Guillaume Chervet -- chore: add license [`3d2ba13`](https://github.com/AxaGuilDEv/react-oidc/commit/3d2ba1328685a2aec3b5d158db9047870ed236c4) by Cyril Lakech -- Add Codacy badge [`400b938`](https://github.com/AxaGuilDEv/react-oidc/commit/400b93878c0b55b831de63b5bd01de82ac6d389c) by The Codacy Badger +# Changelog + +## 7.26.0 + +- [b9656c2](https://github.com/AxaFrance/oidc-client/commit/b9656c2559993efe94a121c442000969b1eaba2b) - feat(react-oidc): enforce uniqueness of redirect_uri and silent_redirect_uri (#1606) (release), 2025-09-17 by *Jean-Marc Rakotoarisoa* +- [960a694](https://github.com/AxaFrance/oidc-client/commit/960a69472b75e12490025ee3b46d15643c0e35a6) - fix(oidc-client): Clear userInfo in storage in clearAsync function (#1603), 2025-09-17 by *Mérill Téterel* + + +## v7.25.16 + +- [c79907b](https://github.com/AxaFrance/oidc-client/commit/c79907b63af69352ed660e97d9e61265bc155131) - fix(oidc-client): renew token silent login (release) (#1598), 2025-09-04 by *Guillaume Chervet* + + +## v7.25.15 + +- [f4ce35e](https://github.com/AxaFrance/oidc-client/commit/f4ce35e4e272de9e4f4387494877bab5939fa1a9) - fix(oidc-client): implement consistent storage caching for userInfo and well-known configuration (release) (#1592), 2025-09-02 by *Michael Sverdlov* + + +## v7.25.14 + +- [f5b86ff](https://github.com/AxaFrance/oidc-client/commit/f5b86ffe656845c26b6f7bcf88da43cf8ece173e) - fix(renewTokens): prevent infinite loop on renew token flow (#1581) (release), 2025-08-02 by *Matheus Frigo* + + +## v7.25.13 + +- [31661bc](https://github.com/AxaFrance/oidc-client/commit/31661bc16d67866b6e8d5b978b117600b769fe28) - refcator(all): update dependencies (#1567) (release), 2025-05-05 by *Guillaume Chervet* + + +## v7.25.12 + +- [f19cca8](https://github.com/AxaFrance/oidc-client/commit/f19cca8c4a0aa24f5646e13c80610148037e3bad) - fix(oidc-service-worker): stream already consumed (#1558) (release), 2025-04-30 by *Guillaume Chervet* + + +## v7.25.11 + +- [e5e958a](https://github.com/AxaFrance/oidc-client/commit/e5e958a34f39ab349b34e094bc17f5df3b49b8f9) - fix(oidc-service-worker): missing body (#1556) (release), 2025-04-29 by *Guillaume Chervet* + + +## v7.25.10 + +- [dbb52da](https://github.com/AxaFrance/oidc-client/commit/dbb52dad456d2429d21fd5a645ff27d6b21e056a) - fix(serviceworker): ios (#1554) (release), 2025-04-24 by *Guillaume Chervet* +- [f2f447e](https://github.com/AxaFrance/oidc-client/commit/f2f447e34805822387281126b93ec39153fb5672) - refactor(all): updates libraries, 2025-04-14 by *Guillaume Chervet* + + +## v7.25.9 + +- [c1ece66](https://github.com/AxaFrance/oidc-client/commit/c1ece663131db50a8c1152b18be0d3d5f6a0025e) - fix(oidc): make bearer fetch works on safari back (release) (#1550), 2025-04-11 by *Guillaume Chervet* + + +## v7.25.8 + +- [4c85da7](https://github.com/AxaFrance/oidc-client/commit/4c85da7d0e0e802c95efe31c5de948ac5abd5494) - fix(oidc-service-worker): Error with latest Safari (#1547) (release), 2025-04-04 by *Guillaume Chervet* + + +## v7.25.7 + +- [930ad03](https://github.com/AxaFrance/oidc-client/commit/930ad0367cfcaa5bd15726c17501d70b0768ce5e) - fix(oidc-service-worker): fetch already consume (release) (#1534), 2025-04-01 by *Guillaume Chervet* + + +## v7.25.6 + +- [2cb8cde](https://github.com/AxaFrance/oidc-client/commit/2cb8cdeafdb39fadc19beb878808a5d2291cd6fa) - fix(oidc): multi-tab dpop not working with (#1531) (release), 2025-03-28 by *Guillaume Chervet* + + +## v7.25.5 + +- [d7567ba](https://github.com/AxaFrance/oidc-client/commit/d7567ba28c0dfe9b248be52ecfac4df6f98b397b) - feature(oidc-service-worker): multi tab auth (#1528) (release), 2025-03-27 by *Guillaume Chervet* + + +## v7.25.4 + +- [1b2fa1d](https://github.com/AxaFrance/oidc-client/commit/1b2fa1da513b419c2c28e67a331d12670b07a94d) - refactor(oidc): update librairie (release), 2025-03-25 by *Guillaume Chervet* + + +## v7.25.3 + +- [ca0f064](https://github.com/AxaFrance/oidc-client/commit/ca0f0645c52dd827b97912d5ee6f1836e05f56e1) - fix(oidc): lost session back (release) (#1514), 2025-02-06 by *Guillaume Chervet* + + +## v7.25.2 + +- [15900f4](https://github.com/AxaFrance/oidc-client/commit/15900f42e42539a5b12a4c23959ec95c695426d9) - fix(oidc): MonitorSession/CheckSession initializes only on one tab (release) (#1513), 2025-02-05 by *Guillaume Chervet* + + +## v7.25.1 + +- [f0641a6](https://github.com/AxaFrance/oidc-client/commit/f0641a6ff21a7cf600ee5e782a3e3114b462551c) - fix(oidc): remove use of localStorage for cache (release), 2025-02-05 by *Guillaume Chervet* + + +## v7.25.0 + +- [07754f5](https://github.com/AxaFrance/oidc-client/commit/07754f5643cbe21e6e6eb248b8a6398bd0de2fd7) - fix(oidc): refresh silent signin scope=null (release) (#1503), 2025-01-24 by *Guillaume Chervet* +- [2c08373](https://github.com/AxaFrance/oidc-client/commit/2c0837357b341eeeabbe16b40857240e7d2a596b) - feat(all): update libraries (#1494), 2025-01-12 by *Guillaume Chervet* + + +## v7.24.1 + +- [3fe0511](https://github.com/AxaFrance/oidc-client/commit/3fe05117c29704f9be56604eb9ffa7195bcdc517) - refactor(react-oidc): react 19 compatibility (#1493) (release), 2025-01-10 by *Guillaume Chervet* + + +## v7.24.0 + +- [de5da36](https://github.com/AxaFrance/oidc-client/commit/de5da362de4e3f10d46ffdfafd324e14e173b78c) - feat(scope): scope can be change dynamically (release) (#1489), 2025-01-03 by *Guillaume Chervet* + + +## v7.23.1 + +- [0f69a11](https://github.com/AxaFrance/oidc-client/commit/0f69a114564134dee63f78654b9af82f0b291ec9) - fix(oidc): login async promise (release), 2024-11-27 by *Guillaume Chervet* + + +## v7.23.0 + +- [30fda23](https://github.com/AxaFrance/oidc-client/commit/30fda231324b18bb026de30e537e0bce7cc3bbc1) - feat(oidc-react): add missing scope property in login route (release), 2024-11-22 by *Guillaume Chervet* +- [4d77aae](https://github.com/AxaFrance/oidc-client/commit/4d77aae5ec4564f1866ebc9ba5e9f2ad1bd51b63) - fix(oidc): dpop typo (#1482), 2024-11-08 by *Guillaume Chervet* +- [08a21f8](https://github.com/AxaFrance/oidc-client/commit/08a21f89842f1aa8123bfd1eea046a8f1d4a8e96) - fix(demo): better demo (#1480), 2024-11-05 by *Guillaume Chervet* + + +## v7.22.32 + +- [3f885fc](https://github.com/AxaFrance/oidc-client/commit/3f885fc158ded05ea37b9d7925bd801b63321231) - fix(oidc): remove console.log (release), 2024-10-04 by *Guillaume Chervet* + + +## v7.22.31 + +- [cc731c1](https://github.com/AxaFrance/oidc-client/commit/cc731c15f1d72ce4d21a7958ca15128ae1dcdd89) - fix(oidc): force sw update when new registration appears (release) (#1449), 2024-10-02 by *wermanoid* + + +## v7.22.30 + +- [8c98b27](https://github.com/AxaFrance/oidc-client/commit/8c98b2701e1118538455816ca458062cfc07d716) - fix(oidc): remove missing console.log (#1472) (release), 2024-10-01 by *Guillaume Chervet* + + +## v7.22.29 + +- [e297a7b](https://github.com/AxaFrance/oidc-client/commit/e297a7b5bd9d3eebb7cea443185039a7cb74d2f4) - fix(oidc): navigator locks null (#1466) (release), 2024-09-29 by *Guillaume Chervet* + + +## v7.22.28 + +- [346bdce](https://github.com/AxaFrance/oidc-client/commit/346bdce138a6b43ab4b31b56447161f9a6cdadeb) - fix(oidc): fetchWithTokens was using a snapshot of tokens (#1465) (release), 2024-09-29 by *Guillaume Chervet* + + +## v7.22.27 + +- [6354370](https://github.com/AxaFrance/oidc-client/commit/63543705c9b9a8182d47564bfc24a811c1f50e84) - fix(oidc): user reload time before expiration (release) (#1464), 2024-09-28 by *Guillaume Chervet* + + +## v7.22.26 + +- [10e7257](https://github.com/AxaFrance/oidc-client/commit/10e7257a0d2257bd8905b3b00ca1fe7ad757e74c) - fix(oidc): lock unexpected behavior (#1459) (release), 2024-09-27 by *Guillaume Chervet* + + +## v7.22.25 + +- [3a0d48e](https://github.com/AxaFrance/oidc-client/commit/3a0d48ea0d3609d31de0f45d6aebfb1a23b25e73) - fix(oidc): number timer increase (#1457) (release), 2024-09-26 by *Guillaume Chervet* + + +## v7.22.24 + +- [b34eabf](https://github.com/AxaFrance/oidc-client/commit/b34eabf39ce108f8de93a49f1a4d9ec6e46d642c) - refactor(all): update dependencies (#1446) (release), 2024-09-02 by *Guillaume Chervet* +- [35081e1](https://github.com/AxaFrance/oidc-client/commit/35081e16b947ebd490b83a1f6d6b9dc101363736) - Merge branch 'main' of https://github.com/AxaFrance/oidc-client into HEAD, 2024-08-25 by *Guillaume Chervet* +- [70dd233](https://github.com/AxaFrance/oidc-client/commit/70dd233f69f2b2a9c5da4a2514e2cc657cf435a2) - Merge branch 'main' of https://github.com/AxaFrance/oidc-client, 2024-08-25 by *Guillaume Chervet* +- [47f9de1](https://github.com/AxaFrance/oidc-client/commit/47f9de1f648838ae085c45a5dcd55687f80829c5) - fix(oidc): remove no-existing property add typings (release), 2024-08-25 by *Guillaume Chervet* + + +## v7.22.23 + +- [d15a57d](https://github.com/AxaFrance/oidc-client/commit/d15a57d98309db99d3bcd8d1a6a4fbeffe1b5402) - Fix(oidc): usage of config option service_worker_register (#1440) (release), 2024-08-25 by *Thomas Miliopoulos* + + +## v7.22.22 + +- [d213de1](https://github.com/AxaFrance/oidc-client/commit/d213de1a49d891cc1c0f399621f696ed861c145e) - doc(oidc) :Update README.md (release), 2024-08-20 by *Guillaume Chervet* +- [1159262](https://github.com/AxaFrance/oidc-client/commit/115926280965cffc5a4f7ea2234bf1a0017ff896) - fix(logout): should work correctly with multiple tabs (alpha) (#1435), 2024-08-13 by *wermanoid* +- [23ae6ba](https://github.com/AxaFrance/oidc-client/commit/23ae6ba287a85cc879c92228feb3855dcbe2930e) - fix(oidc): Add undefined as union type into arguments for login, logout, renewTokens (#1429) (alpha), 2024-08-02 by *ShimpeiKamiguchi* + + +## v7.22.21 + +- [318de92](https://github.com/AxaFrance/oidc-client/commit/318de922980c167dd9fc1a743d2dedd106b9a02d) - fix(oidc): Add null as union type into arguments for login, logout, renewTokens functions (#1427) (release), 2024-07-26 by *ShimpeiKamiguchi* + + +## v7.22.20 + +- [05ace2d](https://github.com/AxaFrance/oidc-client/commit/05ace2dce4a36493b1d127d049c3ef7d5ebd90b4) - fix(oidc): record tabIds when service worker receives init event (release), 2024-07-22 by *mkrzempek* +- [6b5f6b4](https://github.com/AxaFrance/oidc-client/commit/6b5f6b428aba70b32d5264b0de89752a00b352e3) - refactor(initWorker): null coalescing, 2024-07-21 by *Jason Finch* +- [34bd8e4](https://github.com/AxaFrance/oidc-client/commit/34bd8e4b3388761b2127a9c73980d74edac7b3ad) - refactor(parameters): Default parameters should be last.sonarlint(typescript:S1788), 2024-07-21 by *Jason Finch* +- [44fa6f2](https://github.com/AxaFrance/oidc-client/commit/44fa6f2678f989ee23a84a506aea3caf159b9c2c) - fix spelling `token_acquired`, 2024-07-21 by *Jason Finch* +- [32a2af3](https://github.com/AxaFrance/oidc-client/commit/32a2af3028cd69581d1ab0ee183c7b3146998b41) - chore(lint): Fix lint warnings., 2024-07-21 by *Jason Finch* + + +## v7.22.19 + +- [2cf0b62](https://github.com/AxaFrance/oidc-client/commit/2cf0b6243b39f3927d75fb80a96030259b7c16a2) - fix(oidc): autorenew from custom fetch was broken (release), 2024-07-20 by *Guillaume Chervet* +- [f1d9da4](https://github.com/AxaFrance/oidc-client/commit/f1d9da44647d5b754df9c73cadb899179a98982b) - fix(oidc): lint (alpha), 2024-07-19 by *Guillaume Chervet* +- [e4f4d97](https://github.com/AxaFrance/oidc-client/commit/e4f4d9774acb94f968b566b69cb8f11581a76830) - chore: apply prettier in repo, 2024-07-18 by *Alex Werman* +- [02b00e0](https://github.com/AxaFrance/oidc-client/commit/02b00e075aeb8a291e1fc72b28ffe4eab1787db4) - fix(eslint): Fix ESLint to run prettier, 2024-07-17 by *Jason Finch* +- [9191b0c](https://github.com/AxaFrance/oidc-client/commit/9191b0c2f95491fd12cf93673bb468d9b6d61774) - chore(packages): Bump packages for eslint/prettier, 2024-07-17 by *Jason Finch* +- [a082b20](https://github.com/AxaFrance/oidc-client/commit/a082b20a943ab6322e69c00770d8ba86c9b8eaa2) - fix (Lint): Fix lint errors after rebase., 2024-07-17 by *Jason Finch* +- [f6cf194](https://github.com/AxaFrance/oidc-client/commit/f6cf194d9c14d7eba20f23a89e215bb9cc6cacd1) - refactor(silentcallback): Catch any errors in async playCallbackAsync, 2024-07-13 by *Jason Finch* +- [8797330](https://github.com/AxaFrance/oidc-client/commit/8797330ea5060a77b8d10a352ff166a33210f6aa) - refactor(lint): Fix minor lint issues, 2024-07-13 by *Jason Finch* +- [bb7bc92](https://github.com/AxaFrance/oidc-client/commit/bb7bc929f7a1bc4f1d210216d89fad881056990f) - fix (lint): Fix all lint errors reporting by eslint., 2024-07-12 by *Jason Finch* +- [cd2f57e](https://github.com/AxaFrance/oidc-client/commit/cd2f57edb99e04495b9884723cd05277a45aad43) - fix(demo): Update configurations.ts, 2024-07-16 by *Guillaume Chervet* + + +## v7.22.18 + +- [5ee0cc8](https://github.com/AxaFrance/oidc-client/commit/5ee0cc8f6d823056da221ad081c3821ba9fac343) - fix(oidc): separate state, nonce and codeVerifier for each tab (release) (#1402), 2024-07-16 by *Miya* + + +## v7.22.17 + +- [b099078](https://github.com/AxaFrance/oidc-client/commit/b099078f9d4b61dffd03034f511a4f32e80977a8) - fix(oidc): clenup client internal promises when requests are finished (release) (#1417), 2024-07-15 by *wermanoid* +- [01f0714](https://github.com/AxaFrance/oidc-client/commit/01f0714241e6442e6b58fcba8b86804ed75cec09) - tests(domain): Be more explicit about intent of test, is to not throw, not return undefined. (#1413), 2024-07-15 by *Jason Finch* +- [b94fa5c](https://github.com/AxaFrance/oidc-client/commit/b94fa5ca90bd366c4f59a870c428f42872bfacaa) - docs: Minor language change. (#1412), 2024-07-15 by *Jason Finch* +- [7caee91](https://github.com/AxaFrance/oidc-client/commit/7caee919b4854526dad83203216965746baecabe) - build(job): Update job scripts to v4. (earlier versions are marked deprecated) (#1411), 2024-07-15 by *Jason Finch* +- [a46b1aa](https://github.com/AxaFrance/oidc-client/commit/a46b1aabe19db70beac342c557ae2c986d16eae7) - fix (FetchToken): Fix FetchToken param to be boolean (#1414), 2024-07-15 by *Jason Finch* +- [a989ed2](https://github.com/AxaFrance/oidc-client/commit/a989ed29f46b66483bc2c7c51e73bcc19b2c9736) - build(lint): Update lint step to run. (#1409), 2024-07-13 by *Jason Finch* + + +## v7.22.16 + +- [72a6373](https://github.com/AxaFrance/oidc-client/commit/72a6373402a53aaaf01ad7fac22f8ad8c6feaff0) - fix(oidc): improve error handling (release) (#1403), 2024-07-11 by *Miya* +- [c56ceb8](https://github.com/AxaFrance/oidc-client/commit/c56ceb815b28dd5990fe4a1679a61bcebc7e525a) - docs(readme): Update README.md (#1407), 2024-07-12 by *Jason Finch* + + +## v7.22.15 + +- [73eae7e](https://github.com/AxaFrance/oidc-client/commit/73eae7e9d68dea6ebec0ed82ba7873941c0e371e) - refactor(oidcServiceWorker): Extract GetCurrentDatabaseTokenEndpoint, add tests. (#1405) (release), 2024-07-11 by *Jason Finch* +- [e51aef2](https://github.com/AxaFrance/oidc-client/commit/e51aef268e783259c035e3ba58bf9aa16a111bea) - fix (Style): fix 'container' classname in demo. (#1401), 2024-07-11 by *Jason Finch* + + +## v7.22.14 + +- [25c55ee](https://github.com/AxaFrance/oidc-client/commit/25c55eeb7682356c13987a91d7b8645cca1b0ad5) - refactor(oidc): null coalescing (#1404) (release), 2024-07-11 by *Jason Finch* + + +## v7.22.13 + +- [95c814d](https://github.com/AxaFrance/oidc-client/commit/95c814dd9dd325a3a00c3a0dc049d301d983514e) - fix(ci): setup pnpm (release) (#1399), 2024-07-05 by *Guillaume Chervet* + + +## v7.22.12 + + + +## v7.22.11 + + + +## v7.22.10 + +- [6c80c5c](https://github.com/AxaFrance/oidc-client/commit/6c80c5cc77750aead50e62136a6594b05f21b42b) - fix(oidc): logout trigger login (release) (#1394), 2024-07-04 by *Guillaume Chervet* + + +## v7.22.9 + +- [77eb9e1](https://github.com/AxaFrance/oidc-client/commit/77eb9e1841814cfeb6c6672159740dad4c0a9d4d) - fix(oidc): MessageChannel is not closed after message is received (release) (#1396), 2024-07-02 by *radk0s* + + +## v7.22.8 + +- [c4cf94b](https://github.com/AxaFrance/oidc-client/commit/c4cf94b62a7b2c45cf0f94438a02f0cb5f06b9b0) - fix(oidc): remove dynamic web worker blocked by policies (release) (#1386), 2024-06-18 by *Guillaume Chervet* + + +## v7.22.7 + +- [9f4cbf4](https://github.com/AxaFrance/oidc-client/commit/9f4cbf414e1b41f448b2a36d759a035786d26668) - fix(oidc): 2 readmes with the same name (release) (#1377), 2024-06-07 by *meesvandongen* +- [0bfabd4](https://github.com/AxaFrance/oidc-client/commit/0bfabd41d67cad57415905b7ce729ee4fe85c8b4) - fix(oidc): session lost to quickly (alpha) (#1381), 2024-06-07 by *Guillaume Chervet* + + +## v7.22.6 + +- [bcba15b](https://github.com/AxaFrance/oidc-client/commit/bcba15b412063d139c0902de117b0516150c13a2) - fix(react-oidc): compatibility with react 19 (release) (#1372), 2024-05-22 by *Guillaume Chervet* +- [c49a857](https://github.com/AxaFrance/oidc-client/commit/c49a8572702c485c9a089b0f9aa11eb4bc6e7f1d) - refactor(test): add missing logout test case, 2024-05-22 by *Guillaume Chervet* + + +## v7.22.5 + +- [8d9fd95](https://github.com/AxaFrance/oidc-client/commit/8d9fd9550a74a771936f0e686eb31fe271cd912b) - fix(oidc): user loaded 401 when preload true and not serviceworder mode (release), 2024-05-19 by *Guillaume Chervet* +- [d764b2b](https://github.com/AxaFrance/oidc-client/commit/d764b2bd7319711c49a393c1fd3496d054661065) - refatcor(all): update librairies, 2024-05-18 by *Guillaume Chervet* + + +## v7.22.4 + +- [64c76e0](https://github.com/AxaFrance/oidc-client/commit/64c76e0b1f4fccf1c0ed93269a0307212be9d661) - feature(oidc):preload user (release) (#1352), 2024-04-23 by *Guillaume Chervet* + + +## v7.22.3 + +- [5af8075](https://github.com/AxaFrance/oidc-client/commit/5af807548e35c64da74fc3547e35c8ec512399ba) - fix(all): types import in index.ts for all typescript (release), 2024-04-18 by *Guillaume Chervet* + + +## v7.22.2 + +- [b17217d](https://github.com/AxaFrance/oidc-client/commit/b17217d6b829dee3b28f444fda099fce9c94bc41) - fix(react-oidc): unused var in User.txs (release), 2024-04-16 by *Guillaume Chervet* + + +## v7.22.1 + +- [be24658](https://github.com/AxaFrance/oidc-client/commit/be2465852e837b749abd3a86c5c0caa57a2ea8b6) - refactor(all): update libs (release), 2024-04-15 by *Guillaume Chervet* + + +## v7.22.0 + +- [032a00b](https://github.com/AxaFrance/oidc-client/commit/032a00b501557fe6b5be48e83e4914051ee2c7f0) - feat(oidc): control dpop injection (release) (#1342), 2024-04-10 by *Guillaume Chervet* + + +## v7.21.0 + +- [8335b5a](https://github.com/AxaFrance/oidc-client/commit/8335b5a6f5c02d320d642a022ff3828513f5a43e) - feat(dpop): add extras (alpha) (#1325) (release), 2024-03-28 by *Guillaume Chervet* + + +## v7.20.1 + +- [9a3ad3a](https://github.com/AxaFrance/oidc-client/commit/9a3ad3a474a66cc77fa2c3eb3eafa42f167f1e45) - feature(oidc): token renew only when required (release) (#1327), 2024-03-24 by *Guillaume Chervet* + + +## v7.20.0 + +- [44d15be](https://github.com/AxaFrance/oidc-client/commit/44d15be1c4d8f5069f15ddc5351e546fc5eb7730) - fix(oidc): userInfo 401 on first login (release), 2024-03-22 by *Guillaume Chervet* +- [c7793c9](https://github.com/AxaFrance/oidc-client/commit/c7793c9913128dbb82a60dff11261ca5b4749f0c) - feat(oidc-client): add dpop extras to claims (alpha), 2024-03-19 by *Guillaume Chervet* + + +## v7.19.6 + +- [b7568f8](https://github.com/AxaFrance/oidc-client/commit/b7568f8d73d21ba1b7cd4890bff2ad30941696e2) - fix(oidc-service-worker): normalize userinfo endpoint in service worker (#1320) (release), 2024-03-13 by *meesvandongen* + + diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index acd889a70..4cf779635 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,41 +1,62 @@ -# Contributing to @axa-fr/react-oidc +# Contributing to @axa-fr/oidc-client -First, ensure you have the [latest `npm`](https://docs.npmjs.com/). +First, ensure you have the [latest `pnpm`](https://pnpm.io/). To get started with the repository: ```sh -git clone https://github.com/AxaGuilDEv/react-oidc.git -cd react-oidc/packages/react -npm install -npm start +git clone https://github.com/AxaFrance/oidc-client.git + +cd oidc-client +pnpm install + +# oidc client demo +cd examples/oidc-client-demo +pnpm install +pnpm start +# then navigate to http://localhost:5174 + +# react vite demo +cd examples/react-oidc-demo +pnpm install +pnpm start +# then navigate to http://localhost:4200 + +# react NextJS demo +cd examples/nextjs-demo +pnpm install +pnpm run dev +# then navigate to http://localhost:3001 ``` + You are now ready to contribute! ## Pull Request Please respect the following [PULL_REQUEST_TEMPLATE.md](./PULL_REQUEST_TEMPLATE.md) -Packages are automaticaly published on npm when a PR is merged on main. +Packages are automatically published on npm when a PR is merged on main. Example of commit messages : To publish a patch version (0.0.x) : + - fix(oidc): my message (alpha) => will publish next patch as an alpha - chore(oidc): my message (beta) => will publish next patch as an beta - refactor(oidc): my message (release) => will publish next patch release (with automatic git tag and release) To publish a minor version (0.x.0) : + - feat(oidc): my message (alpha) => will publish next minor as an alpha - feat(oidc): my message (beta) => will publish next minor as an beta - feat(oidc): my message (release) => will publish next minor release (with automatic git tag and release) To publish a major version (x.0.0) : + - fix(oidc): my message containing BREACKING word (alpha) => will publish next major as an alpha - fix(oidc): my message containing BREACKING word (beta) => will publish next major as an beta - fix(oidc): my message containing BREACKING word (release) => will publish next major release (with automatic git tag and release) - ## Issue Please respect the following [ISSUE_TEMPLATE.md](./ISSUE_TEMPLATE.md) diff --git a/FAQ.md b/FAQ.md new file mode 100644 index 000000000..cb3904add --- /dev/null +++ b/FAQ.md @@ -0,0 +1,125 @@ +# FAQ (Frequently Asked Questions) + +## Condition to make silent signing work + +Third-party cookies are blocked by default on Safari and will be blocked on all browsers soon. +Today, silent signing works on Safari only if the OIDC provider and the client application are on the same domain. + +To guarantee that silent signing functions on all browsers, place your OIDC provider on the same domain as your client application. + +Example domains that work: + +https://oidc-provider.axa.fr +https://my-app.axa.fr + +Silent signing uses cookies from your OIDC provider to restore the session and retrieve tokens. +It opens an IFrame in the background, directed to a specific page on your OIDC provider. + +## Condition to make Single Logout to work + +The same domain constraint for "silent signing" applies to Single Logout. + +Single Logout allows you to disconnect from multiple OIDC Client sessions in one action, even if you are connected to different applications. + +## Condition to make Monitor Session to work + +Same domain constraint for "silent signing" applies to "monitorSession". + +Monitor session notifies you when your session expires or when you are disconnected from your OIDC provider. + +## Does Service Worker is mandatory ? + +Service Worker can be disable. +You can use classic mode without Service Worker. + +Just comment "service_worker_relative_url" like bellow: + +```javascript +export const configuration = { + client_id: 'interactive.public.short', + redirect_uri: window.location.origin + '/#/authentication/callback', + silent_redirect_uri: window.location.origin + '/#/authentication/silent-callback', + scope: 'openid profile email api offline_access', + authority: 'https://demo.duendesoftware.com', + // service_worker_relative_url: '/OidcServiceWorker.js', + service_worker_only: false, +}; +``` + +If your Service Worker file is already registered on your browser, your need to unregister it. For example from chrome dev tool. + +## Tokens are always refreshed in background every seconds + +The @axa-fr/oidc-client automatically refreshes tokens in the background. +It refreshes tokens before expiration to maintain valid tokens at all times. + +If your token session lifetime is too short, frequent refreshes will occur. +Token refreshing starts 120 seconds before expiration. + +Setting a session validity longer than 3 minutes is advisable. + +By default, @axa-fr/oidc-client chooses the shorter lifetime between access_token and id_token. +Use the "token_renew_mode" option to change this behavior. + +- **token_renew_mode**: String, // Optional, update tokens based on the selected token(s) lifetime: "access_token_or_id_token_invalid" (default), "access_token_invalid", "id_token_invalid" + +## window.crypto.subtle is unavailable over HTTP + +The library doesn't work over HTTP. Use HTTPS. +Setting up HTTPS is relatively easy, even for local development. + +https://github.com/AxaFrance/react-oidc/issues/1028 + +## Why OIDC at Client side instead of BFF (Backend for Frontend) ? + +We recommend @axa-fr/oidc-client for these reasons: + +Secure by default: Uses Service Worker. Server-side OIDC can be insecure if poorly configured. Client-side reuses server-side configurations, usually set by experts. +Fine-grained scope control: Easier to tailor token scope and lifetime for specific scenarios when using client-side OIDC. +No server needed: Client-side OIDC eliminates the need for a separate authentication server, saving money. +Quick time-to-market: Start with client-side OIDC, migrate to server-side if needed. Both are compatible. + +

+ @axa-fr/oidc-client is one of the securest way to Authenticate. +
+ @axa-fr/oidc-client is one of the securest way to Authenticate. +

+ +

+ Service Worker lifetime drawback. +
+ Service Worker lifetime drawback. +

+ +

+ @axa-fr/oidc-client is the simplest and cheapest. +
+ @axa-fr/oidc-client is the simplest and cheapest. +

+ +## Good Security Practices : does a Hacker can unregister the Service Worker and retrieve tokens via an Iframe ? + +To block token retrieval via an Iframe call and prevent Service Worker unregistration, comply with these practices: + +1 - Correctly configure the CSP (Content Security Policy) on the server side. +Example: + +```bash +server: { + headers: { + "Content-Security-Policy": "script-src 'self';", + }, + } +``` + +This blocks dynamic script injection into an iframe. + +2 - Initialize `` for **React** or the redirect callback for **oidc-client** at the start of your application script. +Configure it before making any fetch calls to services. +This guards against XSS attacks. diff --git a/MIGRATION_GUIDE_V3_TO_V4.md b/MIGRATION_GUIDE_V3_TO_V4.md index dbf072330..91ecb47d7 100644 --- a/MIGRATION_GUIDE_V3_TO_V4.md +++ b/MIGRATION_GUIDE_V3_TO_V4.md @@ -18,24 +18,25 @@ Main provider component have been renamed ```javascript import { AuthenticationProvider } from '@axa-fr/react-oidc-context'; -// old v3 +// old v3 - - +; // in v4 becomes import { OidcProvider } from '@axa-fr/react-oidc-context'; // loggerLevel : Logger property has been removed in v4 - - +; ``` Provider properties have changed, you need to keep only required properties for v4 else it won't work. ```javascript -// old v3 +// old v3 const propTypes = { notAuthenticated: PropTypes.elementType, // react component displayed during authentication notAuthorized: PropTypes.elementType, // react component displayed in case user is not Authorised @@ -75,7 +76,7 @@ const propTypes = { UserStore: PropTypes.func, }; -// new v4 +// new v4 const propTypes = { loadingComponent: PropTypes.elementType, // you can inject your own loading component sessionLostComponent: PropTypes.elementType, // you can inject your own session lost component @@ -100,25 +101,27 @@ const propTypes = { Manage Oidc actions and information ```javascript - -// old v3 +// old v3 import { useReactOidc } from '@axa-fr/react-oidc-context'; -const { isEnabled, login, logout, oidcUser, events } = useReactOidc(); +const { isEnabled, login, logout, oidcUser, events } = useReactOidc(); - -// new v4 -import { useOidc, useOidcAccessToken, useOidcIdToken, useOidcUser } from '@axa-fr/react-oidc-context'; +// new v4 +import { + useOidc, + useOidcAccessToken, + useOidcIdToken, + useOidcUser, +} from '@axa-fr/react-oidc-context'; const { login, logout, isAuthenticated } = useOidc(); // login and logout return a Promise const { oidcUser, isOidcUserLoading } = useOidcUser(); // Return user_info endpoint data const { accessToken, accessTokenPayload } = useOidcAccessToken(); // Contain access_token metadata acess_token is a JWK const { idToken, idTokenPayload } = useOidcIdToken(); // contain IDToken metadata - ``` ```javascript -// old v3 +// old v3 import { withFetchRedirectionOn401, withFetchSilentAuthenticateAndRetryOn401, withFetchRedirectionOn403, @@ -160,7 +163,7 @@ Then edit `OidcTrustedDomains.js` in "public" folder for your need // OidcTrustedDomains.js // Add here trusted domains, access tokens will be send to const trustedDomains = { - default:["http://localhost:4200"], + default: ['http://localhost:4200'], }; ``` diff --git a/MIGRATION_GUIDE_V3_TO_V5.md b/MIGRATION_GUIDE_V3_TO_V5.md index f67cae5de..2e68c48bc 100644 --- a/MIGRATION_GUIDE_V3_TO_V5.md +++ b/MIGRATION_GUIDE_V3_TO_V5.md @@ -20,24 +20,25 @@ Main provider component have been renamed ```javascript import { AuthenticationProvider } from '@axa-fr/react-oidc-context'; -// old v3 +// old v3 - - +; // in v5 becomes import { OidcProvider } from '@axa-fr/react-oidc-context'; // loggerLevel : Logger property has been removed in v4 - - +; ``` Provider properties have changed, you need to keep only required properties for v4 else it won't work. ```javascript -// old v3 +// old v3 const propTypes = { notAuthenticated: PropTypes.elementType, // react component displayed during authentication notAuthorized: PropTypes.elementType, // react component displayed in case user is not Authorised @@ -103,16 +104,19 @@ const propTypes = { Manage Oidc actions and information ```javascript - -// old v3 +// old v3 import { useReactOidc } from '@axa-fr/react-oidc-context'; -const { isEnabled, login, logout, oidcUser, events } = useReactOidc(); - +const { isEnabled, login, logout, oidcUser, events } = useReactOidc(); // new v5 -import { useOidc, useOidcAccessToken, useOidcIdToken, useOidcUser } from '@axa-fr/react-oidc-context'; - -const { login, logout, isAuthenticated} = useOidc(); // login and logout return a Promise +import { + useOidc, + useOidcAccessToken, + useOidcIdToken, + useOidcUser, +} from '@axa-fr/react-oidc-context'; + +const { login, logout, isAuthenticated } = useOidc(); // login and logout return a Promise const { oidcUser, oidcUserLoadingState } = useOidcUser(); // Return user_info endpoint data const { accessToken, accessTokenPayload } = useOidcAccessToken(); // Contain access_token metadata acess_token is a JWK const { idToken, idTokenPayload } = useOidcIdToken(); // contain IDToken metadata @@ -120,7 +124,7 @@ const { idToken, idTokenPayload } = useOidcIdToken(); // contain IDToken metadat ```javascript -// old v3 +// old v3 import { withFetchRedirectionOn401, withFetchSilentAuthenticateAndRetryOn401, withFetchRedirectionOn403, @@ -136,7 +140,7 @@ import { withOidcFetch } from '@axa-fr/react-oidc-context'; // withFetchToken in v3 have been rename to withOidcFetch and set inside '@axa-fr/react-oidc-context' package withOidcFetch() - + ``` If you need a very secure mode where refresh_token and access_token will be hide behind a service worker that will proxify requests. @@ -162,7 +166,7 @@ Then edit `OidcTrustedDomains.js` in "public" folder for your need // OidcTrustedDomains.js // Add here trusted domains, access tokens will be send to const trustedDomains = { - default:["http://localhost:4200"], + default: ['http://localhost:4200'], }; ``` diff --git a/MIGRATION_GUIDE_V6_TO_V7.md b/MIGRATION_GUIDE_V6_TO_V7.md new file mode 100644 index 000000000..e3b5838fb --- /dev/null +++ b/MIGRATION_GUIDE_V6_TO_V7.md @@ -0,0 +1,17 @@ +# Migrating from v6 to v7 + +- Package `@axa-fr/vanilla-oidc` as been renamed to `@axa-fr/oidc-client` +- VanillaOidc class as been renamed to OidcClient +- On version 7.3.0 configuration.service_worker_convert_all_requests_to_cors as been moved to TrustedDomains.js + +```javascript +// Service worker will continue to give access token to the JavaScript client +// Ideal to hide refresh token from client JavaScript, but to retrieve access_token for some +// scenarios which require it. For example, to send it via websocket connection. +trustedDomains.config_show_access_token = { + domains: ['https://demo.duendesoftware.com'], + showAccessToken: true, + // convertAllRequestsToCorsExceptNavigate: false, // default value is false + // setAccessTokenToNavigateRequests: true, // default value is true +}; +``` diff --git a/README.md b/README.md new file mode 100644 index 000000000..823aad7ee --- /dev/null +++ b/README.md @@ -0,0 +1,183 @@ +# @axa-fr/oidc-client + +[![Continuous Integration](https://github.com/AxaFrance/react-oidc/actions/workflows/npm-publish.yml/badge.svg)](https://github.com/AxaFrance/react-oidc/actions/workflows/npm-publish.yml) +[![Quality Gate](https://sonarcloud.io/api/project_badges/measure?project=AxaGuilDEv_react-oidc&metric=alert_status)](https://sonarcloud.io/dashboard?id=AxaGuilDEv_react-oidc) [![Reliability](https://sonarcloud.io/api/project_badges/measure?project=AxaGuilDEv_react-oidc&metric=reliability_rating)](https://sonarcloud.io/component_measures?id=AxaGuilDEv_react-oidc&metric=reliability_rating) [![Security](https://sonarcloud.io/api/project_badges/measure?project=AxaGuilDEv_react-oidc&metric=security_rating)](https://sonarcloud.io/component_measures?id=AxaGuilDEv_react-oidc&metric=security_rating) [![Code Coverage](https://sonarcloud.io/api/project_badges/measure?project=AxaGuilDEv_react-oidc&metric=coverage)](https://sonarcloud.io/component_measures?id=AxaGuilDEv_react-oidc&metric=Coverage) [![Twitter](https://img.shields.io/twitter/follow/GuildDEvOpen?style=social)](https://twitter.com/intent/follow?screen_name=GuildDEvOpen) + +

+ Sample React Oicd +

+ +- [About](#about) +- [Getting Started](#getting-started) +- [Run The Demos](#run-the-demos) +- [How It Works](#how-it-works) +- Packages + - [`@axa-fr/oidc-client`](./packages/oidc-client#readme.md) [![npm version](https://badge.fury.io/js/%40axa-fr%2Foidc-client.svg)](https://badge.fury.io/js/%40axa-fr%2Foidc-client) + - [`@axa-fr/react-oidc`](./packages/react-oidc#readme.md) [![npm version](https://badge.fury.io/js/%40axa-fr%2Freact-oidc.svg)](https://badge.fury.io/js/%40axa-fr%2Freact-oidc) + - `@axa-fr/svelte-oidc` : we are looking for contributor + - `@axa-fr/vue-oidc` : we are looking for contributor + - `@axa-fr/angular-oidc` : we are looking for contributor +- [FAQ](#FAQ) +- [Migrations](#migrations) +- [Contribute](#contribute) + +## About + +**@axa-fr/oidc-client** the lightest and securest library to manage authentication with OpenID Connect (OIDC) and OAuth2 protocol. It is compatible with all OIDC providers. +**@axa-fr/oidc-client** is a pure javascript library. It works with any JavaScript framework or library. +**@axa-fr/react-oidc** is for **React** (compatible next.js, etc.), we expect soon to provide one for **Vue**, **Angular** and **Svelte**. + +Demos: + +- Try the react demo at https://black-rock-0dc6b0d03.1.azurestaticapps.net/ (most advanced) +- Try the pure javascript demo at https://icy-glacier-004ab4303.2.azurestaticapps.net/ + +**@axa-fr/oidc-client** is: + +- **Secure** : + - With Demonstrating Proof of Possession (DPoP), your access_token and refresh_token are not usable outside your browser context (big protection) + - With the use of Service Worker, your tokens (refresh_token and/or access_token) are not accessible to the JavaScript client code (if you follow good practices from [`FAQ`](https://github.com/AxaFrance/oidc-client/blob/main/FAQ.md) section) + - OIDC using client side Code Credential Grant with pkce only +- **Lightweight** : Unpacked Size on npm is **274 kB**, Minified `61.1kB`, Minified+GZIPPED `16.8kB` [Pkg stats via Bundlephobia.com](https://bundlephobia.com/package/@axa-fr/react-oidc) +- **Simple** + - refresh_token and access_token are auto refreshed in background + - with the use of the Service Worker, you do not need to inject the access_token in every fetch, you have only to configure OidcTrustedDomains.js file +- **Multiple Authentication** : + - You can authenticate many times to the same provider with different scope (for example you can acquire a new 'payment' scope for a payment) + - You can authenticate to multiple different providers inside the same SPA (single page application) website +- **Flexible** : + - Work with Service Worker (more secure) and without for older browser (less secure). + - You can disable Service Worker if you want (but less secure) and just use SessionStorage or LocalStorage mode. + +Works perfectly well with: + +- [Auth0](https://auth0.com/) +- [Duende Identity Server](https://duendesoftware.com/) +- [Identity Server 4](https://github.com/IdentityServer/IdentityServer4) +- Azure AD +- Google +- AWS +- [Keycloak](https://www.keycloak.org/) +- etc., all OIDC providers + +## Getting Started + +### Getting Started with @axa-fr/oidc-client + +```sh +npm install @axa-fr/oidc-client --save + +# To install or update OidcServiceWorker.js file, you can run +node ./node_modules/@axa-fr/oidc-client/bin/copy-service-worker-files.mjs public + +# If you have a "public" folder, the 2 files will be created : +# ./public/OidcServiceWorker.js <-- will be updated at each "npm install" +# ./public/OidcTrustedDomains.js <-- won't be updated if already exist +``` + +> [!WARNING] +> If you use `Service Worker` mode, the `OidcServiceWorker.js` file should always be up to date with the version of the library. You may setup a postinstall script in your `package.json` file to update it at each npm install. For example : + +```json + "scripts": { + ... + "postinstall": "node ./node_modules/@axa-fr/oidc-client/bin/copy-service-worker-files.mjs public" + }, +``` + +More documentation : + +- [`@axa-fr/oidc-client`](./packages/oidc-client#readme) + +### Getting Started with @axa-fr/react-oidc + +```sh +npm install @axa-fr/react-oidc --save + +# To install or update OidcServiceWorker.js file, you can run +node ./node_modules/@axa-fr/react-oidc/bin/copy-service-worker-files.mjs public + +# If you have a "public" folder, the 2 files will be created : +# ./public/OidcServiceWorker.js <-- will be updated at each "npm install" +# ./public/OidcTrustedDomains.js <-- won't be updated if already exist +``` + +> [!WARNING] +> If you use Service Worker mode, the OidcServiceWorker.js file should always be up-to-date with the version of the library. You may setup a postinstall script in your package.json file to update it at each npm install. For example : + +```json + "scripts": { + ... + "postinstall": "node ./node_modules/@axa-fr/react-oidc/bin/copy-service-worker-files.mjs public" + }, +``` + +More documentation: + +- [`@axa-fr/react-oidc`](./packages/react-oidc#readme) + +## Run The Demos + +```sh +git clone https://github.com/AxaFrance/oidc-client.git + +cd oidc-client +pnpm install + +# oidc client demo +cd examples/oidc-client-demo +pnpm install +pnpm start +# then navigate to http://localhost:5174 + +# react vite demo +cd examples/react-oidc-demo +pnpm install +pnpm start +# then navigate to http://localhost:4200 + +# react NextJS demo +cd examples/nextjs-demo +pnpm install +pnpm run dev +# then navigate to http://localhost:3001 +``` + +## How It Works + +

+ Schema Authorization Code Grant with pcke flow on the using service worker +
+ The service worker catch access_token and refresh_token that will never be accessible to the client. +

+ +These components encapsulate the use of "`@axa-fr/oidc-client`" in order to hide workflow complexity. +Internally for "`@axa-fr/react-oidc`", native History API is used to be router library agnostic. + +More information about OIDC : + +- [French : Augmentez la sécurité et la simplicité de votre Système d’Information OpenID Connect](https://medium.com/just-tech-it-now/augmentez-la-s%C3%A9curit%C3%A9-et-la-simplicit%C3%A9-de-votre-syst%C3%A8me-dinformation-avec-oauth-2-0-cf0732d71284) +- [English : Increase the security and simplicity of your information system with OpenID Connect](https://medium.com/just-tech-it-now/increase-the-security-and-simplicity-of-your-information-system-with-openid-connect-fa8c26b99d6d) +- [English: youtube react-oidc introduction](https://www.youtube.com/watch?v=frIJfavZkUE&list=PL8EMdIH6Mzxy2kHtsVOEWqNz-OaM_D_fB&index=1) +- [French: youtube react-oidc introduction](https://www.youtube.com/watch?v=H-mLMGzQ_y0&list=PL8EMdIH6Mzxy2kHtsVOEWqNz-OaM_D_fB&index=2) + +## FAQ + +- Frequented Asked Question [`FAQ`](./FAQ.md) + +## Migrations + +- Migrating from v3 to v4 [`guide`](./MIGRATION_GUIDE_V3_TO_V4.md) +- Migrating from v3 to v5 [`guide`](./MIGRATION_GUIDE_V3_TO_V5.md) +- Migrating from v4 to v5 [`guide`](./MIGRATION_GUIDE_V4_TO_V5.md) +- Migrating from v5 to v6 [`guide`](./MIGRATION_GUIDE_V5_TO_V6.md) +- Migrating from v6 to v7 [`guide`](./MIGRATION_GUIDE_V6_TO_V7.md) + +## Contribute + +- [How to run the solution and to contribute](./CONTRIBUTING.md) +- [Please respect our code of conduct](./CODE_OF_CONDUCT.md) diff --git a/__mocks__/fileMock.js b/__mocks__/fileMock.js deleted file mode 100644 index 86059f362..000000000 --- a/__mocks__/fileMock.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = 'test-file-stub'; diff --git a/__mocks__/styleMock.js b/__mocks__/styleMock.js deleted file mode 100644 index f053ebf79..000000000 --- a/__mocks__/styleMock.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = {}; diff --git a/bin/generate-changelog.sh b/bin/generate-changelog.sh new file mode 100755 index 000000000..25084aaaf --- /dev/null +++ b/bin/generate-changelog.sh @@ -0,0 +1,54 @@ +#!/bin/bash + +num_tags=60 +excluded_author="GitHub" +project_url="https://github.com/AxaFrance/oidc-client/commit" + +# Get all tag names in reverse order +tags=(`git tag -l --sort=-creatordate | head -$num_tags`) + +# File to save the log +outfile=CHANGELOG.md + +# Write the header +echo "# Changelog" > $outfile +echo "" >> $outfile + +# Iterate over tags array +for((i=0; i<${#tags[@]}-1; i++)) +do +# current tag +current=${tags[$i]} +# previous tag +previous=${tags[$i+1]} + +# Write header for current tag +echo "## $current" >> $outfile +echo "## $current" +echo "" >> $outfile + +# Get commit hashes: between current and previous tag +hashes=(`git log --pretty=format:"%H" $previous..$current`) + +# Output commit log for each hash +for hash in ${hashes[@]} +do + # Check the author of the commit + author=$(git log -1 --pretty=format:"%an" $hash) + + # Exclude commits from the specified author + if [ "$author" != "$excluded_author" ]; then + # Get commit log in the desired format. + # You can modify the 'format' as per your need. Please refer 'PRETTY FORMATS' section of git-log man page + log=$(git log -1 --pretty=format:"[%h]($project_url/%H) - %s, %ad by *%an*" --date=short $hash) + + # Write formatted log to CHANGELOG.md file + echo "- $log" >> $outfile + echo "- $log" + fi +done + +# Space between two tags +echo "" >> $outfile +echo "" >> $outfile +done diff --git a/changelog-template.hbs b/changelog-template.hbs deleted file mode 100644 index ff4d159ef..000000000 --- a/changelog-template.hbs +++ /dev/null @@ -1,27 +0,0 @@ -### Changelog -All notable changes to this project will be documented in this file. - -{{#each releases}} - {{#if href}} - {{#if major}} - ### [{{title}}]({{href}}) - {{else}} - #### [{{title}}]({{href}}) - {{/if}} - {{else}} - #### {{title}} - {{/if}} - {{#if tag}} - > {{niceDate}} - {{/if}} - {{#each merges}} - - {{message}}{{#if href}} [`#{{id}}`]({{href}}){{/if}} by {{author}} - {{/each}} - {{#each fixes}} - - {{commit.subject}}{{#each fixes}}{{#if href}} [`#{{id}}`]({{href}}) by {{author}}{{/if}}{{/each}} - {{/each}} - {{#each commits}} - - {{subject}}{{#if href}} [`{{shorthash}}`]({{href}}) by {{author}} {{/if}} - {{/each}} - -{{/each}} \ No newline at end of file diff --git a/config/defaultEslintConfig.cjs b/config/defaultEslintConfig.cjs deleted file mode 100644 index 712543dd7..000000000 --- a/config/defaultEslintConfig.cjs +++ /dev/null @@ -1,151 +0,0 @@ -module.exports = { - parser: '@typescript-eslint/parser', - extends: [ - 'standard', - // 'plugin:react/recommended', - 'plugin:react-hooks/recommended', - 'plugin:@typescript-eslint/eslint-recommended', - 'plugin:@typescript-eslint/recommended', - // 'plugin:import/errors', - //'plugin:import/warnings', - 'plugin:import/typescript', - 'plugin:jsx-a11y/recommended', - ], - plugins: ['simple-import-sort', 'testing-library'], - env: { - node: true, - es6: true, - browser: true, - }, - parserOptions: { - ecmaVersion: 2018, - sourceType: 'module', - ecmaFeatures: { - jsx: true, - }, - // typescript-eslint specific options - warnOnUnsupportedTypeScriptVersion: true, - }, - rules: { - // '@typescript-eslint/indent': ['error', 2], - '@typescript-eslint/interface-name-prefix': 'off', - '@typescript-eslint/no-non-null-assertion': 'off', - '@typescript-eslint/explicit-module-boundary-types': 'off', - '@typescript-eslint/no-explicit-any': 'off', - '@typescript-eslint/ban-ts-comment': 'off', - 'no-unused-vars': 'off', - '@typescript-eslint/no-unused-vars': [ - 'error', - { - argsIgnorePattern: '^_|req|res|next|err|ctx|args|context|info', - ignoreRestSiblings: true, - }, - ], - 'no-array-constructor': 'off', - '@typescript-eslint/no-array-constructor': 'warn', - 'no-redeclare': 'off', - '@typescript-eslint/no-redeclare': 'warn', - 'no-use-before-define': 'off', - '@typescript-eslint/no-use-before-define': [ - 'warn', - { - functions: false, - classes: false, - variables: false, - typedefs: false, - }, - ], - 'no-unused-expressions': 'off', - '@typescript-eslint/no-unused-expressions': [ - 'error', - { - allowShortCircuit: true, - allowTernary: true, - allowTaggedTemplates: true, - }, - ], - '@typescript-eslint/triple-slash-reference': 'off', - '@typescript-eslint/member-delimiter-style': [ - 'error', - { - multiline: { - delimiter: 'semi', - requireLast: true, - }, - singleline: { - delimiter: 'semi', - requireLast: false, - }, - }, - ], - camelcase: 'off', - 'comma-dangle': [ - 'error', - { - arrays: 'always-multiline', - objects: 'always-multiline', - imports: 'always-multiline', - exports: 'always-multiline', - functions: 'always-multiline', - }, - ], - 'array-callback-return': 'warn', - 'jsx-quotes': ['error', 'prefer-double'], - // 'max-len': ['error', { code: 120 }], - indent: 'off', - // quotes: ['error', 'single'], - semi: ['error', 'always'], - 'space-before-function-paren': 'off', - - 'import/no-named-as-default': 'off', - 'import/no-named-as-default-member': 'off', - 'import/default': 'off', - 'import/named': 'off', - 'import/namespace': 'off', - 'import/no-unresolved': 'off', - 'simple-import-sort/imports': 'error', - 'simple-import-sort/exports': 'error', - 'react/prop-types': 'off', - 'react/jsx-wrap-multilines': 'error', - 'react/react-in-jsx-scope': 'off', - 'react/display-name': 'off', - // https://github.com/facebook/react/tree/master/packages/eslint-plugin-react-hooks - 'react-hooks/rules-of-hooks': 'error', - 'react-hooks/exhaustive-deps': 'off', - }, - - overrides: [ - { - files: ['*.js', '*.jsx'], - rules: { - '@typescript-eslint/no-var-requires': 'off', - }, - }, - { - // 3) Now we enable eslint-plugin-testing-library rules or preset only for matching files! - files: ['**/?(*.)+(spec|test).[jt]s?(x)'], - extends: ['plugin:testing-library/react'], - rules: { - 'testing-library/await-async-query': 'error', - 'testing-library/no-await-sync-query': 'error', - 'testing-library/no-debugging-utils': 'warn', - 'testing-library/no-dom-import': 'off', - 'testing-library/no-unnecessary-act': 'off', - }, - }, - ], - - settings: { - react: { - version: 'detect', - }, - 'import/parsers': { - '@typescript-eslint/parser': ['.ts', '.tsx'], - }, - 'import/resolver': { - typescript: { - alwaysTryTypes: true, - }, - }, - }, - }; \ No newline at end of file diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 000000000..719d3b183 --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,220 @@ +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +import { fixupConfigRules, fixupPluginRules } from '@eslint/compat'; +import { FlatCompat } from '@eslint/eslintrc'; +import js from '@eslint/js'; +import typescriptEslint from '@typescript-eslint/eslint-plugin'; +import tsParser from '@typescript-eslint/parser'; +import prettier from 'eslint-plugin-prettier/recommended'; +import react from 'eslint-plugin-react'; +import simpleImportSort from 'eslint-plugin-simple-import-sort'; +//import testingLibrary from "eslint-plugin-testing-library"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const compat = new FlatCompat({ + baseDirectory: __dirname, + recommendedConfig: js.configs.recommended, + allConfig: js.configs.all, +}); + +export default [ + { + ignores: [ + '**/*.d.ts', + 'packages/**/dist/**/*', + 'packages/**/public/**/*', + 'packages/**/coverage/**/*', + 'packages/**/fixtures/**/*', + '**/node_modules', + 'public/**/*', + 'examples/**/static/**/*', + 'examples/**/dist/**/*', + 'examples/**/OidcTrustedDomains.js', + 'examples/**/OidcServiceWorker.js', + 'examples/**/nextjs-demo/**', + 'scripts/**/*', + '**/.github', + '**/.changeset', + '**/vite.config.js', + '**/webpack-runtime.js', + '.prettierrc.cjs', + ], + }, + ...fixupConfigRules( + compat.extends( + 'plugin:react/recommended', + 'plugin:react-hooks/recommended', + 'eslint:recommended', + 'plugin:@typescript-eslint/eslint-recommended', + 'plugin:@typescript-eslint/recommended', + 'plugin:import/typescript', + 'plugin:jsx-a11y/recommended', + ), + ), + { + plugins: { + '@typescript-eslint': fixupPluginRules(typescriptEslint), + 'simple-import-sort': simpleImportSort, + //"testing-library": testingLibrary, //Not compatible with ESLint9 yet https://github.com/jsx-eslint/eslint-plugin-react/issues/3699 + react: fixupPluginRules(react), + }, + languageOptions: { + parser: tsParser, + ecmaVersion: 2022, + sourceType: 'module', + + parserOptions: { + project: ['./tsconfig.eslint.json', './packages/*/tsconfig.eslint.json'], + + ecmaFeatures: { + jsx: true, + }, + + warnOnUnsupportedTypeScriptVersion: true, + }, + }, + + settings: { + env: { + browser: true, + node: true, + }, + react: { + version: '18', + }, + + 'import/resolver': { + typescript: { + alwaysTryTypes: true, + }, + }, + }, + + rules: { + '@typescript-eslint/interface-name-prefix': 'off', + '@typescript-eslint/no-non-null-assertion': 'off', + '@typescript-eslint/explicit-module-boundary-types': 'off', + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/ban-ts-comment': 'off', + 'no-unused-vars': 'off', + + '@typescript-eslint/no-unused-vars': [ + 'error', + { + argsIgnorePattern: '^_|req|res|next|err|ctx|args|context|info|index|data', + ignoreRestSiblings: true, + }, + ], + + 'no-array-constructor': 'off', + '@typescript-eslint/no-array-constructor': 'warn', + 'no-redeclare': 'off', + '@typescript-eslint/no-redeclare': 'warn', + 'no-use-before-define': 'off', + + '@typescript-eslint/no-use-before-define': [ + 'warn', + { + functions: false, + classes: false, + variables: false, + typedefs: false, + }, + ], + + 'no-unused-expressions': 'off', + + '@typescript-eslint/no-unused-expressions': [ + 'error', + { + allowShortCircuit: true, + allowTernary: true, + allowTaggedTemplates: true, + }, + ], + + '@typescript-eslint/triple-slash-reference': 'off', + + '@typescript-eslint/member-delimiter-style': [ + 'error', + { + multiline: { + delimiter: 'semi', + requireLast: true, + }, + + singleline: { + delimiter: 'semi', + requireLast: false, + }, + }, + ], + + camelcase: 'off', + + 'comma-dangle': [ + 'error', + { + arrays: 'always-multiline', + objects: 'always-multiline', + imports: 'always-multiline', + exports: 'always-multiline', + functions: 'always-multiline', + }, + ], + + 'array-callback-return': 'warn', + 'jsx-quotes': ['error', 'prefer-double'], + indent: 'off', + semi: ['error', 'always'], + 'space-before-function-paren': 'off', + 'import/no-named-as-default': 'off', + 'import/no-named-as-default-member': 'off', + 'import/default': 'off', + 'import/named': 'off', + 'import/namespace': 'off', + 'import/no-unresolved': 'off', + 'simple-import-sort/imports': 'error', + 'simple-import-sort/exports': 'error', + 'react/prop-types': 'off', + 'react/jsx-wrap-multilines': 'error', + 'react/react-in-jsx-scope': 'off', + 'react/display-name': 'off', + 'react-hooks/rules-of-hooks': 'error', + 'react-hooks/exhaustive-deps': 'off', + }, + }, + { + files: ['**/*.js', '**/*.jsx'], + + rules: { + '@typescript-eslint/no-var-requires': 'off', + + 'react/no-unknown-property': [ + 2, + { + ignore: ['jsx', 'global'], + }, + ], + }, + }, + prettier, + //Not compatible with ESLint9 yet https://github.com/jsx-eslint/eslint-plugin-react/issues/3699 + // ...compat.extends("plugin:testing-library/react").map(config => ({ + // ...config, + // files: ["**/?(*.)+(spec|test).[jt]s?(x)"], + // })), { + // files: ["**/?(*.)+(spec|test).[jt]s?(x)"], + + // rules: { + // "testing-library/no-container": "off" + // "testing-library/await-async-query": "error", + // "testing-library/no-await-sync-query": "error", + // testing-library/no-debugging-utils": "off", + // "testing-library/no-dom-import": "off", + // "testing-library/no-unnecessary-act": "off", + // }, + // } +]; diff --git a/examples/nextjs-demo/README.md b/examples/nextjs-demo/README.md index ee14292a3..763bd368f 100644 --- a/examples/nextjs-demo/README.md +++ b/examples/nextjs-demo/README.md @@ -1,6 +1,7 @@ # Nextjs @axa-fr/react-oidc demo ## Getting Started + ```sh git clone https://github.com/AxaGuilDEv/react-oidc.git cd react-oidc/packages/nextjs-demo @@ -11,44 +12,49 @@ npm run dev To work with NextJS you need to inject your own history surcharge like the sample below. component/layout.js + ```javascript import { OidcProvider } from '@axa-fr/react-oidc'; -import { useRouter } from 'next/router' +import { useRouter } from 'next/router'; const configuration = { - client_id: 'interactive.public.short', - redirect_uri: 'http://localhost:3001/#authentication/callback', - silent_redirect_uri: 'http://localhost:3001/#authentication/silent-callback', // Optional activate silent-signin that use cookies between OIDC server and client javascript to restore the session - scope: 'openid profile email api offline_access', - authority: 'https://demo.duendesoftware.com' + client_id: 'interactive.public.short', + redirect_uri: 'http://localhost:3001/#authentication/callback', + silent_redirect_uri: 'http://localhost:3001/#authentication/silent-callback', // Optional activate silent-signin that use cookies between OIDC server and client javascript to restore the session + scope: 'openid profile email api offline_access', + authority: 'https://demo.duendesoftware.com', }; -const onEvent=(configurationName, eventName, data )=>{ +const onEvent = (configurationName, eventName, data) => { console.log(`oidc:${configurationName}:${eventName}`, data); -} +}; export default function Layout({ children }) { - const router = useRouter() - const withCustomHistory= () => { + const router = useRouter(); + const withCustomHistory = () => { return { - replaceState: (url) => { - router.replace({ - pathname: url, - }).then(() => { + replaceState: url => { + router + .replace({ + pathname: url, + }) + .then(() => { window.dispatchEvent(new Event('popstate')); - }); - } + }); + }, }; }; - + return ( - <> - -
{children}
-
- - ) + <> + +
{children}
+
+ + ); } - - -``` \ No newline at end of file +``` diff --git a/examples/nextjs-demo/components/layout.js b/examples/nextjs-demo/components/layout.js index ca6a0aa79..fa8a54e09 100644 --- a/examples/nextjs-demo/components/layout.js +++ b/examples/nextjs-demo/components/layout.js @@ -1,37 +1,46 @@ import { OidcProvider } from '@axa-fr/react-oidc'; -import { useRouter } from 'next/router' +import { useRouter } from 'next/router'; +import React from 'react'; const configuration = { - client_id: 'interactive.public.short', + client_id: 'interactive.public', redirect_uri: 'http://localhost:3001/#authentication/callback', silent_redirect_uri: 'http://localhost:3001/#authentication/silent-callback', // Optional activate silent-signin that use cookies between OIDC server and client javascript to restore the session scope: 'openid profile email api offline_access', - authority: 'https://demo.duendesoftware.com' + authority: 'https://demo.duendesoftware.com', + preload_user_info: 'true', }; -const onEvent=(configurationName, eventName, data )=>{ - console.log(`oidc:${configurationName}:${eventName}`, data); - } +const onEvent = (configurationName, eventName, data) => { + // eslint-disable-next-line no-undef + console.log(`oidc:${configurationName}:${eventName}`, data); +}; export default function Layout({ children }) { - const router = useRouter() - const withCustomHistory= () => { - return { - replaceState: (url) => { - router.replace({ - pathname: url, - }).then(() => { - window.dispatchEvent(new Event('popstate')); - } - ) - } - }; + const router = useRouter(); + const withCustomHistory = () => { + return { + replaceState: url => { + router + .replace({ + pathname: url, + }) + .then(() => { + // eslint-disable-next-line no-undef + window.dispatchEvent(new Event('popstate')); + }); + }, }; + }; return ( <> - -
{children}
+ +
{children}
- ) -} \ No newline at end of file + ); +} diff --git a/examples/nextjs-demo/package-lock.json b/examples/nextjs-demo/package-lock.json deleted file mode 100644 index 211d03362..000000000 --- a/examples/nextjs-demo/package-lock.json +++ /dev/null @@ -1,611 +0,0 @@ -{ - "name": "nextjs-demo", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "dependencies": { - "@axa-fr/react-oidc": "6.22.15", - "next": "latest", - "react": "latest", - "react-dom": "latest" - } - }, - "node_modules/@axa-fr/react-oidc": { - "version": "6.22.15", - "resolved": "https://registry.npmjs.org/@axa-fr/react-oidc/-/react-oidc-6.22.15.tgz", - "integrity": "sha512-6/CpYONlBRFyJ8HW98dWkMX8LpdOD6EjGB2PvgL3p1K2fyPk/MVQKTsYGUBWnJILddxsyioqys3kWYprc4Cujw==", - "hasInstallScript": true, - "dependencies": { - "base64-js": "1.5.1" - }, - "peerDependencies": { - "react": "^17.0.0 || ^18.0.0", - "react-dom": "^17.0.0 || ^18.0.0" - } - }, - "node_modules/@next/env": { - "version": "12.1.6", - "resolved": "https://registry.npmjs.org/@next/env/-/env-12.1.6.tgz", - "integrity": "sha512-Te/OBDXFSodPU6jlXYPAXpmZr/AkG6DCATAxttQxqOWaq6eDFX25Db3dK0120GZrSZmv4QCe9KsZmJKDbWs4OA==" - }, - "node_modules/@next/swc-android-arm-eabi": { - "version": "12.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-12.1.6.tgz", - "integrity": "sha512-BxBr3QAAAXWgk/K7EedvzxJr2dE014mghBSA9iOEAv0bMgF+MRq4PoASjuHi15M2zfowpcRG8XQhMFtxftCleQ==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-android-arm64": { - "version": "12.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-android-arm64/-/swc-android-arm64-12.1.6.tgz", - "integrity": "sha512-EboEk3ROYY7U6WA2RrMt/cXXMokUTXXfnxe2+CU+DOahvbrO8QSWhlBl9I9ZbFzJx28AGB9Yo3oQHCvph/4Lew==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-darwin-arm64": { - "version": "12.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.1.6.tgz", - "integrity": "sha512-P0EXU12BMSdNj1F7vdkP/VrYDuCNwBExtRPDYawgSUakzi6qP0iKJpya2BuLvNzXx+XPU49GFuDC5X+SvY0mOw==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-darwin-x64": { - "version": "12.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-12.1.6.tgz", - "integrity": "sha512-9FptMnbgHJK3dRDzfTpexs9S2hGpzOQxSQbe8omz6Pcl7rnEp9x4uSEKY51ho85JCjL4d0tDLBcXEJZKKLzxNg==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-arm-gnueabihf": { - "version": "12.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.1.6.tgz", - "integrity": "sha512-PvfEa1RR55dsik/IDkCKSFkk6ODNGJqPY3ysVUZqmnWMDSuqFtf7BPWHFa/53znpvVB5XaJ5Z1/6aR5CTIqxPw==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-arm64-gnu": { - "version": "12.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.1.6.tgz", - "integrity": "sha512-53QOvX1jBbC2ctnmWHyRhMajGq7QZfl974WYlwclXarVV418X7ed7o/EzGY+YVAEKzIVaAB9JFFWGXn8WWo0gQ==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-arm64-musl": { - "version": "12.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.1.6.tgz", - "integrity": "sha512-CMWAkYqfGdQCS+uuMA1A2UhOfcUYeoqnTW7msLr2RyYAys15pD960hlDfq7QAi8BCAKk0sQ2rjsl0iqMyziohQ==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-x64-gnu": { - "version": "12.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.1.6.tgz", - "integrity": "sha512-AC7jE4Fxpn0s3ujngClIDTiEM/CQiB2N2vkcyWWn6734AmGT03Duq6RYtPMymFobDdAtZGFZd5nR95WjPzbZAQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-x64-musl": { - "version": "12.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.1.6.tgz", - "integrity": "sha512-c9Vjmi0EVk0Kou2qbrynskVarnFwfYIi+wKufR9Ad7/IKKuP6aEhOdZiIIdKsYWRtK2IWRF3h3YmdnEa2WLUag==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-win32-arm64-msvc": { - "version": "12.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.1.6.tgz", - "integrity": "sha512-3UTOL/5XZSKFelM7qN0it35o3Cegm6LsyuERR3/OoqEExyj3aCk7F025b54/707HTMAnjlvQK3DzLhPu/xxO4g==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-win32-ia32-msvc": { - "version": "12.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.1.6.tgz", - "integrity": "sha512-8ZWoj6nCq6fI1yCzKq6oK0jE6Mxlz4MrEsRyu0TwDztWQWe7rh4XXGLAa2YVPatYcHhMcUL+fQQbqd1MsgaSDA==", - "cpu": [ - "ia32" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-win32-x64-msvc": { - "version": "12.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.1.6.tgz", - "integrity": "sha512-4ZEwiRuZEicXhXqmhw3+de8Z4EpOLQj/gp+D9fFWo6ii6W1kBkNNvvEx4A90ugppu+74pT1lIJnOuz3A9oQeJA==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001359", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001359.tgz", - "integrity": "sha512-Xln/BAsPzEuiVLgJ2/45IaqD9jShtk3Y33anKb4+yLwQzws3+v6odKfpgES/cDEaZMLzSChpIGdbOYtH9MyuHw==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - } - ] - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, - "node_modules/nanoid": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/next": { - "version": "12.1.6", - "resolved": "https://registry.npmjs.org/next/-/next-12.1.6.tgz", - "integrity": "sha512-cebwKxL3/DhNKfg9tPZDQmbRKjueqykHHbgaoG4VBRH3AHQJ2HO0dbKFiS1hPhe1/qgc2d/hFeadsbPicmLD+A==", - "dependencies": { - "@next/env": "12.1.6", - "caniuse-lite": "^1.0.30001332", - "postcss": "8.4.5", - "styled-jsx": "5.0.2" - }, - "bin": { - "next": "dist/bin/next" - }, - "engines": { - "node": ">=12.22.0" - }, - "optionalDependencies": { - "@next/swc-android-arm-eabi": "12.1.6", - "@next/swc-android-arm64": "12.1.6", - "@next/swc-darwin-arm64": "12.1.6", - "@next/swc-darwin-x64": "12.1.6", - "@next/swc-linux-arm-gnueabihf": "12.1.6", - "@next/swc-linux-arm64-gnu": "12.1.6", - "@next/swc-linux-arm64-musl": "12.1.6", - "@next/swc-linux-x64-gnu": "12.1.6", - "@next/swc-linux-x64-musl": "12.1.6", - "@next/swc-win32-arm64-msvc": "12.1.6", - "@next/swc-win32-ia32-msvc": "12.1.6", - "@next/swc-win32-x64-msvc": "12.1.6" - }, - "peerDependencies": { - "fibers": ">= 3.1.0", - "node-sass": "^6.0.0 || ^7.0.0", - "react": "^17.0.2 || ^18.0.0-0", - "react-dom": "^17.0.2 || ^18.0.0-0", - "sass": "^1.3.0" - }, - "peerDependenciesMeta": { - "fibers": { - "optional": true - }, - "node-sass": { - "optional": true - }, - "sass": { - "optional": true - } - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" - }, - "node_modules/postcss": { - "version": "8.4.5", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.5.tgz", - "integrity": "sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg==", - "dependencies": { - "nanoid": "^3.1.30", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/react": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", - "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==", - "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-dom": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", - "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==", - "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "scheduler": "^0.20.2" - }, - "peerDependencies": { - "react": "17.0.2" - } - }, - "node_modules/scheduler": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", - "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", - "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" - } - }, - "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/styled-jsx": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.0.2.tgz", - "integrity": "sha512-LqPQrbBh3egD57NBcHET4qcgshPks+yblyhPlH2GY8oaDgKs8SK4C3dBh3oSJjgzJ3G5t1SYEZGHkP+QEpX9EQ==", - "engines": { - "node": ">= 12.0.0" - }, - "peerDependencies": { - "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0" - }, - "peerDependenciesMeta": { - "@babel/core": { - "optional": true - }, - "babel-plugin-macros": { - "optional": true - } - } - } - }, - "dependencies": { - "@axa-fr/react-oidc": { - "version": "6.22.15", - "resolved": "https://registry.npmjs.org/@axa-fr/react-oidc/-/react-oidc-6.22.15.tgz", - "integrity": "sha512-6/CpYONlBRFyJ8HW98dWkMX8LpdOD6EjGB2PvgL3p1K2fyPk/MVQKTsYGUBWnJILddxsyioqys3kWYprc4Cujw==", - "requires": { - "base64-js": "1.5.1" - } - }, - "@next/env": { - "version": "12.1.6", - "resolved": "https://registry.npmjs.org/@next/env/-/env-12.1.6.tgz", - "integrity": "sha512-Te/OBDXFSodPU6jlXYPAXpmZr/AkG6DCATAxttQxqOWaq6eDFX25Db3dK0120GZrSZmv4QCe9KsZmJKDbWs4OA==" - }, - "@next/swc-android-arm-eabi": { - "version": "12.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-12.1.6.tgz", - "integrity": "sha512-BxBr3QAAAXWgk/K7EedvzxJr2dE014mghBSA9iOEAv0bMgF+MRq4PoASjuHi15M2zfowpcRG8XQhMFtxftCleQ==", - "optional": true - }, - "@next/swc-android-arm64": { - "version": "12.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-android-arm64/-/swc-android-arm64-12.1.6.tgz", - "integrity": "sha512-EboEk3ROYY7U6WA2RrMt/cXXMokUTXXfnxe2+CU+DOahvbrO8QSWhlBl9I9ZbFzJx28AGB9Yo3oQHCvph/4Lew==", - "optional": true - }, - "@next/swc-darwin-arm64": { - "version": "12.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.1.6.tgz", - "integrity": "sha512-P0EXU12BMSdNj1F7vdkP/VrYDuCNwBExtRPDYawgSUakzi6qP0iKJpya2BuLvNzXx+XPU49GFuDC5X+SvY0mOw==", - "optional": true - }, - "@next/swc-darwin-x64": { - "version": "12.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-12.1.6.tgz", - "integrity": "sha512-9FptMnbgHJK3dRDzfTpexs9S2hGpzOQxSQbe8omz6Pcl7rnEp9x4uSEKY51ho85JCjL4d0tDLBcXEJZKKLzxNg==", - "optional": true - }, - "@next/swc-linux-arm-gnueabihf": { - "version": "12.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.1.6.tgz", - "integrity": "sha512-PvfEa1RR55dsik/IDkCKSFkk6ODNGJqPY3ysVUZqmnWMDSuqFtf7BPWHFa/53znpvVB5XaJ5Z1/6aR5CTIqxPw==", - "optional": true - }, - "@next/swc-linux-arm64-gnu": { - "version": "12.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.1.6.tgz", - "integrity": "sha512-53QOvX1jBbC2ctnmWHyRhMajGq7QZfl974WYlwclXarVV418X7ed7o/EzGY+YVAEKzIVaAB9JFFWGXn8WWo0gQ==", - "optional": true - }, - "@next/swc-linux-arm64-musl": { - "version": "12.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.1.6.tgz", - "integrity": "sha512-CMWAkYqfGdQCS+uuMA1A2UhOfcUYeoqnTW7msLr2RyYAys15pD960hlDfq7QAi8BCAKk0sQ2rjsl0iqMyziohQ==", - "optional": true - }, - "@next/swc-linux-x64-gnu": { - "version": "12.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.1.6.tgz", - "integrity": "sha512-AC7jE4Fxpn0s3ujngClIDTiEM/CQiB2N2vkcyWWn6734AmGT03Duq6RYtPMymFobDdAtZGFZd5nR95WjPzbZAQ==", - "optional": true - }, - "@next/swc-linux-x64-musl": { - "version": "12.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.1.6.tgz", - "integrity": "sha512-c9Vjmi0EVk0Kou2qbrynskVarnFwfYIi+wKufR9Ad7/IKKuP6aEhOdZiIIdKsYWRtK2IWRF3h3YmdnEa2WLUag==", - "optional": true - }, - "@next/swc-win32-arm64-msvc": { - "version": "12.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.1.6.tgz", - "integrity": "sha512-3UTOL/5XZSKFelM7qN0it35o3Cegm6LsyuERR3/OoqEExyj3aCk7F025b54/707HTMAnjlvQK3DzLhPu/xxO4g==", - "optional": true - }, - "@next/swc-win32-ia32-msvc": { - "version": "12.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.1.6.tgz", - "integrity": "sha512-8ZWoj6nCq6fI1yCzKq6oK0jE6Mxlz4MrEsRyu0TwDztWQWe7rh4XXGLAa2YVPatYcHhMcUL+fQQbqd1MsgaSDA==", - "optional": true - }, - "@next/swc-win32-x64-msvc": { - "version": "12.1.6", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.1.6.tgz", - "integrity": "sha512-4ZEwiRuZEicXhXqmhw3+de8Z4EpOLQj/gp+D9fFWo6ii6W1kBkNNvvEx4A90ugppu+74pT1lIJnOuz3A9oQeJA==", - "optional": true - }, - "base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" - }, - "caniuse-lite": { - "version": "1.0.30001359", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001359.tgz", - "integrity": "sha512-Xln/BAsPzEuiVLgJ2/45IaqD9jShtk3Y33anKb4+yLwQzws3+v6odKfpgES/cDEaZMLzSChpIGdbOYtH9MyuHw==" - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, - "loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "requires": { - "js-tokens": "^3.0.0 || ^4.0.0" - } - }, - "nanoid": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==" - }, - "next": { - "version": "12.1.6", - "resolved": "https://registry.npmjs.org/next/-/next-12.1.6.tgz", - "integrity": "sha512-cebwKxL3/DhNKfg9tPZDQmbRKjueqykHHbgaoG4VBRH3AHQJ2HO0dbKFiS1hPhe1/qgc2d/hFeadsbPicmLD+A==", - "requires": { - "@next/env": "12.1.6", - "@next/swc-android-arm-eabi": "12.1.6", - "@next/swc-android-arm64": "12.1.6", - "@next/swc-darwin-arm64": "12.1.6", - "@next/swc-darwin-x64": "12.1.6", - "@next/swc-linux-arm-gnueabihf": "12.1.6", - "@next/swc-linux-arm64-gnu": "12.1.6", - "@next/swc-linux-arm64-musl": "12.1.6", - "@next/swc-linux-x64-gnu": "12.1.6", - "@next/swc-linux-x64-musl": "12.1.6", - "@next/swc-win32-arm64-msvc": "12.1.6", - "@next/swc-win32-ia32-msvc": "12.1.6", - "@next/swc-win32-x64-msvc": "12.1.6", - "caniuse-lite": "^1.0.30001332", - "postcss": "8.4.5", - "styled-jsx": "5.0.2" - } - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" - }, - "picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" - }, - "postcss": { - "version": "8.4.5", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.5.tgz", - "integrity": "sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg==", - "requires": { - "nanoid": "^3.1.30", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.1" - } - }, - "react": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", - "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==", - "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" - } - }, - "react-dom": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", - "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==", - "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "scheduler": "^0.20.2" - } - }, - "scheduler": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", - "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", - "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" - } - }, - "source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==" - }, - "styled-jsx": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.0.2.tgz", - "integrity": "sha512-LqPQrbBh3egD57NBcHET4qcgshPks+yblyhPlH2GY8oaDgKs8SK4C3dBh3oSJjgzJ3G5t1SYEZGHkP+QEpX9EQ==", - "requires": {} - } - } -} diff --git a/examples/nextjs-demo/package.json b/examples/nextjs-demo/package.json index 4ba56d7f6..48f54b625 100644 --- a/examples/nextjs-demo/package.json +++ b/examples/nextjs-demo/package.json @@ -3,7 +3,8 @@ "scripts": { "dev": "next dev -p 3001", "build": "next build", - "start": "next start" + "start": "next start", + "postinstall": "node ./node_modules/@axa-fr/react-oidc/bin/copy-service-worker-files.mjs public" }, "dependencies": { "@axa-fr/react-oidc": "workspace:*", diff --git a/examples/nextjs-demo/pages/_app.js b/examples/nextjs-demo/pages/_app.js index 09bfde03a..95cf06fe0 100644 --- a/examples/nextjs-demo/pages/_app.js +++ b/examples/nextjs-demo/pages/_app.js @@ -1,9 +1,9 @@ -import Layout from '../components/layout' +import Layout from '../components/layout'; export default function MyApp({ Component, pageProps }) { return ( - ) -} \ No newline at end of file + ); +} diff --git a/examples/nextjs-demo/pages/index.js b/examples/nextjs-demo/pages/index.js index 44b8015e2..59d6a5f0c 100644 --- a/examples/nextjs-demo/pages/index.js +++ b/examples/nextjs-demo/pages/index.js @@ -1,80 +1,97 @@ -import Head from 'next/head' -import { OidcSecure, useOidcAccessToken, useOidcIdToken, useOidcUser, OidcUserStatus} from '@axa-fr/react-oidc'; - +import { + OidcSecure, + OidcUserStatus, + useOidc, + useOidcAccessToken, + useOidcIdToken, + useOidcUser, +} from '@axa-fr/react-oidc'; +import Head from 'next/head'; + +const isBrowser = () => typeof window !== 'undefined'; const DisplayUserInfo = () => { - const{ oidcUser, oidcUserLoadingState } = useOidcUser(); - - switch (oidcUserLoadingState){ - case OidcUserStatus.Loading: - return

User Information are loading

; - case OidcUserStatus.Unauthenticated: - return

you are not authenticated

; - case OidcUserStatus.LoadingError: - return

Fail to load user information

; - default: - return ( -
-
-
User information
-

{JSON.stringify(oidcUser)}

-
-
- ); + const { oidcUser, oidcUserLoadingState } = useOidcUser(); + const { isAuthenticated } = useOidc(); + console.log( + 'isBrowser: ' + isBrowser() + ', isAuthenticated: ' + isAuthenticated + ', oidcUser: ', + ); + console.log(oidcUser); + + switch (oidcUserLoadingState) { + case OidcUserStatus.Loading: + return

User Information are loading

; + case OidcUserStatus.Unauthenticated: + return

you are not authenticated

; + case OidcUserStatus.LoadingError: + return

Fail to load user information

; + default: + return ( +
+
+
User information
+

{JSON.stringify(oidcUser)}

+
+
+ ); } }; export const Profile = () => { - return ( -
- - - -
+
+ + + +
); -} +}; const DisplayAccessToken = () => { - const{ accessToken, accessTokenPayload } = useOidcAccessToken(); + const { accessToken, accessTokenPayload } = useOidcAccessToken(); - if(!accessToken){ - return

you are not authenticated

+ if (!accessToken) { + return

you are not authenticated

; } return ( -
-
-
Access Token
-

Please consider to configure the ServiceWorker in order to protect your application from XSRF attacks. "access_token" and "refresh_token" will never be accessible from your client side javascript.

- {

Access Token: {JSON.stringify(accessToken)}

} - {accessTokenPayload != null &&

Access Token Payload: {JSON.stringify(accessTokenPayload)}

} -
+
+
+
Access Token
+

+ Please consider to configure the ServiceWorker in order to protect your application from + XSRF attacks. "access_token" and "refresh_token" will never be + accessible from your client side javascript. +

+ {

Access Token: {JSON.stringify(accessToken)}

} + {accessTokenPayload != null && ( +

Access Token Payload: {JSON.stringify(accessTokenPayload)}

+ )}
- ) +
+ ); }; +const DisplayIdToken = () => { + const { idToken, idTokenPayload } = useOidcIdToken(); -const DisplayIdToken =() => { - const{ idToken, idTokenPayload } = useOidcIdToken(); - - if(!idToken){ - return

you are not authenticated

+ if (!idToken) { + return

you are not authenticated

; } return ( -
-
-
ID Token
- {

IdToken: {JSON.stringify(idToken)}

} - {idTokenPayload != null &&

IdToken Payload: {JSON.stringify(idTokenPayload)}

} -
+
+
+
ID Token
+ {

IdToken: {JSON.stringify(idToken)}

} + {idTokenPayload != null && ( +

IdToken Payload: {JSON.stringify(idTokenPayload)}

+ )}
+
); -} - -export default function Home({}) { - +}; +export default function Home() { return (
@@ -83,18 +100,16 @@ export default function Home({}) {
-

- Welcome to Next.js @axa-fr/react-oidc demo! + Welcome to{' '} + Next.js @axa-fr/react-oidc demo!

- +
- -
-
+
- ) + ); } import Layout from '../components/layout'; Home.getLayout = function getLayout(page) { - return ( - - {page} - - ) -} \ No newline at end of file + return {page}; +}; diff --git a/examples/nextjs-demo/public/OidcTrustedDomains.js b/examples/nextjs-demo/public/OidcTrustedDomains.js new file mode 100644 index 000000000..e72a3d143 --- /dev/null +++ b/examples/nextjs-demo/public/OidcTrustedDomains.js @@ -0,0 +1,29 @@ +// Add bellow trusted domains, access tokens will automatically injected to be send to +// trusted domain can also be a path like https://www.myapi.com/users, +// then all subroute like https://www.myapi.com/useers/1 will be authorized to send access_token to. + +// Domains used by OIDC server must be also declared here +// eslint-disable-next-line @typescript-eslint/no-unused-vars +const trustedDomains = { + default: ['https://demo.duendesoftware.com', 'https://kdhttps.auth0.com'], + config_classic: ['https://demo.duendesoftware.com'], + config_without_silent_login: ['https://demo.duendesoftware.com'], + config_without_refresh_token: ['https://demo.duendesoftware.com'], + config_without_refresh_token_silent_login: ['https://demo.duendesoftware.com'], + config_google: ['https://oauth2.googleapis.com', 'https://openidconnect.googleapis.com'], + config_with_hash: ['https://demo.duendesoftware.com'], +}; + +// Service worker will continue to give access token to the JavaScript client +// Ideal to hide refresh token from client JavaScript, but to retrieve access_token for some +// scenarios which require it. For example, to send it via websocket connection. +trustedDomains.config_show_access_token = { + domains: ['https://demo.duendesoftware.com'], + showAccessToken: true, +}; + +// This example defines domains used by OIDC server separately from domains to which access tokens will be injected. +trustedDomains.config_separate_oidc_access_token_domains = { + oidcDomains: ['https://demo.duendesoftware.com'], + accessTokenDomains: ['https://myapi'], +}; diff --git a/examples/oidc-client-demo/index.html b/examples/oidc-client-demo/index.html index d0912cccb..c6cff7e96 100644 --- a/examples/oidc-client-demo/index.html +++ b/examples/oidc-client-demo/index.html @@ -1,4 +1,4 @@ - + @@ -9,7 +9,13 @@ +

@axa-de/oidc-client

+

+ OpenId Connect, OIDC client is free under licence MIT. Available on + github axa oidc-client +

- +
+ diff --git a/examples/oidc-client-demo/package.json b/examples/oidc-client-demo/package.json index bfc877e94..861d153c9 100644 --- a/examples/oidc-client-demo/package.json +++ b/examples/oidc-client-demo/package.json @@ -3,18 +3,16 @@ "version": "1.0.0", "private": true, "dependencies": { - "@axa-fr/vanilla-oidc": "workspace:~", - "@testing-library/jest-dom": "^5.16.5", - "@testing-library/user-event": "^13.5.0", - "@types/jest": "^27.5.2", - "typescript": "^5.1.6", - "web-vitals": "^3.4.0" + "@axa-fr/oidc-client": "workspace:~", + "typescript": "5.7.3", + "web-vitals": "4.2.4" }, "scripts": { "start": "vite", "build": "vite build", "serve": "vite preview", - "clean": "rimraf dist" + "clean": "rimraf dist", + "postinstall": "node ./node_modules/@axa-fr/oidc-client/bin/copy-service-worker-files.mjs public" }, "browserslist": { "production": [ @@ -29,8 +27,8 @@ ] }, "devDependencies": { - "@types/node": "^18.11.9", + "@types/node": "20.11.26", "cross-env": "^7.0.3", - "vite": "^4.4.4" + "vite": "5.1.6" } } diff --git a/examples/oidc-client-demo/public/OidcTrustedDomains.js b/examples/oidc-client-demo/public/OidcTrustedDomains.js index c1b0f6fc3..656ff28f4 100644 --- a/examples/oidc-client-demo/public/OidcTrustedDomains.js +++ b/examples/oidc-client-demo/public/OidcTrustedDomains.js @@ -4,21 +4,29 @@ // Domains used by OIDC server must be also declared here // eslint-disable-next-line @typescript-eslint/no-unused-vars const trustedDomains = { - default: ['https://demo.duendesoftware.com', 'https://kdhttps.auth0.com'], - config_classic: ['https://demo.duendesoftware.com'], - config_without_silent_login: ['https://demo.duendesoftware.com'], - config_without_refresh_token: ['https://demo.duendesoftware.com'], - config_without_refresh_token_silent_login: ['https://demo.duendesoftware.com'], - config_google: ['https://oauth2.googleapis.com', 'https://openidconnect.googleapis.com'], - config_with_hash: ['https://demo.duendesoftware.com'], + default: ['https://demo.duendesoftware.com', 'https://kdhttps.auth0.com'], + config_classic: ['https://demo.duendesoftware.com'], + config_with_monitor_session: ['https://demo.duendesoftware.com'], + config_without_silent_login: ['https://demo.duendesoftware.com'], + config_without_refresh_token: ['https://demo.duendesoftware.com'], + config_without_refresh_token_silent_login: ['https://demo.duendesoftware.com'], + config_google: [ + 'https://oauth2.googleapis.com', + 'https://openidconnect.googleapis.com', + 'https://accounts.google.com', + ], + config_with_hash: ['https://demo.duendesoftware.com'], }; // Service worker will continue to give access token to the JavaScript client // Ideal to hide refresh token from client JavaScript, but to retrieve access_token for some // scenarios which require it. For example, to send it via websocket connection. -trustedDomains.config_show_access_token = { domains: ["https://demo.duendesoftware.com"], showAccessToken: true }; +trustedDomains.config_show_access_token = { + domains: ['https://demo.duendesoftware.com'], + showAccessToken: true, +}; // This example defines domains used by OIDC server separately from domains to which access tokens will be injected. trustedDomains.config_separate_oidc_access_token_domains = { - oidcDomains: ["https://demo.duendesoftware.com"], - accessTokenDomains: ["https://myapi"] + oidcDomains: ['https://demo.duendesoftware.com'], + accessTokenDomains: ['https://myapi'], }; -//# sourceMappingURL=OidcTrustedDomains.js.map \ No newline at end of file +//# sourceMappingURL=OidcTrustedDomains.js.map diff --git a/examples/oidc-client-demo/public/staticwebapp.config.json b/examples/oidc-client-demo/public/staticwebapp.config.json new file mode 100644 index 000000000..ee582c8f9 --- /dev/null +++ b/examples/oidc-client-demo/public/staticwebapp.config.json @@ -0,0 +1,15 @@ +{ + "navigationFallback": { + "rewrite": "index.html", + "exclude": ["*.{svg,png,jpg,gif}", "*.{css,scss}", "*.js"] + }, + "globalHeaders": { + "content-security-policy": "script-src 'self' 'unsafe-eval'", + "Access-Control-Allow-Origin": "*", + "X-Frame-Options": "SAMEORIGIN", + "X-Permitted-Cross-Domain-Policies": "none", + "Referrer-Policy": "no-referrer", + "X-Content-Type-Options": "nosniff", + "Permissions-Policy": "autoplay=()" + } +} diff --git a/examples/oidc-client-demo/src/index.tsx b/examples/oidc-client-demo/src/index.tsx index 664937d13..e23e1c11a 100644 --- a/examples/oidc-client-demo/src/index.tsx +++ b/examples/oidc-client-demo/src/index.tsx @@ -1,151 +1,194 @@ -import { VanillaOidc } from '@axa-fr/vanilla-oidc'; -class Router -{ getCustomHistory(){ - const generateKey = () => - Math.random() - .toString(36) - .substr(2, 6); - - // Exported only for test - type WindowInternal = Window & { - CustomEvent?: new (typeArg: string, eventInitDict?: CustomEventInit) => CustomEvent; - Event: typeof Event; - }; - - type IPrototype = { - prototype: any; - }; - - type InitCustomEventParams = { - bubbles: boolean; - cancelable: boolean; - detail: T; - }; - - // IE Polyfill for CustomEvent - const CreateEvent = (windowInternal: Window, documentInternal: Document) => ( - event: string, - params: InitCustomEventParams, - ): CustomEvent => { - // @ts-ignore - if (typeof windowInternal.CustomEvent === 'function') { - // @ts-ignore - return new windowInternal.CustomEvent(event, params); - } - const paramsToFunction = params || { bubbles: false, cancelable: false, detail: undefined }; - const evt: CustomEvent = documentInternal.createEvent('CustomEvent'); - evt.initCustomEvent(event, paramsToFunction.bubbles, paramsToFunction.cancelable, paramsToFunction.detail); - // @ts-ignore - (evt as CustomEvent & IPrototype).prototype = windowInternal.Event.prototype; - return evt; - }; - - type WindowHistoryState = typeof window.history.state; - - type CustomHistory = { - replaceState(url?: string | null, stateHistory?: WindowHistoryState): void; +import { OidcClient } from '@axa-fr/oidc-client'; + +class Router { + getCustomHistory() { + const generateKey = () => Math.random().toString(36).substr(2, 6); + + // Exported only for test + type WindowInternal = Window & { + CustomEvent?: new (typeArg: string, eventInitDict?: CustomEventInit) => CustomEvent; + Event: typeof Event; + }; + + type IPrototype = { + prototype: any; + }; + + type InitCustomEventParams = { + bubbles: boolean; + cancelable: boolean; + detail: T; + }; + + // IE Polyfill for CustomEvent + const CreateEvent = + (windowInternal: Window, documentInternal: Document) => + (event: string, params: InitCustomEventParams): CustomEvent => { + // @ts-ignore + if (typeof windowInternal.CustomEvent === 'function') { + // @ts-ignore + return new windowInternal.CustomEvent(event, params); } - - const getHistory = ( - windowInternal: WindowInternal, - CreateEventInternal: (event: string, params?: InitCustomEventParams) => CustomEvent, - generateKeyInternal: typeof generateKey, - ): CustomHistory => { - return { - replaceState: (url?: string | null, stateHistory?: WindowHistoryState): void => { - const key = generateKeyInternal(); - const state = stateHistory || windowInternal.history.state; - // @ts-ignore - windowInternal.history.replaceState({ key, state }, null, url); - windowInternal.dispatchEvent(CreateEventInternal('popstate')); - }, - }; - }; - + const paramsToFunction = params || { bubbles: false, cancelable: false, detail: undefined }; + const evt: CustomEvent = documentInternal.createEvent('CustomEvent'); + evt.initCustomEvent( + event, + paramsToFunction.bubbles, + paramsToFunction.cancelable, + paramsToFunction.detail, + ); // @ts-ignore + (evt as CustomEvent & IPrototype).prototype = windowInternal.Event.prototype; + return evt; + }; + + type WindowHistoryState = typeof window.history.state; + + type CustomHistory = { + replaceState(url?: string | null, stateHistory?: WindowHistoryState): void; + }; + + const getHistory = ( + windowInternal: WindowInternal, + CreateEventInternal: (event: string, params?: InitCustomEventParams) => CustomEvent, + generateKeyInternal: typeof generateKey, + ): CustomHistory => { + return { + replaceState: (url?: string | null, stateHistory?: WindowHistoryState): void => { + const key = generateKeyInternal(); + const state = stateHistory || windowInternal.history.state; + // @ts-ignore + windowInternal.history.replaceState({ key, state }, null, url); + windowInternal.dispatchEvent(CreateEventInternal('popstate')); + }, + }; + }; + + // @ts-ignore const getCustomHistory = () => getHistory(window, CreateEvent(window, document), generateKey); - return getCustomHistory(); - } - + return getCustomHistory(); + } } -const router = new Router(); +const display = (element: any) => { + // @ts-ignore + element.innerHTML = `
+

Game Hack Challenge

+ +

Game, let's try to make an XSS attacks to retrieve some secure tokens !

+

Service Worker mode is not magic https://datatracker.ietf.org/doc/html/draft-ietf-oauth-browser-based-apps#payload-new-flow + So let try to hack it ! +

+

Service Worker mode is secure if your follow 2 following rules:

+

Rule 1: Configure CSP

+

+ Add CSP header to forbid to write dynamic iframe with javascript dynamic inside. + You should never add "unsafe-inline" in your CSP header. +

+            Content-Security-Policy: script-src 'self';  // Secure
+            
+

Rule 2: Apply redirect URI before any WebService call

+ Set up the redirect_uri and redirect_silent_uri at the top level of your javascript application before any XSS attack could be executed. +

+

Let's play

+

To help you for this game, we set up 'unsafe-eval' in the CSP header to allow the eval function to be executed and allow you to hack the application like a big XSS attack.

+
+            Content-Security-Policy: script-src 'self' 'unsafe-eval'; 
+            
+ + + + +
`; + // @ts-ignore + window.document.getElementById('buttonxsshack').addEventListener('click', () => { + // @ts-ignore + eval(document.getElementById('xsshack').value); + }); +}; + +// @ts-ignore +export const execute = () => { + const router = new Router(); -document.body.innerHTML = `
`; -const element = document.getElementById("my-vanilla-app"); + const root = document.getElementById('root'); + const game = document.getElementById('game'); -export const configuration = { + const configuration = { client_id: 'interactive.public.short', redirect_uri: window.location.origin + '/#/authentication/callback', silent_redirect_uri: window.location.origin + '/#/authentication/silent-callback', scope: 'openid profile email api offline_access', authority: 'https://demo.duendesoftware.com', refresh_time_before_tokens_expiration_in_second: 40, - service_worker_relative_url:'/OidcServiceWorker.js', - service_worker_only: false, - // monitor_session: true, -}; + service_worker_relative_url: '/OidcServiceWorker.js', + service_worker_only: true, + }; -const href = window.location.href; + const href = window.location.href; -const vanillaOidc = VanillaOidc.getOrCreate(() => fetch)(configuration); + const vanillaOidc = OidcClient.getOrCreate(() => fetch)(configuration); -console.log(href); + // @ts-ignore + function logout() { + vanillaOidc.logoutAsync(); + } + console.log(href); -vanillaOidc.tryKeepExistingSessionAsync().then(() => { - if(href.includes(configuration.redirect_uri)){ - // @ts-ignore - element.innerHTML = `
-

@axa-fr/vanilla-oidc demo

+ if (href.includes(configuration.redirect_uri)) { + // @ts-ignore + root.innerHTML = `
+

Login demo

Loading callback

`; - vanillaOidc.loginCallbackAsync().then(()=>{ - router.getCustomHistory().replaceState("/"); - // @ts-ignore - window.logout = () => vanillaOidc.logoutAsync(); - let tokens = vanillaOidc.tokens; - // @ts-ignore - element.innerHTML = `
-

@axa-fr/vanilla-oidc demo

- -

Authenticated

-
${JSON.stringify(tokens,null,'\t')}
-
` - }); - return - } - - let tokens = vanillaOidc.tokens; - - if(tokens){ - - // @ts-ignore - window.logout = () => vanillaOidc.logoutAsync(); - // @ts-ignore - element.innerHTML = `
-

@axa-fr/vanilla-oidc demo

- -

Authenticated

-
${JSON.stringify(tokens,null,'\t')}
-
` - - } - else { + vanillaOidc.loginCallbackAsync().then(() => { + router.getCustomHistory().replaceState('/'); + display(game); + // @ts-ignore + root.innerHTML = `
+

Login demo Authenticated

+ +
${JSON.stringify(vanillaOidc.tokens, null, '\t')}
+
`; + // @ts-ignore + window.document.getElementById('logout').addEventListener('click', logout); + }); + return; + } + + vanillaOidc.tryKeepExistingSessionAsync().then(() => { + const tokens = vanillaOidc.tokens; + if (tokens) { + display(game); + // @ts-ignore + root.innerHTML = `
+

Login demo Authenticated

+ +
${JSON.stringify(tokens, null, '\t')}
+
`; + // @ts-ignore + window.document.getElementById('logout').addEventListener('click', logout); + } else { + // @ts-ignore + function login() { // @ts-ignore - window.login= () => { - // @ts-ignore - element.innerHTML = `
-

@axa-fr/vanilla-oidc demo

+ root.innerHTML = `
+

Login demo

Loading

`; - vanillaOidc.loginAsync("/") - }; - // @ts-ignore - element.innerHTML = `
-

@axa-fr/vanilla-oidc demo

- -
` + vanillaOidc.loginAsync('/'); + } + display(game); + // @ts-ignore + root.innerHTML = `
+

Login demo

+ +
`; + // @ts-ignore + document.getElementById('login').addEventListener('click', login); } -}) + }); +}; +execute(); diff --git a/examples/oidc-client-demo/tsconfig.json b/examples/oidc-client-demo/tsconfig.json index a273b0cfc..9d379a3c4 100644 --- a/examples/oidc-client-demo/tsconfig.json +++ b/examples/oidc-client-demo/tsconfig.json @@ -1,11 +1,7 @@ { "compilerOptions": { "target": "es5", - "lib": [ - "dom", - "dom.iterable", - "esnext" - ], + "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, "skipLibCheck": true, "esModuleInterop": true, @@ -20,7 +16,5 @@ "noEmit": true, "jsx": "react-jsx" }, - "include": [ - "src" - ] + "include": ["src"] } diff --git a/examples/oidc-client-demo/vite.config.js b/examples/oidc-client-demo/vite.config.js index 755ce8f3c..ddb44ece7 100644 --- a/examples/oidc-client-demo/vite.config.js +++ b/examples/oidc-client-demo/vite.config.js @@ -4,5 +4,10 @@ export default defineConfig({ build: { sourcemap: true, minify: false, - } + }, + server: { + headers: { + 'Content-Security-Policy': "script-src 'self' 'unsafe-eval';", + }, + }, }); diff --git a/examples/react-oidc-demo/.eslintrc.cjs b/examples/react-oidc-demo/.eslintrc.cjs deleted file mode 100644 index 968c0320f..000000000 --- a/examples/react-oidc-demo/.eslintrc.cjs +++ /dev/null @@ -1,18 +0,0 @@ -module.exports = { - extends: [__dirname+'/config/defaultEslintConfig.cjs'], - parserOptions: { - project: './tsconfig.eslint.json', - tsconfigRootDir: __dirname, - }, - rules: { - '@typescript-eslint/naming-convention': [ - 'error', - { - 'selector': 'variable', - 'types': ['boolean'], - 'format': ['PascalCase'], - 'prefix': ['is', 'with', 'should', 'has', 'can', 'did', 'will'] - } - ] - } - } \ No newline at end of file diff --git a/examples/react-oidc-demo/README.md b/examples/react-oidc-demo/README.md index 102b48cfa..8558a506f 100644 --- a/examples/react-oidc-demo/README.md +++ b/examples/react-oidc-demo/README.md @@ -63,14 +63,23 @@ The only file you should edit is "OidcTrustedDomains.js". // Domains used by OIDC server must be also declared here const trustedDomains = { - default: ["https://demo.duendesoftware.com", "https://www.myapi.com/users"], + default: ['https://demo.duendesoftware.com', 'https://www.myapi.com/users'], }; // Service worker will continue to give access token to the JavaScript client // Ideal to hide refresh token from client JavaScript, but to retrieve access_token for some // scenarios which require it. For example, to send it via websocket connection. -trustedDomains.config_show_access_token = { domains : ["https://demo.duendesoftware.com"], showAccessToken: true }; +trustedDomains.config_show_access_token = { + domains: ['https://demo.duendesoftware.com'], + showAccessToken: true, +}; +// Setting allowMultiTabLogin to true will enable storing login-specific parameters (state, nonce, code verifier) +// separately for each tab. This will prevent errors when logins are initiated from multiple tabs. +trustedDomains.config_multi_tab_login = { + domains: ['https://demo.duendesoftware.com'], + allowMultiTabLogin: true, +}; ``` ## Run The Demo @@ -94,24 +103,23 @@ The default routes used internally : - www.your-app.fr/authentication/callback ```javascript -import React from "react"; -import { render } from "react-dom"; -import { BrowserRouter as Router } from "react-router-dom"; -import { OidcProvider } from "@axa-fr/react-oidc"; -import Header from "./Layout/Header"; -import Routes from "./Router"; +import React from 'react'; +import { render } from 'react-dom'; +import { BrowserRouter as Router } from 'react-router-dom'; +import { OidcProvider } from '@axa-fr/react-oidc'; +import Header from './Layout/Header'; +import Routes from './Router'; // This configuration use hybrid mode // ServiceWorker are used if available (more secure) else tokens are given to the client // You need to give inside your code the "access_token" when using fetch const configuration = { - client_id: "interactive.public.short", - redirect_uri: window.location.origin + "/authentication/callback", - silent_redirect_uri: - window.location.origin + "/authentication/silent-callback", - scope: "openid profile email api offline_access", // offline_access scope allow your client to retrieve the refresh_token - authority: "https://demo.duendesoftware.com", - service_worker_relative_url: "/OidcServiceWorker.js", + client_id: 'interactive.public.short', + redirect_uri: window.location.origin + '/authentication/callback', + silent_redirect_uri: window.location.origin + '/authentication/silent-callback', + scope: 'openid profile email api offline_access', // offline_access scope allow your client to retrieve the refresh_token + authority: 'https://demo.duendesoftware.com', + service_worker_relative_url: '/OidcServiceWorker.js', service_worker_only: false, }; @@ -124,7 +132,7 @@ const App = () => ( ); -render(, document.getElementById("root")); +render(, document.getElementById('root')); ``` ```javascript @@ -178,8 +186,8 @@ const propTypes = { "useOidc" returns all props from the Hook : ```javascript -import React from "react"; -import { useOidc } from "./oidc"; +import React from 'react'; +import { useOidc } from './oidc'; export const Home = () => { const { login, logout, renewTokens, isAuthenticated } = useOidc(); @@ -189,33 +197,19 @@ export const Home = () => {
Welcome !!!
-

- React Demo Application protected by OpenId Connect -

+

React Demo Application protected by OpenId Connect

{!isAuthenticated && ( - )} {isAuthenticated && ( - )} {isAuthenticated && ( - )} @@ -238,8 +232,8 @@ The Hook method exposes : `OidcSecure` component trigger authentication in case user is not authenticated. So, the children of that component can be accessible only once you are connected. ```javascript -import React from "react"; -import { OidcSecure } from "@axa-fr/react-oidc"; +import React from 'react'; +import { OidcSecure } from '@axa-fr/react-oidc'; const AdminSecure = () => ( @@ -256,12 +250,12 @@ export default AdminSecure; "withOidcSecure" act the same as "OidcSecure" it also trigger authentication in case user is not authenticated. ```javascript -import React from "react"; -import { Switch, Route } from "react-router-dom"; -import { withOidcSecure } from "@axa-fr/react-oidc"; -import Home from "../Pages/Home"; -import Dashboard from "../Pages/Dashboard"; -import Admin from "../Pages/Admin"; +import React from 'react'; +import { Switch, Route } from 'react-router-dom'; +import { withOidcSecure } from '@axa-fr/react-oidc'; +import Home from '../Pages/Home'; +import Dashboard from '../Pages/Dashboard'; +import Admin from '../Pages/Admin'; const Routes = () => ( @@ -278,7 +272,7 @@ export default Routes; ## How to get "Access Token" : Hook method ```javascript -import { useOidcAccessToken } from "@axa-fr/react-oidc"; +import { useOidcAccessToken } from '@axa-fr/react-oidc'; const DisplayAccessToken = () => { const { accessToken, accessTokenPayload } = useOidcAccessToken(); @@ -290,11 +284,10 @@ const DisplayAccessToken = () => {
Access Token
-

- Please consider to configure the ServiceWorker in order to protect - your application from XSRF attacks. ""access_token" and - "refresh_token" will never be accessible from your client side - javascript. +

+ Please consider to configure the ServiceWorker in order to protect your application from + XSRF attacks. ""access_token" and "refresh_token" will never be accessible from your + client side javascript.

{

{JSON.stringify(accessToken)}

} {accessTokenPayload != null && ( @@ -309,7 +302,7 @@ const DisplayAccessToken = () => { ## How to get IDToken : Hook method ```javascript -import { useOidcIdToken } from "@axa-fr/react-oidc"; +import { useOidcIdToken } from '@axa-fr/react-oidc'; const DisplayIdToken = () => { const { idToken, idTokenPayload } = useOidcIdToken(); @@ -323,9 +316,7 @@ const DisplayIdToken = () => {
ID Token
{

{JSON.stringify(idToken)}

} - {idTokenPayload != null && ( -

{JSON.stringify(idTokenPayload)}

- )} + {idTokenPayload != null &&

{JSON.stringify(idTokenPayload)}

}
); @@ -335,7 +326,7 @@ const DisplayIdToken = () => { ## How to get User Information : Hook method ```javascript -import { useOidcUser, UserStatus } from "@axa-fr/react-oidc"; +import { useOidcUser, UserStatus } from '@axa-fr/react-oidc'; const DisplayUserInfo = () => { const { oidcUser, oidcUserLoadingState } = useOidcUser(); @@ -366,8 +357,8 @@ If your are not using the service worker. Fetch function need to send AccessToke This Hook give you a wrapped fetch that add the access token for you. ```javascript -import React, { useEffect, useState } from "react"; -import { useOidcFetch, OidcSecure } from "@axa-fr/react-oidc"; +import React, { useEffect, useState } from 'react'; +import { useOidcFetch, OidcSecure } from '@axa-fr/react-oidc'; const DisplayUserInfo = ({ fetch }) => { const [oidcUser, setOidcUser] = useState(null); @@ -375,16 +366,14 @@ const DisplayUserInfo = ({ fetch }) => { useEffect(() => { const fetchUserInfoAsync = async () => { - const res = await fetch( - "https://demo.duendesoftware.com/connect/userinfo", - ); + const res = await fetch('https://demo.duendesoftware.com/connect/userinfo'); if (res.status != 200) { return null; } return res.json(); }; let isMounted = true; - fetchUserInfoAsync().then((userInfo) => { + fetchUserInfoAsync().then(userInfo => { if (isMounted) { setLoading(false); setOidcUser(userInfo); @@ -404,9 +393,7 @@ const DisplayUserInfo = ({ fetch }) => {
User information
- {oidcUser != null && ( -

{JSON.stringify(oidcUser)}

- )} + {oidcUser != null &&

{JSON.stringify(oidcUser)}

}
@@ -429,8 +416,8 @@ If your are not using the service worker. Fetch function need to send AccessToke This HOC give you a wrapped fetch that add the access token for you. ```javascript -import React, { useEffect, useState } from "react"; -import { useOidcFetch, OidcSecure } from "@axa-fr/react-oidc"; +import React, { useEffect, useState } from 'react'; +import { useOidcFetch, OidcSecure } from '@axa-fr/react-oidc'; const DisplayUserInfo = ({ fetch }) => { const [oidcUser, setOidcUser] = useState(null); @@ -438,16 +425,14 @@ const DisplayUserInfo = ({ fetch }) => { useEffect(() => { const fetchUserInfoAsync = async () => { - const res = await fetch( - "https://demo.duendesoftware.com/connect/userinfo", - ); + const res = await fetch('https://demo.duendesoftware.com/connect/userinfo'); if (res.status != 200) { return null; } return res.json(); }; let isMounted = true; - fetchUserInfoAsync().then((userInfo) => { + fetchUserInfoAsync().then(userInfo => { if (isMounted) { setLoading(false); setOidcUser(userInfo); @@ -467,9 +452,7 @@ const DisplayUserInfo = ({ fetch }) => {
User information
- {oidcUser != null && ( -

{JSON.stringify(oidcUser)}

- )} + {oidcUser != null &&

{JSON.stringify(oidcUser)}

}
@@ -490,23 +473,23 @@ You can inject your own components. All components definition receive props `configurationName`. Please checkout the demo for more complete example. ```javascript -import React from "react"; -import { render } from "react-dom"; -import { BrowserRouter as Router } from "react-router-dom"; -import { OidcProvider } from "@axa-fr/react-oidc"; -import Header from "./Layout/Header"; -import Routes from "./Router"; +import React from 'react'; +import { render } from 'react-dom'; +import { BrowserRouter as Router } from 'react-router-dom'; +import { OidcProvider } from '@axa-fr/react-oidc'; +import Header from './Layout/Header'; +import Routes from './Router'; // This configuration use hybrid mode // ServiceWorker are used if available (more secure) else tokens are given to the client // You need to give inside your code the "access_token" when using fetch const configuration = { - client_id: "interactive.public.short", - redirect_uri: "http://localhost:4200/authentication/callback", - silent_redirect_uri: "http://localhost:4200/authentication/silent-callback", - scope: "openid profile email api offline_access", - authority: "https://demo.identityserver.io", - service_worker_relative_url: "/OidcServiceWorker.js", + client_id: 'interactive.public.short', + redirect_uri: 'http://localhost:4200/authentication/callback', + silent_redirect_uri: 'http://localhost:4200/authentication/silent-callback', + scope: 'openid profile email api offline_access', + authority: 'https://demo.identityserver.io', + service_worker_relative_url: '/OidcServiceWorker.js', service_worker_only: false, }; @@ -542,12 +525,12 @@ const App = () => ( ); -render(, document.getElementById("root")); +render(, document.getElementById('root')); ``` ## How It Works -These components encapsulate the use of "@axa-fr/vanilla-oidc" in order to hide workflow complexity. +These components encapsulate the use of "@axa-fr/oidc-client" in order to hide workflow complexity. Internally, native History API is used to be router library agnostic. More information about OIDC @@ -562,15 +545,15 @@ To work with NextJS you need to inject your own history surcharge like the sampl **component/layout.js** ```javascript -import { OidcProvider } from "@axa-fr/react-oidc"; -import { useRouter } from "next/router"; +import { OidcProvider } from '@axa-fr/react-oidc'; +import { useRouter } from 'next/router'; const configuration = { - client_id: "interactive.public.short", - redirect_uri: "http://localhost:3001/#authentication/callback", - silent_redirect_uri: "http://localhost:3001/#authentication/silent-callback", // Optional activate silent-login that use cookies between OIDC server and client javascript to restore the session - scope: "openid profile email api offline_access", - authority: "https://demo.duendesoftware.com", + client_id: 'interactive.public.short', + redirect_uri: 'http://localhost:3001/#authentication/callback', + silent_redirect_uri: 'http://localhost:3001/#authentication/silent-callback', // Optional activate silent-login that use cookies between OIDC server and client javascript to restore the session + scope: 'openid profile email api offline_access', + authority: 'https://demo.duendesoftware.com', }; const onEvent = (configurationName, eventName, data) => { @@ -581,13 +564,13 @@ export default function Layout({ children }) { const router = useRouter(); const withCustomHistory = () => { return { - replaceState: (url) => { + replaceState: url => { router .replace({ pathname: url, }) .then(() => { - window.dispatchEvent(new Event("popstate")); + window.dispatchEvent(new Event('popstate')); }); }, }; @@ -615,14 +598,13 @@ For more information checkout the [NextJS React OIDC demo](https://github.com/Ax ```javascript export const configurationIdentityServerWithHash = { - client_id: "interactive.public.short", - redirect_uri: window.location.origin + "#authentication-callback", - silent_redirect_uri: - window.location.origin + "#authentication-silent-callback", - scope: "openid profile email api offline_access", - authority: "https://demo.duendesoftware.com", + client_id: 'interactive.public.short', + redirect_uri: window.location.origin + '#authentication-callback', + silent_redirect_uri: window.location.origin + '#authentication-silent-callback', + scope: 'openid profile email api offline_access', + authority: 'https://demo.duendesoftware.com', refresh_time_before_tokens_expiration_in_second: 70, - service_worker_relative_url: "/OidcServiceWorker.js", + service_worker_relative_url: '/OidcServiceWorker.js', service_worker_only: false, }; ``` diff --git a/examples/react-oidc-demo/index.html b/examples/react-oidc-demo/index.html index 0bb0aea6f..8a5870109 100644 --- a/examples/react-oidc-demo/index.html +++ b/examples/react-oidc-demo/index.html @@ -1,13 +1,10 @@ - + - + React App diff --git a/examples/react-oidc-demo/package.json b/examples/react-oidc-demo/package.json index 66c06e02f..c2cac7264 100644 --- a/examples/react-oidc-demo/package.json +++ b/examples/react-oidc-demo/package.json @@ -11,41 +11,33 @@ "url": "https://github.com/AxaGuilDEv/react-oidc.git" }, "scripts": { - "start": "vite", + "start": "pnpm prestart && pnpm vite", + "prestart": "node ./node_modules/@axa-fr/react-oidc/bin/copy-service-worker-files.mjs public", "build": "vite build", "serve": "vite preview", - "clean": "rimraf dist" + "clean": "rimraf dist", + "postinstall": "node ./node_modules/@axa-fr/react-oidc/bin/copy-service-worker-files.mjs public" + }, + "dependencies": { + "@axa-fr/react-oidc": "workspace:*", + "react": "^19.0.0", + "react-dom": "^19.0.0", + "react-router-dom": "^6.22.3" }, "devDependencies": { - "@axa-fr/vanilla-oidc": "workspace:*", - "@axa-fr/react-oidc":"workspace:*", - "@axa-fr/oidc-client-service-worker": "workspace:*", - "@testing-library/jest-dom": "5.16.5", - "@testing-library/react": "13.3.0", - "@testing-library/user-event": "14.4.3", - "@types/react": "^18.2.15", - "@typescript-eslint/eslint-plugin": "^5.50.0", - "@typescript-eslint/parser": "^5.50.0", - "@vitejs/plugin-react": "4.0.3", - "@vitest/coverage-c8": "^0.33.0", + "@testing-library/jest-dom": "6.6.3", + "@testing-library/react": "15.0.7", + "@testing-library/user-event": "14.5.2", + "@types/react": "19.0.5", + "@vitejs/plugin-react": "4.3.4", "bootstrap": "^4.6.2", "copyfiles": "2.4.1", "cross-env": "^7.0.3", - "eslint": "^8.26.0", - "eslint-config-standard": "^17.1.0", - "eslint-config-standard-with-typescript": "^36.1.0", - "eslint-import-resolver-typescript": "^3.5.5", - "eslint-plugin-react": "^7.32.2", - "eslint-plugin-simple-import-sort": "^10.0.0", - "jsdom": "22.1.0", - "msw": "1.2.2", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "react-router-dom": "^6.14.1", - "typescript": "5.1.6", - "vite": "^4.4.4", - "vite-plugin-dts": "^3.3.0", - "vitest": "^0.33.0" + "jsdom": "26.0.0", + "typescript": "5.7.3", + "vite": "6.0.7", + "vite-plugin-dts": "4.5.0", + "vitest": "2.1.8" }, "license": "MIT", "publishConfig": { diff --git a/examples/react-oidc-demo/public/OidcServiceWorker.js.map b/examples/react-oidc-demo/public/OidcServiceWorker.js.map deleted file mode 100644 index 07cfaecde..000000000 --- a/examples/react-oidc-demo/public/OidcServiceWorker.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"OidcServiceWorker.js","sources":["../src/constants.ts","../src/utils/domains.ts","../src/utils/strings.ts","../src/utils/tokens.ts","../src/utils/serializeHeaders.ts","../src/utils/sleep.ts","../src/utils/codeVerifier.ts","../src/OidcServiceWorker.ts"],"sourcesContent":["const scriptFilename = 'OidcTrustedDomains.js'; /* global trustedDomains */\r\nconst acceptAnyDomainToken = '*';\r\n\r\ntype TokenType = {\r\n readonly REFRESH_TOKEN: string;\r\n readonly ACCESS_TOKEN: string;\r\n readonly NONCE_TOKEN: string;\r\n readonly CODE_VERIFIER: string;\r\n};\r\n\r\nconst TOKEN: TokenType = {\r\n REFRESH_TOKEN: 'REFRESH_TOKEN_SECURED_BY_OIDC_SERVICE_WORKER',\r\n ACCESS_TOKEN: 'ACCESS_TOKEN_SECURED_BY_OIDC_SERVICE_WORKER',\r\n NONCE_TOKEN: 'NONCE_SECURED_BY_OIDC_SERVICE_WORKER',\r\n CODE_VERIFIER: 'CODE_VERIFIER_SECURED_BY_OIDC_SERVICE_WORKER',\r\n};\r\n\r\ntype TokenRenewModeType = {\r\n readonly access_token_or_id_token_invalid: string;\r\n readonly access_token_invalid: string;\r\n readonly id_token_invalid: string;\r\n};\r\n\r\nconst TokenRenewMode: TokenRenewModeType = {\r\n access_token_or_id_token_invalid: 'access_token_or_id_token_invalid',\r\n access_token_invalid: 'access_token_invalid',\r\n id_token_invalid: 'id_token_invalid',\r\n};\r\n\r\nconst openidWellknownUrlEndWith = '/.well-known/openid-configuration';\r\n\r\nexport { scriptFilename, acceptAnyDomainToken, TOKEN, TokenRenewMode, openidWellknownUrlEndWith };\r\n","import { DomainDetails, TrustedDomains } from './../types';\r\nimport {\r\n acceptAnyDomainToken,\r\n openidWellknownUrlEndWith,\r\n scriptFilename,\r\n} from '../constants';\r\nimport { Database, Domain, OidcConfig } from '../types';\r\n\r\nfunction checkDomain(domains: Domain[], endpoint: string) {\r\n if (!endpoint) {\r\n return;\r\n }\r\n\r\n const domain = domains.find((domain) => {\r\n let testable: RegExp;\r\n\r\n if (typeof domain === 'string') {\r\n testable = new RegExp(`^${domain}`);\r\n } else {\r\n testable = domain;\r\n }\r\n\r\n return testable.test?.(endpoint);\r\n });\r\n if (!domain) {\r\n throw new Error(\r\n 'Domain ' +\r\n endpoint +\r\n ' is not trusted, please add domain in ' +\r\n scriptFilename\r\n );\r\n }\r\n}\r\n\r\nexport const getDomains = (trustedDomain: Domain[] | DomainDetails, type: 'oidc' | 'accessToken') => {\r\n if(Array.isArray(trustedDomain)) {\r\n return trustedDomain;\r\n }\r\n\r\n return trustedDomain[`${type}Domains`] ?? trustedDomain.domains ?? [];\r\n}\r\n\r\nconst getCurrentDatabaseDomain = (\r\n database: Database,\r\n url: string,\r\n trustedDomains: TrustedDomains\r\n) => {\r\n if (url.endsWith(openidWellknownUrlEndWith)) {\r\n return null;\r\n }\r\n for (const [key, currentDatabase] of Object.entries(database)) {\r\n const oidcServerConfiguration = currentDatabase.oidcServerConfiguration;\r\n\r\n if (!oidcServerConfiguration) {\r\n continue;\r\n }\r\n\r\n if (\r\n oidcServerConfiguration.tokenEndpoint &&\r\n url === oidcServerConfiguration.tokenEndpoint\r\n ) {\r\n continue;\r\n }\r\n if (\r\n oidcServerConfiguration.revocationEndpoint &&\r\n url === oidcServerConfiguration.revocationEndpoint\r\n ) {\r\n continue;\r\n }\r\n const trustedDomain = trustedDomains == null ? [] : trustedDomains[key];\r\n\r\n const domains = getDomains(trustedDomain, 'accessToken');\r\n const domainsToSendTokens = oidcServerConfiguration.userInfoEndpoint\r\n ? [oidcServerConfiguration.userInfoEndpoint, ...domains]\r\n : [...domains];\r\n\r\n let hasToSendToken = false;\r\n if (domainsToSendTokens.find((f) => f === acceptAnyDomainToken)) {\r\n hasToSendToken = true;\r\n } else {\r\n for (let i = 0; i < domainsToSendTokens.length; i++) {\r\n let domain = domainsToSendTokens[i];\r\n\r\n if (typeof domain === 'string') {\r\n domain = new RegExp(`^${domain}`);\r\n }\r\n\r\n if (domain.test?.(url)) {\r\n hasToSendToken = true;\r\n break;\r\n }\r\n }\r\n }\r\n\r\n if (hasToSendToken) {\r\n if (!currentDatabase.tokens) {\r\n return null;\r\n }\r\n return currentDatabase;\r\n }\r\n }\r\n return null;\r\n};\r\n\r\nexport { checkDomain, getCurrentDatabaseDomain };\r\n","/**\r\n * Count occurances of letter in string\r\n * @param str\r\n * @param find\r\n * @returns\r\n */\r\nexport function countLetter(str: string, find: string) {\r\n return str.split(find).length - 1;\r\n}\r\n","import { TOKEN, TokenRenewMode } from '../constants';\r\nimport { OidcConfig, OidcConfiguration, OidcServerConfiguration, Tokens } from '../types';\r\nimport { countLetter } from './strings';\r\n\r\nfunction parseJwt(token: string) {\r\n return JSON.parse(\r\n b64DecodeUnicode(token.split('.')[1].replace('-', '+').replace('_', '/'))\r\n );\r\n}\r\nfunction b64DecodeUnicode(str: string) {\r\n return decodeURIComponent(\r\n Array.prototype.map\r\n .call(\r\n atob(str),\r\n (c) => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)\r\n )\r\n .join('')\r\n );\r\n}\r\n\r\nfunction computeTimeLeft(\r\n refreshTimeBeforeTokensExpirationInSecond: number,\r\n expiresAt: number\r\n) {\r\n const currentTimeUnixSecond = new Date().getTime() / 1000;\r\n return Math.round(\r\n expiresAt -\r\n refreshTimeBeforeTokensExpirationInSecond -\r\n currentTimeUnixSecond\r\n );\r\n}\r\n\r\nfunction isTokensValid(tokens: Tokens | null) {\r\n if (!tokens) {\r\n return false;\r\n }\r\n return computeTimeLeft(0, tokens.expiresAt) > 0;\r\n}\r\n\r\nconst extractTokenPayload = (token?: string) => {\r\n try {\r\n if (!token) {\r\n return null;\r\n }\r\n if (countLetter(token, '.') === 2) {\r\n return parseJwt(token);\r\n } else {\r\n return null;\r\n }\r\n } catch (e) {\r\n console.warn(e);\r\n }\r\n return null;\r\n};\r\n\r\n// https://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation (excluding rules #1, #4, #5, #7, #8, #12, and #13 which did not apply).\r\n// https://github.com/openid/AppAuth-JS/issues/65\r\nconst isTokensOidcValid = (\r\n tokens: Tokens,\r\n nonce: string | null,\r\n oidcServerConfiguration: OidcServerConfiguration\r\n): { isValid: boolean; reason: string } => {\r\n if (tokens.idTokenPayload) {\r\n const idTokenPayload = tokens.idTokenPayload;\r\n // 2: The Issuer Identifier for the OpenID Provider (which is typically obtained during Discovery) MUST exactly match the value of the iss (issuer) Claim.\r\n if (oidcServerConfiguration.issuer !== idTokenPayload.iss) {\r\n return { isValid: false, reason: 'Issuer does not match' };\r\n }\r\n // 3: The Client MUST validate that the aud (audience) Claim contains its client_id value registered at the Issuer identified by the iss (issuer) Claim as an audience. The aud (audience) Claim MAY contain an array with more than one element. The ID Token MUST be rejected if the ID Token does not list the Client as a valid audience, or if it contains additional audiences not trusted by the Client.\r\n\r\n // 6: If the ID Token is received via direct communication between the Client and the Token Endpoint (which it is in this flow), the TLS server validation MAY be used to validate the issuer in place of checking the token signature. The Client MUST validate the signature of all other ID Tokens according to JWS [JWS] using the algorithm specified in the JWT alg Header Parameter. The Client MUST use the keys provided by the Issuer.\r\n\r\n // 9: The current time MUST be before the time represented by the exp Claim.\r\n const currentTimeUnixSecond = new Date().getTime() / 1000;\r\n if (idTokenPayload.exp && idTokenPayload.exp < currentTimeUnixSecond) {\r\n return { isValid: false, reason: 'Token expired' };\r\n }\r\n // 10: The iat Claim can be used to reject tokens that were issued too far away from the current time, limiting the amount of time that nonces need to be stored to prevent attacks. The acceptable range is Client specific.\r\n const timeInSevenDays = 60 * 60 * 24 * 7;\r\n if (\r\n idTokenPayload.iat &&\r\n idTokenPayload.iat + timeInSevenDays < currentTimeUnixSecond\r\n ) {\r\n return { isValid: false, reason: 'Token is used from too long time' };\r\n }\r\n // 11: If a nonce value was sent in the Authentication Request, a nonce Claim MUST be present and its value checked to verify that it is the same value as the one that was sent in the Authentication Request. The Client SHOULD check the nonce value for replay attacks. The precise method for detecting replay attacks is Client specific.\r\n if (nonce && idTokenPayload.nonce && idTokenPayload.nonce !== nonce) {\r\n return { isValid: false, reason: 'Nonce does not match' };\r\n }\r\n }\r\n return { isValid: true, reason: '' };\r\n};\r\n\r\nfunction _hideTokens(tokens: Tokens, currentDatabaseElement: OidcConfig, configurationName: string) {\r\n if (!tokens.issued_at) {\r\n const currentTimeUnixSecond = new Date().getTime() / 1000;\r\n tokens.issued_at = currentTimeUnixSecond;\r\n }\r\n\r\n const accessTokenPayload = extractTokenPayload(tokens.access_token);\r\n const secureTokens = {\r\n ...tokens,\r\n accessTokenPayload,\r\n };\r\n if (currentDatabaseElement.hideAccessToken) {\r\n secureTokens.access_token = TOKEN.ACCESS_TOKEN + '_' + configurationName;\r\n }\r\n tokens.accessTokenPayload = accessTokenPayload;\r\n\r\n let _idTokenPayload = null;\r\n if (tokens.id_token) {\r\n _idTokenPayload = extractTokenPayload(tokens.id_token);\r\n tokens.idTokenPayload = {..._idTokenPayload};\r\n if (_idTokenPayload.nonce && currentDatabaseElement.nonce != null) {\r\n const keyNonce =\r\n TOKEN.NONCE_TOKEN + '_' + currentDatabaseElement.configurationName;\r\n _idTokenPayload.nonce = keyNonce;\r\n }\r\n secureTokens.idTokenPayload = _idTokenPayload;\r\n }\r\n if (tokens.refresh_token) {\r\n secureTokens.refresh_token =\r\n TOKEN.REFRESH_TOKEN + '_' + configurationName;\r\n }\r\n\r\n const idTokenExpiresAt =\r\n _idTokenPayload && _idTokenPayload.exp\r\n ? _idTokenPayload.exp\r\n : Number.MAX_VALUE;\r\n const accessTokenExpiresAt =\r\n accessTokenPayload && accessTokenPayload.exp\r\n ? accessTokenPayload.exp\r\n : tokens.issued_at + tokens.expires_in;\r\n\r\n let expiresAt: number;\r\n const tokenRenewMode = (\r\n currentDatabaseElement.oidcConfiguration as OidcConfiguration\r\n ).token_renew_mode;\r\n if (tokenRenewMode === TokenRenewMode.access_token_invalid) {\r\n expiresAt = accessTokenExpiresAt;\r\n } else if (tokenRenewMode === TokenRenewMode.id_token_invalid) {\r\n expiresAt = idTokenExpiresAt;\r\n } else {\r\n expiresAt =\r\n idTokenExpiresAt < accessTokenExpiresAt\r\n ? idTokenExpiresAt\r\n : accessTokenExpiresAt;\r\n }\r\n secureTokens.expiresAt = expiresAt;\r\n\r\n tokens.expiresAt = expiresAt;\r\n const nonce = currentDatabaseElement.nonce\r\n ? currentDatabaseElement.nonce.nonce\r\n : null;\r\n const {isValid, reason} = isTokensOidcValid(\r\n tokens,\r\n nonce,\r\n currentDatabaseElement.oidcServerConfiguration as OidcServerConfiguration\r\n ); //TODO: Type assertion, could be null.\r\n if (!isValid) {\r\n throw Error(`Tokens are not OpenID valid, reason: ${reason}`);\r\n }\r\n\r\n // When refresh_token is not rotated we reuse ald refresh_token\r\n if (\r\n currentDatabaseElement.tokens != null &&\r\n 'refresh_token' in currentDatabaseElement.tokens &&\r\n !('refresh_token' in tokens)\r\n ) {\r\n const refreshToken = currentDatabaseElement.tokens.refresh_token;\r\n\r\n currentDatabaseElement.tokens = {\r\n ...tokens,\r\n refresh_token: refreshToken,\r\n };\r\n } else {\r\n currentDatabaseElement.tokens = tokens;\r\n }\r\n\r\n currentDatabaseElement.status = 'LOGGED_IN';\r\n return secureTokens;\r\n}\r\n\r\nfunction hideTokens(currentDatabaseElement: OidcConfig) {\r\n const configurationName = currentDatabaseElement.configurationName;\r\n return (response: Response) => {\r\n if (response.status !== 200) {\r\n return response;\r\n }\r\n return response.json().then((tokens: Tokens) => {\r\n const secureTokens = _hideTokens(tokens, currentDatabaseElement, configurationName);\r\n const body = JSON.stringify(secureTokens);\r\n return new Response(body, response);\r\n });\r\n };\r\n}\r\n\r\nexport {\r\n b64DecodeUnicode,\r\n computeTimeLeft,\r\n isTokensValid,\r\n extractTokenPayload,\r\n isTokensOidcValid,\r\n hideTokens,\r\n _hideTokens\r\n};\r\n","import { FetchHeaders } from '../types';\r\n\r\nfunction serializeHeaders(headers: Headers) {\r\n const headersObj: Record = {};\r\n for (const key of (headers as FetchHeaders).keys()) {\r\n if (headers.has(key)) {\r\n headersObj[key] = headers.get(key) as string;\r\n }\r\n }\r\n return headersObj;\r\n}\r\nexport {serializeHeaders};","const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));\r\nexport { sleep };\r\n","\r\n\r\nexport function replaceCodeVerifier(codeVerifier:string, newCodeVerifier:string):string {\r\n const regex = /code_verifier=[A-Za-z0-9_-]+/i;\r\n return codeVerifier.replace(regex, `code_verifier=${newCodeVerifier}`);\r\n}","import { acceptAnyDomainToken, TOKEN, scriptFilename } from './constants';\r\nimport {\r\n TrustedDomains,\r\n Database,\r\n OidcConfig,\r\n OidcConfiguration,\r\n MessageEventData,\r\n // TrustedDomainsShowAccessToken,\r\n} from './types';\r\nimport {\r\n checkDomain,\r\n getCurrentDatabaseDomain,\r\n hideTokens,\r\n isTokensValid,\r\n serializeHeaders,\r\n sleep,\r\n getDomains,\r\n} from './utils';\r\nimport {replaceCodeVerifier} from \"./utils/codeVerifier\";\r\n\r\nconst _self = self as ServiceWorkerGlobalScope & typeof globalThis;\r\n\r\ndeclare let trustedDomains: TrustedDomains;\r\n\r\n_self.importScripts(scriptFilename);\r\n\r\nconst id = Math.round(new Date().getTime() / 1000).toString();\r\n\r\nconst keepAliveJsonFilename = 'OidcKeepAliveServiceWorker.json';\r\nconst handleInstall = (event: ExtendableEvent) => {\r\n console.log('[OidcServiceWorker] service worker installed ' + id);\r\n event.waitUntil(_self.skipWaiting());\r\n};\r\n\r\nconst handleActivate = (event: ExtendableEvent) => {\r\n console.log('[OidcServiceWorker] service worker activated ' + id);\r\n event.waitUntil(_self.clients.claim());\r\n};\r\n\r\nlet currentLoginCallbackConfigurationName: string | null = null;\r\nconst database: Database = {\r\n default: {\r\n configurationName: 'default',\r\n tokens: null,\r\n status: null,\r\n state: null,\r\n codeVerifier: null,\r\n nonce: null,\r\n oidcServerConfiguration: null,\r\n hideAccessToken: true,\r\n },\r\n};\r\n\r\nconst getCurrentDatabasesTokenEndpoint = (database: Database, url: string) => {\r\n const databases: OidcConfig[] = [];\r\n for (const [, value] of Object.entries(database)) {\r\n if (\r\n value.oidcServerConfiguration != null &&\r\n url.startsWith(value.oidcServerConfiguration.tokenEndpoint)\r\n ) {\r\n databases.push(value);\r\n } else if (\r\n value.oidcServerConfiguration != null &&\r\n value.oidcServerConfiguration.revocationEndpoint &&\r\n url.startsWith(value.oidcServerConfiguration.revocationEndpoint)\r\n ) {\r\n databases.push(value);\r\n }\r\n }\r\n return databases;\r\n};\r\n\r\nconst keepAliveAsync = async (event: FetchEvent) => {\r\n const originalRequest = event.request;\r\n const isFromVanilla = originalRequest.headers.has('oidc-vanilla');\r\n const init = { status: 200, statusText: 'oidc-service-worker' };\r\n const response = new Response('{}', init);\r\n if (!isFromVanilla) {\r\n const originalRequestUrl = new URL(originalRequest.url);\r\n const minSleepSeconds = Number(originalRequestUrl.searchParams.get('minSleepSeconds')) || 240;\r\n for (let i = 0; i < minSleepSeconds; i++) {\r\n await sleep(1000 + Math.floor(Math.random() * 1000));\r\n const cache = await caches.open('oidc_dummy_cache');\r\n await cache.put(event.request, response.clone());\r\n }\r\n }\r\n return response;\r\n};\r\n\r\nconst handleFetch = async (event: FetchEvent) => {\r\n const originalRequest = event.request;\r\n const url = originalRequest.url;\r\n if (originalRequest.url.includes(keepAliveJsonFilename)) {\r\n event.respondWith(keepAliveAsync(event));\r\n return;\r\n }\r\n\r\n const currentDatabaseForRequestAccessToken = getCurrentDatabaseDomain(\r\n database,\r\n originalRequest.url,\r\n trustedDomains\r\n );\r\n if (\r\n currentDatabaseForRequestAccessToken &&\r\n currentDatabaseForRequestAccessToken.tokens &&\r\n currentDatabaseForRequestAccessToken.tokens.access_token\r\n ) {\r\n while (\r\n currentDatabaseForRequestAccessToken.tokens &&\r\n !isTokensValid(currentDatabaseForRequestAccessToken.tokens)\r\n ) {\r\n await sleep(200);\r\n }\r\n const newRequest =\r\n originalRequest.mode == 'navigate'\r\n ? new Request(originalRequest, {\r\n headers: {\r\n ...serializeHeaders(originalRequest.headers),\r\n authorization:\r\n 'Bearer ' +\r\n currentDatabaseForRequestAccessToken.tokens.access_token,\r\n },\r\n })\r\n : new Request(originalRequest, {\r\n headers: {\r\n ...serializeHeaders(originalRequest.headers),\r\n authorization:\r\n 'Bearer ' +\r\n currentDatabaseForRequestAccessToken.tokens.access_token,\r\n },\r\n mode: (\r\n currentDatabaseForRequestAccessToken.oidcConfiguration as OidcConfiguration\r\n ).service_worker_convert_all_requests_to_cors\r\n ? 'cors'\r\n : originalRequest.mode,\r\n });\r\n\r\n //@ts-ignore -- TODO: review, waitUntil takes a promise, this returns a void\r\n event.waitUntil(event.respondWith(fetch(newRequest)));\r\n\r\n return;\r\n }\r\n\r\n if (event.request.method !== 'POST') {\r\n return;\r\n }\r\n\r\n let currentDatabase: OidcConfig | null = null;\r\n const currentDatabases = getCurrentDatabasesTokenEndpoint(\r\n database,\r\n originalRequest.url\r\n );\r\n const numberDatabase = currentDatabases.length;\r\n if (numberDatabase > 0) {\r\n const maPromesse = new Promise((resolve, reject) => {\r\n const clonedRequest = originalRequest.clone();\r\n const response = clonedRequest.text().then((actualBody) => {\r\n if (\r\n actualBody.includes(TOKEN.REFRESH_TOKEN) ||\r\n actualBody.includes(TOKEN.ACCESS_TOKEN)\r\n ) {\r\n let newBody = actualBody;\r\n for (let i = 0; i < numberDatabase; i++) {\r\n const currentDb = currentDatabases[i];\r\n\r\n if (currentDb && currentDb.tokens != null) {\r\n const keyRefreshToken =\r\n TOKEN.REFRESH_TOKEN + '_' + currentDb.configurationName;\r\n if (actualBody.includes(keyRefreshToken)) {\r\n newBody = newBody.replace(\r\n keyRefreshToken,\r\n encodeURIComponent(currentDb.tokens.refresh_token as string)\r\n );\r\n currentDatabase = currentDb;\r\n break;\r\n }\r\n const keyAccessToken =\r\n TOKEN.ACCESS_TOKEN + '_' + currentDb.configurationName;\r\n if (actualBody.includes(keyAccessToken)) {\r\n newBody = newBody.replace(\r\n keyAccessToken,\r\n encodeURIComponent(currentDb.tokens.access_token)\r\n );\r\n currentDatabase = currentDb;\r\n break;\r\n }\r\n }\r\n }\r\n const fetchPromise = fetch(originalRequest, {\r\n body: newBody,\r\n method: clonedRequest.method,\r\n headers: {\r\n ...serializeHeaders(originalRequest.headers),\r\n },\r\n mode: clonedRequest.mode,\r\n cache: clonedRequest.cache,\r\n redirect: clonedRequest.redirect,\r\n referrer: clonedRequest.referrer,\r\n credentials: clonedRequest.credentials,\r\n integrity: clonedRequest.integrity,\r\n });\r\n\r\n if (\r\n currentDatabase &&\r\n currentDatabase.oidcServerConfiguration != null &&\r\n currentDatabase.oidcServerConfiguration.revocationEndpoint &&\r\n url.startsWith(\r\n currentDatabase.oidcServerConfiguration.revocationEndpoint\r\n )\r\n ) {\r\n return fetchPromise.then(async (response) => {\r\n const text = await response.text();\r\n return new Response(text, response);\r\n });\r\n }\r\n return fetchPromise.then(hideTokens(currentDatabase as OidcConfig)); //todo type assertion to OidcConfig but could be null, NEEDS REVIEW\r\n } else if (\r\n actualBody.includes('code_verifier=') &&\r\n currentLoginCallbackConfigurationName\r\n ) {\r\n currentDatabase = database[currentLoginCallbackConfigurationName];\r\n currentLoginCallbackConfigurationName = null;\r\n let newBody = actualBody;\r\n if (currentDatabase && currentDatabase.codeVerifier != null) {\r\n newBody = replaceCodeVerifier(newBody, currentDatabase.codeVerifier);\r\n }\r\n\r\n return fetch(originalRequest, {\r\n body: newBody,\r\n method: clonedRequest.method,\r\n headers: {\r\n ...serializeHeaders(originalRequest.headers),\r\n },\r\n mode: clonedRequest.mode,\r\n cache: clonedRequest.cache,\r\n redirect: clonedRequest.redirect,\r\n referrer: clonedRequest.referrer,\r\n credentials: clonedRequest.credentials,\r\n integrity: clonedRequest.integrity,\r\n }).then(hideTokens(currentDatabase));\r\n }\r\n return undefined;\r\n });\r\n response\r\n .then((r) => {\r\n if (r !== undefined) {\r\n resolve(r);\r\n } else {\r\n console.log('success undefined');\r\n reject(new Error('Response is undefined inside a success'));\r\n }\r\n })\r\n .catch((err) => {\r\n if (err !== undefined) {\r\n reject(err);\r\n } else {\r\n console.log('error undefined');\r\n reject(new Error('Response is undefined inside a error'));\r\n }\r\n });\r\n });\r\n\r\n //@ts-ignore -- TODO: review, waitUntil takes a promise, this returns a void\r\n event.waitUntil(event.respondWith(maPromesse));\r\n }\r\n};\r\n\r\ntype TrustedDomainsShowAccessToken = {\r\n [key: string]: boolean\r\n}\r\n\r\nconst trustedDomainsShowAccessToken: TrustedDomainsShowAccessToken = {};\r\n\r\nconst handleMessage = (event: ExtendableMessageEvent) => {\r\n const port = event.ports[0];\r\n const data = event.data as MessageEventData;\r\n const configurationName = data.configurationName;\r\n let currentDatabase = database[configurationName];\r\n if(trustedDomains== null){\r\n trustedDomains = {};\r\n }\r\n if (!currentDatabase) {\r\n \r\n if (trustedDomainsShowAccessToken[configurationName] === undefined) {\r\n let trustedDomain = trustedDomains[configurationName];\r\n trustedDomainsShowAccessToken[configurationName] = Array.isArray(trustedDomain) ? false : trustedDomain.showAccessToken;\r\n }\r\n database[configurationName] = {\r\n tokens: null,\r\n state: null,\r\n codeVerifier: null,\r\n oidcServerConfiguration: null,\r\n oidcConfiguration: undefined,\r\n nonce: null,\r\n status: null,\r\n configurationName,\r\n hideAccessToken: !trustedDomainsShowAccessToken[configurationName],\r\n };\r\n currentDatabase = database[configurationName];\r\n \r\n if (!trustedDomains[configurationName]) {\r\n trustedDomains[configurationName] = [];\r\n }\r\n }\r\n\r\n switch (data.type) {\r\n case 'clear':\r\n currentDatabase.tokens = null;\r\n currentDatabase.state = null;\r\n currentDatabase.codeVerifier = null;\r\n currentDatabase.status = data.data.status;\r\n port.postMessage({ configurationName });\r\n return;\r\n case 'init': {\r\n const oidcServerConfiguration = data.data.oidcServerConfiguration;\r\n let trustedDomain = trustedDomains[configurationName];\r\n const domains = getDomains(trustedDomain, 'oidc');\r\n if (!domains.find((f) => f === acceptAnyDomainToken)) {\r\n [\r\n oidcServerConfiguration.tokenEndpoint,\r\n oidcServerConfiguration.revocationEndpoint,\r\n oidcServerConfiguration.userInfoEndpoint,\r\n oidcServerConfiguration.issuer,\r\n ].forEach((url) => {\r\n checkDomain(domains, url);\r\n });\r\n }\r\n currentDatabase.oidcServerConfiguration = oidcServerConfiguration;\r\n currentDatabase.oidcConfiguration = data.data.oidcConfiguration;\r\n const where = data.data.where;\r\n if (\r\n where === 'loginCallbackAsync' ||\r\n where === 'tryKeepExistingSessionAsync'\r\n ) {\r\n currentLoginCallbackConfigurationName = configurationName;\r\n } else {\r\n currentLoginCallbackConfigurationName = null;\r\n }\r\n\r\n if (!currentDatabase.tokens) {\r\n port.postMessage({\r\n tokens: null,\r\n status: currentDatabase.status,\r\n configurationName,\r\n });\r\n } else {\r\n const tokens = {\r\n ...currentDatabase.tokens,\r\n };\r\n if(currentDatabase.hideAccessToken) {\r\n tokens.access_token = TOKEN.ACCESS_TOKEN + '_' + configurationName;\r\n }\r\n if (tokens.refresh_token) {\r\n tokens.refresh_token = TOKEN.REFRESH_TOKEN + '_' + configurationName;\r\n }\r\n if (\r\n tokens.idTokenPayload &&\r\n tokens.idTokenPayload.nonce &&\r\n currentDatabase.nonce != null\r\n ) {\r\n tokens.idTokenPayload.nonce =\r\n TOKEN.NONCE_TOKEN + '_' + configurationName;\r\n }\r\n port.postMessage({\r\n tokens,\r\n status: currentDatabase.status,\r\n configurationName,\r\n });\r\n }\r\n return;\r\n }\r\n case 'setState':\r\n currentDatabase.state = data.data.state;\r\n port.postMessage({ configurationName });\r\n return;\r\n case 'getState': {\r\n const state = currentDatabase.state;\r\n port.postMessage({ configurationName, state });\r\n return;\r\n }\r\n case 'setCodeVerifier':\r\n currentDatabase.codeVerifier = data.data.codeVerifier;\r\n port.postMessage({ configurationName });\r\n return;\r\n case 'getCodeVerifier': {\r\n port.postMessage({\r\n configurationName,\r\n codeVerifier: currentDatabase.codeVerifier != null ? TOKEN.CODE_VERIFIER + '_' + configurationName : null,\r\n });\r\n return;\r\n }\r\n case 'setSessionState':\r\n currentDatabase.sessionState = data.data.sessionState;\r\n port.postMessage({ configurationName });\r\n return;\r\n case 'getSessionState': {\r\n const sessionState = currentDatabase.sessionState;\r\n port.postMessage({ configurationName, sessionState });\r\n return;\r\n }\r\n case 'setNonce': {\r\n let nonce = data.data.nonce;\r\n if (nonce) {\r\n currentDatabase.nonce = nonce;\r\n }\r\n port.postMessage({configurationName});\r\n return;\r\n }\r\n case 'getNonce': {\r\n const keyNonce = TOKEN.NONCE_TOKEN + '_' + configurationName;\r\n const nonce = currentDatabase.nonce ? keyNonce : null;\r\n port.postMessage({configurationName, nonce});\r\n return;\r\n }\r\n default:\r\n currentDatabase.items = { ...data.data };\r\n port.postMessage({ configurationName });\r\n }\r\n};\r\n\r\n_self.addEventListener('install', handleInstall);\r\n_self.addEventListener('activate', handleActivate);\r\n_self.addEventListener('fetch', handleFetch);\r\n_self.addEventListener('message', handleMessage);\r\n"],"names":["domain","database","trustedDomains","response"],"mappings":"AAAA,MAAM,iBAAiB;AACvB,MAAM,uBAAuB;AAS7B,MAAM,QAAmB;AAAA,EACvB,eAAe;AAAA,EACf,cAAc;AAAA,EACd,aAAa;AAAA,EACb,eAAe;AACjB;AAQA,MAAM,iBAAqC;AAAA,EACzC,kCAAkC;AAAA,EAClC,sBAAsB;AAAA,EACtB,kBAAkB;AACpB;AAEA,MAAM,4BAA4B;ACrBlC,SAAS,YAAY,SAAmB,UAAkB;AACxD,MAAI,CAAC,UAAU;AACb;AAAA,EACF;AAEA,QAAM,SAAS,QAAQ,KAAK,CAACA,YAAW;ADb1C;ACcQ,QAAA;AAEA,QAAA,OAAOA,YAAW,UAAU;AAC9B,iBAAW,IAAI,OAAO,IAAIA,OAAM,EAAE;AAAA,IAAA,OAC7B;AACMA,iBAAAA;AAAAA,IACb;AAEO,YAAA,cAAS,SAAT,kCAAgB;AAAA,EAAQ,CAChC;AACD,MAAI,CAAC,QAAQ;AACX,UAAM,IAAI;AAAA,MACR,YACE,WACA,2CACA;AAAA,IAAA;AAAA,EAEN;AACF;AAEa,MAAA,aAAa,CAAC,eAAyC,SAAiC;AAChG,MAAA,MAAM,QAAQ,aAAa,GAAG;AACxB,WAAA;AAAA,EACT;AAEA,SAAO,cAAc,GAAG,IAAI,SAAS,KAAK,cAAc,WAAW;AACrE;AAEA,MAAM,2BAA2B,CAC/BC,WACA,KACAC,oBACG;AD9CL;AC+CM,MAAA,IAAI,SAAS,yBAAyB,GAAG;AACpC,WAAA;AAAA,EACT;AACA,aAAW,CAAC,KAAK,eAAe,KAAK,OAAO,QAAoBD,SAAQ,GAAG;AACzE,UAAM,0BAA0B,gBAAgB;AAEhD,QAAI,CAAC,yBAAyB;AAC5B;AAAA,IACF;AAEA,QACE,wBAAwB,iBACxB,QAAQ,wBAAwB,eAChC;AACA;AAAA,IACF;AACA,QACE,wBAAwB,sBACxB,QAAQ,wBAAwB,oBAChC;AACA;AAAA,IACF;AACA,UAAM,gBAAgBC,mBAAkB,OAAO,CAAA,IAAKA,gBAAe,GAAG;AAEhE,UAAA,UAAU,WAAW,eAAe,aAAa;AACjD,UAAA,sBAAsB,wBAAwB,mBAChD,CAAC,wBAAwB,kBAAkB,GAAG,OAAO,IACrD,CAAC,GAAG,OAAO;AAEf,QAAI,iBAAiB;AACrB,QAAI,oBAAoB,KAAK,CAAC,MAAM,MAAM,oBAAoB,GAAG;AAC9C,uBAAA;AAAA,IAAA,OACZ;AACL,eAAS,IAAI,GAAG,IAAI,oBAAoB,QAAQ,KAAK;AAC/C,YAAA,SAAS,oBAAoB,CAAC;AAE9B,YAAA,OAAO,WAAW,UAAU;AAC9B,mBAAS,IAAI,OAAO,IAAI,MAAM,EAAE;AAAA,QAClC;AAEI,aAAA,YAAO,SAAP,gCAAc,MAAM;AACL,2BAAA;AACjB;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,QAAI,gBAAgB;AACd,UAAA,CAAC,gBAAgB,QAAQ;AACpB,eAAA;AAAA,MACT;AACO,aAAA;AAAA,IACT;AAAA,EACF;AACO,SAAA;AACT;AChGgB,SAAA,YAAY,KAAa,MAAc;AACrD,SAAO,IAAI,MAAM,IAAI,EAAE,SAAS;AAClC;ACJA,SAAS,SAAS,OAAe;AAC/B,SAAO,KAAK;AAAA,IACV,iBAAiB,MAAM,MAAM,GAAG,EAAE,CAAC,EAAE,QAAQ,KAAK,GAAG,EAAE,QAAQ,KAAK,GAAG,CAAC;AAAA,EAAA;AAE5E;AACA,SAAS,iBAAiB,KAAa;AAC9B,SAAA;AAAA,IACL,MAAM,UAAU,IACb;AAAA,MACC,KAAK,GAAG;AAAA,MACR,CAAC,MAAM,OAAO,OAAO,EAAE,WAAW,CAAC,EAAE,SAAS,EAAE,GAAG,MAAM,EAAE;AAAA,IAAA,EAE5D,KAAK,EAAE;AAAA,EAAA;AAEd;AAEA,SAAS,gBACP,2CACA,WACA;AACA,QAAM,yBAAwB,oBAAI,KAAK,GAAE,YAAY;AACrD,SAAO,KAAK;AAAA,IACV,YACE,4CACA;AAAA,EAAA;AAEN;AAEA,SAAS,cAAc,QAAuB;AAC5C,MAAI,CAAC,QAAQ;AACJ,WAAA;AAAA,EACT;AACA,SAAO,gBAAgB,GAAG,OAAO,SAAS,IAAI;AAChD;AAEA,MAAM,sBAAsB,CAAC,UAAmB;AAC1C,MAAA;AACF,QAAI,CAAC,OAAO;AACH,aAAA;AAAA,IACT;AACA,QAAI,YAAY,OAAO,GAAG,MAAM,GAAG;AACjC,aAAO,SAAS,KAAK;AAAA,IAAA,OAChB;AACE,aAAA;AAAA,IACT;AAAA,WACO,GAAG;AACV,YAAQ,KAAK,CAAC;AAAA,EAChB;AACO,SAAA;AACT;AAIA,MAAM,oBAAoB,CACxB,QACA,OACA,4BACyC;AACzC,MAAI,OAAO,gBAAgB;AACzB,UAAM,iBAAiB,OAAO;AAE1B,QAAA,wBAAwB,WAAW,eAAe,KAAK;AACzD,aAAO,EAAE,SAAS,OAAO,QAAQ,wBAAwB;AAAA,IAC3D;AAMA,UAAM,yBAAwB,oBAAI,KAAK,GAAE,YAAY;AACrD,QAAI,eAAe,OAAO,eAAe,MAAM,uBAAuB;AACpE,aAAO,EAAE,SAAS,OAAO,QAAQ,gBAAgB;AAAA,IACnD;AAEM,UAAA,kBAAkB,KAAK,KAAK,KAAK;AACvC,QACE,eAAe,OACf,eAAe,MAAM,kBAAkB,uBACvC;AACA,aAAO,EAAE,SAAS,OAAO,QAAQ,mCAAmC;AAAA,IACtE;AAEA,QAAI,SAAS,eAAe,SAAS,eAAe,UAAU,OAAO;AACnE,aAAO,EAAE,SAAS,OAAO,QAAQ,uBAAuB;AAAA,IAC1D;AAAA,EACF;AACA,SAAO,EAAE,SAAS,MAAM,QAAQ,GAAG;AACrC;AAEA,SAAS,YAAY,QAAgB,wBAAoC,mBAA2B;AAC9F,MAAA,CAAC,OAAO,WAAW;AACrB,UAAM,yBAAwB,oBAAI,KAAK,GAAE,YAAY;AACrD,WAAO,YAAY;AAAA,EACrB;AAEM,QAAA,qBAAqB,oBAAoB,OAAO,YAAY;AAClE,QAAM,eAAe;AAAA,IACnB,GAAG;AAAA,IACH;AAAA,EAAA;AAEF,MAAI,uBAAuB,iBAAiB;AAC7B,iBAAA,eAAe,MAAM,eAAe,MAAM;AAAA,EACzD;AACA,SAAO,qBAAqB;AAE5B,MAAI,kBAAkB;AACtB,MAAI,OAAO,UAAU;AACD,sBAAA,oBAAoB,OAAO,QAAQ;AAC9C,WAAA,iBAAiB,EAAC,GAAG;AAC5B,QAAI,gBAAgB,SAAS,uBAAuB,SAAS,MAAM;AACjE,YAAM,WACF,MAAM,cAAc,MAAM,uBAAuB;AACrD,sBAAgB,QAAQ;AAAA,IAC1B;AACA,iBAAa,iBAAiB;AAAA,EAChC;AACA,MAAI,OAAO,eAAe;AACX,iBAAA,gBACT,MAAM,gBAAgB,MAAM;AAAA,EAClC;AAEA,QAAM,mBACF,mBAAmB,gBAAgB,MAC7B,gBAAgB,MAChB,OAAO;AACX,QAAA,uBACF,sBAAsB,mBAAmB,MACnC,mBAAmB,MACnB,OAAO,YAAY,OAAO;AAEhC,MAAA;AACE,QAAA,iBACF,uBAAuB,kBACzB;AACE,MAAA,mBAAmB,eAAe,sBAAsB;AAC9C,gBAAA;AAAA,EAAA,WACH,mBAAmB,eAAe,kBAAkB;AACjD,gBAAA;AAAA,EAAA,OACP;AAED,gBAAA,mBAAmB,uBACb,mBACA;AAAA,EACZ;AACA,eAAa,YAAY;AAEzB,SAAO,YAAY;AACnB,QAAM,QAAQ,uBAAuB,QAC/B,uBAAuB,MAAM,QAC7B;AACA,QAAA,EAAC,SAAS,OAAA,IAAU;AAAA,IACtB;AAAA,IACA;AAAA,IACA,uBAAuB;AAAA,EAAA;AAE3B,MAAI,CAAC,SAAS;AACN,UAAA,MAAM,wCAAwC,MAAM,EAAE;AAAA,EAC9D;AAII,MAAA,uBAAuB,UAAU,QACjC,mBAAmB,uBAAuB,UAC1C,EAAE,mBAAmB,SACvB;AACM,UAAA,eAAe,uBAAuB,OAAO;AAEnD,2BAAuB,SAAS;AAAA,MAC9B,GAAG;AAAA,MACH,eAAe;AAAA,IAAA;AAAA,EACjB,OACK;AACL,2BAAuB,SAAS;AAAA,EAClC;AAEA,yBAAuB,SAAS;AACzB,SAAA;AACT;AAEA,SAAS,WAAW,wBAAoC;AACtD,QAAM,oBAAoB,uBAAuB;AACjD,SAAO,CAAC,aAAuB;AACzB,QAAA,SAAS,WAAW,KAAK;AACpB,aAAA;AAAA,IACT;AACA,WAAO,SAAS,KAAA,EAAO,KAAe,CAAC,WAAmB;AACxD,YAAM,eAAe,YAAY,QAAQ,wBAAwB,iBAAiB;AAC5E,YAAA,OAAO,KAAK,UAAU,YAAY;AACjC,aAAA,IAAI,SAAS,MAAM,QAAQ;AAAA,IAAA,CACnC;AAAA,EAAA;AAEL;ACjMA,SAAS,iBAAiB,SAAkB;AAC1C,QAAM,aAAqC,CAAA;AAChC,aAAA,OAAQ,QAAyB,QAAQ;AAC9C,QAAA,QAAQ,IAAI,GAAG,GAAG;AACpB,iBAAW,GAAG,IAAI,QAAQ,IAAI,GAAG;AAAA,IACnC;AAAA,EACF;AACO,SAAA;AACT;ACVA,MAAM,QAAQ,CAAC,OAAe,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,EAAE,CAAC;ACE9D,SAAA,oBAAoB,cAAqB,iBAA+B;AACpF,QAAM,QAAQ;AACd,SAAO,aAAa,QAAQ,OAAO,iBAAiB,eAAe,EAAE;AACzE;ACeA,MAAM,QAAQ;AAId,MAAM,cAAc,cAAc;AAElC,MAAM,KAAK,KAAK,OAAU,oBAAA,QAAO,YAAY,GAAI,EAAE;AAEnD,MAAM,wBAAwB;AAC9B,MAAM,gBAAgB,CAAC,UAA2B;AACxC,UAAA,IAAI,kDAAkD,EAAE;AAC1D,QAAA,UAAU,MAAM,YAAa,CAAA;AACrC;AAEA,MAAM,iBAAiB,CAAC,UAA2B;AACzC,UAAA,IAAI,kDAAkD,EAAE;AAChE,QAAM,UAAU,MAAM,QAAQ,MAAO,CAAA;AACvC;AAEA,IAAI,wCAAuD;AAC3D,MAAM,WAAqB;AAAA,EACzB,SAAS;AAAA,IACP,mBAAmB;AAAA,IACnB,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,OAAO;AAAA,IACP,cAAc;AAAA,IACd,OAAO;AAAA,IACP,yBAAyB;AAAA,IACzB,iBAAiB;AAAA,EACnB;AACF;AAEA,MAAM,mCAAmC,CAACD,WAAoB,QAAgB;AAC5E,QAAM,YAA0B,CAAA;AAChC,aAAW,CAAG,EAAA,KAAK,KAAK,OAAO,QAAoBA,SAAQ,GAAG;AAE1D,QAAA,MAAM,2BAA2B,QACjC,IAAI,WAAW,MAAM,wBAAwB,aAAa,GAC1D;AACA,gBAAU,KAAK,KAAK;AAAA,IAEpB,WAAA,MAAM,2BAA2B,QACjC,MAAM,wBAAwB,sBAC9B,IAAI,WAAW,MAAM,wBAAwB,kBAAkB,GAC/D;AACA,gBAAU,KAAK,KAAK;AAAA,IACtB;AAAA,EACF;AACO,SAAA;AACT;AAEA,MAAM,iBAAiB,OAAO,UAAsB;AAClD,QAAM,kBAAkB,MAAM;AAC9B,QAAM,gBAAgB,gBAAgB,QAAQ,IAAI,cAAc;AAChE,QAAM,OAAO,EAAE,QAAQ,KAAK,YAAY,sBAAsB;AAC9D,QAAM,WAAW,IAAI,SAAS,MAAM,IAAI;AACxC,MAAI,CAAC,eAAe;AAClB,UAAM,qBAAqB,IAAI,IAAI,gBAAgB,GAAG;AACtD,UAAM,kBAAkB,OAAO,mBAAmB,aAAa,IAAI,iBAAiB,CAAC,KAAK;AAC1F,aAAS,IAAI,GAAG,IAAI,iBAAiB,KAAK;AAClC,YAAA,MAAM,MAAO,KAAK,MAAM,KAAK,OAAO,IAAI,GAAI,CAAC;AACnD,YAAM,QAAQ,MAAM,OAAO,KAAK,kBAAkB;AAClD,YAAM,MAAM,IAAI,MAAM,SAAS,SAAS,OAAO;AAAA,IACjD;AAAA,EACF;AACO,SAAA;AACT;AAEA,MAAM,cAAc,OAAO,UAAsB;AAC/C,QAAM,kBAAkB,MAAM;AAC9B,QAAM,MAAM,gBAAgB;AAC5B,MAAI,gBAAgB,IAAI,SAAS,qBAAqB,GAAG;AACjD,UAAA,YAAY,eAAe,KAAK,CAAC;AACvC;AAAA,EACF;AAEA,QAAM,uCAAuC;AAAA,IAC3C;AAAA,IACA,gBAAgB;AAAA,IAChB;AAAA,EAAA;AAEF,MACE,wCACA,qCAAqC,UACrC,qCAAqC,OAAO,cAC5C;AACA,WACE,qCAAqC,UACrC,CAAC,cAAc,qCAAqC,MAAM,GAC1D;AACA,YAAM,MAAM,GAAG;AAAA,IACjB;AACA,UAAM,aACJ,gBAAgB,QAAQ,aACpB,IAAI,QAAQ,iBAAiB;AAAA,MAC3B,SAAS;AAAA,QACP,GAAG,iBAAiB,gBAAgB,OAAO;AAAA,QAC3C,eACE,YACA,qCAAqC,OAAO;AAAA,MAChD;AAAA,IAAA,CACD,IACD,IAAI,QAAQ,iBAAiB;AAAA,MAC3B,SAAS;AAAA,QACP,GAAG,iBAAiB,gBAAgB,OAAO;AAAA,QAC3C,eACE,YACA,qCAAqC,OAAO;AAAA,MAChD;AAAA,MACA,MACE,qCAAqC,kBACrC,8CACE,SACA,gBAAgB;AAAA,IAAA,CACrB;AAGP,UAAM,UAAU,MAAM,YAAY,MAAM,UAAU,CAAC,CAAC;AAEpD;AAAA,EACF;AAEI,MAAA,MAAM,QAAQ,WAAW,QAAQ;AACnC;AAAA,EACF;AAEA,MAAI,kBAAqC;AACzC,QAAM,mBAAmB;AAAA,IACvB;AAAA,IACA,gBAAgB;AAAA,EAAA;AAElB,QAAM,iBAAiB,iBAAiB;AACxC,MAAI,iBAAiB,GAAG;AACtB,UAAM,aAAa,IAAI,QAAkB,CAAC,SAAS,WAAW;AACtD,YAAA,gBAAgB,gBAAgB;AACtC,YAAM,WAAW,cAAc,KAAO,EAAA,KAAK,CAAC,eAAe;AAEvD,YAAA,WAAW,SAAS,MAAM,aAAa,KACvC,WAAW,SAAS,MAAM,YAAY,GACtC;AACA,cAAI,UAAU;AACd,mBAAS,IAAI,GAAG,IAAI,gBAAgB,KAAK;AACjC,kBAAA,YAAY,iBAAiB,CAAC;AAEhC,gBAAA,aAAa,UAAU,UAAU,MAAM;AACzC,oBAAM,kBACJ,MAAM,gBAAgB,MAAM,UAAU;AACpC,kBAAA,WAAW,SAAS,eAAe,GAAG;AACxC,0BAAU,QAAQ;AAAA,kBAChB;AAAA,kBACA,mBAAmB,UAAU,OAAO,aAAuB;AAAA,gBAAA;AAE3C,kCAAA;AAClB;AAAA,cACF;AACA,oBAAM,iBACJ,MAAM,eAAe,MAAM,UAAU;AACnC,kBAAA,WAAW,SAAS,cAAc,GAAG;AACvC,0BAAU,QAAQ;AAAA,kBAChB;AAAA,kBACA,mBAAmB,UAAU,OAAO,YAAY;AAAA,gBAAA;AAEhC,kCAAA;AAClB;AAAA,cACF;AAAA,YACF;AAAA,UACF;AACM,gBAAA,eAAe,MAAM,iBAAiB;AAAA,YAC1C,MAAM;AAAA,YACN,QAAQ,cAAc;AAAA,YACtB,SAAS;AAAA,cACP,GAAG,iBAAiB,gBAAgB,OAAO;AAAA,YAC7C;AAAA,YACA,MAAM,cAAc;AAAA,YACpB,OAAO,cAAc;AAAA,YACrB,UAAU,cAAc;AAAA,YACxB,UAAU,cAAc;AAAA,YACxB,aAAa,cAAc;AAAA,YAC3B,WAAW,cAAc;AAAA,UAAA,CAC1B;AAED,cACE,mBACA,gBAAgB,2BAA2B,QAC3C,gBAAgB,wBAAwB,sBACxC,IAAI;AAAA,YACF,gBAAgB,wBAAwB;AAAA,UAAA,GAE1C;AACO,mBAAA,aAAa,KAAK,OAAOE,cAAa;AACrC,oBAAA,OAAO,MAAMA,UAAS;AACrB,qBAAA,IAAI,SAAS,MAAMA,SAAQ;AAAA,YAAA,CACnC;AAAA,UACH;AACA,iBAAO,aAAa,KAAK,WAAW,eAA6B,CAAC;AAAA,QAElE,WAAA,WAAW,SAAS,gBAAgB,KACpC,uCACA;AACA,4BAAkB,SAAS,qCAAqC;AACxB,kDAAA;AACxC,cAAI,UAAU;AACV,cAAA,mBAAmB,gBAAgB,gBAAgB,MAAM;AACjD,sBAAA,oBAAoB,SAAS,gBAAgB,YAAY;AAAA,UACrE;AAEA,iBAAO,MAAM,iBAAiB;AAAA,YAC5B,MAAM;AAAA,YACN,QAAQ,cAAc;AAAA,YACtB,SAAS;AAAA,cACP,GAAG,iBAAiB,gBAAgB,OAAO;AAAA,YAC7C;AAAA,YACA,MAAM,cAAc;AAAA,YACpB,OAAO,cAAc;AAAA,YACrB,UAAU,cAAc;AAAA,YACxB,UAAU,cAAc;AAAA,YACxB,aAAa,cAAc;AAAA,YAC3B,WAAW,cAAc;AAAA,UAC1B,CAAA,EAAE,KAAK,WAAW,eAAe,CAAC;AAAA,QACrC;AACO,eAAA;AAAA,MAAA,CACR;AAEE,eAAA,KAAK,CAAC,MAAM;AACX,YAAI,MAAM,QAAW;AACnB,kBAAQ,CAAC;AAAA,QAAA,OACJ;AACL,kBAAQ,IAAI,mBAAmB;AACxB,iBAAA,IAAI,MAAM,wCAAwC,CAAC;AAAA,QAC5D;AAAA,MAAA,CACD,EACA,MAAM,CAAC,QAAQ;AACd,YAAI,QAAQ,QAAW;AACrB,iBAAO,GAAG;AAAA,QAAA,OACL;AACL,kBAAQ,IAAI,iBAAiB;AACtB,iBAAA,IAAI,MAAM,sCAAsC,CAAC;AAAA,QAC1D;AAAA,MAAA,CACD;AAAA,IAAA,CACJ;AAGD,UAAM,UAAU,MAAM,YAAY,UAAU,CAAC;AAAA,EAC/C;AACF;AAMA,MAAM,gCAA+D,CAAA;AAErE,MAAM,gBAAgB,CAAC,UAAkC;AACjD,QAAA,OAAO,MAAM,MAAM,CAAC;AAC1B,QAAM,OAAO,MAAM;AACnB,QAAM,oBAAoB,KAAK;AAC3B,MAAA,kBAAkB,SAAS,iBAAiB;AAChD,MAAG,kBAAiB,MAAK;AACvB,qBAAiB,CAAA;AAAA,EACnB;AACA,MAAI,CAAC,iBAAiB;AAEhB,QAAA,8BAA8B,iBAAiB,MAAM,QAAW;AAC9D,UAAA,gBAAgB,eAAe,iBAAiB;AACpD,oCAA8B,iBAAiB,IAAI,MAAM,QAAQ,aAAa,IAAI,QAAQ,cAAc;AAAA,IAC1G;AACA,aAAS,iBAAiB,IAAI;AAAA,MAC5B,QAAQ;AAAA,MACR,OAAO;AAAA,MACP,cAAc;AAAA,MACd,yBAAyB;AAAA,MACzB,mBAAmB;AAAA,MACnB,OAAO;AAAA,MACP,QAAQ;AAAA,MACR;AAAA,MACA,iBAAiB,CAAC,8BAA8B,iBAAiB;AAAA,IAAA;AAEnE,sBAAkB,SAAS,iBAAiB;AAExC,QAAA,CAAC,eAAe,iBAAiB,GAAG;AACvB,qBAAA,iBAAiB,IAAI;IACtC;AAAA,EACF;AAEA,UAAQ,KAAK,MAAM;AAAA,IACjB,KAAK;AACH,sBAAgB,SAAS;AACzB,sBAAgB,QAAQ;AACxB,sBAAgB,eAAe;AACf,sBAAA,SAAS,KAAK,KAAK;AAC9B,WAAA,YAAY,EAAE,kBAAA,CAAmB;AACtC;AAAA,IACF,KAAK,QAAQ;AACL,YAAA,0BAA0B,KAAK,KAAK;AACtC,UAAA,gBAAgB,eAAe,iBAAiB;AAC9C,YAAA,UAAU,WAAW,eAAe,MAAM;AAChD,UAAI,CAAC,QAAQ,KAAK,CAAC,MAAM,MAAM,oBAAoB,GAAG;AACpD;AAAA,UACE,wBAAwB;AAAA,UACxB,wBAAwB;AAAA,UACxB,wBAAwB;AAAA,UACxB,wBAAwB;AAAA,QAAA,EACxB,QAAQ,CAAC,QAAQ;AACjB,sBAAY,SAAS,GAAG;AAAA,QAAA,CACzB;AAAA,MACH;AACF,sBAAgB,0BAA0B;AACxB,sBAAA,oBAAoB,KAAK,KAAK;AACxC,YAAA,QAAQ,KAAK,KAAK;AAEtB,UAAA,UAAU,wBACV,UAAU,+BACV;AACwC,gDAAA;AAAA,MAAA,OACnC;AACmC,gDAAA;AAAA,MAC1C;AAEI,UAAA,CAAC,gBAAgB,QAAQ;AAC3B,aAAK,YAAY;AAAA,UACf,QAAQ;AAAA,UACR,QAAQ,gBAAgB;AAAA,UACxB;AAAA,QAAA,CACD;AAAA,MAAA,OACI;AACL,cAAM,SAAS;AAAA,UACb,GAAG,gBAAgB;AAAA,QAAA;AAErB,YAAG,gBAAgB,iBAAiB;AAC3B,iBAAA,eAAe,MAAM,eAAe,MAAM;AAAA,QACnD;AACA,YAAI,OAAO,eAAe;AACjB,iBAAA,gBAAgB,MAAM,gBAAgB,MAAM;AAAA,QACrD;AACA,YACE,OAAO,kBACP,OAAO,eAAe,SACtB,gBAAgB,SAAS,MACzB;AACA,iBAAO,eAAe,QACpB,MAAM,cAAc,MAAM;AAAA,QAC9B;AACA,aAAK,YAAY;AAAA,UACf;AAAA,UACA,QAAQ,gBAAgB;AAAA,UACxB;AAAA,QAAA,CACD;AAAA,MACH;AACA;AAAA,IACF;AAAA,IACA,KAAK;AACa,sBAAA,QAAQ,KAAK,KAAK;AAC7B,WAAA,YAAY,EAAE,kBAAA,CAAmB;AACtC;AAAA,IACF,KAAK,YAAY;AACf,YAAM,QAAQ,gBAAgB;AAC9B,WAAK,YAAY,EAAE,mBAAmB,MAAO,CAAA;AAC7C;AAAA,IACF;AAAA,IACA,KAAK;AACa,sBAAA,eAAe,KAAK,KAAK;AACpC,WAAA,YAAY,EAAE,kBAAA,CAAmB;AACtC;AAAA,IACF,KAAK,mBAAmB;AACtB,WAAK,YAAY;AAAA,QACf;AAAA,QACA,cAAc,gBAAgB,gBAAgB,OAAO,MAAM,gBAAgB,MAAM,oBAAoB;AAAA,MAAA,CACtG;AACD;AAAA,IACF;AAAA,IACA,KAAK;AACa,sBAAA,eAAe,KAAK,KAAK;AACpC,WAAA,YAAY,EAAE,kBAAA,CAAmB;AACtC;AAAA,IACF,KAAK,mBAAmB;AACtB,YAAM,eAAe,gBAAgB;AACrC,WAAK,YAAY,EAAE,mBAAmB,aAAc,CAAA;AACpD;AAAA,IACF;AAAA,IACA,KAAK,YAAY;AACX,UAAA,QAAQ,KAAK,KAAK;AACtB,UAAI,OAAO;AACT,wBAAgB,QAAQ;AAAA,MAC1B;AACK,WAAA,YAAY,EAAC,kBAAA,CAAkB;AACpC;AAAA,IACF;AAAA,IACA,KAAK,YAAY;AACT,YAAA,WAAW,MAAM,cAAc,MAAM;AACrC,YAAA,QAAQ,gBAAgB,QAAQ,WAAW;AACjD,WAAK,YAAY,EAAC,mBAAmB,MAAM,CAAA;AAC3C;AAAA,IACF;AAAA,IACA;AACE,sBAAgB,QAAQ,EAAE,GAAG,KAAK,KAAK;AAClC,WAAA,YAAY,EAAE,kBAAA,CAAmB;AAAA,EAC1C;AACF;AAEA,MAAM,iBAAiB,WAAW,aAAa;AAC/C,MAAM,iBAAiB,YAAY,cAAc;AACjD,MAAM,iBAAiB,SAAS,WAAW;AAC3C,MAAM,iBAAiB,WAAW,aAAa;"} \ No newline at end of file diff --git a/examples/react-oidc-demo/public/OidcTrustedDomains.js b/examples/react-oidc-demo/public/OidcTrustedDomains.js index c1b0f6fc3..a6fc4a35a 100644 --- a/examples/react-oidc-demo/public/OidcTrustedDomains.js +++ b/examples/react-oidc-demo/public/OidcTrustedDomains.js @@ -4,21 +4,41 @@ // Domains used by OIDC server must be also declared here // eslint-disable-next-line @typescript-eslint/no-unused-vars const trustedDomains = { - default: ['https://demo.duendesoftware.com', 'https://kdhttps.auth0.com'], - config_classic: ['https://demo.duendesoftware.com'], - config_without_silent_login: ['https://demo.duendesoftware.com'], - config_without_refresh_token: ['https://demo.duendesoftware.com'], - config_without_refresh_token_silent_login: ['https://demo.duendesoftware.com'], - config_google: ['https://oauth2.googleapis.com', 'https://openidconnect.googleapis.com'], - config_with_hash: ['https://demo.duendesoftware.com'], + default: ['https://demo.duendesoftware.com', 'https://kdhttps.auth0.com'], + config_classic: ['https://demo.duendesoftware.com'], + config_with_monitor_session: ['https://demo.duendesoftware.com'], + config_without_silent_login: ['https://demo.duendesoftware.com'], + config_without_refresh_token: ['https://demo.duendesoftware.com'], + config_without_refresh_token_silent_login: ['https://demo.duendesoftware.com'], + config_google: [ + 'https://oauth2.googleapis.com', + 'https://openidconnect.googleapis.com', + 'https://accounts.google.com', + ], + config_with_hash: ['https://demo.duendesoftware.com'], }; // Service worker will continue to give access token to the JavaScript client // Ideal to hide refresh token from client JavaScript, but to retrieve access_token for some // scenarios which require it. For example, to send it via websocket connection. -trustedDomains.config_show_access_token = { domains: ["https://demo.duendesoftware.com"], showAccessToken: true }; +trustedDomains.config_show_access_token = { + domains: ['https://demo.duendesoftware.com'], + showAccessToken: true, +}; // This example defines domains used by OIDC server separately from domains to which access tokens will be injected. trustedDomains.config_separate_oidc_access_token_domains = { - oidcDomains: ["https://demo.duendesoftware.com"], - accessTokenDomains: ["https://myapi"] + oidcDomains: ['https://demo.duendesoftware.com'], + accessTokenDomains: ['https://myapi'], +}; + +trustedDomains.config_with_dpop = { + domains: ['https://demo.duendesoftware.com'], + demonstratingProofOfPossession: true, + demonstratingProofOfPossessionOnlyWhenDpopHeaderPresent: false, + allowMultiTabLogin: true, +}; + +trustedDomains.config_multi_tab_login = { + domains: ['https://demo.duendesoftware.com'], + allowMultiTabLogin: true, }; //# sourceMappingURL=OidcTrustedDomains.js.map \ No newline at end of file diff --git a/examples/react-oidc-demo/public/package.json b/examples/react-oidc-demo/public/package.json index cf6f816bf..1ddfbbf0b 100644 --- a/examples/react-oidc-demo/public/package.json +++ b/examples/react-oidc-demo/public/package.json @@ -58,4 +58,4 @@ "last 1 safari version" ] } -} \ No newline at end of file +} diff --git a/examples/react-oidc-demo/public/staticwebapp.config.json b/examples/react-oidc-demo/public/staticwebapp.config.json index ba338eae6..c0be511eb 100644 --- a/examples/react-oidc-demo/public/staticwebapp.config.json +++ b/examples/react-oidc-demo/public/staticwebapp.config.json @@ -1,6 +1,15 @@ { - "navigationFallback": { - "rewrite": "index.html", - "exclude": ["*.{svg,png,jpg,gif}","*.{css,scss}","*.js"] - } -} \ No newline at end of file + "navigationFallback": { + "rewrite": "index.html", + "exclude": ["*.{svg,png,jpg,gif}", "*.{css,scss}", "*.js"] + }, + "globalHeaders": { + "content-security-policy": "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; connect-src 'self' https://demo.duendesoftware.com; media-src 'self'; object-src 'none'; frame-src 'self' https://demo.duendesoftware.com; base-uri 'self'; form-action 'self'; frame-ancestors 'self' https://demo.duendesoftware.com; block-all-mixed-content; upgrade-insecure-requests;", + "Access-Control-Allow-Origin": "*", + "X-Frame-Options": "SAMEORIGIN", + "X-Permitted-Cross-Domain-Policies": "none", + "Referrer-Policy": "no-referrer", + "X-Content-Type-Options": "nosniff", + "Permissions-Policy": "autoplay=()" + } +} diff --git a/examples/react-oidc-demo/public/tsconfig.eslint.json b/examples/react-oidc-demo/public/tsconfig.eslint.json index e9041fd6b..b90fc83e0 100644 --- a/examples/react-oidc-demo/public/tsconfig.eslint.json +++ b/examples/react-oidc-demo/public/tsconfig.eslint.json @@ -1,4 +1,4 @@ { "extends": "./tsconfig.json", "include": ["src"] -} \ No newline at end of file +} diff --git a/examples/react-oidc-demo/public/vite.config.js b/examples/react-oidc-demo/public/vite.config.js index 13467b083..62d54db3b 100644 --- a/examples/react-oidc-demo/public/vite.config.js +++ b/examples/react-oidc-demo/public/vite.config.js @@ -3,13 +3,15 @@ import { defineConfig } from 'vite'; import dts from 'vite-plugin-dts'; export default defineConfig({ - plugins: [dts({ - insertTypesEntry: true, - })], + plugins: [ + dts({ + insertTypesEntry: true, + }), + ], test: { coverage: { - provider: 'c8' - } + provider: 'c8', + }, }, build: { minify: false, //default esbuild @@ -29,8 +31,7 @@ export default defineConfig({ output: { // Provide global variables to use in the UMD build // for externalized deps - globals: { - }, + globals: {}, }, }, }, diff --git a/examples/react-oidc-demo/src/App.spec.tsx b/examples/react-oidc-demo/src/App.spec.tsx index 3b3523295..ee2438010 100644 --- a/examples/react-oidc-demo/src/App.spec.tsx +++ b/examples/react-oidc-demo/src/App.spec.tsx @@ -1,64 +1,130 @@ -import React from 'react' -import {rest} from 'msw' -import {setupServer} from 'msw/node' -import {render, fireEvent, waitFor, screen} from '@testing-library/react' -import '@testing-library/jest-dom' -import App from "./App"; -import {sleepAsync} from "./oidc/vanilla/initWorker"; -import { describe, it, expect } from 'vitest'; - +import '@testing-library/jest-dom'; + +import { fireEvent, render, screen } from '@testing-library/react'; +import { rest } from 'msw'; +import { setupServer } from 'msw/node'; +import { describe, expect, it } from 'vitest'; + +import App from './App'; +import { sleepAsync } from './utils/sleep'; + const server = setupServer( - rest.get('http://api/.well-known/openid-configuration', (req, res, ctx) => { - return res( ctx.status(200),ctx.json({ - "issuer":"https://demo.identityserver.io", - "jwks_uri":"https://demo.identityserver.io/.well-known/openid-configuration/jwks", - "authorization_endpoint":"https://demo.identityserver.io/connect/authorize", - "token_endpoint":"https://demo.identityserver.io/connect/token", - "userinfo_endpoint":"https://demo.identityserver.io/connect/userinfo", - "end_session_endpoint":"https://demo.identityserver.io/connect/endsession", - "check_session_iframe":"https://demo.identityserver.io/connect/checksession", - "revocation_endpoint":"https://demo.identityserver.io/connect/revocation", - "introspection_endpoint":"https://demo.identityserver.io/connect/introspect", - "device_authorization_endpoint":"https://demo.identityserver.io/connect/deviceauthorization","frontchannel_logout_supported":true,"frontchannel_logout_session_supported":true,"backchannel_logout_supported":true,"backchannel_logout_session_supported":true,"scopes_supported":["openid","profile","email","api","api.scope1","api.scope2","scope2","policyserver.runtime","policyserver.management","offline_access"],"claims_supported":["sub","name","family_name","given_name","middle_name","nickname","preferred_username","profile","picture","website","gender","birthdate","zoneinfo","locale","updated_at","email","email_verified"],"grant_types_supported":["authorization_code","client_credentials","refresh_token","implicit","password","urn:ietf:params:oauth:grant-type:device_code"],"response_types_supported":["code","token","id_token","id_token token","code id_token","code token","code id_token token"],"response_modes_supported":["form_post","query","fragment"],"token_endpoint_auth_methods_supported":["client_secret_basic","client_secret_post"],"id_token_signing_alg_values_supported":["RS256"],"subject_types_supported":["public"],"code_challenge_methods_supported":["plain","S256"],"request_parameter_supported":true})) - }), -) + rest.get('http://api/.well-known/openid-configuration', (req, res, ctx) => { + return res( + ctx.status(200), + ctx.json({ + issuer: 'https://demo.identityserver.io', + jwks_uri: 'https://demo.identityserver.io/.well-known/openid-configuration/jwks', + authorization_endpoint: 'https://demo.identityserver.io/connect/authorize', + token_endpoint: 'https://demo.identityserver.io/connect/token', + userinfo_endpoint: 'https://demo.identityserver.io/connect/userinfo', + end_session_endpoint: 'https://demo.identityserver.io/connect/endsession', + check_session_iframe: 'https://demo.identityserver.io/connect/checksession', + revocation_endpoint: 'https://demo.identityserver.io/connect/revocation', + introspection_endpoint: 'https://demo.identityserver.io/connect/introspect', + device_authorization_endpoint: 'https://demo.identityserver.io/connect/deviceauthorization', + frontchannel_logout_supported: true, + frontchannel_logout_session_supported: true, + backchannel_logout_supported: true, + backchannel_logout_session_supported: true, + scopes_supported: [ + 'openid', + 'profile', + 'email', + 'api', + 'api.scope1', + 'api.scope2', + 'scope2', + 'policyserver.runtime', + 'policyserver.management', + 'offline_access', + ], + claims_supported: [ + 'sub', + 'name', + 'family_name', + 'given_name', + 'middle_name', + 'nickname', + 'preferred_username', + 'profile', + 'picture', + 'website', + 'gender', + 'birthdate', + 'zoneinfo', + 'locale', + 'updated_at', + 'email', + 'email_verified', + ], + grant_types_supported: [ + 'authorization_code', + 'client_credentials', + 'refresh_token', + 'implicit', + 'password', + 'urn:ietf:params:oauth:grant-type:device_code', + ], + response_types_supported: [ + 'code', + 'token', + 'id_token', + 'id_token token', + 'code id_token', + 'code token', + 'code id_token token', + ], + response_modes_supported: ['form_post', 'query', 'fragment'], + token_endpoint_auth_methods_supported: ['client_secret_basic', 'client_secret_post'], + id_token_signing_alg_values_supported: ['RS256'], + subject_types_supported: ['public'], + code_challenge_methods_supported: ['plain', 'S256'], + request_parameter_supported: true, + }), + ); + }), +); -// @ts-ignore -global.window["crypto"]={ - // @ts-ignore - getRandomValues:(buffer)=>{return ""}, - // @ts-ignore - subtle:{ - // @ts-ignore - digest:(algo, code) => {return Promise.resolve(new ArrayBuffer(32))}} -} -// @ts-ignore -const url = "http://dummy.com"; +global.window['crypto'] = { + // @ts-ignore + getRandomValues: () => { + return ''; + }, + // @ts-ignore + subtle: { + digest: () => { + return Promise.resolve(new ArrayBuffer(32)); + }, + }, +}; +const url = 'http://dummy.com'; Object.defineProperty(global.window, 'location', { - value: { - href: url - } + value: { + href: url, + }, }); -beforeAll(() => server.listen()) -afterEach(() => server.resetHandlers()) -afterAll(() => server.close()) +beforeAll(() => server.listen()); +afterEach(() => server.resetHandlers()); +afterAll(() => server.close()); describe('Authenticating test suite', () => { - it('Load home page then login should log', async () => { - - const configuration = { - client_id: 'interactive.public.short', - redirect_uri: 'http://localhost:4200/authentication/callback', - scope: 'openid profile email api offline_access', - authority: 'http://api', - refresh_time_before_tokens_expiration_in_second: 70, - }; - // @ts-ignore - const { getByText } = render(); - await waitFor(() => getByText('GitHub @axa-fr/react-oidc')); - fireEvent.click(screen.getByText('Login')); - await waitFor(() => getByText('Authentication in progress')); - await sleepAsync(4000); - expect(global.window.location.href).toBe("https://demo.duendesoftware.com/connect/authorize?client_id=interactive.public.short&redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Fauthentication%2Fcallback&scope=openid%20profile%20email%20api%20offline_access&response_type=code&youhou_demo=youhou&state=AAAAAAAAAAAAAAAA&nonce=AAAAAAAAAAAA&code_challenge=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA&code_challenge_method=S256"); - }); + it('Load home page then login should log', async () => { + const configuration = { + client_id: 'interactive.public.short', + redirect_uri: 'http://localhost:4200/authentication/callback', + scope: 'openid profile email api offline_access', + authority: 'http://api', + refresh_time_before_tokens_expiration_in_second: 70, + }; + // @ts-ignore + render(); + await screen.findByText('GitHub @axa-fr/react-oidc'); + fireEvent.click(screen.getByText('Login')); + await screen.findByText('Authentication in progress'); + await sleepAsync(4000); + expect(global.window.location.href).toBe( + 'https://demo.duendesoftware.com/connect/authorize?client_id=interactive.public.short&redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Fauthentication%2Fcallback&scope=openid%20profile%20email%20api%20offline_access&response_type=code&youhou_demo=youhou&state=AAAAAAAAAAAAAAAA&nonce=AAAAAAAAAAAA&code_challenge=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA&code_challenge_method=S256', + ); + }); }); diff --git a/examples/react-oidc-demo/src/App.tsx b/examples/react-oidc-demo/src/App.tsx index 62d6615d5..5f3d32335 100644 --- a/examples/react-oidc-demo/src/App.tsx +++ b/examples/react-oidc-demo/src/App.tsx @@ -1,105 +1,138 @@ +import { OidcProvider, withOidcSecure } from '@axa-fr/react-oidc'; import React, { useReducer } from 'react'; import { BrowserRouter, NavLink, Route, Routes } from 'react-router-dom'; +import CodeExecutor from './CodeExecutor'; import { configurationIdentityServer } from './configurations.js'; import { FetchUserHoc, FetchUserHook } from './FetchUser.js'; import { Home } from './Home.js'; import { MultiAuthContainer } from './MultiAuth.js'; -import { OidcProvider, withOidcSecure } from '@axa-fr/react-oidc'; import { Profile, SecureProfile } from './Profile.js'; const OidcSecureHoc = withOidcSecure(Profile); -const getRandomInt = (max) => { +const getRandomInt = max => { return Math.floor(Math.random() * max); }; function reducer(state, action) { switch (action.type) { - case 'event': - { - const id = getRandomInt(9999999999999).toString(); - return [{ ...action.data, id, date: Date.now() }, ...state]; - } + case 'event': { + const id = getRandomInt(9999999999999).toString(); + return [{ ...action.data, id, date: Date.now() }, ...state]; + } default: throw new Error(); } } - function App() { - // eslint-disable-next-line @typescript-eslint/naming-convention const [show, setShow] = React.useState(false); const [events, dispatch] = useReducer(reducer, []); const onEvent = (configurationName, eventName, data) => { - // console.log(`oidc:${configurationName}:${eventName}`, data); + // console.log(`oidc:${configurationName}:${eventName}`, data); dispatch({ type: 'event', data: { name: `oidc:${configurationName}:${eventName}`, data } }); }; - return (<> + return ( + <> + + + - - - - -
- - } /> - } /> - } /> - } /> - } /> - } /> - } /> - -
+
+
-
-
-
+
-
+
Default configuration Events
{events.map(e => { const date = new Date(e.date); const dateFormated = `${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}`; - return

{dateFormated} {e.name}: { JSON.stringify(e.data)}

; + return ( +

+ {dateFormated} {e.name}: {JSON.stringify(e.data)} +

+ ); })}
-
+
+ + ); } diff --git a/examples/react-oidc-demo/src/CodeExecutor.tsx b/examples/react-oidc-demo/src/CodeExecutor.tsx new file mode 100644 index 000000000..1767b1df1 --- /dev/null +++ b/examples/react-oidc-demo/src/CodeExecutor.tsx @@ -0,0 +1,41 @@ +import React, { useState } from 'react'; + +const CodeExecutor: React.FC = () => { + const [code, setCode] = useState(''); + const [output, setOutput] = useState(''); + + const executeCode = () => { + try { + const result = eval(` + (function() { + ${code} + })() + `); + setOutput(String(result)); + } catch (error) { + setOutput(`Erreur : ${(error as Error).message}`); + } + }; + + return ( +
+

Execute your JavaScript Code

+ + +
+

Result :

+
{output}
+
+
+ ); +}; + +export default CodeExecutor; diff --git a/examples/react-oidc-demo/src/FetchUser.tsx b/examples/react-oidc-demo/src/FetchUser.tsx index e1e7fd920..ba250352d 100644 --- a/examples/react-oidc-demo/src/FetchUser.tsx +++ b/examples/react-oidc-demo/src/FetchUser.tsx @@ -1,52 +1,63 @@ -import React, { useEffect, useState } from 'react'; import { OidcSecure, useOidcFetch, withOidcFetch } from '@axa-fr/react-oidc'; +import React, { useEffect, useState } from 'react'; const DisplayUserInfo = ({ fetch }) => { - const [oidcUser, setOidcUser] = useState(null); - const [isLoading, setLoading] = useState(true); + const [oidcUser, setOidcUser] = useState(null); + const [isLoading, setLoading] = useState(true); - useEffect(() => { - const fetchUserInfoAsync = async () => { - const res = await fetch('https://demo.duendesoftware.com/connect/userinfo'); - if (res.status !== 200) { - return null; - } - return res.json(); - }; - let isMounted = true; - fetchUserInfoAsync().then((userInfo) => { - if (isMounted) { - setLoading(false); - setOidcUser(userInfo); - } - }); - return () => { - isMounted = false; - }; - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); + useEffect(() => { + const fetchUserInfoAsync = async () => { + const res = await fetch('https://demo.duendesoftware.com/connect/userinfo'); + if (res.status !== 200) { + return null; + } + return res.json(); + }; + let isMounted = true; + fetchUserInfoAsync().then(userInfo => { + if (isMounted) { + setLoading(false); + setOidcUser(userInfo); + } + }); + return () => { + isMounted = false; + }; + }, []); - if (isLoading) { - return <>Loading; - } + if (isLoading) { + return <>Loading; + } - return ( -
-
-
-
User information
- {oidcUser != null &&

{JSON.stringify(oidcUser)}

} -
-
+ return ( +
+
+
+
User information
+ {oidcUser != null &&

{JSON.stringify(oidcUser)}

}
- ); +
+
+ ); }; const UserInfoWithFetchHoc = withOidcFetch(fetch)(DisplayUserInfo); -export const FetchUserHoc = () => ; +export const FetchUserHoc = () => ( + + + +); -export const FetchUserHook = () => { - const { fetch } = useOidcFetch(); - return ; +export const FetchUserHook = (props: any) => { + const { fetch } = useOidcFetch( + window.fetch, + props.configurationName, + props.demonstratingProofOfPossession ?? false, + ); + return ( + + + + ); }; diff --git a/examples/react-oidc-demo/src/Home.tsx b/examples/react-oidc-demo/src/Home.tsx index 420695fa5..2b9d269c7 100644 --- a/examples/react-oidc-demo/src/Home.tsx +++ b/examples/react-oidc-demo/src/Home.tsx @@ -1,23 +1,81 @@ -import React from 'react'; - import { useOidc } from '@axa-fr/react-oidc'; +import React from 'react'; +import { useNavigate } from 'react-router-dom'; export const Home = () => { - const { login, logout, renewTokens, isAuthenticated } = useOidc(); + const { login, logout, renewTokens, isAuthenticated } = useOidc(); + const navigate = useNavigate(); + + const navigateProfile = () => { + navigate('/profile'); + }; - return ( -
-
-
-
Home
-

React Demo Application protected by OpenId Connect. More info on about oidc on GitHub @axa-fr/react-oidc

- {!isAuthenticated &&

} - {isAuthenticated &&

} - {isAuthenticated &&

} - {isAuthenticated &&

} - {isAuthenticated &&

} -
-
+ return ( +
+
+
+
Home
+

+ React Demo Application protected by OpenId Connect. More info on about oidc on{' '} + GitHub @axa-fr/react-oidc +

+ {!isAuthenticated && ( +

+ +

+ )} + {isAuthenticated && ( +

+ +

+ )} + {isAuthenticated && ( +

+ +

+ )} + {isAuthenticated && ( +

+ +

+ )} + {isAuthenticated && ( +

+ +

+ )} + {isAuthenticated && ( +

+ +

+ )} +

+ +

- ); +
+
+ ); }; diff --git a/examples/react-oidc-demo/src/MultiAuth.tsx b/examples/react-oidc-demo/src/MultiAuth.tsx index 85a88266c..1bf2550e2 100644 --- a/examples/react-oidc-demo/src/MultiAuth.tsx +++ b/examples/react-oidc-demo/src/MultiAuth.tsx @@ -1,7 +1,18 @@ +import { + Fetch, + OidcProvider, + useOidc, + useOidcAccessToken, + useOidcIdToken, +} from '@axa-fr/react-oidc'; import React, { useReducer, useState } from 'react'; -import { configurationGoogle, configurationIdentityServer, configurationIdentityServerWithHash } from './configurations'; -import { Fetch, OidcProvider, useOidc, useOidcAccessToken, useOidcIdToken } from '@axa-fr/react-oidc'; +import { + configurationGoogle, + configurationIdentityServer, + configurationIdentityServerWithHash, +} from './configurations'; +import { FetchUserHook } from './FetchUser'; import AuthenticatingError from './override/AuthenticateError.component'; import Authenticating from './override/Authenticating.component'; import { CallBackSuccess } from './override/Callback.component'; @@ -9,182 +20,280 @@ import Loading from './override/Loading.component'; import ServiceWorkerNotSupported from './override/ServiceWorkerNotSupported.component'; import SessionLost from './override/SessionLost.component'; -const fetchWithLogs = (fetch: Fetch) => async (...params: Parameters) => { +const fetchWithLogs = + (fetch: Fetch) => + async (...params: Parameters) => { const [url, options, ...rest] = params; console.log('fetchWithLogs', url, options, ...rest); return await fetch(url, options, ...rest); -}; + }; const MultiAuth = ({ configurationName, handleConfigurationChange }) => { - const { login, logout, isAuthenticated } = useOidc(configurationName); - const { isAuthenticated: isAuthenticatedDefault } = useOidc('default'); - const [fname, setFname] = useState(''); + const { login, logout, isAuthenticated } = useOidc(configurationName); + const { isAuthenticated: isAuthenticatedDefault } = useOidc('default'); + const [fname, setFname] = useState(''); - const handleChange = e => { - setFname(e.target.value); - }; - return ( -
-
-
-
Multiple Authentication
-
- -
-

React Demo Application protected by OpenId Connect with MultipleAuthentication. -
For example, config_1 can have other sensitive scope, config_2 does not ask for the "offline_access" so it does not retrieve the most sensitive token "refresh_token" for very sensitive operation, it retrive only access_token valid for a small amout of time.

- - {!isAuthenticated && } - {isAuthenticatedDefault && } - {isAuthenticated && } -
-
+ const handleChange = e => { + setFname(e.target.value); + }; + return ( +
+
+
+
Multiple Authentication
+
+ +
+

+ React Demo Application protected by OpenId Connect with MultipleAuthentication. +
+ For example, config_1 can have other sensitive scope, config_2 does not ask for the + "offline_access" so it does not retrieve the most sensitive token + "refresh_token" for very sensitive operation, it retrive only access_token + valid for a small amout of time. +

+ + {!isAuthenticated && ( + + )} + {isAuthenticatedDefault && ( + + )} + {isAuthenticated && ( + + )}
- ); +
+
+ ); }; if (!sessionStorage.configurationName) { - sessionStorage.configurationName = 'config_classic'; + sessionStorage.configurationName = 'config_classic'; } -const getRandomInt = (max) => { - return Math.floor(Math.random() * max); +const getRandomInt = max => { + return Math.floor(Math.random() * max); }; function reducer(state, action) { - switch (action.type) { - case 'event': - { - const id = getRandomInt(9999999999999).toString(); - return [{ ...action.data, id, date: Date.now() }, ...state]; - } - default: - throw new Error(); + switch (action.type) { + case 'event': { + const id = getRandomInt(9999999999999).toString(); + return [{ ...action.data, id, date: Date.now() }, ...state]; } + default: + throw new Error(); + } } export const MultiAuthContainer = () => { - const [isSessionLost, setIsSessionLost] = useState(false); - const [configurationName, setConfigurationName] = useState(sessionStorage.configurationName); - const [events, dispatch] = useReducer(reducer, []); - const callBack = window.location.origin + '/multi-auth/authentification/callback2'; - const silent_redirect_uri = window.location.origin + '/multi-auth/authentification/silent-callback2'; - const configurations = { - config_classic: { - ...configurationIdentityServer, - redirect_uri: callBack, - silent_redirect_uri, - scope: 'openid profile email api offline_access', - client_id: 'interactive.public.short', - }, - config_without_refresh_token: { - ...configurationIdentityServer, - redirect_uri: callBack, - silent_redirect_uri, - scope: 'openid profile email api', - }, - config_without_silent_login: { - ...configurationIdentityServer, - redirect_uri: callBack, - silent_redirect_uri: '', - scope: 'openid profile email api offline_access', - }, - config_without_refresh_token_silent_login: { - ...configurationIdentityServer, - redirect_uri: callBack, - silent_redirect_uri: '', - scope: 'openid profile email api', -}, - config_show_access_token: { - ...configurationIdentityServer, - redirect_uri: callBack, - silent_redirect_uri, - }, - config_google: { ...configurationGoogle }, - config_with_hash: { ...configurationIdentityServerWithHash }, - config_separate_oidc_access_token_domains: { - ...configurationIdentityServer, - redirect_uri: callBack, - silent_redirect_uri, - }, - }; - const handleConfigurationChange = (event) => { - const configurationName = event.target.value; - sessionStorage.configurationName = configurationName; - setConfigurationName(configurationName); - }; + const [isSessionLost, setIsSessionLost] = useState(false); + const [configurationName, setConfigurationName] = useState(sessionStorage.configurationName); + const [events, dispatch] = useReducer(reducer, []); + const callBack = window.location.origin + '/multi-auth/authentification/callback'; + const silent_redirect_uri = + window.location.origin + '/multi-auth/authentification/silent-callback'; + const configurations = { + config_classic: { + ...configurationIdentityServer, + redirect_uri: callBack, + silent_redirect_uri, + scope: 'openid profile email api offline_access', + client_id: 'interactive.public.short', + }, + config_without_refresh_token: { + ...configurationIdentityServer, + redirect_uri: callBack, + silent_redirect_uri, + scope: 'openid profile email api', + }, + config_without_silent_login: { + ...configurationIdentityServer, + redirect_uri: callBack, + silent_redirect_uri: '', + scope: 'openid profile email api offline_access', + }, + config_with_monitor_session: { + ...configurationIdentityServer, + redirect_uri: callBack, + silent_redirect_uri, + monitor_session: true, + }, + config_without_refresh_token_silent_login: { + ...configurationIdentityServer, + redirect_uri: callBack, + silent_redirect_uri: '', + scope: 'openid profile email api', + }, + config_show_access_token: { + ...configurationIdentityServer, + redirect_uri: callBack, + silent_redirect_uri, + }, + config_google: { ...configurationGoogle }, + config_with_hash: { ...configurationIdentityServerWithHash }, + config_separate_oidc_access_token_domains: { + ...configurationIdentityServer, + redirect_uri: callBack, + silent_redirect_uri, + }, + config_with_dpop: { + ...configurationIdentityServer, + redirect_uri: callBack, + silent_redirect_uri, + demonstrating_proof_of_possession: true, + /*demonstrating_proof_of_possession_configuration: { + importKeyAlgorithm: { + name: "RSASSA-PKCS1-v1_5", + hash: { name: "SHA-256" }, //can be "SHA-1", "SHA-256", "SHA-384", or "SHA-512" + }, + signAlgorithm: { name: "RSASSA-PKCS1-v1_5" }, + generateKeyAlgorithm: { + name: "RSASSA-PKCS1-v1_5", + modulusLength: 2048, //can be 1024, 2048, or 4096 + publicExponent: new Uint8Array([0x01, 0x00, 0x01]), + hash: { name: "SHA-256" }, //can be "SHA-1", "SHA-256", "SHA-384", or "SHA-512" + }, + digestAlgorithm: { name: "SHA-256" }, + jwtHeaderAlgorithm: "RS256", + },*/ + }, + config_multi_tab_login: { + ...configurationIdentityServer, + redirect_uri: callBack, + silent_redirect_uri, + scope: 'openid profile email api offline_access', + client_id: 'interactive.public.short', + }, + }; + const handleConfigurationChange = event => { + const configurationName = event.target.value; + sessionStorage.configurationName = configurationName; + setConfigurationName(configurationName); + }; - const onSessionLost = () => { - setIsSessionLost(true); - }; - const onEvent = (configurationName, eventName, data) => { - // console.log(`oidc:${configurationName}:${eventName}`, data); - dispatch({ type: 'event', data: { name: `oidc:${configurationName}:${eventName}`, data } }); - }; + const onSessionLost = () => { + setIsSessionLost(true); + }; + const onEvent = (configurationName, eventName, data) => { + // console.log(`oidc:${configurationName}:${eventName}`, data); + dispatch({ type: 'event', data: { name: `oidc:${configurationName}:${eventName}`, data } }); + }; - return ( - <> - fetchWithLogs(fetch)} - > - { isSessionLost && } - - - -
-
-
-
Current configuration Events
-
- {events.map(e => { - const date = new Date(e.date); - const dateFormated = `${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}`; - return

{dateFormated} {e.name}: { JSON.stringify(e.data)}

; - })} -
-
-
+ return ( + <> + fetchWithLogs(fetch)} + > + {isSessionLost && } + + + +
+
+
+
Current configuration Events
+
+ {events.map(e => { + const date = new Date(e.date); + const dateFormated = `${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}`; + return ( +

+ {dateFormated} {e.name}: {JSON.stringify(e.data)} +

+ ); + })}
+
+
+
- ); + ); }; const DisplayAccessToken = ({ configurationName }) => { - const { accessToken, accessTokenPayload } = useOidcAccessToken(configurationName); - const { idTokenPayload } = useOidcIdToken(configurationName); - - if (!accessToken) { - return

you are not authentified

; - } - return ( -
-
-
Access Token
-

Please consider to configure the ServiceWorker in order to protect your application from XSRF attacks. "access_token" and "refresh_token" will never be accessible from your client side javascript.

- {

Access Token: {JSON.stringify(accessToken)}

} - {accessTokenPayload != null &&

Access Token Payload: {JSON.stringify(accessTokenPayload)}

} -
Id Token
- {idTokenPayload != null &&

Access Token Payload: {JSON.stringify(idTokenPayload)}

} -
+ const { accessToken, accessTokenPayload } = useOidcAccessToken(configurationName); + const { idTokenPayload } = useOidcIdToken(configurationName); + const demonstratingProofOfPossession = configurationName == 'config_with_dpop'; + if (!accessToken) { + return

you are not authentified

; + } + return ( + <> +
+
+
Access Token
+

+ Please consider to configure the ServiceWorker in order to protect your application from + XSRF attacks. "access_token" and "refresh_token" will never be + accessible from your client side javascript. +

+ {

Access Token: {JSON.stringify(accessToken)}

} + {accessTokenPayload != null && ( +

Access Token Payload: {JSON.stringify(accessTokenPayload)}

+ )} +
Id Token
+ {idTokenPayload != null && ( +

Access Token Payload: {JSON.stringify(idTokenPayload)}

+ )}
- ); +
+ + + ); }; diff --git a/examples/react-oidc-demo/src/Profile.tsx b/examples/react-oidc-demo/src/Profile.tsx index dd2cfcb95..0ac98e57d 100644 --- a/examples/react-oidc-demo/src/Profile.tsx +++ b/examples/react-oidc-demo/src/Profile.tsx @@ -1,77 +1,109 @@ +import { + OidcSecure, + type OidcUserInfo, + OidcUserStatus, + useOidc, + useOidcAccessToken, + useOidcIdToken, + useOidcUser, +} from '@axa-fr/react-oidc'; import React from 'react'; -import { type OidcUserInfo, OidcSecure, OidcUserStatus, useOidcAccessToken, useOidcIdToken, useOidcUser } from '@axa-fr/react-oidc'; -interface OidcUserRoleInfo extends OidcUserInfo{ - role?: string[]; +interface OidcUserRoleInfo extends OidcUserInfo { + role?: string[]; } const DisplayUserInfo = () => { - const { oidcUser, oidcUserLoadingState, reloadOidcUser } = useOidcUser(); + const { oidcUser, oidcUserLoadingState, reloadOidcUser } = useOidcUser(); - switch (oidcUserLoadingState) { - case OidcUserStatus.Loading: - return

User Information are loading

; - case OidcUserStatus.Unauthenticated: - return

you are not authenticated

; - case OidcUserStatus.LoadingError: - return

Fail to load user information

; - default: - return ( -
-
-
User information
-

{JSON.stringify(oidcUser)}

-

-
-
- ); - } + switch (oidcUserLoadingState) { + case OidcUserStatus.Loading: + return

User Information are loading

; + case OidcUserStatus.Unauthenticated: + return

you are not authenticated

; + case OidcUserStatus.LoadingError: + return

Fail to load user information

; + default: + return ( +
+
+
User information
+

{JSON.stringify(oidcUser)}

+

+ +

+
+
+ ); + } }; export const Profile = () => { - return ( -
- - - -
- ); + const { logout, isAuthenticated } = useOidc(); + return ( +
+ {isAuthenticated && ( +

+ +

+ )} + + + +
+ ); }; const DisplayAccessToken = () => { - const { accessToken, accessTokenPayload } = useOidcAccessToken(); + const { accessToken, accessTokenPayload } = useOidcAccessToken(); - if (!accessToken) { - return

you are not authenticated

; - } - return ( -
-
-
Access Token
-

Please consider to configure the ServiceWorker in order to protect your application from XSRF attacks. "access_token" and "refresh_token" will never be accessible from your client side javascript.

- {

Access Token: {JSON.stringify(accessToken)}

} - {accessTokenPayload != null &&

Access Token Payload: {JSON.stringify(accessTokenPayload)}

} -
-
- ); + if (!accessToken) { + return

you are not authenticated

; + } + return ( +
+
+
Access Token
+

+ Please consider to configure the ServiceWorker in order to protect your application from + XSRF attacks. "access_token" and "refresh_token" will never be + accessible from your client side javascript. +

+ {

Access Token: {JSON.stringify(accessToken)}

} + {accessTokenPayload != null && ( +

Access Token Payload: {JSON.stringify(accessTokenPayload)}

+ )} +
+
+ ); }; const DisplayIdToken = () => { - const { idToken, idTokenPayload } = useOidcIdToken(); + const { idToken, idTokenPayload } = useOidcIdToken(); - if (!idToken) { - return

you are not authenticated

; - } + if (!idToken) { + return

you are not authenticated

; + } - return ( -
-
-
ID Token
- {

IdToken: {JSON.stringify(idToken)}

} - {idTokenPayload != null &&

IdToken Payload: {JSON.stringify(idTokenPayload)}

} -
-
- ); + return ( +
+
+
ID Token
+ {

IdToken: {JSON.stringify(idToken)}

} + {idTokenPayload != null && ( +

IdToken Payload: {JSON.stringify(idTokenPayload)}

+ )} +
+
+ ); }; -export const SecureProfile = () => ; +export const SecureProfile = () => ( + + + +); diff --git a/examples/react-oidc-demo/src/configurations.ts b/examples/react-oidc-demo/src/configurations.ts index 99526d406..fed9140a9 100644 --- a/examples/react-oidc-demo/src/configurations.ts +++ b/examples/react-oidc-demo/src/configurations.ts @@ -1,91 +1,61 @@ -import { TokenRenewMode } from '@axa-fr/react-oidc'; +import { TokenAutomaticRenewMode, TokenRenewMode } from '@axa-fr/react-oidc'; export const configurationIdentityServer = { - client_id: 'interactive.public.short', - redirect_uri: window.location.origin + '/authentication/callback', - silent_redirect_uri: window.location.origin + '/authentication/silent-callback', - // silent_login_uri: window.location.origin + '/authentication/silent-login', - scope: 'openid profile email api offline_access', - authority: 'https://demo.duendesoftware.com', - // authority_time_cache_wellknowurl_in_second: 60* 60, - refresh_time_before_tokens_expiration_in_second: 40, - service_worker_relative_url: '/OidcServiceWorker.js', - service_worker_only: false, - // storage: localStorage, - // silent_login_timeout: 3333000 - // monitor_session: true, - extras: { youhou_demo: 'youhou' }, - token_renew_mode: TokenRenewMode.access_token_invalid, -}; - -export const configurationIdentityServer1 = { - client_id: 'balosar-blazo', - redirect_uri: window.location.origin + '/authentication/callback', - silent_redirect_uri: window.location.origin + '/authentication/silent-callback', - // silent_login_uri: window.location.origin + '/authentication/silent-login', - scope: 'openid offline_access profile email', - authority: 'https://localhost:44310', - // authority_time_cache_wellknowurl_in_second: 60* 60, - refresh_time_before_tokens_expiration_in_second: 40, - // service_worker_relative_url: '/OidcServiceWorker.js', - service_worker_only: false, - // storage: localStorage, - // silent_login_timeout: 3333000 - // monitor_session: true, - token_renew_mode: TokenRenewMode.access_token_invalid, + client_id: 'interactive.public.short', + redirect_uri: window.location.origin + '/authentication/callback', + silent_redirect_uri: window.location.origin + '/authentication/silent-callback', + scope: 'openid profile email api offline_access', + authority: 'https://demo.duendesoftware.com', + refresh_time_before_tokens_expiration_in_second: 40, + token_renew_mode: TokenRenewMode.access_token_invalid, + token_automatic_renew_mode: TokenAutomaticRenewMode.AutomaticBeforeTokenExpiration, + service_worker_relative_url: '/OidcServiceWorker.js', + service_worker_only: false, }; export const configurationIdentityServerWithHash = { - client_id: 'interactive.public.short', - redirect_uri: window.location.origin + '/multi-auth/authentification#authentication-callback', - silent_redirect_uri: window.location.origin + '/multi-auth/authentification#authentication-silent-callback', - silent_login_uri: window.location.origin + '/multi-auth/authentification#authentication-silent-login', - scope: 'openid profile email api offline_access', - authority: 'https://demo.duendesoftware.com', - refresh_time_before_tokens_expiration_in_second: 10, - service_worker_relative_url: '/OidcServiceWorker.js', - service_worker_only: false, + client_id: 'interactive.public.short', + redirect_uri: window.location.origin + '/multi-auth/authentification#authentication-callback', + silent_redirect_uri: + window.location.origin + '/multi-auth/authentification#authentication-silent-callback', + silent_login_uri: + window.location.origin + '/multi-auth/authentification#authentication-silent-login', + scope: 'openid profile email api offline_access', + authority: 'https://demo.duendesoftware.com', + refresh_time_before_tokens_expiration_in_second: 10, + service_worker_relative_url: '/OidcServiceWorker.js', + service_worker_only: false, }; export const configurationIdentityServerWithoutDiscovery = { - client_id: 'interactive.public.short', - redirect_uri: window.location.origin + '/authentication/callback', - silent_redirect_uri: window.location.origin + '/authentication/silent-callback', - scope: 'openid profile email api offline_access', - authority: 'https://demo.duendesoftware.com', - authority_configuration: { - authorization_endpoint: 'https://demo.duendesoftware.com/connect/authorize', - token_endpoint: 'https://demo.duendesoftware.com/connect/token', - userinfo_endpoint: 'https://demo.duendesoftware.com/connect/userinfo', - end_session_endpoint: 'https://demo.duendesoftware.com/connect/endsession', - revocation_endpoint: 'https://demo.duendesoftware.com/connect/revocation', - check_session_iframe: 'https://demo.duendesoftware.com/connect/checksession', - }, - refresh_time_before_tokens_expiration_in_second: 10, - service_worker_relative_url: '/OidcServiceWorker.js', - service_worker_only: false, -}; - -export const configurationAuth0 = { - client_id: 'xGZxEAJhzlkuQUlWl90y1ntIX-0UDWHx', - redirect_uri: window.location.origin + '/callback', - scope: 'openid profile email api offline_access', - authority: 'https://kdhttps.auth0.com', - refresh_time_before_tokens_expiration_in_second: 10, - service_worker_relative_url: '/OidcServiceWorker.js', - service_worker_only: false, + client_id: 'interactive.public.short', + redirect_uri: window.location.origin + '/authentication/callback', + silent_redirect_uri: window.location.origin + '/authentication/silent-callback', + scope: 'openid profile email api offline_access', + authority: 'https://demo.duendesoftware.com', + authority_configuration: { + authorization_endpoint: 'https://demo.duendesoftware.com/connect/authorize', + token_endpoint: 'https://demo.duendesoftware.com/connect/token', + userinfo_endpoint: 'https://demo.duendesoftware.com/connect/userinfo', + end_session_endpoint: 'https://demo.duendesoftware.com/connect/endsession', + revocation_endpoint: 'https://demo.duendesoftware.com/connect/revocation', + check_session_iframe: 'https://demo.duendesoftware.com/connect/checksession', + }, + refresh_time_before_tokens_expiration_in_second: 10, + service_worker_relative_url: '/OidcServiceWorker.js', + service_worker_only: false, }; export const configurationGoogle = { - client_id: '908893276222-f2drloh56ll0g99md38lv2k810d0nk0p.apps.googleusercontent.com', - redirect_uri: `${window.location.origin}/multi-auth/callback-google`, - silent_redirect_uri: window.location.origin + '/multi-auth/silent-callback-google', - scope: 'openid profile email', - authority: 'https://accounts.google.com/', - service_worker_relative_url: '/OidcServiceWorker.js', - service_worker_only: false, - token_request_extras: { - client_secret: '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', - }, - monitor_session: false, + client_id: '908893276222-f2drloh56ll0g99md38lv2k810d0nk0p.apps.googleusercontent.com', + redirect_uri: `${window.location.origin}/multi-auth/callback-google`, + silent_redirect_uri: window.location.origin + '/multi-auth/silent-callback-google', + scope: 'openid profile email', + authority: 'https://accounts.google.com/', + service_worker_relative_url: '/OidcServiceWorker.js', + service_worker_only: false, + token_request_extras: { + client_secret: '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', + }, + monitor_session: false, }; diff --git a/examples/react-oidc-demo/src/index.css b/examples/react-oidc-demo/src/index.css index ec2585e8c..89e57c7cc 100644 --- a/examples/react-oidc-demo/src/index.css +++ b/examples/react-oidc-demo/src/index.css @@ -1,13 +1,11 @@ body { margin: 0; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', - 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', - sans-serif; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', + 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } code { - font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', - monospace; + font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace; } diff --git a/examples/react-oidc-demo/src/index.tsx b/examples/react-oidc-demo/src/index.tsx index 2583fb626..103bf6bb2 100644 --- a/examples/react-oidc-demo/src/index.tsx +++ b/examples/react-oidc-demo/src/index.tsx @@ -8,4 +8,8 @@ import App from './App'; const container = document.getElementById('root'); const root = createRoot(container); -root.render(); +root.render( + + + , +); diff --git a/examples/react-oidc-demo/src/override/AuthenticateError.component.tsx b/examples/react-oidc-demo/src/override/AuthenticateError.component.tsx index 90678b533..abe4434e9 100644 --- a/examples/react-oidc-demo/src/override/AuthenticateError.component.tsx +++ b/examples/react-oidc-demo/src/override/AuthenticateError.component.tsx @@ -3,12 +3,12 @@ import { ComponentType } from 'react'; import { style } from './style.js'; const AuthenticatingError: ComponentType = ({ configurationName }) => ( -
-
-

Error authentication for {configurationName}

-

An error occurred during authentication.

-
-
+
+
+

Error authentication for {configurationName}

+

An error occurred during authentication.

+
+
); export default AuthenticatingError; diff --git a/examples/react-oidc-demo/src/override/Authenticating.component.tsx b/examples/react-oidc-demo/src/override/Authenticating.component.tsx index ff39ba67d..0341dfb4e 100644 --- a/examples/react-oidc-demo/src/override/Authenticating.component.tsx +++ b/examples/react-oidc-demo/src/override/Authenticating.component.tsx @@ -2,10 +2,12 @@ import { PropsWithChildren } from 'react'; import { style } from './style'; -const Authenticating : PropsWithChildren = ({ configurationName }) => ( -
+const Authenticating: PropsWithChildren = ({ configurationName }) => ( +
-

Authentication in progress for {configurationName}

+

+ Authentication in progress for {configurationName} +

You will be redirected to the login page.

diff --git a/examples/react-oidc-demo/src/override/Callback.component.tsx b/examples/react-oidc-demo/src/override/Callback.component.tsx index a814590f5..e2dd98838 100644 --- a/examples/react-oidc-demo/src/override/Callback.component.tsx +++ b/examples/react-oidc-demo/src/override/Callback.component.tsx @@ -2,13 +2,14 @@ import { ComponentType } from 'react'; import { style } from './style.js'; -export const CallBackSuccess: ComponentType = ({ configurationName }) => (<>
-
-

Authentication complete for {configurationName}

-

You will be redirected to your application.

-
-
-
-
- +export const CallBackSuccess: ComponentType = ({ configurationName }) => ( + <> +
+
+

Authentication complete for {configurationName}

+

You will be redirected to your application.

+
+
+
+ ); diff --git a/examples/react-oidc-demo/src/override/Loading.component.tsx b/examples/react-oidc-demo/src/override/Loading.component.tsx index f5e35dc5e..5e037ae7b 100644 --- a/examples/react-oidc-demo/src/override/Loading.component.tsx +++ b/examples/react-oidc-demo/src/override/Loading.component.tsx @@ -2,8 +2,8 @@ import { ComponentType } from 'react'; import { style } from './style.js'; -const Loading : ComponentType = ({ configurationName }) => ( - +const Loading: ComponentType = ({ configurationName }) => ( + Loading for {configurationName} ); diff --git a/examples/react-oidc-demo/src/override/ServiceWorkerNotSupported.component.tsx b/examples/react-oidc-demo/src/override/ServiceWorkerNotSupported.component.tsx index 1e4be2e1c..1a11d624d 100644 --- a/examples/react-oidc-demo/src/override/ServiceWorkerNotSupported.component.tsx +++ b/examples/react-oidc-demo/src/override/ServiceWorkerNotSupported.component.tsx @@ -2,11 +2,16 @@ import { ComponentType } from 'react'; import { style } from './style.js'; -const ServiceWorkerNotSupported : ComponentType = ({ configurationName }) => ( +const ServiceWorkerNotSupported: ComponentType = ({ configurationName }) => (
-

Unable to authenticate on this browser for {configurationName}

-

Your browser is not secure enough to make authentication work. Try updating your browser or use a newer browser.

+

+ Unable to authenticate on this browser for {configurationName} +

+

+ Your browser is not secure enough to make authentication work. Try updating your browser or + use a newer browser. +

); diff --git a/examples/react-oidc-demo/src/override/SessionLost.component.tsx b/examples/react-oidc-demo/src/override/SessionLost.component.tsx index b90000eab..1b932023e 100644 --- a/examples/react-oidc-demo/src/override/SessionLost.component.tsx +++ b/examples/react-oidc-demo/src/override/SessionLost.component.tsx @@ -1,22 +1,32 @@ +import { useOidc } from '@axa-fr/react-oidc'; import { ComponentType } from 'react'; +import { useNavigate } from 'react-router-dom'; -import { useOidc } from '@axa-fr/react-oidc'; import { style } from './style.js'; export const SessionLost: ComponentType = ({ configurationName }) => { - const { login } = useOidc(configurationName); + const { login } = useOidc(configurationName); + const navigate = useNavigate(); + const navigateProfile = () => { + navigate('/profile'); + }; - return ( -
-
-

Session timed out for {configurationName}

-

- Your session has expired. Please re-authenticate. -

- -
+ return ( +
+
+

Session timed out for {configurationName}

+

+ Your session has expired. Please re-authenticate. +

+ +
- ); +
+ ); }; export default SessionLost; diff --git a/examples/react-oidc-demo/src/utils/sleep.ts b/examples/react-oidc-demo/src/utils/sleep.ts new file mode 100644 index 000000000..529268d5c --- /dev/null +++ b/examples/react-oidc-demo/src/utils/sleep.ts @@ -0,0 +1,3 @@ +export const sleepAsync = milliseconds => { + return new Promise(resolve => setTimeout(resolve, milliseconds)); +}; diff --git a/examples/react-oidc-demo/tsconfig.eslint.json b/examples/react-oidc-demo/tsconfig.eslint.json index e9041fd6b..b90fc83e0 100644 --- a/examples/react-oidc-demo/tsconfig.eslint.json +++ b/examples/react-oidc-demo/tsconfig.eslint.json @@ -1,4 +1,4 @@ { "extends": "./tsconfig.json", "include": ["src"] -} \ No newline at end of file +} diff --git a/examples/react-oidc-demo/tsconfig.json b/examples/react-oidc-demo/tsconfig.json index cb88bdd34..60aae80a8 100644 --- a/examples/react-oidc-demo/tsconfig.json +++ b/examples/react-oidc-demo/tsconfig.json @@ -25,7 +25,5 @@ "esModuleInterop": true, "allowSyntheticDefaultImports": true }, - "exclude": [ - "node_modules", - ] -} \ No newline at end of file + "exclude": ["node_modules"] +} diff --git a/examples/react-oidc-demo/vite.config.js b/examples/react-oidc-demo/vite.config.js index e7b88685e..197494e22 100644 --- a/examples/react-oidc-demo/vite.config.js +++ b/examples/react-oidc-demo/vite.config.js @@ -9,5 +9,10 @@ export default defineConfig({ build: { sourcemap: true, minify: false, - } + }, + server: { + headers: { + //"Content-Security-Policy": "script-src 'unsafe-inline' https://www.google-analitics.com;", + }, + }, }); diff --git a/package.json b/package.json index 830679489..3c2dedc8f 100644 --- a/package.json +++ b/package.json @@ -6,9 +6,8 @@ "license": "MIT", "workspaces": [ "packages/oidc-service-worker", - "packages/vanilla", - "packages/react", - "packages/vanilla-demo" + "packages/oidc-client", + "packages/react-oidc" ], "keywords": [ "react", @@ -22,26 +21,36 @@ "preinstall": "npx only-allow pnpm", "format": "prettier --write --cache .", "lint": "eslint --cache .", + "lint-fix": "eslint --cache --fix .", "outdated": "pnpm outdated -r", "test": "pnpm run test --workspaces --if-present", "build": "pnpm -r --filter=./packages/* run build" }, "devDependencies": { - "eslint": "^8.45.0", - "eslint-define-config": "^1.21.0", - "eslint-plugin-import": "^2.27.5", - "eslint-plugin-jsx-a11y": "^6.7.1", - "eslint-plugin-n": "^16.0.1", - "eslint-plugin-react-hooks": "^4.6.0", - "eslint-plugin-regexp": "^1.15.0", - "eslint-plugin-testing-library": "^5.11.0", - "tslib": "^2.6.0", - "tsx": "^3.12.7", - "typescript": "^5.1.6", - "vitest": "^0.33.0" + "@eslint/compat": "^1.2.9", + "@typescript-eslint/eslint-plugin": "^8.32.0", + "@typescript-eslint/parser": "^8.32.0", + "eslint": "^9.26.0", + "eslint-config-prettier": "^10.1.2", + "eslint-define-config": "^2.1.0", + "eslint-plugin-import": "^2.31.0", + "eslint-plugin-jsx-a11y": "^6.10.2", + "eslint-plugin-n": "^17.17.0", + "eslint-plugin-no-only-tests": "^3.3.0", + "eslint-plugin-prettier": "^5.4.0", + "eslint-plugin-react": "^7.37.5", + "eslint-plugin-react-hooks": "^5.2.0", + "eslint-plugin-regexp": "^2.7.0", + "eslint-plugin-simple-import-sort": "^12.1.1", + "eslint-plugin-testing-library": "^7.1.1", + "prettier": "^3.5.3", + "tslib": "^2.8.1", + "tsx": "4.19.4", + "typescript": "5.8.3", + "vitest": "3.1.3" }, "engines": { - "node": "16.* || >= 18.0.0" + "node": ">= 18.0.0" }, - "packageManager": "pnpm@8.6.7" + "packageManager": "pnpm@8.6.11" } diff --git a/packages/oidc-client-service-worker/.eslintrc.cjs b/packages/oidc-client-service-worker/.eslintrc.cjs deleted file mode 100644 index a37905353..000000000 --- a/packages/oidc-client-service-worker/.eslintrc.cjs +++ /dev/null @@ -1,18 +0,0 @@ -module.exports = { - extends: [__dirname + '/config/defaultEslintConfig.cjs'], - parserOptions: { - project: './tsconfig.eslint.json', - tsconfigRootDir: __dirname, - }, - rules: { - '@typescript-eslint/naming-convention': [ - 'error', - { - selector: 'variable', - types: ['boolean'], - format: ['PascalCase'], - prefix: ['is', 'with', 'should', 'has', 'can', 'did', 'will'], - }, - ], - }, -}; diff --git a/packages/oidc-client-service-worker/config/defaultEslintConfig.cjs b/packages/oidc-client-service-worker/config/defaultEslintConfig.cjs deleted file mode 100644 index c3fa61f5b..000000000 --- a/packages/oidc-client-service-worker/config/defaultEslintConfig.cjs +++ /dev/null @@ -1,148 +0,0 @@ -module.exports = { - parser: '@typescript-eslint/parser', - extends: [ - 'standard', - 'plugin:react/recommended', - 'plugin:react-hooks/recommended', - 'plugin:@typescript-eslint/eslint-recommended', - 'plugin:@typescript-eslint/recommended', - 'plugin:import/typescript', - 'plugin:jsx-a11y/recommended', - ], - plugins: ['simple-import-sort', 'testing-library'], - env: { - node: true, - es6: true, - browser: true, - }, - parserOptions: { - ecmaVersion: 2018, - sourceType: 'module', - ecmaFeatures: { - jsx: true, - }, - // typescript-eslint specific options - warnOnUnsupportedTypeScriptVersion: true, - }, - rules: { - '@typescript-eslint/interface-name-prefix': 'off', - '@typescript-eslint/no-non-null-assertion': 'off', - '@typescript-eslint/explicit-module-boundary-types': 'off', - '@typescript-eslint/no-explicit-any': 'off', - '@typescript-eslint/ban-ts-comment': 'off', - 'no-unused-vars': 'off', - '@typescript-eslint/no-unused-vars': [ - 'error', - { - argsIgnorePattern: '^_|req|res|next|err|ctx|args|context|info', - ignoreRestSiblings: true, - }, - ], - 'no-array-constructor': 'off', - '@typescript-eslint/no-array-constructor': 'warn', - 'no-redeclare': 'off', - '@typescript-eslint/no-redeclare': 'warn', - 'no-use-before-define': 'off', - '@typescript-eslint/no-use-before-define': [ - 'warn', - { - functions: false, - classes: false, - variables: false, - typedefs: false, - }, - ], - 'no-unused-expressions': 'off', - '@typescript-eslint/no-unused-expressions': [ - 'error', - { - allowShortCircuit: true, - allowTernary: true, - allowTaggedTemplates: true, - }, - ], - '@typescript-eslint/triple-slash-reference': 'off', - '@typescript-eslint/member-delimiter-style': [ - 'error', - { - multiline: { - delimiter: 'semi', - requireLast: true, - }, - singleline: { - delimiter: 'semi', - requireLast: false, - }, - }, - ], - camelcase: 'off', - 'comma-dangle': [ - 'error', - { - arrays: 'always-multiline', - objects: 'always-multiline', - imports: 'always-multiline', - exports: 'always-multiline', - functions: 'always-multiline', - }, - ], - 'array-callback-return': 'warn', - 'jsx-quotes': ['error', 'prefer-double'], - // 'max-len': ['error', { code: 120 }], - indent: 'off', - // quotes: ['error', 'single'], - semi: ['error', 'always'], - 'space-before-function-paren': 'off', - - 'import/no-named-as-default': 'off', - 'import/no-named-as-default-member': 'off', - 'import/default': 'off', - 'import/named': 'off', - 'import/namespace': 'off', - 'import/no-unresolved': 'off', - 'simple-import-sort/imports': 'error', - 'simple-import-sort/exports': 'error', - 'react/prop-types': 'off', - 'react/jsx-wrap-multilines': 'error', - 'react/react-in-jsx-scope': 'off', - 'react/display-name': 'off', - // https://github.com/facebook/react/tree/master/packages/eslint-plugin-react-hooks - 'react-hooks/rules-of-hooks': 'error', - 'react-hooks/exhaustive-deps': 'off', - }, - - overrides: [ - { - files: ['*.js', '*.jsx'], - rules: { - '@typescript-eslint/no-var-requires': 'off', - }, - }, - { - // 3) Now we enable eslint-plugin-testing-library rules or preset only for matching files! - files: ['**/?(*.)+(spec|test).[jt]s?(x)'], - extends: ['plugin:testing-library/react'], - rules: { - 'testing-library/await-async-query': 'error', - 'testing-library/no-await-sync-query': 'error', - 'testing-library/no-debugging-utils': 'warn', - 'testing-library/no-dom-import': 'off', - 'testing-library/no-unnecessary-act': 'off', - }, - }, - ], - - settings: { - react: { - version: 'detect', - }, - 'import/parsers': { - '@typescript-eslint/parser': ['.ts', '.tsx'], - }, - 'import/resolver': { - typescript: { - alwaysTryTypes: true, - }, - }, - }, - }; \ No newline at end of file diff --git a/packages/oidc-client-service-worker/package.json b/packages/oidc-client-service-worker/package.json index 399a8169c..4a15d0e69 100644 --- a/packages/oidc-client-service-worker/package.json +++ b/packages/oidc-client-service-worker/package.json @@ -1,8 +1,8 @@ { "name": "@axa-fr/oidc-client-service-worker", - "version": "6.16.1", - "private": true, + "version": "7.26.0", "type": "module", + "private": false, "main": "dist/OidcServiceWorker.js", "types": "dist/OidcServiceWorker.d.ts", "description": "OpenID Connect & OAuth authentication service worker", @@ -19,6 +19,10 @@ "oauth2", "oauth" ], + "repository": { + "type": "git", + "url": "https://github.com/AxaFrance/oidc-client.git" + }, "scripts": { "copy": "cpy --flat ./src/OidcTrustedDomains.js ./dist/", "build": "tsc && vite build && pnpm run copy", @@ -30,23 +34,18 @@ "lint": "eslint src" }, "devDependencies": { - "@typescript-eslint/eslint-plugin": "^5.50.0", - "@typescript-eslint/parser": "^5.50.0", - "@vitest/coverage-c8": "^0.33.0", - "cpy": "^10.1.0", + "@vitest/coverage-v8": "3.1.3", + "cpy": "11.1.0", "cpy-cli": "^5.0.0", - "eslint": "^8.26.0", - "eslint-config-standard": "^17.1.0", - "eslint-config-standard-with-typescript": "^36.1.0", - "eslint-import-resolver-typescript": "^3.5.5", - "eslint-plugin-react": "^7.32.2", - "eslint-plugin-simple-import-sort": "^10.0.0", - "rimraf": "5.0.1", - "msw": "1.2.2", - "typescript": "5.1.6", - "vite": "^4.4.4", - "vite-plugin-dts": "^3.3.0", - "vitest": "^0.33.0" + "rimraf": "6.0.1", + "typescript": "5.8.3", + "vite": "6.3.5", + "vite-plugin-dts": "4.5.3", + "vitest": "3.1.3" + }, + "publishConfig": { + "access": "public", + "registry": "https://registry.npmjs.org/" }, "license": "MIT", "browserslist": { @@ -61,4 +60,4 @@ "last 1 safari version" ] } -} \ No newline at end of file +} diff --git a/packages/oidc-client-service-worker/src/OidcServiceWorker.ts b/packages/oidc-client-service-worker/src/OidcServiceWorker.ts index 22c940865..07d42b2a9 100644 --- a/packages/oidc-client-service-worker/src/OidcServiceWorker.ts +++ b/packages/oidc-client-service-worker/src/OidcServiceWorker.ts @@ -1,80 +1,60 @@ import { acceptAnyDomainToken, scriptFilename, TOKEN } from './constants'; -import { - Database, - MessageEventData, - OidcConfig, - OidcConfiguration, - TrustedDomains, - // TrustedDomainsShowAccessToken, -} from './types'; +import { base64urlOfHashOfASCIIEncodingAsync } from './crypto'; +import { getDpopConfiguration, getDpopOnlyWhenDpopHeaderPresent } from './dpop'; +import { generateJwkAsync, generateJwtDemonstratingProofOfPossessionAsync } from './jwt'; +import { getCurrentDatabasesTokenEndpoint } from './oidcConfig'; +import { Database, MessageEventData, OidcConfig, TrustedDomains } from './types'; import { checkDomain, getCurrentDatabaseDomain, getDomains, hideTokens, isTokensValid, + normalizeUrl, serializeHeaders, sleep, } from './utils'; -import { replaceCodeVerifier } from './utils/codeVerifier'; +import { + extractConfigurationNameFromCodeVerifier, + replaceCodeVerifier, +} from './utils/codeVerifier'; +import version from './version'; + +// @ts-ignore +if (typeof trustedTypes !== 'undefined' && typeof trustedTypes.createPolicy === 'function') { + // @ts-ignore + trustedTypes.createPolicy('default', { + createScriptURL: function (url: string) { + if (url === scriptFilename) { + return url; + } else { + throw new Error('Untrusted script URL blocked: ' + url); + } + }, + }); +} const _self = self as ServiceWorkerGlobalScope & typeof globalThis; +// Déclare `trustedDomains` qui vient de l'extérieur : declare let trustedDomains: TrustedDomains; _self.importScripts(scriptFilename); const id = Math.round(new Date().getTime() / 1000).toString(); - +console.log('init service worker with id', id); const keepAliveJsonFilename = 'OidcKeepAliveServiceWorker.json'; -const handleInstall = (event: ExtendableEvent) => { - console.log('[OidcServiceWorker] service worker installed ' + id); - event.waitUntil(_self.skipWaiting()); -}; - -const handleActivate = (event: ExtendableEvent) => { - console.log('[OidcServiceWorker] service worker activated ' + id); - event.waitUntil(_self.clients.claim()); -}; - -let currentLoginCallbackConfigurationName: string | null = null; -const database: Database = { - default: { - configurationName: 'default', - tokens: null, - status: null, - state: null, - codeVerifier: null, - nonce: null, - oidcServerConfiguration: null, - hideAccessToken: true, - }, -}; - -const getCurrentDatabasesTokenEndpoint = (database: Database, url: string) => { - const databases: OidcConfig[] = []; - for (const [, value] of Object.entries(database)) { - if ( - value.oidcServerConfiguration != null && - url.startsWith(value.oidcServerConfiguration.tokenEndpoint) - ) { - databases.push(value); - } else if ( - value.oidcServerConfiguration != null && - value.oidcServerConfiguration.revocationEndpoint && - url.startsWith(value.oidcServerConfiguration.revocationEndpoint) - ) { - databases.push(value); - } - } - return databases; -}; +const database: Database = {}; +/** + * Routine keepAlive : renvoie une réponse après un "sleep" éventuel. + */ const keepAliveAsync = async (event: FetchEvent) => { const originalRequest = event.request; const isFromVanilla = originalRequest.headers.has('oidc-vanilla'); const init = { status: 200, statusText: 'oidc-service-worker' }; const response = new Response('{}', init); + if (!isFromVanilla) { const originalRequestUrl = new URL(originalRequest.url); const minSleepSeconds = Number(originalRequestUrl.searchParams.get('minSleepSeconds')) || 240; @@ -87,204 +67,378 @@ const keepAliveAsync = async (event: FetchEvent) => { return response; }; -const handleFetch = async (event: FetchEvent) => { - const originalRequest = event.request; - const url = originalRequest.url; - if (originalRequest.url.includes(keepAliveJsonFilename)) { - event.respondWith(keepAliveAsync(event)); - return; - } - - const currentDatabaseForRequestAccessToken = getCurrentDatabaseDomain( - database, - originalRequest.url, - trustedDomains, - ); +/** + * Génération d'en-têtes DPoP s'il y a configuration dpop. + */ +async function generateDpopAsync( + originalRequest: Request, + currentDatabase: OidcConfig | null, + url: string, + extrasClaims = {}, +) { + const headersExtras = serializeHeaders(originalRequest.headers); if ( - currentDatabaseForRequestAccessToken && - currentDatabaseForRequestAccessToken.tokens && - currentDatabaseForRequestAccessToken.tokens.access_token + currentDatabase?.demonstratingProofOfPossessionConfiguration && + currentDatabase.demonstratingProofOfPossessionJwkJson && + (!currentDatabase.demonstratingProofOfPossessionOnlyWhenDpopHeaderPresent || + (currentDatabase.demonstratingProofOfPossessionOnlyWhenDpopHeaderPresent && + headersExtras.dpop)) ) { - while ( - currentDatabaseForRequestAccessToken.tokens && - !isTokensValid(currentDatabaseForRequestAccessToken.tokens) - ) { - await sleep(200); - } - const newRequest = - originalRequest.mode === 'navigate' - ? new Request(originalRequest, { - headers: { - ...serializeHeaders(originalRequest.headers), - authorization: - 'Bearer ' + - currentDatabaseForRequestAccessToken.tokens.access_token, - }, - }) - : new Request(originalRequest, { - headers: { - ...serializeHeaders(originalRequest.headers), - authorization: - 'Bearer ' + - currentDatabaseForRequestAccessToken.tokens.access_token, - }, - mode: ( - currentDatabaseForRequestAccessToken.oidcConfiguration as OidcConfiguration - ).service_worker_convert_all_requests_to_cors - ? 'cors' - : originalRequest.mode, - }); - - // @ts-ignore -- TODO: review, waitUntil takes a promise, this returns a void - event.waitUntil(event.respondWith(fetch(newRequest))); + const dpopConfiguration = currentDatabase.demonstratingProofOfPossessionConfiguration; + const jwk = currentDatabase.demonstratingProofOfPossessionJwkJson; + const method = originalRequest.method; + const dpop = await generateJwtDemonstratingProofOfPossessionAsync(self)(dpopConfiguration)( + jwk, + method, + url, + extrasClaims, + ); - return; + headersExtras.dpop = dpop; + if (currentDatabase.demonstratingProofOfPossessionNonce != null) { + headersExtras.nonce = currentDatabase.demonstratingProofOfPossessionNonce; + } } + return headersExtras; +} - if (event.request.method !== 'POST') { - return; +/** + * Nouveau handleFetch : on n’est plus async "directement". + * On encapsule toute la logique dans un `respondWith((async () => { ... })())`. + */ +const handleFetch = (event: FetchEvent): void => { + /** + * Exit early for requests that do not need to have an auth token attached. + */ + const bypassedDestinations = ['image', 'font', 'media', 'document', 'iframe', 'script']; + if (bypassedDestinations.includes(event.request.destination)) { + return; // Don't call event.respondWith() - let browser handle naturally } + event.respondWith( + (async (): Promise => { + try { + const originalRequest = event.request; + const url = normalizeUrl(originalRequest.url); - let currentDatabase: OidcConfig | null = null; - const currentDatabases = getCurrentDatabasesTokenEndpoint( - database, - originalRequest.url, - ); - const numberDatabase = currentDatabases.length; - if (numberDatabase > 0) { - const maPromesse = new Promise((resolve, reject) => { - const clonedRequest = originalRequest.clone(); - const response = clonedRequest.text().then((actualBody) => { - if ( - actualBody.includes(TOKEN.REFRESH_TOKEN) || - actualBody.includes(TOKEN.ACCESS_TOKEN) - ) { - let newBody = actualBody; - for (let i = 0; i < numberDatabase; i++) { - const currentDb = currentDatabases[i]; - - if (currentDb && currentDb.tokens != null) { - const keyRefreshToken = - TOKEN.REFRESH_TOKEN + '_' + currentDb.configurationName; - if (actualBody.includes(keyRefreshToken)) { - newBody = newBody.replace( - keyRefreshToken, - encodeURIComponent(currentDb.tokens.refresh_token as string), - ); - currentDatabase = currentDb; - break; - } - const keyAccessToken = - TOKEN.ACCESS_TOKEN + '_' + currentDb.configurationName; - if (actualBody.includes(keyAccessToken)) { - newBody = newBody.replace( - keyAccessToken, - encodeURIComponent(currentDb.tokens.access_token), - ); - currentDatabase = currentDb; - break; - } - } + // 1) Si on est sur la ressource KeepAlive + if (url.includes(keepAliveJsonFilename)) { + return keepAliveAsync(event); + } + + // 2) Cas normal : on regarde si on a un token + const currentDatabasesForRequestAccessToken = getCurrentDatabaseDomain( + database, + url, + trustedDomains, + ); + + const authorization = originalRequest.headers.get('authorization'); + let authenticationMode = 'Bearer'; + let key = 'default'; + + if (authorization) { + const split = authorization.split(' '); + authenticationMode = split[0]; + if (split[1]?.includes('ACCESS_TOKEN_SECURED_BY_OIDC_SERVICE_WORKER_')) { + key = split[1].split('ACCESS_TOKEN_SECURED_BY_OIDC_SERVICE_WORKER_')[1]; } - const fetchPromise = fetch(originalRequest, { - body: newBody, - method: clonedRequest.method, - headers: { - ...serializeHeaders(originalRequest.headers), - }, - mode: clonedRequest.mode, - cache: clonedRequest.cache, - redirect: clonedRequest.redirect, - referrer: clonedRequest.referrer, - credentials: clonedRequest.credentials, - integrity: clonedRequest.integrity, - }); + } - if ( - currentDatabase && - currentDatabase.oidcServerConfiguration != null && - currentDatabase.oidcServerConfiguration.revocationEndpoint && - url.startsWith( - currentDatabase.oidcServerConfiguration.revocationEndpoint, - ) + const currentDatabaseForRequestAccessToken = currentDatabasesForRequestAccessToken?.find( + c => c.configurationName.endsWith(key), + ); + + // 2a) Si on a déjà des tokens valides + if (currentDatabaseForRequestAccessToken?.tokens?.access_token) { + // On attend que le token soit valide (refresh possible en parallèle) + while ( + currentDatabaseForRequestAccessToken.tokens && + !isTokensValid(currentDatabaseForRequestAccessToken.tokens) ) { - return fetchPromise.then(async (response) => { - const text = await response.text(); - return new Response(text, response); - }); + await sleep(200); } - return fetchPromise.then(hideTokens(currentDatabase as OidcConfig)); // todo type assertion to OidcConfig but could be null, NEEDS REVIEW - } else if ( - actualBody.includes('code_verifier=') && - currentLoginCallbackConfigurationName - ) { - currentDatabase = database[currentLoginCallbackConfigurationName]; - currentLoginCallbackConfigurationName = null; - let newBody = actualBody; - if (currentDatabase && currentDatabase.codeVerifier != null) { - newBody = replaceCodeVerifier(newBody, currentDatabase.codeVerifier); + + // Ajustement du mode + let requestMode = originalRequest.mode; + if ( + originalRequest.mode !== 'navigate' && + currentDatabaseForRequestAccessToken.convertAllRequestsToCorsExceptNavigate + ) { + requestMode = 'cors'; } - return fetch(originalRequest, { - body: newBody, - method: clonedRequest.method, - headers: { + // Construction des en-têtes + let headers: { [p: string]: string }; + + // Pas de token sur la requête "navigate" si setAccessTokenToNavigateRequests = false + if ( + originalRequest.mode === 'navigate' && + !currentDatabaseForRequestAccessToken.setAccessTokenToNavigateRequests + ) { + headers = { ...serializeHeaders(originalRequest.headers), - }, - mode: clonedRequest.mode, - cache: clonedRequest.cache, - redirect: clonedRequest.redirect, - referrer: clonedRequest.referrer, - credentials: clonedRequest.credentials, - integrity: clonedRequest.integrity, - }).then(hideTokens(currentDatabase)); - } - return undefined; - }); - response - .then((r) => { - if (r !== undefined) { - resolve(r); + }; } else { - console.log('success undefined'); - reject(new Error('Response is undefined inside a success')); + // On injecte le token + if ( + authenticationMode.toLowerCase() === 'dpop' || + (!currentDatabaseForRequestAccessToken.demonstratingProofOfPossessionOnlyWhenDpopHeaderPresent && + currentDatabaseForRequestAccessToken.demonstratingProofOfPossessionConfiguration) + ) { + // Mode DPoP + const claimsExtras = { + ath: await base64urlOfHashOfASCIIEncodingAsync( + currentDatabaseForRequestAccessToken.tokens.access_token, + ), + }; + const dpopHeaders = await generateDpopAsync( + originalRequest, + currentDatabaseForRequestAccessToken, + url, + claimsExtras, + ); + headers = { + ...dpopHeaders, + authorization: `DPoP ${currentDatabaseForRequestAccessToken.tokens.access_token}`, + }; + } else { + // Mode Bearer + headers = { + ...serializeHeaders(originalRequest.headers), + authorization: `${authenticationMode} ${currentDatabaseForRequestAccessToken.tokens.access_token}`, + }; + } } - }) - .catch((err) => { - if (err !== undefined) { - reject(err); + + let init: RequestInit; + if (originalRequest.mode === 'navigate') { + init = { + headers: headers, + }; } else { - console.log('error undefined'); - reject(new Error('Response is undefined inside a error')); + init = { + headers: headers, + mode: requestMode, + }; } - }); - }); - // @ts-ignore -- TODO: review, waitUntil takes a promise, this returns a void - event.waitUntil(event.respondWith(maPromesse)); - } -}; + const newRequest = new Request(originalRequest, init); + return fetch(newRequest); + } -type TrustedDomainsShowAccessToken = { - [key: string]: boolean; -} + // 3) S’il ne s’agit pas d’un POST => on laisse passer + if (event.request.method !== 'POST') { + return fetch(originalRequest); + } + + // 4) Cas POST vers un endpoint connu (token, revocation) + const currentDatabases = getCurrentDatabasesTokenEndpoint(database, url); + const numberDatabase = currentDatabases.length; -const trustedDomainsShowAccessToken: TrustedDomainsShowAccessToken = {}; + if (numberDatabase > 0) { + // On gère tout dans une promesse + const responsePromise = new Promise((resolve, reject) => { + const clonedRequest = originalRequest.clone(); + clonedRequest + .text() + .then(async actualBody => { + let currentDatabase: OidcConfig | null = null; + try { + // 4a) S’il y a un refresh_token masqué + if ( + actualBody.includes(TOKEN.REFRESH_TOKEN) || + actualBody.includes(TOKEN.ACCESS_TOKEN) + ) { + let headers = serializeHeaders(originalRequest.headers); + let newBody = actualBody; -const handleMessage = (event: ExtendableMessageEvent) => { + for (let i = 0; i < numberDatabase; i++) { + const currentDb = currentDatabases[i]; + if (currentDb?.tokens) { + const claimsExtras = { + ath: await base64urlOfHashOfASCIIEncodingAsync( + currentDb.tokens.access_token, + ), + }; + headers = await generateDpopAsync( + originalRequest, + currentDb, + url, + claimsExtras, + ); + + const keyRefreshToken = encodeURIComponent( + `${TOKEN.REFRESH_TOKEN}_${currentDb.configurationName}`, + ); + if (actualBody.includes(keyRefreshToken)) { + newBody = newBody.replace( + keyRefreshToken, + encodeURIComponent(currentDb.tokens.refresh_token as string), + ); + currentDatabase = currentDb; + break; + } + + const keyAccessToken = encodeURIComponent( + `${TOKEN.ACCESS_TOKEN}_${currentDb.configurationName}`, + ); + if (actualBody.includes(keyAccessToken)) { + newBody = newBody.replace( + keyAccessToken, + encodeURIComponent(currentDb.tokens.access_token), + ); + currentDatabase = currentDb; + break; + } + } + } + + const fetchPromise = fetch(originalRequest, { + body: newBody, + method: clonedRequest.method, + headers, + mode: clonedRequest.mode, + cache: clonedRequest.cache, + redirect: clonedRequest.redirect, + referrer: clonedRequest.referrer, + credentials: clonedRequest.credentials, + integrity: clonedRequest.integrity, + }); + + // Cas “revocationEndpoint” ? + if ( + currentDatabase?.oidcServerConfiguration?.revocationEndpoint && + url.startsWith( + normalizeUrl(currentDatabase.oidcServerConfiguration.revocationEndpoint), + ) + ) { + // On ne modifie pas le corps + const resp = await fetchPromise; + const txt = await resp.text(); + resolve(new Response(txt, resp)); + return; + } + + // Sinon on “cache” les tokens dans la réponse + const hidden = await fetchPromise.then( + hideTokens(currentDatabase as OidcConfig), + ); + resolve(hidden); + return; + } + + // 4b) Sinon si c’est le code_verifier + const isCodeVerifier = actualBody.includes('code_verifier='); + if (isCodeVerifier) { + const currentLoginCallbackConfigurationName = + extractConfigurationNameFromCodeVerifier(actualBody); + if ( + !currentLoginCallbackConfigurationName || + currentLoginCallbackConfigurationName === '' + ) { + throw new Error('No configuration name found in code_verifier'); + } + currentDatabase = database[currentLoginCallbackConfigurationName]; + let newBody = actualBody; + const codeVerifier = currentDatabase.codeVerifier; + if (codeVerifier != null) { + newBody = replaceCodeVerifier(newBody, codeVerifier); + } + + const headersExtras = await generateDpopAsync( + originalRequest, + currentDatabase, + url, + ); + const resp = await fetch(originalRequest, { + body: newBody, + method: clonedRequest.method, + headers: headersExtras, + mode: clonedRequest.mode, + cache: clonedRequest.cache, + redirect: clonedRequest.redirect, + referrer: clonedRequest.referrer, + credentials: clonedRequest.credentials, + integrity: clonedRequest.integrity, + }); + const hidden = await hideTokens(currentDatabase)(resp); + resolve(hidden); + return; + } + + // 4c) Sinon on laisse passer tel quel + const normalResp = await fetch(originalRequest, { + body: actualBody, + method: clonedRequest.method, + headers: serializeHeaders(originalRequest.headers), + mode: clonedRequest.mode, + cache: clonedRequest.cache, + redirect: clonedRequest.redirect, + referrer: clonedRequest.referrer, + credentials: clonedRequest.credentials, + integrity: clonedRequest.integrity, + }); + resolve(normalResp); + } catch (err) { + reject(err); + } + }) + .catch(reject); + }); + + // On renvoie simplement la promesse + return responsePromise; + } + + // 5) Par défaut, on laisse passer la requête + return fetch(originalRequest); + } catch (err) { + // En cas d’erreur imprévue, on log et on retourne une 500 + console.error('[OidcServiceWorker] handleFetch error:', err); + return new Response('Service Worker Error', { status: 500 }); + } + })(), + ); +}; + +// ---- Gestion des messages depuis la page +const handleMessage = async (event: ExtendableMessageEvent) => { const port = event.ports[0]; const data = event.data as MessageEventData; - const configurationName = data.configurationName; - let currentDatabase = database[configurationName]; + + if (event.data?.type === 'SKIP_WAITING') { + await _self.skipWaiting(); + return; + } else if (event.data.type === 'claim') { + _self.clients.claim().then(() => port.postMessage({})); + return; + } + + const configurationName = data.configurationName.split('#')[0]; + if (trustedDomains == null) { trustedDomains = {}; } + + const trustedDomain = trustedDomains[configurationName]; + const allowMultiTabLogin = Array.isArray(trustedDomain) + ? false + : trustedDomain.allowMultiTabLogin; + + const tabId = allowMultiTabLogin ? data.tabId : 'default'; + const configurationNameWithTabId = `${configurationName}#tabId=${tabId}`; + + let currentDatabase = database[configurationNameWithTabId]; if (!currentDatabase) { - if (trustedDomainsShowAccessToken[configurationName] === undefined) { - const trustedDomain = trustedDomains[configurationName]; - trustedDomainsShowAccessToken[configurationName] = Array.isArray(trustedDomain) ? false : trustedDomain.showAccessToken; - } - database[configurationName] = { + const showAccessToken = Array.isArray(trustedDomain) ? false : trustedDomain.showAccessToken; + const doNotSetAccessTokenToNavigateRequests = Array.isArray(trustedDomain) + ? true + : trustedDomain.setAccessTokenToNavigateRequests; + const convertAllRequestsToCorsExceptNavigate = Array.isArray(trustedDomain) + ? false + : trustedDomain.convertAllRequestsToCorsExceptNavigate; + + database[configurationNameWithTabId] = { tokens: null, state: null, codeVerifier: null, @@ -292,10 +446,17 @@ const handleMessage = (event: ExtendableMessageEvent) => { oidcConfiguration: undefined, nonce: null, status: null, - configurationName, - hideAccessToken: !trustedDomainsShowAccessToken[configurationName], + configurationName: configurationNameWithTabId, + hideAccessToken: !showAccessToken, + setAccessTokenToNavigateRequests: doNotSetAccessTokenToNavigateRequests ?? true, + convertAllRequestsToCorsExceptNavigate: convertAllRequestsToCorsExceptNavigate ?? false, + demonstratingProofOfPossessionNonce: null, + demonstratingProofOfPossessionJwkJson: null, + demonstratingProofOfPossessionConfiguration: null, + demonstratingProofOfPossessionOnlyWhenDpopHeaderPresent: false, + allowMultiTabLogin: allowMultiTabLogin ?? false, }; - currentDatabase = database[configurationName]; + currentDatabase = database[configurationNameWithTabId]; if (!trustedDomains[configurationName]) { trustedDomains[configurationName] = []; @@ -307,33 +468,50 @@ const handleMessage = (event: ExtendableMessageEvent) => { currentDatabase.tokens = null; currentDatabase.state = null; currentDatabase.codeVerifier = null; + currentDatabase.nonce = null; + currentDatabase.demonstratingProofOfPossessionNonce = null; + currentDatabase.demonstratingProofOfPossessionJwkJson = null; + currentDatabase.demonstratingProofOfPossessionConfiguration = null; + currentDatabase.demonstratingProofOfPossessionOnlyWhenDpopHeaderPresent = false; currentDatabase.status = data.data.status; port.postMessage({ configurationName }); return; + case 'init': { const oidcServerConfiguration = data.data.oidcServerConfiguration; - const trustedDomain = trustedDomains[configurationName]; const domains = getDomains(trustedDomain, 'oidc'); - if (!domains.find((f) => f === acceptAnyDomainToken)) { + + if (!domains.some(domain => domain === acceptAnyDomainToken)) { [ oidcServerConfiguration.tokenEndpoint, oidcServerConfiguration.revocationEndpoint, oidcServerConfiguration.userInfoEndpoint, oidcServerConfiguration.issuer, - ].forEach((url) => { - checkDomain(domains, url); + ].forEach(u => { + checkDomain(domains, u); }); } - currentDatabase.oidcServerConfiguration = oidcServerConfiguration; + + currentDatabase.oidcServerConfiguration = oidcServerConfiguration; currentDatabase.oidcConfiguration = data.data.oidcConfiguration; - const where = data.data.where; - if ( - where === 'loginCallbackAsync' || - where === 'tryKeepExistingSessionAsync' - ) { - currentLoginCallbackConfigurationName = configurationName; - } else { - currentLoginCallbackConfigurationName = null; + + // Cas DPoP + if (currentDatabase.demonstratingProofOfPossessionConfiguration == null) { + const demonstratingProofOfPossessionConfiguration = getDpopConfiguration(trustedDomain); + if (demonstratingProofOfPossessionConfiguration != null) { + if (currentDatabase.oidcConfiguration.demonstrating_proof_of_possession) { + console.warn( + 'In service worker, demonstrating_proof_of_possession must be configured from trustedDomains file', + ); + } + currentDatabase.demonstratingProofOfPossessionConfiguration = + demonstratingProofOfPossessionConfiguration; + currentDatabase.demonstratingProofOfPossessionJwkJson = await generateJwkAsync(self)( + demonstratingProofOfPossessionConfiguration.generateKeyAlgorithm, + ); + currentDatabase.demonstratingProofOfPossessionOnlyWhenDpopHeaderPresent = + getDpopOnlyWhenDpopHeaderPresent(trustedDomain) ?? false; + } } if (!currentDatabase.tokens) { @@ -341,62 +519,88 @@ const handleMessage = (event: ExtendableMessageEvent) => { tokens: null, status: currentDatabase.status, configurationName, + version, }); } else { - const tokens = { - ...currentDatabase.tokens, - }; + const tokens = { ...currentDatabase.tokens }; if (currentDatabase.hideAccessToken) { - tokens.access_token = TOKEN.ACCESS_TOKEN + '_' + configurationName; + tokens.access_token = `${TOKEN.ACCESS_TOKEN}_${configurationName}#tabId=${tabId}`; } if (tokens.refresh_token) { - tokens.refresh_token = TOKEN.REFRESH_TOKEN + '_' + configurationName; + tokens.refresh_token = `${TOKEN.REFRESH_TOKEN}_${configurationName}#tabId=${tabId}`; } - if ( - tokens.idTokenPayload && - tokens.idTokenPayload.nonce && - currentDatabase.nonce != null - ) { - tokens.idTokenPayload.nonce = - TOKEN.NONCE_TOKEN + '_' + configurationName; + if (tokens?.idTokenPayload?.nonce && currentDatabase.nonce != null) { + tokens.idTokenPayload.nonce = `${TOKEN.NONCE_TOKEN}_${configurationName}#tabId=${tabId}`; } port.postMessage({ tokens, status: currentDatabase.status, configurationName, + version, }); } return; } - case 'setState': + + case 'setDemonstratingProofOfPossessionNonce': { + currentDatabase.demonstratingProofOfPossessionNonce = + data.data.demonstratingProofOfPossessionNonce; + port.postMessage({ configurationName }); + return; + } + + case 'getDemonstratingProofOfPossessionNonce': { + const demonstratingProofOfPossessionNonce = + currentDatabase.demonstratingProofOfPossessionNonce; + port.postMessage({ + configurationName, + demonstratingProofOfPossessionNonce, + }); + return; + } + + case 'setState': { currentDatabase.state = data.data.state; port.postMessage({ configurationName }); return; + } + case 'getState': { const state = currentDatabase.state; port.postMessage({ configurationName, state }); return; } - case 'setCodeVerifier': + + case 'setCodeVerifier': { currentDatabase.codeVerifier = data.data.codeVerifier; port.postMessage({ configurationName }); return; + } + case 'getCodeVerifier': { + const codeVerifier = + currentDatabase.codeVerifier != null + ? `${TOKEN.CODE_VERIFIER}_${configurationName}#tabId=${tabId}` + : null; port.postMessage({ configurationName, - codeVerifier: currentDatabase.codeVerifier != null ? TOKEN.CODE_VERIFIER + '_' + configurationName : null, + codeVerifier, }); return; } - case 'setSessionState': + + case 'setSessionState': { currentDatabase.sessionState = data.data.sessionState; port.postMessage({ configurationName }); return; + } + case 'getSessionState': { const sessionState = currentDatabase.sessionState; port.postMessage({ configurationName, sessionState }); return; } + case 'setNonce': { const nonce = data.data.nonce; if (nonce) { @@ -405,19 +609,19 @@ const handleMessage = (event: ExtendableMessageEvent) => { port.postMessage({ configurationName }); return; } + case 'getNonce': { - const keyNonce = TOKEN.NONCE_TOKEN + '_' + configurationName; + const keyNonce = `${TOKEN.NONCE_TOKEN}_${configurationName}#tabId=${tabId}`; const nonce = currentDatabase.nonce ? keyNonce : null; port.postMessage({ configurationName, nonce }); return; } + default: - currentDatabase.items = { ...data.data }; - port.postMessage({ configurationName }); + return; } }; -_self.addEventListener('install', handleInstall); -_self.addEventListener('activate', handleActivate); +// Écouteurs _self.addEventListener('fetch', handleFetch); _self.addEventListener('message', handleMessage); diff --git a/packages/oidc-client-service-worker/src/OidcTrustedDomains.js b/packages/oidc-client-service-worker/src/OidcTrustedDomains.js index 1aea5cd1a..97ad89303 100644 --- a/packages/oidc-client-service-worker/src/OidcTrustedDomains.js +++ b/packages/oidc-client-service-worker/src/OidcTrustedDomains.js @@ -3,24 +3,29 @@ // then all subroute like https://www.myapi.com/useers/1 will be authorized to send access_token to. // Domains used by OIDC server must be also declared here -// eslint-disable-next-line @typescript-eslint/no-unused-vars + const trustedDomains = { - default: ['https://demo.duendesoftware.com', 'https://kdhttps.auth0.com'], - config_classic: ['https://demo.duendesoftware.com'], - config_without_silent_login: ['https://demo.duendesoftware.com'], - config_without_refresh_token: ['https://demo.duendesoftware.com'], - config_without_refresh_token_silent_login: ['https://demo.duendesoftware.com'], - config_google: ['https://oauth2.googleapis.com', 'https://openidconnect.googleapis.com'], - config_with_hash: ['https://demo.duendesoftware.com'], + default: ['https://demo.duendesoftware.com', 'https://kdhttps.auth0.com'], + config_classic: ['https://demo.duendesoftware.com'], + config_without_silent_login: ['https://demo.duendesoftware.com'], + config_without_refresh_token: ['https://demo.duendesoftware.com'], + config_without_refresh_token_silent_login: ['https://demo.duendesoftware.com'], + config_google: ['https://oauth2.googleapis.com', 'https://openidconnect.googleapis.com'], + config_with_hash: ['https://demo.duendesoftware.com'], }; // Service worker will continue to give access token to the JavaScript client // Ideal to hide refresh token from client JavaScript, but to retrieve access_token for some // scenarios which require it. For example, to send it via websocket connection. -trustedDomains.config_show_access_token = { domains: ['https://demo.duendesoftware.com'], showAccessToken: true }; +trustedDomains.config_show_access_token = { + domains: ['https://demo.duendesoftware.com'], + showAccessToken: true, + // convertAllRequestsToCorsExceptNavigate: false, + // setAccessTokenToNavigateRequests: true, +}; // This example defines domains used by OIDC server separately from domains to which access tokens will be injected. trustedDomains.config_separate_oidc_access_token_domains = { - oidcDomains: ['https://demo.duendesoftware.com'], - accessTokenDomains: ['https://myapi'], + oidcDomains: ['https://demo.duendesoftware.com'], + accessTokenDomains: ['https://myapi'], }; diff --git a/packages/oidc-client-service-worker/src/__tests__/oidcConfig.spec.ts b/packages/oidc-client-service-worker/src/__tests__/oidcConfig.spec.ts new file mode 100644 index 000000000..43bf98f69 --- /dev/null +++ b/packages/oidc-client-service-worker/src/__tests__/oidcConfig.spec.ts @@ -0,0 +1,154 @@ +import { describe, expect, it } from 'vitest'; + +import { getCurrentDatabasesTokenEndpoint } from '../oidcConfig'; +import { Database } from '../types'; + +const oidcConfigDefaults = { + demonstratingProofOfPossessionConfiguration: null, + configurationName: '', + tokens: null, + status: null, + state: null, + codeVerifier: null, + nonce: null, + hideAccessToken: false, + convertAllRequestsToCorsExceptNavigate: true, + setAccessTokenToNavigateRequests: true, + demonstratingProofOfPossessionNonce: null, + demonstratingProofOfPossessionJwkJson: null, + demonstratingProofOfPossessionOnlyWhenDpopHeaderPresent: false, + allowMultiTabLogin: true, +}; + +const oidcServerConfigDefault = { + revocationEndpoint: '', + tokenEndpoint: '', + issuer: '', + userInfoEndpoint: '', + authorizationEndpoint: '', +}; + +describe('getCurrentDatabasesTokenEndpoint', () => { + it('should return configs with matching token endpoint', () => { + const database: Database = { + config1: { + ...oidcConfigDefaults, + oidcServerConfiguration: { + ...oidcServerConfigDefault, + tokenEndpoint: 'https://example.com/token', + }, + }, + config2: { + ...oidcConfigDefaults, + oidcServerConfiguration: { + ...oidcServerConfigDefault, + tokenEndpoint: 'https://example.org/token', + }, + }, + config3: { + ...oidcConfigDefaults, + oidcServerConfiguration: { + ...oidcServerConfigDefault, + revocationEndpoint: 'https://example.net/revoke', + }, + }, + }; + + const url = 'https://example.com/token'; + const result = getCurrentDatabasesTokenEndpoint(database, url); + + expect(result).toHaveLength(1); + expect(result[0]).toBe(database.config1); + }); + + it('should return configs with matching revocation endpoint', () => { + const database = { + config1: { + ...oidcConfigDefaults, + oidcServerConfiguration: { + ...oidcServerConfigDefault, + revocationEndpoint: 'https://example.com/revoke', + }, + }, + config2: { + ...oidcConfigDefaults, + oidcServerConfiguration: { + ...oidcServerConfigDefault, + revocationEndpoint: 'https://example.org/revoke', + }, + }, + config3: { + ...oidcConfigDefaults, + oidcServerConfiguration: { + ...oidcServerConfigDefault, + tokenEndpoint: 'https://example.net/token', + }, + }, + }; + + const url = 'https://example.com/revoke'; + const result = getCurrentDatabasesTokenEndpoint(database, url); + + expect(result).toHaveLength(1); + expect(result[0]).toBe(database.config1); + }); + + it('should return multiple matching configs', () => { + const database = { + config1: { + ...oidcConfigDefaults, + oidcServerConfiguration: { + ...oidcServerConfigDefault, + tokenEndpoint: 'https://example.com/token', + revocationEndpoint: 'https://example.com/revoke', + }, + }, + config2: { + ...oidcConfigDefaults, + oidcServerConfiguration: { + ...oidcServerConfigDefault, + tokenEndpoint: 'https://example.org/token', + }, + }, + config3: { + ...oidcConfigDefaults, + oidcServerConfiguration: { + ...oidcServerConfigDefault, + tokenEndpoint: 'https://example.com/token', + revocationEndpoint: 'https://example.com/revoke', + }, + }, + }; + + const url = 'https://example.com/token'; + const result = getCurrentDatabasesTokenEndpoint(database, url); + + expect(result).toHaveLength(2); + expect(result).toContain(database.config1); + expect(result).toContain(database.config3); + }); + + it('should return empty array for no matching configs', () => { + const database = { + config1: { + ...oidcConfigDefaults, + oidcServerConfiguration: { + ...oidcServerConfigDefault, + tokenEndpoint: 'https://example.com/token', + }, + }, + config2: { + ...oidcConfigDefaults, + oidcServerConfiguration: { + ...oidcServerConfigDefault, + revocationEndpoint: 'https://example.org/revoke', + }, + }, + }; + + const url = 'https://example.net/other'; + const result = getCurrentDatabasesTokenEndpoint(database, url); + + expect(result).toHaveLength(0); + }); +}); diff --git a/packages/oidc-client-service-worker/src/crypto.ts b/packages/oidc-client-service-worker/src/crypto.ts new file mode 100644 index 000000000..31172f2b2 --- /dev/null +++ b/packages/oidc-client-service-worker/src/crypto.ts @@ -0,0 +1,22 @@ +import { uint8ToUrlBase64 } from './jwt'; + +export function textEncodeLite(str: string) { + const buf = new ArrayBuffer(str.length); + const bufView = new Uint8Array(buf); + + for (let i = 0; i < str.length; i++) { + bufView[i] = str.charCodeAt(i); + } + return bufView; +} + +export function base64urlOfHashOfASCIIEncodingAsync(code: string): Promise { + return new Promise((resolve, reject) => { + crypto.subtle.digest('SHA-256', textEncodeLite(code)).then( + buffer => { + return resolve(uint8ToUrlBase64(new Uint8Array(buffer))); + }, + error => reject(error), + ); + }); +} diff --git a/packages/oidc-client-service-worker/src/dpop.ts b/packages/oidc-client-service-worker/src/dpop.ts new file mode 100644 index 000000000..79a668d41 --- /dev/null +++ b/packages/oidc-client-service-worker/src/dpop.ts @@ -0,0 +1,36 @@ +import { defaultDemonstratingProofOfPossessionConfiguration } from './jwt'; +import { Domain, DomainDetails } from './types.js'; + +const isDpop = (trustedDomain: Domain[] | DomainDetails): boolean => { + if (Array.isArray(trustedDomain)) { + return false; + } + return trustedDomain.demonstratingProofOfPossession ?? false; +}; + +export const getDpopConfiguration = (trustedDomain: Domain[] | DomainDetails) => { + if (!isDpop(trustedDomain)) { + return null; + } + + if (Array.isArray(trustedDomain)) { + return null; + } + + return ( + trustedDomain.demonstratingProofOfPossessionConfiguration ?? + defaultDemonstratingProofOfPossessionConfiguration + ); +}; + +export const getDpopOnlyWhenDpopHeaderPresent = (trustedDomain: Domain[] | DomainDetails) => { + if (!isDpop(trustedDomain)) { + return null; + } + + if (Array.isArray(trustedDomain)) { + return null; + } + + return trustedDomain.demonstratingProofOfPossessionOnlyWhenDpopHeaderPresent ?? true; +}; diff --git a/packages/oidc-client-service-worker/src/jwt.ts b/packages/oidc-client-service-worker/src/jwt.ts new file mode 100644 index 000000000..a0c7068b1 --- /dev/null +++ b/packages/oidc-client-service-worker/src/jwt.ts @@ -0,0 +1,279 @@ +// code base on https://coolaj86.com/articles/sign-jwt-webcrypto-vanilla-js/ + +// String (UCS-2) to Uint8Array +// +// because... JavaScript, Strings, and Buffers +// @ts-ignore +import { DemonstratingProofOfPossessionConfiguration } from './types'; + +function strToUint8(str: string) { + return new TextEncoder().encode(str); +} + +// Binary String to URL-Safe Base64 +// +// btoa (Binary-to-Ascii) means "binary string" to base64 +// @ts-ignore +function binToUrlBase64(bin) { + return btoa(bin).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+/g, ''); +} + +// UTF-8 to Binary String +// +// Because JavaScript has a strange relationship with strings +// https://coolaj86.com/articles/base64-unicode-utf-8-javascript-and-you/ +// @ts-ignore +function utf8ToBinaryString(str) { + const escstr = encodeURIComponent(str); + // replaces any uri escape sequence, such as %0A, + // with binary escape, such as 0x0A + // @ts-ignore + return escstr.replace(/%([0-9A-F]{2})/g, function (match: string, p1) { + return String.fromCharCode(parseInt(p1, 16)); + }); +} + +// Uint8Array to URL Safe Base64 +// +// the shortest distant between two encodings... binary string +// @ts-ignore +export const uint8ToUrlBase64 = (uint8: Uint8Array) => { + let bin = ''; + // @ts-ignore + uint8.forEach(function (code) { + bin += String.fromCharCode(code); + }); + return binToUrlBase64(bin); +}; + +// UCS-2 String to URL-Safe Base64 +// +// btoa doesn't work on UTF-8 strings +// @ts-ignore +function strToUrlBase64(str) { + return binToUrlBase64(utf8ToBinaryString(str)); +} + +export const defaultDemonstratingProofOfPossessionConfiguration: DemonstratingProofOfPossessionConfiguration = + { + importKeyAlgorithm: { + name: 'ECDSA', + namedCurve: 'P-256', + hash: { name: 'ES256' }, + }, + signAlgorithm: { name: 'ECDSA', hash: { name: 'SHA-256' } }, + generateKeyAlgorithm: { + name: 'ECDSA', + namedCurve: 'P-256', + }, + digestAlgorithm: { name: 'SHA-256' }, + jwtHeaderAlgorithm: 'ES256', + }; + +// @ts-ignore +const sign = + (w: any) => + async ( + jwk: any, + headers: any, + claims: any, + demonstratingProofOfPossessionConfiguration: DemonstratingProofOfPossessionConfiguration, + jwtHeaderType = 'dpop+jwt', + ) => { + // Make a shallow copy of the key + // (to set ext if it wasn't already set) + jwk = Object.assign({}, jwk); + + // The headers should probably be empty + headers.typ = jwtHeaderType; + headers.alg = demonstratingProofOfPossessionConfiguration.jwtHeaderAlgorithm; + switch (headers.alg) { + case 'ES256': //if (!headers.kid) { + // alternate: see thumbprint function below + headers.jwk = { kty: jwk.kty, crv: jwk.crv, x: jwk.x, y: jwk.y }; + //} + break; + case 'RS256': + headers.jwk = { kty: jwk.kty, n: jwk.n, e: jwk.e, kid: headers.kid }; + break; + default: + throw new Error('Unknown or not implemented JWS algorithm'); + } + + const jws = { + // @ts-ignore + // JWT "headers" really means JWS "protected headers" + protected: strToUrlBase64(JSON.stringify(headers)), + // @ts-ignore + // JWT "claims" are really a JSON-defined JWS "payload" + payload: strToUrlBase64(JSON.stringify(claims)), + }; + + // To import as EC (ECDSA, P-256, SHA-256, ES256) + const keyType = demonstratingProofOfPossessionConfiguration.importKeyAlgorithm; + + // To make re-exportable as JSON (or DER/PEM) + const exportable = true; + + // Import as a private key that isn't black-listed from signing + const privileges = ['sign']; + + // Actually do the import, which comes out as an abstract key type + // @ts-ignore + const privateKey = await w.crypto.subtle.importKey('jwk', jwk, keyType, exportable, privileges); + // Convert UTF-8 to Uint8Array ArrayBuffer + // @ts-ignore + const data = strToUint8(`${jws.protected}.${jws.payload}`); + + // The signature and hash should match the bit-entropy of the key + // https://tools.ietf.org/html/rfc7518#section-3 + const signatureType = demonstratingProofOfPossessionConfiguration.signAlgorithm; + + const signature = await w.crypto.subtle.sign(signatureType, privateKey, data); + // returns an ArrayBuffer containing a JOSE (not X509) signature, + // which must be converted to Uint8 to be useful + // @ts-ignore + jws.signature = uint8ToUrlBase64(new Uint8Array(signature)); + // JWT is just a "compressed", "protected" JWS + // @ts-ignore + return `${jws.protected}.${jws.payload}.${jws.signature}`; + }; + +export const JWT = { sign }; + +// @ts-ignore +const generate = + (w: any) => async (generateKeyAlgorithm: RsaHashedKeyGenParams | EcKeyGenParams) => { + const keyType = generateKeyAlgorithm; + const exportable = true; + const privileges = ['sign', 'verify']; + // @ts-ignore + const key = await w.crypto.subtle.generateKey(keyType, exportable, privileges); + // returns an abstract and opaque WebCrypto object, + // which in most cases you'll want to export as JSON to be able to save + return await w.crypto.subtle.exportKey('jwk', key.privateKey); + }; + +// Create a Public Key from a Private Key +// +// chops off the private parts +// @ts-ignore +const neuter = jwk => { + const copy = Object.assign({}, jwk); + delete copy.d; + copy.key_ops = ['verify']; + return copy; +}; + +const EC = { + generate, + neuter, +}; +// @ts-ignore +const thumbprint = (w: any) => async (jwk, digestAlgorithm: AlgorithmIdentifier) => { + let sortedPub; + // lexigraphically sorted, no spaces + switch (jwk.kty) { + case 'EC': + sortedPub = '{"crv":"CRV","kty":"EC","x":"X","y":"Y"}' + .replace('CRV', jwk.crv) + .replace('X', jwk.x) + .replace('Y', jwk.y); + break; + case 'RSA': + sortedPub = '{"e":"E","kty":"RSA","n":"N"}'.replace('E', jwk.e).replace('N', jwk.n); + break; + default: + throw new Error('Unknown or not implemented JWK type'); + } + // The hash should match the size of the key, + // but we're only dealing with P-256 + const hash = await w.crypto.subtle.digest(digestAlgorithm, strToUint8(sortedPub)); + return uint8ToUrlBase64(new Uint8Array(hash)); +}; + +export const JWK = { thumbprint }; + +export const generateJwkAsync = + (w: any) => async (generateKeyAlgorithm: RsaHashedKeyGenParams | EcKeyGenParams) => { + // @ts-ignore + const jwk = await EC.generate(w)(generateKeyAlgorithm); + // console.info('Private Key:', JSON.stringify(jwk)); + // @ts-ignore + // console.info('Public Key:', JSON.stringify(EC.neuter(jwk))); + return jwk; + }; + +export const generateJwtDemonstratingProofOfPossessionAsync = + (w: any) => + (demonstratingProofOfPossessionConfiguration: DemonstratingProofOfPossessionConfiguration) => + async (jwk: any, method = 'POST', url: string, extrasClaims = {}) => { + const claims = { + // https://www.rfc-editor.org/rfc/rfc9449.html#name-concept + jti: btoa(guid()), + htm: method, + htu: url, + iat: Math.round(Date.now() / 1000), + ...extrasClaims, + }; + // @ts-ignore + const kid = await JWK.thumbprint(w)( + jwk, + demonstratingProofOfPossessionConfiguration.digestAlgorithm, + ); + // @ts-ignore + const jwt = await JWT.sign(w)( + jwk, + { kid: kid }, + claims, + demonstratingProofOfPossessionConfiguration, + ); + // console.info('JWT:', jwt); + return jwt; + }; + +const guid = () => { + // RFC4122: The version 4 UUID is meant for generating UUIDs from truly-random or + // pseudo-random numbers. + // The algorithm is as follows: + // Set the two most significant bits (bits 6 and 7) of the + // clock_seq_hi_and_reserved to zero and one, respectively. + // Set the four most significant bits (bits 12 through 15) of the + // time_hi_and_version field to the 4-bit version number from + // Section 4.1.3. Version4 + // Set all the other bits to randomly (or pseudo-randomly) chosen + // values. + // UUID = time-low "-" time-mid "-"time-high-and-version "-"clock-seq-reserved and low(2hexOctet)"-" node + // time-low = 4hexOctet + // time-mid = 2hexOctet + // time-high-and-version = 2hexOctet + // clock-seq-and-reserved = hexOctet: + // clock-seq-low = hexOctet + // node = 6hexOctet + // Format: xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx + // y could be 1000, 1001, 1010, 1011 since most significant two bits needs to be 10 + // y values are 8, 9, A, B + const guidHolder = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'; + const hex = '0123456789abcdef'; + let r = 0; + let guidResponse = ''; + for (let i = 0; i < 36; i++) { + if (guidHolder[i] !== '-' && guidHolder[i] !== '4') { + // each x and y needs to be random + r = (Math.random() * 16) | 0; + } + + if (guidHolder[i] === 'x') { + guidResponse += hex[r]; + } else if (guidHolder[i] === 'y') { + // clock-seq-and-reserved first hex is filtered and remaining hex values are random + r &= 0x3; // bit and with 0011 to set pos 2 to zero ?0?? + r |= 0x8; // set pos 3 to 1 as 1??? + guidResponse += hex[r]; + } else { + guidResponse += guidHolder[i]; + } + } + + return guidResponse; +}; diff --git a/packages/oidc-client-service-worker/src/oidcConfig.ts b/packages/oidc-client-service-worker/src/oidcConfig.ts new file mode 100644 index 000000000..e8bfe9e92 --- /dev/null +++ b/packages/oidc-client-service-worker/src/oidcConfig.ts @@ -0,0 +1,17 @@ +import { Database, OidcConfig } from './types'; +import { normalizeUrl } from './utils'; + +const getMatchingOidcConfigurations = (database: Database, url: string): OidcConfig[] => { + return Object.values(database).filter(config => { + const { oidcServerConfiguration } = config || {}; + const { tokenEndpoint, revocationEndpoint } = oidcServerConfiguration || {}; + + const normalizedUrl = normalizeUrl(url); + return ( + (tokenEndpoint && normalizedUrl.startsWith(normalizeUrl(tokenEndpoint))) || + (revocationEndpoint && normalizedUrl.startsWith(normalizeUrl(revocationEndpoint))) + ); + }); +}; + +export { getMatchingOidcConfigurations as getCurrentDatabasesTokenEndpoint }; diff --git a/packages/oidc-client-service-worker/src/types.ts b/packages/oidc-client-service-worker/src/types.ts index 4fbce2143..5eae77bbf 100644 --- a/packages/oidc-client-service-worker/src/types.ts +++ b/packages/oidc-client-service-worker/src/types.ts @@ -1,101 +1,154 @@ export type DomainDetails = { - domains?: Domain[]; - oidcDomains?: Domain[]; - accessTokenDomains?: Domain[]; - showAccessToken: boolean; + domains?: Domain[]; + oidcDomains?: Domain[]; + accessTokenDomains?: Domain[]; + showAccessToken: boolean; + convertAllRequestsToCorsExceptNavigate?: boolean; + setAccessTokenToNavigateRequests?: boolean; + demonstratingProofOfPossession?: boolean; + demonstratingProofOfPossessionOnlyWhenDpopHeaderPresent?: boolean; + demonstratingProofOfPossessionConfiguration?: DemonstratingProofOfPossessionConfiguration; + allowMultiTabLogin?: boolean; +}; + +export interface DemonstratingProofOfPossessionConfiguration { + generateKeyAlgorithm: RsaHashedKeyGenParams | EcKeyGenParams; + digestAlgorithm: AlgorithmIdentifier; + importKeyAlgorithm: + | AlgorithmIdentifier + | RsaHashedImportParams + | EcKeyImportParams + | HmacImportParams + | AesKeyAlgorithm; + signAlgorithm: AlgorithmIdentifier | RsaPssParams | EcdsaParams; + jwtHeaderAlgorithm: string; } export type Domain = string | RegExp; export type TrustedDomains = { - [key: string]: Domain[] | DomainDetails; + [key: string]: Domain[] | DomainDetails; } | null; export type OidcServerConfiguration = { - revocationEndpoint: string; - issuer: string; - authorizationEndpoint: string; - tokenEndpoint: string; - userInfoEndpoint: string; -} + revocationEndpoint: string; + issuer: string; + authorizationEndpoint: string; + tokenEndpoint: string; + userInfoEndpoint: string; +}; export type OidcConfiguration = { - token_renew_mode: string; - service_worker_convert_all_requests_to_cors: boolean; -} + token_renew_mode: string; + demonstrating_proof_of_possession: boolean; +}; // Uncertain why the Headers interface in lib.webworker.d.ts does not have a keys() function, so extending export interface FetchHeaders extends Headers { - keys(): string[]; + keys(): string[]; } -export type Status = 'LOGGED' | 'LOGGED_IN' | 'LOGGED_OUT' | 'NOT_CONNECTED' | 'LOGOUT_FROM_ANOTHER_TAB' | 'SESSION_LOST' | 'REQUIRE_SYNC_TOKENS' | 'FORCE_REFRESH' | null; -export type MessageEventType = 'clear' | 'init' | 'setState' | 'getState' | 'setCodeVerifier' | 'getCodeVerifier' | 'setSessionState' | 'getSessionState' | 'setNonce' | 'getNonce'; +export type Status = + | 'LOGGED' + | 'LOGGED_IN' + | 'LOGGED_OUT' + | 'NOT_CONNECTED' + | 'LOGOUT_FROM_ANOTHER_TAB' + | 'SESSION_LOST' + | 'REQUIRE_SYNC_TOKENS' + | 'FORCE_REFRESH' + | null; +export type MessageEventType = + | 'clear' + | 'init' + | 'setState' + | 'getState' + | 'setCodeVerifier' + | 'getCodeVerifier' + | 'setSessionState' + | 'getSessionState' + | 'setNonce' + | 'getNonce' + | 'setDemonstratingProofOfPossessionNonce' + | 'getDemonstratingProofOfPossessionNonce' + | 'setDemonstratingProofOfPossessionJwk' + | 'getDemonstratingProofOfPossessionJwk'; export type MessageData = { - status: Status; - oidcServerConfiguration: OidcServerConfiguration; - oidcConfiguration: OidcConfiguration; - where: string; - state: string; - codeVerifier: string; - sessionState: string; - nonce: Nonce; -} + status: Status; + oidcServerConfiguration: OidcServerConfiguration; + oidcConfiguration: OidcConfiguration; + where: string; + state: string; + codeVerifier: string; + sessionState: string; + demonstratingProofOfPossessionNonce: string; + demonstratingProofOfPossessionJwkJson: string; + nonce: Nonce; +}; export type MessageEventData = { - configurationName: string; - type: MessageEventType; - data: MessageData; -} + configurationName: string; + tabId: string; + type: MessageEventType; + data: MessageData; +}; export type Nonce = { - nonce: string; + nonce: string; } | null; export type OidcConfig = { - configurationName: string; - tokens: Tokens | null; - status: Status; - state: string | null; - codeVerifier: string | null; - nonce: Nonce; - oidcServerConfiguration: OidcServerConfiguration | null; - oidcConfiguration?: OidcConfiguration; - sessionState?: string | null; - items?: MessageData; - hideAccessToken: boolean; -} + demonstratingProofOfPossessionConfiguration: DemonstratingProofOfPossessionConfiguration | null; + configurationName: string; + tokens: Tokens | null; + status: Status; + state: string | null; + codeVerifier: string | null; + nonce: Nonce; + oidcServerConfiguration: OidcServerConfiguration | null; + oidcConfiguration?: OidcConfiguration; + sessionState?: string | null; + items?: MessageData; + hideAccessToken: boolean; + convertAllRequestsToCorsExceptNavigate: boolean; + setAccessTokenToNavigateRequests: boolean; + demonstratingProofOfPossessionNonce: string | null; + demonstratingProofOfPossessionJwkJson: string | null; + demonstratingProofOfPossessionOnlyWhenDpopHeaderPresent: boolean; + allowMultiTabLogin: boolean; +}; export type IdTokenPayload = { - iss: string; - /** - * (Expiration Time) Claim - */ - exp: number; - /** - * (Issued At) Claim - */ - iat: number; - nonce: string | null; -} + iss: string; + /** + * (Expiration Time) Claim + */ + exp: number; + /** + * (Issued At) Claim + */ + iat: number; + nonce: string | null; +}; export type AccessTokenPayload = { - exp: number; - sub: string; -} + exp: number; + sub: string; + iat: number; +}; export type Tokens = { - issued_at: number; - access_token: string; - accessTokenPayload: AccessTokenPayload | null; - id_token: null | string; - idTokenPayload: IdTokenPayload; - refresh_token?: string; - expiresAt: number; - expires_in: number; + issued_at: number | string; + access_token: string; + accessTokenPayload: AccessTokenPayload | null; + id_token: null | string; + idTokenPayload: IdTokenPayload; + refresh_token?: string; + expiresAt: number; + expires_in: number | string; }; export type Database = { - [key: string]: OidcConfig; -} + [key: string]: OidcConfig; +}; diff --git a/packages/oidc-client-service-worker/src/utils/__tests__/codeVerifier.spec.ts b/packages/oidc-client-service-worker/src/utils/__tests__/codeVerifier.spec.ts index e2ad25a05..e5ab148c1 100644 --- a/packages/oidc-client-service-worker/src/utils/__tests__/codeVerifier.spec.ts +++ b/packages/oidc-client-service-worker/src/utils/__tests__/codeVerifier.spec.ts @@ -1,13 +1,38 @@ import { describe, expect, it } from 'vitest'; -import { replaceCodeVerifier } from '../codeVerifier'; +import { extractConfigurationNameFromCodeVerifier, replaceCodeVerifier } from '../codeVerifier'; describe('replaceCodeVerifier should', () => { - it.each([ - { body: 'code=F5CDCDB9AADB9ADA59560DE80CAAA6688BC5C8BA1CC1C1F9839F7E7B32171B3D-1&grant_type=authorization_code&client_id=interactive.public.short&redirect_uri=http%3A%2F%2Flocalhost%3A4200%2Fauthentication%2Fcallback&code_verifier=ONskPfcbfAYPp5xqhpMstHSz017896R7sy3wqrRdqC8lYB8yQciCCNLooqLC9qHFTF2FFhDQP4m8PEFNSry8eoCbQ9baYcoWjF1bEH6vGWExdTIMqauicjeVxqz58FO8', bodyExpected: 'code=F5CDCDB9AADB9ADA59560DE80CAAA6688BC5C8BA1CC1C1F9839F7E7B32171B3D-1&grant_type=authorization_code&client_id=interactive.public.short&redirect_uri=http%3A%2F%2Flocalhost%3A4200%2Fauthentication%2Fcallback&code_verifier=1234' }, - { body: 'code=F5CDCDB9AADB9ADA59560DE80CAAA6688BC5C8BA1CC1C1F9839F7E7B32171B3D-1&code_verifier=ONskPfcbfAYPp5xqhpMstHSz017896R7sy3wqrRdqC8lYB8yQciCCNLooqLC9qHFTF2FFhDQP4m8PEFNSry8eoCbQ9baYcoWjF1bEH6vGWExdTIMqauicjeVxqz58FO8&grant_type=authorization_code&client_id=interactive.public.short&redirect_uri=http%3A%2F%2Flocalhost%3A4200%2Fauthentication%2Fcallback', bodyExpected: 'code=F5CDCDB9AADB9ADA59560DE80CAAA6688BC5C8BA1CC1C1F9839F7E7B32171B3D-1&code_verifier=1234&grant_type=authorization_code&client_id=interactive.public.short&redirect_uri=http%3A%2F%2Flocalhost%3A4200%2Fauthentication%2Fcallback' }, - ])('inject new codeVerifier', async ({ body, bodyExpected }) => { - const result = replaceCodeVerifier(body, '1234'); - expect(bodyExpected).toEqual(result); - }); + it.each([ + { + body: 'code=F5CDCDB9AADB9ADA59560DE80CAAA6688BC5C8BA1CC1C1F9839F7E7B32171B3D-1&grant_type=authorization_code&client_id=interactive.public.short&redirect_uri=http%3A%2F%2Flocalhost%3A4200%2Fauthentication%2Fcallback&code_verifier=ONskPfcbfAYPp5xqhpMstHSz017896R7sy3wqrRdqC8lYB8yQciCCNLooqLC9qHFTF2FFhDQP4m8PEFNSry8eoCbQ9baYcoWjF1bEH6vGWExdTIMqauicjeVxqz58FO8', + bodyExpected: + 'code=F5CDCDB9AADB9ADA59560DE80CAAA6688BC5C8BA1CC1C1F9839F7E7B32171B3D-1&grant_type=authorization_code&client_id=interactive.public.short&redirect_uri=http%3A%2F%2Flocalhost%3A4200%2Fauthentication%2Fcallback&code_verifier=1234', + }, + { + body: 'code=F5CDCDB9AADB9ADA59560DE80CAAA6688BC5C8BA1CC1C1F9839F7E7B32171B3D-1&code_verifier=ONskPfcbfAYPp5xqhpMstHSz017896R7sy3wqrRdqC8lYB8yQciCCNLooqLC9qHFTF2FFhDQP4m8PEFNSry8eoCbQ9baYcoWjF1bEH6vGWExdTIMqauicjeVxqz58FO8&grant_type=authorization_code&client_id=interactive.public.short&redirect_uri=http%3A%2F%2Flocalhost%3A4200%2Fauthentication%2Fcallback', + bodyExpected: + 'code=F5CDCDB9AADB9ADA59560DE80CAAA6688BC5C8BA1CC1C1F9839F7E7B32171B3D-1&code_verifier=1234&grant_type=authorization_code&client_id=interactive.public.short&redirect_uri=http%3A%2F%2Flocalhost%3A4200%2Fauthentication%2Fcallback', + }, + ])('inject new codeVerifier', async ({ body, bodyExpected }) => { + const result = replaceCodeVerifier(body, '1234'); + expect(bodyExpected).toEqual(result); + }); +}); + +describe('extractConfigurationNameFromCodeVerifier should', () => { + it.each([ + { + body: 'code=56DB8E3592FBD48DCF6F65B38B12845FF0186ECF6D66ECB5425C0F7E658B7951-1&grant_type=authorization_code&client_id=interactive.public.short&redirect_uri=https%3A%2F%2Fblack-rock-0dc6b0d03.1.azurestaticapps.net%2Fauthentication%2Fcallback&code_verifier=CODE_VERIFIER_SECURED_BY_OIDC_SERVICE_WORKER_default_tab1', + expected: 'default_tab1', + }, + { + body: 'code=56DB8E3592FBD48DCF6F65B38B12845FF0186ECF6D66ECB5425C0F7E658B7951-1&code_verifier=CODE_VERIFIER_SECURED_BY_OIDC_SERVICE_WORKER_youhou_tab2&grant_type=authorization_code&client_id=interactive.public.short&redirect_uri=https%3A%2F%2Fblack-rock-0dc6b0d03.1.azurestaticapps.net%2Fauthentication%2Fcallback', + expected: 'youhou_tab2', + }, + ])('inject new codeVerifier', async ({ body, expected }) => { + const configurationName = extractConfigurationNameFromCodeVerifier(body); + console.log(configurationName); + expect(configurationName).toEqual(expected); + }); }); diff --git a/packages/oidc-client-service-worker/src/utils/__tests__/domains.spec.ts b/packages/oidc-client-service-worker/src/utils/__tests__/domains.spec.ts index 9ba81d569..371bd415c 100644 --- a/packages/oidc-client-service-worker/src/utils/__tests__/domains.spec.ts +++ b/packages/oidc-client-service-worker/src/utils/__tests__/domains.spec.ts @@ -1,68 +1,117 @@ -import { describe, expect, it } from 'vitest'; +import { beforeEach, describe, expect, it } from 'vitest'; import { openidWellknownUrlEndWith } from '../../constants'; +import { Database, Tokens, TrustedDomains } from '../../types'; import { checkDomain, getCurrentDatabaseDomain } from '..'; -import { Database, OidcServerConfiguration, Tokens, TrustedDomains } from './../../types'; describe('domains', () => { describe('can check domain matches', () => { - it('can check string domains and return void', () => { - const result = () => - checkDomain( - ['https://securesite.com:3000'], - 'https://securesite.com:3000', - ); - expect(result()).toBeUndefined(); + it('can check string domains without throwing an exception', () => { + expect(() => { + checkDomain(['https://securesite.com:3000'], 'https://securesite.com:3000'); + }).not.toThrow(); }); - it('can check regExp domains and return void when valid', () => { - const result = () => - checkDomain( - [/^https:\/\/securesite\.com/], - 'https://securesite.com:3000', - ); - expect(result()).toBeUndefined(); + it('can check regExp domains without throwing an exception when valid', () => { + expect(() => { + checkDomain([/^https:\/\/securesite\.com/], 'https://securesite.com:3000'); + }).not.toThrow(); }); it('will throw error when domain is not trusted', () => { const result = () => - checkDomain( - ['https://notsecuresite.com'], - 'https://securesite.com:3000', - ); + checkDomain(['https://notsecuresite.com'], 'https://securesite.com:3000'); expect(result).toThrowError(); }); - it('will return void when endpoint is falsy', () => { - const result = () => checkDomain(['https://securesite.com:3000'], ''); - expect(result()).toBeUndefined(); + it('will not throw an exception when endpoint is falsy', () => { + expect(() => { + checkDomain(['https://securesite.com:3000'], ''); + }).not.toThrow(); }); }); describe('getCurrentDatabaseDomain', () => { - const db: Database = { - default: { - configurationName: 'config', - tokens: {} as Tokens, - status: 'NOT_CONNECTED', - state: null, - codeVerifier: null, - nonce: null, - oidcServerConfiguration: {} as OidcServerConfiguration, - hideAccessToken: true, - }, - }; + let db: Database; + + beforeEach(() => { + db = { + default: { + configurationName: 'config', + tokens: {} as Tokens, + status: 'NOT_CONNECTED', + state: null, + codeVerifier: null, + nonce: null, + oidcServerConfiguration: { + authorizationEndpoint: 'https://demo.duendesoftware.com/connect/authorize', + issuer: 'https://demo.duendesoftware.com', + revocationEndpoint: 'https://demo.duendesoftware.com/connect/revocation', + tokenEndpoint: 'https://demo.duendesoftware.com/connect/token', + userInfoEndpoint: 'https://demo.duendesoftware.com/connect/userinfo', + }, + hideAccessToken: true, + convertAllRequestsToCorsExceptNavigate: false, + setAccessTokenToNavigateRequests: true, + demonstratingProofOfPossessionNonce: null, + demonstratingProofOfPossessionJwkJson: null, + demonstratingProofOfPossessionConfiguration: null, + demonstratingProofOfPossessionOnlyWhenDpopHeaderPresent: false, + allowMultiTabLogin: true, + }, + }; + }); it('will return null when url ends with openidWellknownUrlEndWith', () => { const trustedDomains: TrustedDomains = { - default: [ - 'https://demo.duendesoftware.com', - 'https://kdhttps.auth0.com', - ], + default: ['https://demo.duendesoftware.com', 'https://kdhttps.auth0.com'], }; const url = 'http://url' + openidWellknownUrlEndWith; expect(getCurrentDatabaseDomain(db, url, trustedDomains)).toBeNull(); }); + it('will return null when url is the token endpoint', () => { + const trustedDomains: TrustedDomains = { + default: ['https://demo.duendesoftware.com', 'https://kdhttps.auth0.com'], + }; + const url = 'https://demo.duendesoftware.com/connect/token'; + expect(getCurrentDatabaseDomain(db, url, trustedDomains)).toStrictEqual([]); + }); + + it('will return null when url is the token endpoint oidc config token endpoint has a default port', () => { + const trustedDomains: TrustedDomains = { + default: ['https://demo.duendesoftware.com', 'https://kdhttps.auth0.com'], + }; + db['default'].oidcServerConfiguration!.tokenEndpoint = + 'https://demo.duendesoftware.com:443/connect/token'; + + const url = 'https://demo.duendesoftware.com/connect/token'; + expect(getCurrentDatabaseDomain(db, url, trustedDomains)).toStrictEqual([]); + }); + + it('will return null when url is the revocation endpoint', () => { + const trustedDomains: TrustedDomains = { + default: ['https://demo.duendesoftware.com', 'https://kdhttps.auth0.com'], + }; + const url = 'https://demo.duendesoftware.com/connect/revocation'; + expect(getCurrentDatabaseDomain(db, url, trustedDomains)).toStrictEqual([]); + }); + + it('will not return null when url is the userinfo endpoint', () => { + const trustedDomains: TrustedDomains = { + default: ['https://demo.duendesoftware.com', 'https://kdhttps.auth0.com'], + }; + const url = 'https://demo.duendesoftware.com/connect/userinfo'; + expect(getCurrentDatabaseDomain(db, url, trustedDomains)).not.toBeNull(); + }); + + it('will not return null, url is the userinfo endpoint on other domain, default port is set', () => { + db['default'].oidcServerConfiguration!.userInfoEndpoint = + 'https://otherdomain.com:443/connect/userinfo'; + + const url = 'https://otherdomain.com/connect/userinfo'; + expect(getCurrentDatabaseDomain(db, url, null)).not.toBeNull(); + }); + it('will test urls against domains list if accessTokenDomains list is not present', () => { const trustedDomains: TrustedDomains = { default: { @@ -71,7 +120,9 @@ describe('domains', () => { }, }; - expect(getCurrentDatabaseDomain(db, 'https://domain/test', trustedDomains)).toBe(db.default); + expect(getCurrentDatabaseDomain(db, 'https://domain/test', trustedDomains)).toStrictEqual([ + db.default, + ]); }); it('will test urls against accessTokenDomains list if it is present and ignore domains list', () => { @@ -83,8 +134,10 @@ describe('domains', () => { }, }; - expect(getCurrentDatabaseDomain(db, 'https://myapi/test', trustedDomains)).toBe(db.default); - expect(getCurrentDatabaseDomain(db, 'https://domain/test', trustedDomains)).toBeNull(); + expect(getCurrentDatabaseDomain(db, 'https://myapi/test', trustedDomains)).toStrictEqual([ + db.default, + ]); + expect(getCurrentDatabaseDomain(db, 'https://domain/test', trustedDomains)).toStrictEqual([]); }); }); }); diff --git a/packages/oidc-client-service-worker/src/utils/__tests__/normalizeUrl.spec.ts b/packages/oidc-client-service-worker/src/utils/__tests__/normalizeUrl.spec.ts new file mode 100644 index 000000000..98c6826fe --- /dev/null +++ b/packages/oidc-client-service-worker/src/utils/__tests__/normalizeUrl.spec.ts @@ -0,0 +1,28 @@ +import { describe, expect, it } from 'vitest'; + +import { normalizeUrl } from '../normalizeUrl'; + +describe('normalizeUrl', () => { + it('keeps urls the same', () => { + expect(normalizeUrl('http://foo.com/')).toBe('http://foo.com/'); + expect(normalizeUrl('https://foo.com/')).toBe('https://foo.com/'); + }); + it('adds slashes', () => { + expect(normalizeUrl('http://foo.com')).toBe('http://foo.com/'); + }); + it('removes port numbers', () => { + expect(normalizeUrl('http://foo.com:80/')).toBe('http://foo.com/'); + expect(normalizeUrl('https://foo.com:443/')).toBe('https://foo.com/'); + }); + it('removed port numbers and adds slashes', () => { + expect(normalizeUrl('http://foo.com:80')).toBe('http://foo.com/'); + expect(normalizeUrl('https://foo.com:443')).toBe('https://foo.com/'); + }); + it('lowercases urls', () => { + expect(normalizeUrl('http://FOO.com/')).toBe('http://foo.com/'); + }); + + it('keeps invalid urls', () => { + expect(normalizeUrl('foo')).toBe('foo'); + }); +}); diff --git a/packages/oidc-client-service-worker/src/utils/__tests__/serializeHeaders.spec.ts b/packages/oidc-client-service-worker/src/utils/__tests__/serializeHeaders.spec.ts index 945badb74..4b78f43c6 100644 --- a/packages/oidc-client-service-worker/src/utils/__tests__/serializeHeaders.spec.ts +++ b/packages/oidc-client-service-worker/src/utils/__tests__/serializeHeaders.spec.ts @@ -4,9 +4,7 @@ import { serializeHeaders } from '..'; describe('serializeHeaders', () => { it('can serialize basic header', () => { - const result = serializeHeaders( - new Headers({ 'Content-Type': 'application/json' }), - ); // Error: Argument of type 'Headers' is not assignable to parameter of type 'Headers'.(2345 + const result = serializeHeaders(new Headers({ 'Content-Type': 'application/json' })); // Error: Argument of type 'Headers' is not assignable to parameter of type 'Headers'.(2345 expect(result).toEqual({ 'content-type': 'application/json' }); }); }); diff --git a/packages/oidc-client-service-worker/src/utils/__tests__/testHelper.ts b/packages/oidc-client-service-worker/src/utils/__tests__/testHelper.ts index 37e11373b..09d74e46d 100644 --- a/packages/oidc-client-service-worker/src/utils/__tests__/testHelper.ts +++ b/packages/oidc-client-service-worker/src/utils/__tests__/testHelper.ts @@ -44,7 +44,7 @@ class TokenBuilder { return this; } - public WithNonExpiredToken(): TokenBuilder { + public withNonExpiredToken(): TokenBuilder { this.withExpiresAt(currentTimeUnixSeconds() + 60); this.withExpiresIn(currentTimeUnixSeconds() + 60); this.withIssuedAt(currentTimeUnixSeconds() - 60); @@ -56,12 +56,12 @@ class TokenBuilder { return this; } - public withIssuedAt(issued_at: number): TokenBuilder { + public withIssuedAt(issued_at: number | string): TokenBuilder { this.tokens.issued_at = issued_at; return this; } - public withExpiresIn(expires_in: number): TokenBuilder { + public withExpiresIn(expires_in: number | string): TokenBuilder { this.tokens.expires_in = expires_in; return this; } @@ -71,9 +71,7 @@ class TokenBuilder { return this; } - public withAccessTokenPayload( - accessTokenPayload: AccessTokenPayload, - ): TokenBuilder { + public withAccessTokenPayload(accessTokenPayload: AccessTokenPayload): TokenBuilder { this.tokens.accessTokenPayload = accessTokenPayload; return this; } @@ -96,24 +94,14 @@ class TokenBuilder { class OidcConfigurationBuilder { private oidcConfiguration: OidcConfiguration = { token_renew_mode: 'offline', - service_worker_convert_all_requests_to_cors: true, + demonstrating_proof_of_possession: false, }; - public withTokenRenewMode( - token_renew_mode: string, - ): OidcConfigurationBuilder { + public withTokenRenewMode(token_renew_mode: string): OidcConfigurationBuilder { this.oidcConfiguration.token_renew_mode = token_renew_mode; return this; } - public withServiceWorkerConvertAllRequestsToCors( - service_worker_convert_all_requests_to_cors: boolean, - ): OidcConfigurationBuilder { - this.oidcConfiguration.service_worker_convert_all_requests_to_cors = - service_worker_convert_all_requests_to_cors; - return this; - } - public build(): OidcConfiguration { return this.oidcConfiguration; } @@ -124,19 +112,26 @@ class OidcConfigBuilder { configurationName: '', tokens: null, status: 'NOT_CONNECTED', - state: '', - codeVerifier: '', + state: null, + codeVerifier: null, nonce: null, oidcServerConfiguration: null, oidcConfiguration: undefined, sessionState: null, items: undefined, hideAccessToken: true, + convertAllRequestsToCorsExceptNavigate: false, + setAccessTokenToNavigateRequests: true, + demonstratingProofOfPossessionNonce: null, + demonstratingProofOfPossessionJwkJson: null, + demonstratingProofOfPossessionConfiguration: null, + demonstratingProofOfPossessionOnlyWhenDpopHeaderPresent: false, + allowMultiTabLogin: true, }; public withTestingDefault(): OidcConfigBuilder { this.oidcConfig.configurationName = 'test'; - this.oidcConfig.tokens = new TokenBuilder().WithNonExpiredToken().build(); + this.oidcConfig.tokens = new TokenBuilder().withNonExpiredToken().build(); this.oidcConfig.status = 'NOT_CONNECTED'; this.oidcConfig.state = 'state'; this.oidcConfig.codeVerifier = 'codeVerifier'; @@ -193,6 +188,11 @@ class OidcConfigBuilder { return this; } + public withOidcConfiguration(oidcConfiguration: OidcConfiguration): OidcConfigBuilder { + this.oidcConfig.oidcConfiguration = oidcConfiguration; + return this; + } + public build() { return this.oidcConfig; } @@ -208,19 +208,15 @@ class OidcServerConfigBuilder { }; public withTestingDefault(): OidcServerConfigBuilder { - this.oidcServerConfig.revocationEndpoint = - 'http://localhost:3000/revocation'; + this.oidcServerConfig.revocationEndpoint = 'http://localhost:3000/revocation'; this.oidcServerConfig.issuer = 'http://localhost:3000'; - this.oidcServerConfig.authorizationEndpoint = - 'http://localhost:3000/authorization'; + this.oidcServerConfig.authorizationEndpoint = 'http://localhost:3000/authorization'; this.oidcServerConfig.tokenEndpoint = 'http://localhost:3000/token'; this.oidcServerConfig.userInfoEndpoint = 'http://localhost:3000/userinfo'; return this; } - public withRevocationEndpoint( - revocationEndpoint: string, - ): OidcServerConfigBuilder { + public withRevocationEndpoint(revocationEndpoint: string): OidcServerConfigBuilder { this.oidcServerConfig.revocationEndpoint = revocationEndpoint; return this; } @@ -230,9 +226,7 @@ class OidcServerConfigBuilder { return this; } - public withAuthorizationEndpoint( - authorizationEndpoint: string, - ): OidcServerConfigBuilder { + public withAuthorizationEndpoint(authorizationEndpoint: string): OidcServerConfigBuilder { this.oidcServerConfig.authorizationEndpoint = authorizationEndpoint; return this; } @@ -242,9 +236,7 @@ class OidcServerConfigBuilder { return this; } - public withUserInfoEndpoint( - userInfoEndpoint: string, - ): OidcServerConfigBuilder { + public withUserInfoEndpoint(userInfoEndpoint: string): OidcServerConfigBuilder { this.oidcServerConfig.userInfoEndpoint = userInfoEndpoint; return this; } @@ -323,7 +315,7 @@ class ResponseBuilder { throw new Error('Function not implemented.'); }, json: function (): Promise { - return new Promise((resolve) => { + return new Promise(resolve => { resolve(this.bodyContent); }); }, diff --git a/packages/oidc-client-service-worker/src/utils/__tests__/tokens.spec.ts b/packages/oidc-client-service-worker/src/utils/__tests__/tokens.spec.ts index e8b9d0de5..11de6dedf 100644 --- a/packages/oidc-client-service-worker/src/utils/__tests__/tokens.spec.ts +++ b/packages/oidc-client-service-worker/src/utils/__tests__/tokens.spec.ts @@ -1,27 +1,23 @@ import { beforeEach, describe, expect, it } from 'vitest'; import { OidcServerConfiguration } from '../../types'; -import { _hideTokens, extractTokenPayload, isTokensOidcValid, isTokensValid } from '..'; +import { _hideTokens, extractTokenPayload, isTokensOidcValid, isTokensValid, parseJwt } from '..'; import { OidcConfigBuilder, OidcServerConfigBuilder, TokenBuilder } from './testHelper'; describe('tokens', () => { let oidcServerConfig: OidcServerConfiguration; beforeEach(() => { - oidcServerConfig = new OidcServerConfigBuilder() - .withTestingDefault() - .build(); + oidcServerConfig = new OidcServerConfigBuilder().withTestingDefault().build(); }); describe('isTokensValid', () => { it('can check expired token', () => { - expect( - isTokensValid(new TokenBuilder().withExpiredToken().build()), - ).toBeFalsy(); + expect(isTokensValid(new TokenBuilder().withExpiredToken().build())).toBeFalsy(); }); it('can check non-expired token', () => { - const token = new TokenBuilder().WithNonExpiredToken().build(); + const token = new TokenBuilder().withNonExpiredToken().build(); expect(isTokensValid(token)).toBeTruthy(); }); @@ -30,6 +26,35 @@ describe('tokens', () => { }); }); + describe.each([ + [ + 'eyJzZXNzaW9uX3N0YXRlIjoiNzVjYzVlZDItZGYyZC00NTY5LWJmYzUtMThhOThlNjhiZTExIiwic2NvcGUiOiJvcGVuaWQgZW1haWwgcHJvZmlsZSIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJuYW1lIjoixrTHosOBw6zDhyDlsI_lkI0t44Ob44Or44OYIiwicHJlZmVycmVkX3VzZXJuYW1lIjoidGVzdGluZ2NoYXJhY3RlcnNAaW52ZW50ZWRtYWlsLmNvbSIsImdpdmVuX25hbWUiOiLGtMeiw4HDrMOHIiwiZmFtaWx5X25hbWUiOiLlsI_lkI0t44Ob44Or44OYIn0', + { + session_state: '75cc5ed2-df2d-4569-bfc5-18a98e68be11', + scope: 'openid email profile', + email_verified: true, + name: 'ƴǢÁìÇ 小名-ホルヘ', + preferred_username: 'testingcharacters@inventedmail.com', + given_name: 'ƴǢÁìÇ', + family_name: '小名-ホルヘ', + }, + ], + [ + 'eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCI_IjoiYWE_In0', + { + '?': 'aa?', + iat: 1516239022, + name: 'John Doe', + sub: '1234567890', + }, + ], + ])('parseJwtShouldExtractData', (claimsPart, expectedResult) => { + it('should parseJwtShouldExtractData ', async () => { + const result = parseJwt(claimsPart); + expect(expectedResult).toStrictEqual(result); + }); + }); + describe('extractTokenPayload', () => { it('can extract token payload', () => { const result = extractTokenPayload( @@ -53,7 +78,7 @@ describe('tokens', () => { describe('isTokensOidcValid', () => { it('can validate valid token', () => { const token = new TokenBuilder() - .WithNonExpiredToken() + .withNonExpiredToken() .withIdTokenPayload({ iss: oidcServerConfig.issuer, exp: 0, @@ -69,22 +94,76 @@ describe('tokens', () => { describe('_hideTokens', () => { it.each([ - { hideAccessToken: true, expectedAccessToken: 'ACCESS_TOKEN_SECURED_BY_OIDC_SERVICE_WORKER_test' }, - { hideAccessToken: false, expectedAccessToken: 'test_access_token' }, - ])('accesstoken will be hide $hideAccessToken result should be $expectedAccessToken', ({ hideAccessToken, expectedAccessToken }) => { - const token = new TokenBuilder() + { + hideAccessToken: true, + expectedAccessToken: 'ACCESS_TOKEN_SECURED_BY_OIDC_SERVICE_WORKER_test', + issued_at: '0', + expires_in: '2', + }, + { + hideAccessToken: false, + expectedAccessToken: 'test_access_token', + issued_at: 0, + expires_in: 2, + }, + ])( + 'accesstoken will be hide $hideAccessToken result should be $expectedAccessToken', + ({ hideAccessToken, expectedAccessToken, issued_at, expires_in }) => { + const token = new TokenBuilder() .withIdTokenPayload({ iss: oidcServerConfig.issuer, exp: 0, iat: 0, nonce: null, }) - .WithNonExpiredToken() + .withNonExpiredToken() .withAccessToken('test_access_token') + .withExpiresIn(expires_in) + .withIssuedAt(issued_at) + .build(); + const oidcConfiguration = new OidcConfigBuilder() + .withTestingDefault() + .withHideAccessToken(hideAccessToken) .build(); - const oidcConfiguration = new OidcConfigBuilder().withTestingDefault().withHideAccessToken(hideAccessToken).build(); - const secureTokens = _hideTokens(token, oidcConfiguration, 'test'); - expect(secureTokens.access_token).toBe(expectedAccessToken); + const secureTokens = _hideTokens(token, oidcConfiguration, 'test'); + expect(secureTokens.access_token).toBe(expectedAccessToken); + expect(typeof secureTokens.expiresAt).toBe('number'); + }, + ); + + it('should reuse old id_token', () => { + const token = new TokenBuilder().withNonExpiredToken().build(); + // @ts-ignore + delete token.id_token; + // @ts-ignore + delete token.idTokenPayload; + const oidcConfiguration = new OidcConfigBuilder() + .withOidcConfiguration({ + token_renew_mode: 'access_token_invalid', + demonstrating_proof_of_possession: false, + }) + .withOidcServerConfiguration({ + issuer: '', + authorizationEndpoint: '', + revocationEndpoint: '', + tokenEndpoint: '', + userInfoEndpoint: '', + }) + .withTokens( + new TokenBuilder() + .withNonExpiredToken() + .withIdToken('old_id_token') + .withIdTokenPayload({ + iss: oidcServerConfig.issuer, + exp: 0, + iat: 0, + nonce: null, + }) + .build(), + ) + .build(); + _hideTokens(token, oidcConfiguration, 'test'); + expect(token.id_token).toBe('old_id_token'); }); }); }); diff --git a/packages/oidc-client-service-worker/src/utils/codeVerifier.ts b/packages/oidc-client-service-worker/src/utils/codeVerifier.ts index a011716db..46abc8882 100644 --- a/packages/oidc-client-service-worker/src/utils/codeVerifier.ts +++ b/packages/oidc-client-service-worker/src/utils/codeVerifier.ts @@ -1,4 +1,15 @@ -export function replaceCodeVerifier(codeVerifier:string, newCodeVerifier:string):string { - const regex = /code_verifier=[A-Za-z0-9_-]+/i; - return codeVerifier.replace(regex, `code_verifier=${newCodeVerifier}`); +export function replaceCodeVerifier(codeVerifier: string, newCodeVerifier: string): string { + const regex = /[?&]code_verifier=([^&]+)/i; + return codeVerifier.replace(regex, `&code_verifier=${newCodeVerifier}`); } + +export const extractConfigurationNameFromCodeVerifier = (chaine: string): string => { + const regex = /[?&]code_verifier=CODE_VERIFIER_SECURED_BY_OIDC_SERVICE_WORKER_([^&]+)/; + const match = chaine.match(regex); + + if (match && match.length > 0) { + return decodeURIComponent(match[1]); + } else { + return ''; + } +}; diff --git a/packages/oidc-client-service-worker/src/utils/domains.ts b/packages/oidc-client-service-worker/src/utils/domains.ts index 72c8bfa51..aac61e0b4 100644 --- a/packages/oidc-client-service-worker/src/utils/domains.ts +++ b/packages/oidc-client-service-worker/src/utils/domains.ts @@ -1,16 +1,13 @@ -import { - acceptAnyDomainToken, - openidWellknownUrlEndWith, - scriptFilename, -} from '../constants'; +import { acceptAnyDomainToken, openidWellknownUrlEndWith, scriptFilename } from '../constants'; import { Database, Domain, DomainDetails, OidcConfig, TrustedDomains } from '../types'; +import { normalizeUrl } from './normalizeUrl'; -function checkDomain(domains: Domain[], endpoint: string) { +export function checkDomain(domains: Domain[], endpoint: string) { if (!endpoint) { return; } - const domain = domains.find((domain) => { + const domain = domains.find(domain => { let testable: RegExp; if (typeof domain === 'string') { @@ -23,15 +20,15 @@ function checkDomain(domains: Domain[], endpoint: string) { }); if (!domain) { throw new Error( - 'Domain ' + - endpoint + - ' is not trusted, please add domain in ' + - scriptFilename, + 'Domain ' + endpoint + ' is not trusted, please add domain in ' + scriptFilename, ); } } -export const getDomains = (trustedDomain: Domain[] | DomainDetails, type: 'oidc' | 'accessToken') => { +export const getDomains = ( + trustedDomain: Domain[] | DomainDetails, + type: 'oidc' | 'accessToken', +) => { if (Array.isArray(trustedDomain)) { return trustedDomain; } @@ -39,7 +36,7 @@ export const getDomains = (trustedDomain: Domain[] | DomainDetails, type: 'oidc' return trustedDomain[`${type}Domains`] ?? trustedDomain.domains ?? []; }; -const getCurrentDatabaseDomain = ( +export const getCurrentDatabaseDomain = ( database: Database, url: string, trustedDomains: TrustedDomains, @@ -47,6 +44,7 @@ const getCurrentDatabaseDomain = ( if (url.endsWith(openidWellknownUrlEndWith)) { return null; } + const datatases = []; for (const [key, currentDatabase] of Object.entries(database)) { const oidcServerConfiguration = currentDatabase.oidcServerConfiguration; @@ -56,25 +54,25 @@ const getCurrentDatabaseDomain = ( if ( oidcServerConfiguration.tokenEndpoint && - url === oidcServerConfiguration.tokenEndpoint + url === normalizeUrl(oidcServerConfiguration.tokenEndpoint) ) { continue; } if ( oidcServerConfiguration.revocationEndpoint && - url === oidcServerConfiguration.revocationEndpoint + url === normalizeUrl(oidcServerConfiguration.revocationEndpoint) ) { continue; } - const trustedDomain = trustedDomains == null ? [] : trustedDomains[key]; + const trustedDomain = trustedDomains == null ? [] : trustedDomains[key.split('#')[0]]; const domains = getDomains(trustedDomain, 'accessToken'); const domainsToSendTokens = oidcServerConfiguration.userInfoEndpoint - ? [oidcServerConfiguration.userInfoEndpoint, ...domains] + ? [normalizeUrl(oidcServerConfiguration.userInfoEndpoint), ...domains] : [...domains]; let hasToSendToken = false; - if (domainsToSendTokens.find((f) => f === acceptAnyDomainToken)) { + if (domainsToSendTokens.find(f => f === acceptAnyDomainToken)) { hasToSendToken = true; } else { for (let i = 0; i < domainsToSendTokens.length; i++) { @@ -92,13 +90,10 @@ const getCurrentDatabaseDomain = ( } if (hasToSendToken) { - if (!currentDatabase.tokens) { - return null; + if (currentDatabase.tokens) { + datatases.push(currentDatabase); } - return currentDatabase; } } - return null; + return datatases; }; - -export { checkDomain, getCurrentDatabaseDomain }; diff --git a/packages/oidc-client-service-worker/src/utils/index.ts b/packages/oidc-client-service-worker/src/utils/index.ts index 724a65bc7..a8992e9ec 100644 --- a/packages/oidc-client-service-worker/src/utils/index.ts +++ b/packages/oidc-client-service-worker/src/utils/index.ts @@ -1,4 +1,5 @@ export * from './domains'; +export * from './normalizeUrl'; export * from './serializeHeaders'; export * from './sleep'; export * from './strings'; diff --git a/packages/oidc-client-service-worker/src/utils/normalizeUrl.ts b/packages/oidc-client-service-worker/src/utils/normalizeUrl.ts new file mode 100644 index 000000000..caf2e5cfe --- /dev/null +++ b/packages/oidc-client-service-worker/src/utils/normalizeUrl.ts @@ -0,0 +1,8 @@ +export function normalizeUrl(url: string) { + try { + return new URL(url).toString(); + } catch (error) { + console.error(`Failed to normalize url: ${url}`, error); + return url; + } +} diff --git a/packages/oidc-client-service-worker/src/utils/sleep.ts b/packages/oidc-client-service-worker/src/utils/sleep.ts index 195f8233b..9b8f42807 100644 --- a/packages/oidc-client-service-worker/src/utils/sleep.ts +++ b/packages/oidc-client-service-worker/src/utils/sleep.ts @@ -1,2 +1,2 @@ -const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); +const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms)); export { sleep }; diff --git a/packages/oidc-client-service-worker/src/utils/tokens.ts b/packages/oidc-client-service-worker/src/utils/tokens.ts index 75e5cb95f..21a8ec1f5 100644 --- a/packages/oidc-client-service-worker/src/utils/tokens.ts +++ b/packages/oidc-client-service-worker/src/utils/tokens.ts @@ -1,34 +1,29 @@ /* eslint-disable simple-import-sort/exports */ import { TOKEN, TokenRenewMode } from '../constants'; -import { OidcConfig, OidcConfiguration, OidcServerConfiguration, Tokens } from '../types'; +import { + AccessTokenPayload, + IdTokenPayload, + OidcConfig, + OidcConfiguration, + OidcServerConfiguration, + Tokens, +} from '../types'; import { countLetter } from './strings'; -function parseJwt(token: string) { - return JSON.parse( - b64DecodeUnicode(token.split('.')[1].replace('-', '+').replace('_', '/')), - ); -} +export const parseJwt = (payload: string) => { + return JSON.parse(b64DecodeUnicode(payload.replaceAll(/-/g, '+').replaceAll(/_/g, '/'))); +}; function b64DecodeUnicode(str: string) { return decodeURIComponent( Array.prototype.map - .call( - atob(str), - (c) => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2), - ) + .call(atob(str), c => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)) .join(''), ); } -function computeTimeLeft( - refreshTimeBeforeTokensExpirationInSecond: number, - expiresAt: number, -) { +function computeTimeLeft(refreshTimeBeforeTokensExpirationInSecond: number, expiresAt: number) { const currentTimeUnixSecond = new Date().getTime() / 1000; - return Math.round( - expiresAt - - refreshTimeBeforeTokensExpirationInSecond - - currentTimeUnixSecond, - ); + return Math.round(expiresAt - refreshTimeBeforeTokensExpirationInSecond - currentTimeUnixSecond); } function isTokensValid(tokens: Tokens | null) { @@ -44,7 +39,7 @@ const extractTokenPayload = (token?: string) => { return null; } if (countLetter(token, '.') === 2) { - return parseJwt(token); + return parseJwt(token.split('.')[1]); } else { return null; } @@ -64,8 +59,11 @@ const isTokensOidcValid = ( if (tokens.idTokenPayload) { const idTokenPayload = tokens.idTokenPayload; // 2: The Issuer Identifier for the OpenID Provider (which is typically obtained during Discovery) MUST exactly match the value of the iss (issuer) Claim. - if (oidcServerConfiguration.issuer !== idTokenPayload.iss) { - return { isValid: false, reason: 'Issuer does not match' }; + if (idTokenPayload && oidcServerConfiguration.issuer !== idTokenPayload.iss) { + return { + isValid: false, + reason: `Issuer does not match (oidcServerConfiguration issuer) ${oidcServerConfiguration.issuer} !== (idTokenPayload issuer) ${idTokenPayload.iss}`, + }; } // 3: The Client MUST validate that the aud (audience) Claim contains its client_id value registered at the Issuer identified by the iss (issuer) Claim as an audience. The aud (audience) Claim MAY contain an array with more than one element. The ID Token MUST be rejected if the ID Token does not list the Client as a valid audience, or if it contains additional audiences not trusted by the Client. @@ -73,29 +71,65 @@ const isTokensOidcValid = ( // 9: The current time MUST be before the time represented by the exp Claim. const currentTimeUnixSecond = new Date().getTime() / 1000; - if (idTokenPayload.exp && idTokenPayload.exp < currentTimeUnixSecond) { - return { isValid: false, reason: 'Token expired' }; + if (idTokenPayload && idTokenPayload.exp && idTokenPayload.exp < currentTimeUnixSecond) { + return { + isValid: false, + reason: `Token expired at (idTokenPayload exp) ${idTokenPayload.exp} < (currentTimeUnixSecond) ${currentTimeUnixSecond}`, + }; } // 10: The iat Claim can be used to reject tokens that were issued too far away from the current time, limiting the amount of time that nonces need to be stored to prevent attacks. The acceptable range is Client specific. const timeInSevenDays = 60 * 60 * 24 * 7; if ( + idTokenPayload && idTokenPayload.iat && idTokenPayload.iat + timeInSevenDays < currentTimeUnixSecond ) { - return { isValid: false, reason: 'Token is used from too long time' }; + return { + isValid: false, + reason: `Token is used from too long time (idTokenPayload iat + timeInSevenDays) ${idTokenPayload.iat + timeInSevenDays} < (currentTimeUnixSecond) ${currentTimeUnixSecond}`, + }; } // 11: If a nonce value was sent in the Authentication Request, a nonce Claim MUST be present and its value checked to verify that it is the same value as the one that was sent in the Authentication Request. The Client SHOULD check the nonce value for replay attacks. The precise method for detecting replay attacks is Client specific. - if (nonce && idTokenPayload.nonce && idTokenPayload.nonce !== nonce) { - return { isValid: false, reason: 'Nonce does not match' }; + if (idTokenPayload && nonce && idTokenPayload.nonce && idTokenPayload.nonce !== nonce) { + return { + isValid: false, + reason: `Nonce does not match (nonce) ${nonce} !== (idTokenPayload nonce) ${idTokenPayload.nonce}`, + }; } } return { isValid: true, reason: '' }; }; -function _hideTokens(tokens: Tokens, currentDatabaseElement: OidcConfig, configurationName: string) { +function extractedIssueAt( + tokens: Tokens, + accessTokenPayload: AccessTokenPayload | null, + _idTokenPayload: IdTokenPayload, +) { + if (!tokens.issued_at) { + if (accessTokenPayload && accessTokenPayload.iat) { + return accessTokenPayload.iat; + } else if (_idTokenPayload && _idTokenPayload.iat) { + return _idTokenPayload.iat; + } else { + const currentTimeUnixSecond = new Date().getTime() / 1000; + return currentTimeUnixSecond; + } + } else if (typeof tokens.issued_at == 'string') { + return parseInt(tokens.issued_at, 10); + } + return tokens.issued_at; +} + +function _hideTokens( + tokens: Tokens, + currentDatabaseElement: OidcConfig, + configurationName: string, +) { if (!tokens.issued_at) { const currentTimeUnixSecond = new Date().getTime() / 1000; tokens.issued_at = currentTimeUnixSecond; + } else if (typeof tokens.issued_at == 'string') { + tokens.issued_at = parseInt(tokens.issued_at, 10); } const accessTokenPayload = extractTokenPayload(tokens.access_token); @@ -104,71 +138,72 @@ function _hideTokens(tokens: Tokens, currentDatabaseElement: OidcConfig, configu accessTokenPayload, }; if (currentDatabaseElement.hideAccessToken) { - secureTokens.access_token = TOKEN.ACCESS_TOKEN + '_' + configurationName; + secureTokens.access_token = `${TOKEN.ACCESS_TOKEN}_${configurationName}`; } tokens.accessTokenPayload = accessTokenPayload; + // When id_token is not rotated we reuse old id_token + const oldTokens = currentDatabaseElement.tokens; + let id_token: string | null; + if (oldTokens != null && 'id_token' in oldTokens && !('id_token' in tokens)) { + id_token = oldTokens.id_token; + } else { + id_token = tokens.id_token; + } + tokens.id_token = id_token; + let _idTokenPayload = null; - if (tokens.id_token) { - _idTokenPayload = extractTokenPayload(tokens.id_token); - tokens.idTokenPayload = { ..._idTokenPayload }; - if (_idTokenPayload.nonce && currentDatabaseElement.nonce != null) { - const keyNonce = - TOKEN.NONCE_TOKEN + '_' + currentDatabaseElement.configurationName; + if (id_token) { + _idTokenPayload = extractTokenPayload(id_token); + tokens.idTokenPayload = _idTokenPayload != null ? { ..._idTokenPayload } : null; + if (_idTokenPayload && _idTokenPayload.nonce && currentDatabaseElement.nonce != null) { + const keyNonce = `${TOKEN.NONCE_TOKEN}_${currentDatabaseElement.configurationName}`; _idTokenPayload.nonce = keyNonce; } secureTokens.idTokenPayload = _idTokenPayload; } if (tokens.refresh_token) { - secureTokens.refresh_token = - TOKEN.REFRESH_TOKEN + '_' + configurationName; + secureTokens.refresh_token = `${TOKEN.REFRESH_TOKEN}_${configurationName}`; } + tokens.issued_at = extractedIssueAt(tokens, accessTokenPayload, _idTokenPayload); + + const expireIn = + typeof tokens.expires_in == 'string' ? parseInt(tokens.expires_in, 10) : tokens.expires_in; + const idTokenExpiresAt = - _idTokenPayload && _idTokenPayload.exp - ? _idTokenPayload.exp - : Number.MAX_VALUE; + _idTokenPayload && _idTokenPayload.exp ? _idTokenPayload.exp : Number.MAX_VALUE; const accessTokenExpiresAt = - accessTokenPayload && accessTokenPayload.exp - ? accessTokenPayload.exp - : tokens.issued_at + tokens.expires_in; + accessTokenPayload && accessTokenPayload.exp + ? accessTokenPayload.exp + : tokens.issued_at + expireIn; let expiresAt: number; - const tokenRenewMode = ( - currentDatabaseElement.oidcConfiguration as OidcConfiguration - ).token_renew_mode; + const tokenRenewMode = (currentDatabaseElement.oidcConfiguration as OidcConfiguration) + .token_renew_mode; if (tokenRenewMode === TokenRenewMode.access_token_invalid) { expiresAt = accessTokenExpiresAt; } else if (tokenRenewMode === TokenRenewMode.id_token_invalid) { expiresAt = idTokenExpiresAt; } else { - expiresAt = - idTokenExpiresAt < accessTokenExpiresAt - ? idTokenExpiresAt - : accessTokenExpiresAt; + expiresAt = idTokenExpiresAt < accessTokenExpiresAt ? idTokenExpiresAt : accessTokenExpiresAt; } secureTokens.expiresAt = expiresAt; tokens.expiresAt = expiresAt; - const nonce = currentDatabaseElement.nonce - ? currentDatabaseElement.nonce.nonce - : null; + const nonce = currentDatabaseElement.nonce ? currentDatabaseElement.nonce.nonce : null; const { isValid, reason } = isTokensOidcValid( - tokens, - nonce, - currentDatabaseElement.oidcServerConfiguration as OidcServerConfiguration, + tokens, + nonce as string, + currentDatabaseElement.oidcServerConfiguration as OidcServerConfiguration, ); // TODO: Type assertion, could be null. if (!isValid) { throw Error(`Tokens are not OpenID valid, reason: ${reason}`); } - // When refresh_token is not rotated we reuse ald refresh_token - if ( - currentDatabaseElement.tokens != null && - 'refresh_token' in currentDatabaseElement.tokens && - !('refresh_token' in tokens) - ) { - const refreshToken = currentDatabaseElement.tokens.refresh_token; + // When refresh_token is not rotated we reuse old refresh_token + if (oldTokens != null && 'refresh_token' in oldTokens && !('refresh_token' in tokens)) { + const refreshToken = oldTokens.refresh_token; currentDatabaseElement.tokens = { ...tokens, @@ -182,16 +217,29 @@ function _hideTokens(tokens: Tokens, currentDatabaseElement: OidcConfig, configu return secureTokens; } +const demonstratingProofOfPossessionNonceResponseHeader = 'DPoP-Nonce'; function hideTokens(currentDatabaseElement: OidcConfig) { const configurationName = currentDatabaseElement.configurationName; return (response: Response) => { if (response.status !== 200) { return response; } + const newHeaders = new Headers(response.headers); + if (response.headers.has(demonstratingProofOfPossessionNonceResponseHeader)) { + currentDatabaseElement.demonstratingProofOfPossessionNonce = response.headers.get( + demonstratingProofOfPossessionNonceResponseHeader, + ); + newHeaders.delete(demonstratingProofOfPossessionNonceResponseHeader); + } + return response.json().then((tokens: Tokens) => { const secureTokens = _hideTokens(tokens, currentDatabaseElement, configurationName); const body = JSON.stringify(secureTokens); - return new Response(body, response); + return new Response(body, { + status: response.status, + statusText: response.statusText, + headers: newHeaders, + }); }); }; } diff --git a/packages/oidc-client-service-worker/src/version.ts b/packages/oidc-client-service-worker/src/version.ts new file mode 100644 index 000000000..1fe2b83bd --- /dev/null +++ b/packages/oidc-client-service-worker/src/version.ts @@ -0,0 +1 @@ +export default '7.26.0'; diff --git a/packages/oidc-client-service-worker/tsconfig.eslint.json b/packages/oidc-client-service-worker/tsconfig.eslint.json index e9041fd6b..b90fc83e0 100644 --- a/packages/oidc-client-service-worker/tsconfig.eslint.json +++ b/packages/oidc-client-service-worker/tsconfig.eslint.json @@ -1,4 +1,4 @@ { "extends": "./tsconfig.json", "include": ["src"] -} \ No newline at end of file +} diff --git a/packages/oidc-client-service-worker/vite.config.js b/packages/oidc-client-service-worker/vite.config.js index 13467b083..c9a91157a 100644 --- a/packages/oidc-client-service-worker/vite.config.js +++ b/packages/oidc-client-service-worker/vite.config.js @@ -3,14 +3,11 @@ import { defineConfig } from 'vite'; import dts from 'vite-plugin-dts'; export default defineConfig({ - plugins: [dts({ - insertTypesEntry: true, - })], - test: { - coverage: { - provider: 'c8' - } - }, + plugins: [ + dts({ + insertTypesEntry: true, + }), + ], build: { minify: false, //default esbuild sourcemap: true, @@ -29,8 +26,7 @@ export default defineConfig({ output: { // Provide global variables to use in the UMD build // for externalized deps - globals: { - }, + globals: {}, }, }, }, diff --git a/packages/oidc-client/.eslintrc.cjs b/packages/oidc-client/.eslintrc.cjs deleted file mode 100644 index 6f9d07624..000000000 --- a/packages/oidc-client/.eslintrc.cjs +++ /dev/null @@ -1,17 +0,0 @@ -module.exports = { - extends: [__dirname+'/config/defaultEslintConfig.cjs'], - parserOptions: { - tsconfigRootDir: __dirname, - }, - rules: { - '@typescript-eslint/naming-convention': [ - 'error', - { - 'selector': 'variable', - 'types': ['boolean'], - 'format': ['PascalCase'], - 'prefix': ['is', 'with', 'should', 'has', 'can', 'did', 'will'] - } - ] - } - } \ No newline at end of file diff --git a/packages/oidc-client/README.md b/packages/oidc-client/README.md index e0144279d..9edcbbeca 100644 --- a/packages/oidc-client/README.md +++ b/packages/oidc-client/README.md @@ -1,10 +1,21 @@ -# @axa-fr/vanilla-oidc +# @axa-fr/oidc-client [![Continuous Integration](https://github.com/AxaGuilDEv/react-oidc/actions/workflows/npm-publish.yml/badge.svg)](https://github.com/AxaGuilDEv/react-oidc/actions/workflows/npm-publish.yml) [![Quality Gate](https://sonarcloud.io/api/project_badges/measure?project=AxaGuilDEv_react-oidc&metric=alert_status)](https://sonarcloud.io/dashboard?id=AxaGuilDEv_react-oidc) [![Reliability](https://sonarcloud.io/api/project_badges/measure?project=AxaGuilDEv_react-oidc&metric=reliability_rating)](https://sonarcloud.io/component_measures?id=AxaGuilDEv_react-oidc&metric=reliability_rating) [![Security](https://sonarcloud.io/api/project_badges/measure?project=AxaGuilDEv_react-oidc&metric=security_rating)](https://sonarcloud.io/component_measures?id=AxaGuilDEv_react-oidc&metric=security_rating) [![Code Corevage](https://sonarcloud.io/api/project_badges/measure?project=AxaGuilDEv_react-oidc&metric=coverage)](https://sonarcloud.io/component_measures?id=AxaGuilDEv_react-oidc&metric=Coverage) [![Twitter](https://img.shields.io/twitter/follow/GuildDEvOpen?style=social)](https://twitter.com/intent/follow?screen_name=GuildDEvOpen) -Try the demo at https://icy-glacier-004ab4303.2.azurestaticapps.net/ +**@axa-fr/oidc-client** the lightest and securest library to manage authentication with OpenID Connect (OIDC) and OAuth2 protocol. It is compatible with all OIDC providers. +**@axa-fr/oidc-client** is a pure javascript library. It works with any JavaScript framework or library. +We provide a wrapper **@axa-fr/react-oidc** for **React** (compatible next.js) and we expect soon to provide one for **Vue**, **Angular** and **Svelte**. + +- Try the react demo at https://black-rock-0dc6b0d03.1.azurestaticapps.net/ (most advanced) +- Try the pure javascript demo at https://icy-glacier-004ab4303.2.azurestaticapps.net/ + +

+ Sample React Oicd +

- [About](#about) - [Getting Started](#getting-started) @@ -13,42 +24,51 @@ Try the demo at https://icy-glacier-004ab4303.2.azurestaticapps.net/ - [Hash route](#Hash-route) - [Service Worker Support](#service-worker-support) - ## About -@axa-fr/vanilla-oidc is a pure OIDC client library agnostic to any framework. It is used by @axa-fr/react-oidc and can be used by any framework. - -It is a real alternative to existing oidc-client libraries. +@axa-fr/oidc-client is: - **Secure** : - - With the use of Service Worker, your tokens (refresh_token and access_token) are not accessible to the JavaScript client code (big protection against XSRF attacks) - - OIDC using client side Code Credential Grant with PKCE only -- **Lightweight** -- **Simple** : - - refresh_token and access_token are auto refreshed in background - - with the use of the Service Worker, you do not need to inject the access_token in every fetch, you have only to configure `OidcTrustedDomains.js` file -- **No cookies problem** : You can disable silent signin (that internally use an iframe). For your information, your OIDC server should be in the same domain of your website in order to be able to send OIDC server cookies from your website via an internal IFRAME, else, you may encounter COOKIES problem. + - With Demonstrating Proof of Possession (DPoP), your access_token and refresh_token are not usable outside your browser context (big protection) + - With the use of Service Worker, your tokens (refresh_token and/or access_token) are not accessible to the JavaScript client code (if you follow good practices from [`FAQ`](https://github.com/AxaFrance/oidc-client/blob/main/FAQ.md) section) + - OIDC using client side Code Credential Grant with pkce only +- **Lightweight** : Unpacked Size on npm is **274 kB** +- **Simple** + - refresh_token and access_token are auto refreshed in background + - with the use of the Service Worker, you do not need to inject the access_token in every fetch, you have only to configure OidcTrustedDomains.js file - **Multiple Authentication** : - - You can authenticate many times to the same provider with different scope (for example you can acquire a new 'payment' scope for a payment) - - You can authenticate to multiple different providers inside the same SPA (single page application) website + - You can authenticate many times to the same provider with different scope (for example you can acquire a new 'payment' scope for a payment) + - You can authenticate to multiple different providers inside the same SPA (single page application) website - **Flexible** : - - Work with Service Worker (more secure) and without for older browser (less secure) + - Work with Service Worker (more secure) and without for older browser (less secure). + - You can disable Service Worker if you want (but less secure) and just use SessionStorage or LocalStorage mode. ![](https://github.com/AxaGuilDEv/react-oidc/blob/master/docs/img/schema_pcke_client_side_with_service_worker.png?raw=true) The service worker catch **access_token** and **refresh_token** that will never be accessible to the client. - ### Getting Started ```sh -npm install @axa-fr/vanilla-oidc --save +npm install @axa-fr/oidc-client --save + +# To install or update OidcServiceWorker.js file, you can run +node ./node_modules/@axa-fr/oidc-client/bin/copy-service-worker-files.mjs public # If you have a "public" folder, the 2 files will be created : # ./public/OidcServiceWorker.js <-- will be updated at each "npm install" # ./public/OidcTrustedDomains.js <-- won't be updated if already exist ``` +WARNING : If you use Service Worker mode, the OidcServiceWorker.js file should always be up to date with the version of the library. You may setup a postinstall script in your package.json file to update it at each npm install. For example : + +```sh + "scripts": { + ... + "postinstall": "node ./node_modules/@axa-fr/oidc-client/bin/copy-service-worker-files.mjs public" + }, +``` + If you need a very secure mode where refresh_token and access_token will be hide behind a service worker that will proxify requests. The only file you should edit is "OidcTrustedDomains.js". @@ -61,116 +81,348 @@ The only file you should edit is "OidcTrustedDomains.js". // Domains used by OIDC server must be also declared here const trustedDomains = { - default: ["https://demo.duendesoftware.com", "https://www.myapi.com/users"], + default: { + oidcDomains: ['https://demo.duendesoftware.com'], + accessTokenDomains: ['https://www.myapi.com/users'], + }, +}; + +// Service worker will continue to give access token to the JavaScript client +// Ideal to hide refresh token from client JavaScript, but to retrieve access_token for some +// scenarios which require it. For example, to send it via websocket connection. +trustedDomains.config_show_access_token = { + oidcDomains: ['https://demo.duendesoftware.com'], + accessTokenDomains: ['https://www.myapi.com/users'], + showAccessToken: false, + // convertAllRequestsToCorsExceptNavigate: false, // default value is false + // setAccessTokenToNavigateRequests: true, // default value is true +}; + +// DPoP (Demonstrating Proof of Possession) will be activated for the following domains +trustedDomains.config_with_dpop = { + domains: ['https://demo.duendesoftware.com'], + demonstratingProofOfPossession: true, + demonstratingProofOfPossessionOnlyWhenDpopHeaderPresent: true, // default value is false, inject DPOP token only when DPOP header is present + // Optional, more details bellow + /*demonstratingProofOfPossessionConfiguration: { + importKeyAlgorithm: { + name: 'ECDSA', + namedCurve: 'P-256', + hash: {name: 'ES256'} + }, + signAlgorithm: {name: 'ECDSA', hash: {name: 'SHA-256'}}, + generateKeyAlgorithm: { + name: 'ECDSA', + namedCurve: 'P-256' + }, + digestAlgorithm: { name: 'SHA-256' }, + jwtHeaderAlgorithm : 'ES256' + }*/ +}; + +// Setting allowMultiTabLogin to true will enable storing login-specific parameters (state, nonce, code verifier) +// separately for each tab. This will prevent errors when logins are initiated from multiple tabs. +trustedDomains.config_multi_tab_login = { + domains: ['https://demo.duendesoftware.com'], + allowMultiTabLogin: true, }; ``` The code of the demo : ```js -import { VanillaOidc } from '@axa-fr/vanilla-oidc' +import { OidcClient } from '@axa-fr/oidc-client'; export const configuration = { - client_id: 'interactive.public.short', - redirect_uri: window.location.origin + '/#/authentication/callback', - silent_redirect_uri: window.location.origin + '/#/authentication/silent-callback', - scope: 'openid profile email api offline_access', - authority: 'https://demo.duendesoftware.com', - service_worker_relative_url:'/OidcServiceWorker.js', - service_worker_only: false, + client_id: 'interactive.public.short', + redirect_uri: window.location.origin + '/#/authentication/callback', + silent_redirect_uri: window.location.origin + '/#/authentication/silent-callback', + scope: 'openid profile email api offline_access', + authority: 'https://demo.duendesoftware.com', + service_worker_relative_url: '/OidcServiceWorker.js', // just comment that line to disable service worker mode + service_worker_only: false, + demonstrating_proof_of_possession: false, }; const href = window.location.href; -const vanillaOidc = VanillaOidc.getOrCreate(() => fetch)(configuration); +const oidcClient = OidcClient.getOrCreate()(configuration); + +// Use the fetch bellow to inject access_token and DPOP tokens automatically +const oidcFetch = oidcClient.fetchWithTokens(fetch); + +// You can inject you own fetch (default Fetch Interface) function and location object (respecting IOidcLocation interface) +// import {OidcLocation} from '@axa-fr/oidc-client' +// const oidcClient = OidcClient.getOrCreate(() => fetch, new OidcLocation())(configuration); console.log(href); -vanillaOidc.tryKeepExistingSessionAsync().then(() => { - if(href.includes(configuration.redirect_uri)){ - vanillaOidc.loginCallbackAsync().then(()=>{ - window.location.href = "/"; - }); - document.body.innerHTML = `
-

@axa-fr/vanilla-oidc demo

+oidcClient.tryKeepExistingSessionAsync().then(() => { + if (href.includes(configuration.redirect_uri)) { + oidcClient.loginCallbackAsync().then(() => { + window.location.href = '/'; + }); + document.body.innerHTML = `
+

@axa-fr/oidc-client demo

Loading

`; - return - } - - let tokens = vanillaOidc.tokens; + return; + } - if(tokens){ + let tokens = oidcClient.tokens; - // @ts-ignore - window.logout = () => vanillaOidc.logoutAsync(); - document.body.innerHTML = `
-

@axa-fr/vanilla-oidc demo

+ if (tokens) { + // @ts-ignore + window.logout = () => oidcClient.logoutAsync(); + document.body.innerHTML = `
+

@axa-fr/oidc-client demo

Authenticated

-
${JSON.stringify(tokens,null,'\t')}
-
` - - } - else { - // @ts-ignore - window.login= () => vanillaOidc.loginAsync("/"); - document.body.innerHTML = `
-

@axa-fr/vanilla-oidc demo

+
${JSON.stringify(tokens, null, '\t')}
+
`; + } else { + // @ts-ignore + window.login = () => oidcClient.loginAsync('/'); + document.body.innerHTML = `
+

@axa-fr/oidc-client demo

-
` - } -}) +
`; + } +}); +``` + +## Configuration + +```javascript + +const configuration = { + client_id: String.isRequired, // oidc client id + redirect_uri: String.isRequired, // oidc redirect url + silent_redirect_uri: String, // Optional activate silent-signin that use cookies between OIDC server and client javascript to restore sessions + silent_login_uri: String, // Optional, route that triggers the signin + silent_login_timeout: Number, // Optional, default is 12000 milliseconds + scope: String.isRequired, // oidc scope (you need to set "offline_access") + authority: String.isRequired, + storage: Storage, // Default sessionStorage, you can set localStorage, but it is not secure + authority_configuration: { + // Optional for providers that do not implement OIDC server auto-discovery via a .wellknown URL + authorization_endpoint: String, + token_endpoint: String, + userinfo_endpoint: String, + end_session_endpoint: String, + revocation_endpoint: String, + check_session_iframe: String, + issuer: String, + }, + refresh_time_before_tokens_expiration_in_second: Number, // default is 120 seconds + service_worker_relative_url: String, + service_worker_keep_alive_path: String, // default is "/" + service_worker_only: Boolean, // default false, if true, the user will not be able to login if the service worker is not available on its browser + service_worker_activate: () => boolean, // you can take the control of the service worker default activation which use user agent string, if return false, the service worker mode will not be used + service_worker_register: (url: string) => Promise, // Optional, you can take the control of the service worker registration + extras: StringMap | undefined, // ex: {'prompt': 'consent', 'access_type': 'offline'} list of key/value that is sent to the OIDC server (more info: https://github.com/openid/AppAuth-JS) + token_request_extras: StringMap | undefined, // ex: {'prompt': 'consent', 'access_type': 'offline'} list of key/value that is sent to the OIDC server during token request (more info: https://github.com/openid/AppAuth-JS) + authority_time_cache_wellknowurl_in_second: 60 * 60, // Time to cache in seconds of the openid well-known URL, default is 1 hour + authority_timeout_wellknowurl_in_millisecond: 10000, // Timeout in milliseconds of the openid well-known URL, default is 10 seconds, then an error is thrown + monitor_session: Boolean, // Add OpenID monitor session, default is false (more information https://openid.net/specs/openid-connect-session-1_0.html), if you need to set it to true consider https://infi.nl/nieuws/spa-necromancy/ + token_renew_mode: String, // Optional, update tokens based on the selected token(s) lifetime: "access_token_or_id_token_invalid" (default), "access_token_invalid", "id_token_invalid" + token_automatic_renew_mode: TokenAutomaticRenewMode.AutomaticOnlyWhenFetchExecuted, // Optional, default is TokenAutomaticRenewMode.AutomaticBeforeTokensExpiration + // TokenAutomaticRenewMode.AutomaticBeforeTokensExpiration: renew tokens automatically before they expire + // TokenAutomaticRenewMode.AutomaticOnlyWhenFetchExecuted: renew tokens automatically only when fetch is executed + // It requires you to use fetch given by oidcClient.fetchWithTokens(fetch) or to use oidcClient.getValidTokenAsync() + logout_tokens_to_invalidate: Array, // Optional tokens to invalidate during logout, default: ['access_token', 'refresh_token'] + location: ILOidcLocation, // Optional, default is window.location, you can inject your own location object respecting the ILOidcLocation interface + demonstrating_proof_of_possession: Boolean, // Optional, default is false, if true, the the Demonstrating Proof of Possession will be activated //https://www.rfc-editor.org/rfc/rfc9449.html#name-protected-resource-access + demonstrating_proof_of_possession_configuration: DemonstratingProofOfPossessionConfiguration // Optional, more details bellow +}; + + +interface DemonstratingProofOfPossessionConfiguration { + generateKeyAlgorithm: RsaHashedKeyGenParams | EcKeyGenParams, + digestAlgorithm: AlgorithmIdentifier, + importKeyAlgorithm: AlgorithmIdentifier | RsaHashedImportParams | EcKeyImportParams | HmacImportParams | AesKeyAlgorithm, + signAlgorithm: AlgorithmIdentifier | RsaPssParams | EcdsaParams, + jwtHeaderAlgorithm: string +}; + +// default value of demonstrating_proof_of_possession_configuration +const defaultDemonstratingProofOfPossessionConfiguration: DemonstratingProofOfPossessionConfiguration ={ + importKeyAlgorithm: { + name: 'ECDSA', + namedCurve: 'P-256', + hash: {name: 'ES256'} + }, + signAlgorithm: {name: 'ECDSA', hash: {name: 'SHA-256'}}, + generateKeyAlgorithm: { + name: 'ECDSA', + namedCurve: 'P-256' + }, + digestAlgorithm: { name: 'SHA-256' }, + jwtHeaderAlgorithm : 'ES256' +}; ``` -## Configuration +## API ```javascript -const configuration: { - client_id: PropTypes.string.isRequired, // oidc client id - redirect_uri: PropTypes.string.isRequired, // oidc redirect url - silent_redirect_uri: PropTypes.string, // Optional activate silent-signin that use cookies between OIDC server and client javascript to restore sessions - silent_login_uri: PropTypes.string, // Optional, route that trigger the signin - silent_login_timeout: PropTypes.number, // Optional default is 12000 milliseconds - scope: PropTypes.string.isRequired, // oidc scope (you need to set "offline_access") - authority: PropTypes.string.isRequired, - storage: Storage, // Default sessionStorage, you can set localStorage but it is less secure to XSS attacks - authority_configuration: PropTypes.shape({ - // Optional for providers that does not implement OIDC server auto discovery via a .wellknowurl - authorization_endpoint: PropTypes.string, - token_endpoint: PropTypes.string, - userinfo_endpoint: PropTypes.string, - end_session_endpoint: PropTypes.string, - revocation_endpoint: PropTypes.string, - check_session_iframe: PropTypes.string, - issuer: PropTypes.string, - }), - refresh_time_before_tokens_expiration_in_second: PropTypes.number, // default is 120 seconds - service_worker_relative_url: PropTypes.string, - service_worker_only: PropTypes.boolean, // default false - service_worker_convert_all_requests_to_cors: PropTypes.boolean, // force all requests that servie worker upgrades to have 'cors' mode. This allows setting authentication token on requests initialted by html parsing(e.g. img tags, download links etc). - extras: StringMap | undefined, // ex: {'prompt': 'consent', 'access_type': 'offline'} list of key/value that are send to the oidc server (more info: https://github.com/openid/AppAuth-JS) - token_request_extras: StringMap | undefined, // ex: {'prompt': 'consent', 'access_type': 'offline'} list of key/value that are send to the oidc server during token request (more info: https://github.com/openid/AppAuth-JS) - withCustomHistory: PropTypes.function, // Override history modification, return instance with replaceState(url, stateHistory) implemented (like History.replaceState()) - authority_time_cache_wellknowurl_in_second: 60 * 60, // Time to cache in second of openid wellknowurl, default is 1 hour - authority_timeout_wellknowurl_in_millisecond: 10000, // Timeout in millisecond of openid wellknowurl, default is 10 seconds, then error is throwed - monitor_session: PropTypes.boolean, // Add OpenId monitor session, default is false (more information https://openid.net/specs/openid-connect-session-1_0.html), if you need to set it to true consider https://infi.nl/nieuws/spa-necromancy/ - onLogoutFromAnotherTab: Function, // Optional, can be set to override the default behavior, this function is triggered when user with the same subject is logged out from another tab when session_monitor is active - onLogoutFromSameTab: Function, // Optional, can be set to override the default behavior, this function is triggered when user is logged out from same tab when session_monitor is active - token_renew_mode: PropTypes.string, // Optional, update tokens base on the selected token(s) lifetime: "access_token_or_id_token_invalid" (default), "access_token_invalid" , "id_token_invalid" - logout_tokens_to_invalidate : Array // Optional tokens to invalidate during logout, default: ['access_token', 'refresh_token'] - }; +/** + * OidcClient is a class that acts as a wrapper around the `Oidc` object. It provides methods to handle event subscriptions, logins, logouts, token renewals, user information, etc. + */ +export class OidcClient { + /** + * Creates an instance of OidcClient using a provided `Oidc` object. + * @param oidc The instance of the underlying Oidc object to use. + */ + constructor(oidc: Oidc); + + /** + * Subscribes a function to events emitted by the underlying Oidc object. + * @param func The function to be called when an event is emitted. + * @returns A string that identifies the subscription and can be used to unsubscribe later. + */ + subscribeEvents(func: EventSubscriber): string; + + /** + * Removes a subscription to a specified event. + * @param id The identifier of the subscription to remove, obtained during the initial subscription. + */ + removeEventSubscription(id: string): void; + + /** + * Publishes an event with the specified name and associated data. + * @param eventName The name of the event to publish. + * @param data The data associated with the event. + */ + publishEvent(eventName: string, data: any): void; + + /** + * Creates a new instance of OidcClient using a fetch retrieval function `getFetch`, with a given OIDC configuration and an optional name. + * @param getFetch The function to retrieve the `Fetch` object. + * @param configuration The OIDC configuration to use for creating the OidcClient instance. + * @param name The optional name for the created OidcClient instance. + * @returns A new instance of OidcClient with the specified configuration. + */ + static getOrCreate(getFetch: () => Fetch)(configuration: OidcConfiguration, name?: string): OidcClient; + + /** + * Retrieves an existing OidcClient instance with the specified name, or creates a new instance if it does not exist. + * @param name The name of the OidcClient instance to retrieve. + * @returns The existing OidcClient instance or a new instance with the specified name. + */ + static get(name?: string): OidcClient; + + /** + * The names of the events supported by the Oidc class. + */ + static eventNames: Oidc.eventNames; + + /** + * Attempts to keep the existing user session by calling the function of the underlying Oidc object. + * @returns A promise resolved with `true` if the user session was kept, otherwise `false`. + */ + tryKeepExistingSessionAsync(): Promise; + + /** + * Starts the OIDC login process with specified options. + * @param callbackPath The callback path for authentication. + * @param extras Additional parameters to send to the OIDC server during the login request. + * @param isSilentSignin Indicates if the login is silent. + * @param scope The OIDC scope for the login request. + * @param silentLoginOnly Indicates if only silent login is allowed. + * @returns A promise resolved with the login information, or rejected with an error. + */ + loginAsync(callbackPath?: string, extras?: StringMap, isSilentSignin?: boolean, scope?: string, silentLoginOnly?: boolean): Promise; + + /** + * Starts the OIDC logout process with specified options. + * @param callbackPathOrUrl The callback path or URL to use after logout. + * @param extras Additional parameters to send to the OIDC server during the logout request. + * {"no_reload:oidc":"true"} to avoid the page reload after logout. + * you can add extras like {"client_secret:revoke_refresh_token":"secret"} to revoke the refresh token with extra client secret. Any key ending with ":revoke_refresh_token" will be used to revoke the refresh token. + * you can add extras like {"client_secret:revoke_access_token":"secret"} to revoke the access token with extra client secret. Any key ending with ":revoke_access_token" will be used to revoke the access token. + * @returns A promise resolved when the logout is completed. + */ + logoutAsync(callbackPathOrUrl?: string | null | undefined, extras?: StringMap): Promise; + + /** + * Performs the silent login process and retrieves user information. + * @returns A promise resolved when the silent login process is completed. + */ + silentLoginCallbackAsync(): Promise; + + /** + * Renews the user's OIDC tokens. + * @param extras Additional parameters to send to the OIDC server during the token renewal request. + * @returns A promise resolved when the token renewal is completed. + */ + renewTokensAsync(extras?: StringMap): Promise; + + /** + * Performs the callback process after a successful login and automatically renews tokens. + * @returns A promise resolved with the callback information, or rejected with an error. + */ + loginCallbackAsync(): Promise; + + /** + * Retrieves the current OIDC tokens for the user. + */ + get tokens(): Tokens; + + /** + * Retrieves the current OIDC configuration used by the OidcClient instance. + */ + get configuration(): OidcConfiguration; + + /** + * Retrieves the valid OIDC token for the user. + * @param waitMs The maximum wait time in milliseconds to obtain a valid token. + * @param numberWait The number of attempts to obtain a valid token. + * @returns A promise resolved with the valid token, or rejected with an error. + */ + async getValidTokenAsync(waitMs = 200, numberWait = 50): Promise; + + /** + * Retrieves a new fetch function that inject bearer tokens (also DPOP tokens). + * @param fetch The current fetch function to use + * @param demonstrating_proof_of_possession Indicates whether the demonstration of proof of possession should be used. + * @returns Fetch A new fectch function that inject bearer tokens (also DPOP tokens). + */ + fetchWithTokens(fetch: Fetch, demonstrating_proof_of_possession=false): Fetch; + + /** + * Retrieves OIDC user information. + * @param noCache Indicates whether user information should be retrieved bypassing the cache. + * @param demonstrating_proof_of_possession Indicates whether the demonstration of proof of possession should be used. + * @returns A promise resolved with the user information, or rejected with an error. + */ + async userInfoAsync(noCache = false, demonstrating_proof_of_possession=false): Promise; + + /** + * Generate Demonstration of proof of possession. + * @param accessToken The access token to use. + * @param url The url to use. + * @param method The method to use. + * @param extras Additional parameters to send to the OIDC server during the demonstration of proof of possession request. + * @returns A promise resolved with the proof of possession. + */ + async generateDemonstrationOfProofOfPossessionAsync(accessToken:string, url:string, method:string, extras:StringMap= {}): Promise; +} + ``` ## Run The Demo ```sh -git clone https://github.com/AxaGuilDEv/react-oidc.git -cd react-oidc/packages/vanilla-demo -npm install -npm start -# then navigate to http://localhost:3000 +git clone https://github.com/AxaFrance/oidc-client.git +cd oidc-client + +# oidc client demo +cd /examples/oidc-client-demo +pnpm install +pnpm start +# then navigate to http://localhost:5174 + ``` ## How It Works @@ -182,28 +434,22 @@ More information about OIDC - [French : Augmentez la sécurité et la simplicité de votre Système d’Information OpenID Connect](https://medium.com/just-tech-it-now/augmentez-la-s%C3%A9curit%C3%A9-et-la-simplicit%C3%A9-de-votre-syst%C3%A8me-dinformation-avec-oauth-2-0-cf0732d71284) - [English : Increase the security and simplicity of your information system with openid connect](https://medium.com/just-tech-it-now/increase-the-security-and-simplicity-of-your-information-system-with-openid-connect-fa8c26b99d6d) +- [English: youtube OIDC](https://www.youtube.com/watch?v=frIJfavZkUE&list=PL8EMdIH6Mzxy2kHtsVOEWqNz-OaM_D_fB&index=1) +- [French: youtube OIDC](https://www.youtube.com/watch?v=H-mLMGzQ_y0&list=PL8EMdIH6Mzxy2kHtsVOEWqNz-OaM_D_fB&index=2) ## Hash route -`vanilla-oidc` work also with hash route. +`@axa-fr/oidc-client` work also with hash route. ```javascript export const configurationIdentityServerWithHash = { - client_id: "interactive.public.short", - redirect_uri: window.location.origin + "#authentication-callback", - silent_redirect_uri: - window.location.origin + "#authentication-silent-callback", - scope: "openid profile email api offline_access", - authority: "https://demo.duendesoftware.com", + client_id: 'interactive.public.short', + redirect_uri: window.location.origin + '#authentication-callback', + silent_redirect_uri: window.location.origin + '#authentication-silent-callback', + scope: 'openid profile email api offline_access', + authority: 'https://demo.duendesoftware.com', refresh_time_before_tokens_expiration_in_second: 70, - service_worker_relative_url: "/OidcServiceWorker.js", + service_worker_relative_url: '/OidcServiceWorker.js', service_worker_only: false, }; ``` - -## Service Worker Support - -- Firefox : tested on Firefox 98.0.2 -- Chrome/Edge : tested on version upper to 90 -- Opera : tested on version upper to 80 -- Safari : tested on Safari/605.1.15 diff --git a/packages/oidc-client/bin/copy-service-worker-files.mjs b/packages/oidc-client/bin/copy-service-worker-files.mjs new file mode 100644 index 000000000..e26b84a8a --- /dev/null +++ b/packages/oidc-client/bin/copy-service-worker-files.mjs @@ -0,0 +1,76 @@ +/* global console, process */ +/* eslint no-console: "off" */ +import fs from 'fs'; +import path from 'path'; +import { fileURLToPath } from 'url'; + +try { + /** + * Script to run after npm install + * + * Copy selected files to user's directory + */ + const script_prefix = 'oidc-client'; + + const copyFile = async (src, dest, overwrite) => { + if (!fileExists(src)) { + console.log(`[${script_prefix}:skip] file does not exist ${src}`); + return false; + } + if (!overwrite) { + if (fileExists(dest)) { + console.log(`[${script_prefix}:skip] file exists not overwriting ${dest}`); + return true; + } + } + await fs.promises.copyFile(src, dest); + console.log(`[${script_prefix}:copy] ${dest}`); + return true; + }; + + const fileExists = path => { + return !!fs.existsSync(path); + }; + + const initPath = process.cwd(); + const __dirname = path.dirname(fileURLToPath(import.meta.url)); + const srcDir = path.join(__dirname, '..', '..', 'oidc-client-service-worker', 'dist'); + const srcDirFallback = path.join( + __dirname, + '..', + 'node_modules', + '@axa-fr', + 'oidc-client-service-worker', + 'dist', + ); + const destinationFolder = process.argv.length >= 3 ? process.argv[2] : 'public'; + const destinationDir = path.join(initPath, destinationFolder); + + const files = [ + { + fileName: 'OidcServiceWorker.js', + overwrite: true, + }, + { + fileName: 'OidcTrustedDomains.js', + overwrite: false, + }, + ]; + + for await (const file of files) { + const success = await copyFile( + path.join(srcDir, file.fileName), + path.join(destinationDir, file.fileName), + file.overwrite, + ); + if (!success) { + await copyFile( + path.join(srcDirFallback, file.fileName), + path.join(destinationDir, file.fileName), + file.overwrite, + ); + } + } +} catch (err) { + console.warn(err); +} diff --git a/packages/oidc-client/bin/post-install.mjs b/packages/oidc-client/bin/post-install.mjs deleted file mode 100644 index e6dde94e8..000000000 --- a/packages/oidc-client/bin/post-install.mjs +++ /dev/null @@ -1,37 +0,0 @@ -import cpy from 'cpy'; -import path from 'path'; - -/** - * Script to run after npm install - * - * Copy selected files to user's directory - */ - -const initPath = process.env.INIT_CWD; -// console.log('current dir:', process.cwd()); -// console.log('userPath:', initPath); - -function copyProgress(progress) { - console.log('✓ [oidc-client:copy] ', progress.destinationPath); -} - -//TODO: Fragile.. need to find a better way to get the path -const srcDir = '../oidc-client-service-worker/dist/'; -const destinationDir = path.join(initPath, 'public'); -const FILE_EXISTS_CODE = 'EEXIST'; - -await cpy([path.join(srcDir,'OidcServiceWorker.js')], destinationDir, { - overwrite: true, -}).on('progress', copyProgress); - -try { - await cpy([path.join(srcDir,'OidcTrustedDomains.js')], destinationDir, { - overwrite: false, - }).on('progress', copyProgress); -} catch (e) { - if (e.code === FILE_EXISTS_CODE) { - console.log( - `✗ [oidc-client:skip] OidcTrustedDomains.js not copied, already exists in ${destinationDir}` - ); - } else throw e; -} diff --git a/packages/oidc-client/config/defaultEslintConfig.cjs b/packages/oidc-client/config/defaultEslintConfig.cjs deleted file mode 100644 index c3fa61f5b..000000000 --- a/packages/oidc-client/config/defaultEslintConfig.cjs +++ /dev/null @@ -1,148 +0,0 @@ -module.exports = { - parser: '@typescript-eslint/parser', - extends: [ - 'standard', - 'plugin:react/recommended', - 'plugin:react-hooks/recommended', - 'plugin:@typescript-eslint/eslint-recommended', - 'plugin:@typescript-eslint/recommended', - 'plugin:import/typescript', - 'plugin:jsx-a11y/recommended', - ], - plugins: ['simple-import-sort', 'testing-library'], - env: { - node: true, - es6: true, - browser: true, - }, - parserOptions: { - ecmaVersion: 2018, - sourceType: 'module', - ecmaFeatures: { - jsx: true, - }, - // typescript-eslint specific options - warnOnUnsupportedTypeScriptVersion: true, - }, - rules: { - '@typescript-eslint/interface-name-prefix': 'off', - '@typescript-eslint/no-non-null-assertion': 'off', - '@typescript-eslint/explicit-module-boundary-types': 'off', - '@typescript-eslint/no-explicit-any': 'off', - '@typescript-eslint/ban-ts-comment': 'off', - 'no-unused-vars': 'off', - '@typescript-eslint/no-unused-vars': [ - 'error', - { - argsIgnorePattern: '^_|req|res|next|err|ctx|args|context|info', - ignoreRestSiblings: true, - }, - ], - 'no-array-constructor': 'off', - '@typescript-eslint/no-array-constructor': 'warn', - 'no-redeclare': 'off', - '@typescript-eslint/no-redeclare': 'warn', - 'no-use-before-define': 'off', - '@typescript-eslint/no-use-before-define': [ - 'warn', - { - functions: false, - classes: false, - variables: false, - typedefs: false, - }, - ], - 'no-unused-expressions': 'off', - '@typescript-eslint/no-unused-expressions': [ - 'error', - { - allowShortCircuit: true, - allowTernary: true, - allowTaggedTemplates: true, - }, - ], - '@typescript-eslint/triple-slash-reference': 'off', - '@typescript-eslint/member-delimiter-style': [ - 'error', - { - multiline: { - delimiter: 'semi', - requireLast: true, - }, - singleline: { - delimiter: 'semi', - requireLast: false, - }, - }, - ], - camelcase: 'off', - 'comma-dangle': [ - 'error', - { - arrays: 'always-multiline', - objects: 'always-multiline', - imports: 'always-multiline', - exports: 'always-multiline', - functions: 'always-multiline', - }, - ], - 'array-callback-return': 'warn', - 'jsx-quotes': ['error', 'prefer-double'], - // 'max-len': ['error', { code: 120 }], - indent: 'off', - // quotes: ['error', 'single'], - semi: ['error', 'always'], - 'space-before-function-paren': 'off', - - 'import/no-named-as-default': 'off', - 'import/no-named-as-default-member': 'off', - 'import/default': 'off', - 'import/named': 'off', - 'import/namespace': 'off', - 'import/no-unresolved': 'off', - 'simple-import-sort/imports': 'error', - 'simple-import-sort/exports': 'error', - 'react/prop-types': 'off', - 'react/jsx-wrap-multilines': 'error', - 'react/react-in-jsx-scope': 'off', - 'react/display-name': 'off', - // https://github.com/facebook/react/tree/master/packages/eslint-plugin-react-hooks - 'react-hooks/rules-of-hooks': 'error', - 'react-hooks/exhaustive-deps': 'off', - }, - - overrides: [ - { - files: ['*.js', '*.jsx'], - rules: { - '@typescript-eslint/no-var-requires': 'off', - }, - }, - { - // 3) Now we enable eslint-plugin-testing-library rules or preset only for matching files! - files: ['**/?(*.)+(spec|test).[jt]s?(x)'], - extends: ['plugin:testing-library/react'], - rules: { - 'testing-library/await-async-query': 'error', - 'testing-library/no-await-sync-query': 'error', - 'testing-library/no-debugging-utils': 'warn', - 'testing-library/no-dom-import': 'off', - 'testing-library/no-unnecessary-act': 'off', - }, - }, - ], - - settings: { - react: { - version: 'detect', - }, - 'import/parsers': { - '@typescript-eslint/parser': ['.ts', '.tsx'], - }, - 'import/resolver': { - typescript: { - alwaysTryTypes: true, - }, - }, - }, - }; \ No newline at end of file diff --git a/packages/oidc-client/package-lock.json b/packages/oidc-client/package-lock.json deleted file mode 100644 index 65ddfd28d..000000000 --- a/packages/oidc-client/package-lock.json +++ /dev/null @@ -1,4725 +0,0 @@ -{ - "name": "@axa-fr/vanilla-oidc", - "version": "6.24.1", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "@axa-fr/vanilla-oidc", - "version": "6.24.1", - "hasInstallScript": true, - "license": "MIT", - "dependencies": { - "base64-js": "1.5.1" - }, - "devDependencies": { - "@craco/types": "^7.1.0", - "@types/react": "^18.0.21", - "copyfiles": "2.4.1", - "rimraf": "3.0.2", - "typescript": "4.5.5" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", - "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz", - "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/types": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.5.tgz", - "integrity": "sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.5", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@craco/types": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@craco/types/-/types-7.1.0.tgz", - "integrity": "sha512-zdyk2G9UfEItrvnB+sd3xDHB5Mf3dsD6wE+Ex6V+Nch+GSXdFGQfXD/l+ZX9hO03R1rmnJPCxrIRPJUib8Q/MQ==", - "dev": true, - "dependencies": { - "@babel/types": "^7.19.3", - "@jest/types": "^27.5.1", - "@types/eslint": "^8.4.6", - "autoprefixer": "^10.4.12", - "eslint-webpack-plugin": "^3.2.0", - "webpack": "^5.74.0" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", - "dev": true, - "peer": true, - "dependencies": { - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.1.tgz", - "integrity": "sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ==", - "dev": true, - "peer": true, - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.3.tgz", - "integrity": "sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==", - "dev": true, - "peer": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.5.2", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/js": { - "version": "8.43.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.43.0.tgz", - "integrity": "sha512-s2UHCoiXfxMvmfzqoN+vrQ84ahUSYde9qNO1MdxmoEhyHWsfmwOpFlwYV+ePJEVc7gFnATGUi376WowX1N7tFg==", - "dev": true, - "peer": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", - "integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==", - "dev": true, - "peer": true, - "dependencies": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.5" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "peer": true, - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", - "dev": true, - "peer": true - }, - "node_modules/@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", - "dev": true, - "dependencies": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/source-map": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.3.tgz", - "integrity": "sha512-b+fsZXeLYi9fEULmfBrhxn4IrPlINf8fiNarzTof004v3lFdntdwa9PF7vFJqm3mg7s+ScJMxXaE3Acp1irZcg==", - "dev": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", - "dev": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.18", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", - "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "3.1.0", - "@jridgewell/sourcemap-codec": "1.4.14" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "peer": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "peer": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "peer": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@types/eslint": { - "version": "8.40.2", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.40.2.tgz", - "integrity": "sha512-PRVjQ4Eh9z9pmmtaq8nTjZjQwKFk7YIHIud3lRoKRBgUQjgjRmoGxxGEPXQkF+lH7QkHJRNr5F4aBgYCW0lqpQ==", - "dev": true, - "dependencies": { - "@types/estree": "*", - "@types/json-schema": "*" - } - }, - "node_modules/@types/eslint-scope": { - "version": "3.7.4", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz", - "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==", - "dev": true, - "dependencies": { - "@types/eslint": "*", - "@types/estree": "*" - } - }, - "node_modules/@types/estree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz", - "integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==", - "dev": true - }, - "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", - "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", - "dev": true - }, - "node_modules/@types/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "*" - } - }, - "node_modules/@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-report": "*" - } - }, - "node_modules/@types/json-schema": { - "version": "7.0.12", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz", - "integrity": "sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==", - "dev": true - }, - "node_modules/@types/node": { - "version": "20.3.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.3.1.tgz", - "integrity": "sha512-EhcH/wvidPy1WeML3TtYFGR83UzjxeWRen9V402T8aUGYsCHOmfoisV3ZSg03gAFIbLq8TnWOJ0f4cALtnSEUg==", - "dev": true - }, - "node_modules/@types/prop-types": { - "version": "15.7.5", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", - "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==", - "dev": true - }, - "node_modules/@types/react": { - "version": "18.2.13", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.13.tgz", - "integrity": "sha512-vJ+zElvi/Zn9cVXB5slX2xL8PZodPCwPRDpittQdw43JR2AJ5k3vKdgJJyneV/cYgIbLQUwXa9JVDvUZXGba+Q==", - "dev": true, - "dependencies": { - "@types/prop-types": "*", - "@types/scheduler": "*", - "csstype": "^3.0.2" - } - }, - "node_modules/@types/scheduler": { - "version": "0.16.3", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz", - "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==", - "dev": true - }, - "node_modules/@types/yargs": { - "version": "16.0.5", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", - "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@types/yargs-parser": { - "version": "21.0.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", - "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", - "dev": true - }, - "node_modules/@webassemblyjs/ast": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz", - "integrity": "sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==", - "dev": true, - "dependencies": { - "@webassemblyjs/helper-numbers": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6" - } - }, - "node_modules/@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", - "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", - "dev": true - }, - "node_modules/@webassemblyjs/helper-api-error": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", - "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", - "dev": true - }, - "node_modules/@webassemblyjs/helper-buffer": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz", - "integrity": "sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA==", - "dev": true - }, - "node_modules/@webassemblyjs/helper-numbers": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", - "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", - "dev": true, - "dependencies": { - "@webassemblyjs/floating-point-hex-parser": "1.11.6", - "@webassemblyjs/helper-api-error": "1.11.6", - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", - "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", - "dev": true - }, - "node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz", - "integrity": "sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.6", - "@webassemblyjs/helper-buffer": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/wasm-gen": "1.11.6" - } - }, - "node_modules/@webassemblyjs/ieee754": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", - "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", - "dev": true, - "dependencies": { - "@xtuc/ieee754": "^1.2.0" - } - }, - "node_modules/@webassemblyjs/leb128": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", - "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", - "dev": true, - "dependencies": { - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webassemblyjs/utf8": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", - "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", - "dev": true - }, - "node_modules/@webassemblyjs/wasm-edit": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz", - "integrity": "sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.6", - "@webassemblyjs/helper-buffer": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/helper-wasm-section": "1.11.6", - "@webassemblyjs/wasm-gen": "1.11.6", - "@webassemblyjs/wasm-opt": "1.11.6", - "@webassemblyjs/wasm-parser": "1.11.6", - "@webassemblyjs/wast-printer": "1.11.6" - } - }, - "node_modules/@webassemblyjs/wasm-gen": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz", - "integrity": "sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/ieee754": "1.11.6", - "@webassemblyjs/leb128": "1.11.6", - "@webassemblyjs/utf8": "1.11.6" - } - }, - "node_modules/@webassemblyjs/wasm-opt": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz", - "integrity": "sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.6", - "@webassemblyjs/helper-buffer": "1.11.6", - "@webassemblyjs/wasm-gen": "1.11.6", - "@webassemblyjs/wasm-parser": "1.11.6" - } - }, - "node_modules/@webassemblyjs/wasm-parser": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz", - "integrity": "sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.6", - "@webassemblyjs/helper-api-error": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/ieee754": "1.11.6", - "@webassemblyjs/leb128": "1.11.6", - "@webassemblyjs/utf8": "1.11.6" - } - }, - "node_modules/@webassemblyjs/wast-printer": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz", - "integrity": "sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.6", - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@xtuc/ieee754": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "dev": true - }, - "node_modules/@xtuc/long": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", - "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "dev": true - }, - "node_modules/acorn": { - "version": "8.9.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.9.0.tgz", - "integrity": "sha512-jaVNAFBHNLXspO543WnNNPZFRtavh3skAkITqD0/2aeMkKZTN+254PyhwxFYrk3vQ1xfY+2wbesJMs/JC8/PwQ==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-import-assertions": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", - "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", - "dev": true, - "peerDependencies": { - "acorn": "^8" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "peer": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-formats": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", - "dev": true, - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, - "node_modules/ajv-formats/node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-formats/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, - "node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "peerDependencies": { - "ajv": "^6.9.1" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, - "peer": true - }, - "node_modules/autoprefixer": { - "version": "10.4.14", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.14.tgz", - "integrity": "sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/autoprefixer" - } - ], - "dependencies": { - "browserslist": "^4.21.5", - "caniuse-lite": "^1.0.30001464", - "fraction.js": "^4.2.0", - "normalize-range": "^0.1.2", - "picocolors": "^1.0.0", - "postcss-value-parser": "^4.2.0" - }, - "bin": { - "autoprefixer": "bin/autoprefixer" - }, - "engines": { - "node": "^10 || ^12 || >=14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browserslist": { - "version": "4.21.9", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.9.tgz", - "integrity": "sha512-M0MFoZzbUrRU4KNfCrDLnvyE7gub+peetoTid3TBIqtunaDJyXlwhakT+/VkvSXcfIzFfK/nkCs4nmyTmxdNSg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "caniuse-lite": "^1.0.30001503", - "electron-to-chromium": "^1.4.431", - "node-releases": "^2.0.12", - "update-browserslist-db": "^1.0.11" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "peer": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001506", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001506.tgz", - "integrity": "sha512-6XNEcpygZMCKaufIcgpQNZNf00GEqc7VQON+9Rd0K1bMYo8xhMZRAo5zpbnbMNizi4YNgIDAFrdykWsvY3H4Hw==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ] - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/chrome-trace-event": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", - "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", - "dev": true, - "engines": { - "node": ">=6.0" - } - }, - "node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "node_modules/copyfiles": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/copyfiles/-/copyfiles-2.4.1.tgz", - "integrity": "sha512-fereAvAvxDrQDOXybk3Qu3dPbOoKoysFMWtkY3mv5BsL8//OSZVL5DCLYqgRfY5cWirgRzlC+WSrxp6Bo3eNZg==", - "dev": true, - "dependencies": { - "glob": "^7.0.5", - "minimatch": "^3.0.3", - "mkdirp": "^1.0.4", - "noms": "0.0.0", - "through2": "^2.0.1", - "untildify": "^4.0.0", - "yargs": "^16.1.0" - }, - "bin": { - "copyfiles": "copyfiles", - "copyup": "copyfiles" - } - }, - "node_modules/copyfiles/node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "dev": true - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "peer": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/csstype": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", - "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==", - "dev": true - }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "peer": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true, - "peer": true - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "peer": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/electron-to-chromium": { - "version": "1.4.437", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.437.tgz", - "integrity": "sha512-ZFekRuBOHUXp21wrR5lshT6pZa/KmjkhKBAtmZz4NN5sCWlHOk3kdhiwFINrDBsRLX6FjyBAb1TRN+KBeNlyzQ==", - "dev": true - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/enhanced-resolve": { - "version": "5.15.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", - "integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/es-module-lexer": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.3.0.tgz", - "integrity": "sha512-vZK7T0N2CBmBOixhmjdqx2gWVbFZ4DXZ/NyRMZVlJXPa7CyFS+/a4QQsDGDQy9ZfEzxFuNEsMLeQJnKP2p5/JA==", - "dev": true - }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "peer": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "8.43.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.43.0.tgz", - "integrity": "sha512-aaCpf2JqqKesMFGgmRPessmVKjcGXqdlAYLLC3THM8t5nBRZRQ+st5WM/hoJXkdioEXLLbXgclUpM0TXo5HX5Q==", - "dev": true, - "peer": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.4.0", - "@eslint/eslintrc": "^2.0.3", - "@eslint/js": "8.43.0", - "@humanwhocodes/config-array": "^0.11.10", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.0", - "eslint-visitor-keys": "^3.4.1", - "espree": "^9.5.2", - "esquery": "^1.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-scope": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.0.tgz", - "integrity": "sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==", - "dev": true, - "peer": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz", - "integrity": "sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==", - "dev": true, - "peer": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-webpack-plugin": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/eslint-webpack-plugin/-/eslint-webpack-plugin-3.2.0.tgz", - "integrity": "sha512-avrKcGncpPbPSUHX6B3stNGzkKFto3eL+DKM4+VyMrVnhPc3vRczVlCq3uhuFOdRvDHTVXuzwk1ZKUrqDQHQ9w==", - "dev": true, - "dependencies": { - "@types/eslint": "^7.29.0 || ^8.4.1", - "jest-worker": "^28.0.2", - "micromatch": "^4.0.5", - "normalize-path": "^3.0.0", - "schema-utils": "^4.0.0" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0", - "webpack": "^5.0.0" - } - }, - "node_modules/espree": { - "version": "9.5.2", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.2.tgz", - "integrity": "sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==", - "dev": true, - "peer": true, - "dependencies": { - "acorn": "^8.8.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", - "dev": true, - "peer": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/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/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "dev": true, - "engines": { - "node": ">=0.8.x" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true, - "peer": true - }, - "node_modules/fastq": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", - "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", - "dev": true, - "peer": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "peer": true, - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "peer": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "dev": true, - "peer": true, - "dependencies": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flatted": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", - "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", - "dev": true, - "peer": true - }, - "node_modules/fraction.js": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz", - "integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==", - "dev": true, - "engines": { - "node": "*" - }, - "funding": { - "type": "patreon", - "url": "https://www.patreon.com/infusion" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "peer": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/glob-to-regexp": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", - "dev": true - }, - "node_modules/globals": { - "version": "13.20.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", - "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", - "dev": true, - "peer": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true - }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true, - "peer": true - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", - "dev": true, - "peer": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "peer": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "peer": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "peer": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-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, - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, - "peer": true - }, - "node_modules/jest-worker": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.1.3.tgz", - "integrity": "sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g==", - "dev": true, - "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-worker/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "peer": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true, - "peer": true - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "peer": true, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/loader-runner": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", - "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", - "dev": true, - "engines": { - "node": ">=6.11.5" - } - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "peer": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true, - "peer": true - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true, - "peer": true - }, - "node_modules/nanoid": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", - "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "peer": true, - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true, - "peer": true - }, - "node_modules/neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true - }, - "node_modules/node-releases": { - "version": "2.0.12", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.12.tgz", - "integrity": "sha512-QzsYKWhXTWx8h1kIvqfnC++o0pEmpRQA/aenALsL2F4pqNVr7YzcdMlDij5WBnwftRbJCNJL/O7zdKaxKPHqgQ==", - "dev": true - }, - "node_modules/noms": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/noms/-/noms-0.0.0.tgz", - "integrity": "sha1-2o69nzr51nYJGbJ9nNyAkqczKFk=", - "dev": true, - "dependencies": { - "inherits": "^2.0.1", - "readable-stream": "~1.0.31" - } - }, - "node_modules/noms/node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true - }, - "node_modules/noms/node_modules/readable-stream": { - "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "node_modules/noms/node_modules/string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", - "dev": true - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/normalize-range": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", - "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "dev": true, - "peer": true, - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "peer": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "peer": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "peer": true, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/postcss": { - "version": "8.4.24", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.24.tgz", - "integrity": "sha512-M0RzbcI0sO/XJNucsGjvWU9ERWxb/ytp1w6dKtxTKgixdtQDq4rmx/g8W1hnaheq9jgwL/oyEdH5Bc4WwJKMqg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "peer": true, - "dependencies": { - "nanoid": "^3.3.6", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "peer": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true - }, - "node_modules/punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "peer": true - }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "peer": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "peer": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "peer": true, - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "node_modules/schema-utils": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", - "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/schema-utils/node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/schema-utils/node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" - } - }, - "node_modules/schema-utils/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, - "node_modules/serialize-javascript": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", - "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", - "dev": true, - "dependencies": { - "randombytes": "^2.1.0" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "peer": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", - "dev": true, - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "peer": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tapable": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/terser": { - "version": "5.18.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.18.1.tgz", - "integrity": "sha512-j1n0Ao919h/Ai5r43VAnfV/7azUYW43GPxK7qSATzrsERfW7+y2QW9Cp9ufnRF5CQUWbnLSo7UJokSWCqg4tsQ==", - "dev": true, - "dependencies": { - "@jridgewell/source-map": "^0.3.3", - "acorn": "^8.8.2", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - }, - "bin": { - "terser": "bin/terser" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/terser-webpack-plugin": { - "version": "5.3.9", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.9.tgz", - "integrity": "sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.17", - "jest-worker": "^27.4.5", - "schema-utils": "^3.1.1", - "serialize-javascript": "^6.0.1", - "terser": "^5.16.8" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.1.0" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "esbuild": { - "optional": true - }, - "uglify-js": { - "optional": true - } - } - }, - "node_modules/terser-webpack-plugin/node_modules/jest-worker": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", - "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", - "dev": true, - "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": ">= 10.13.0" - } - }, - "node_modules/terser-webpack-plugin/node_modules/schema-utils": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", - "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/terser-webpack-plugin/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true, - "peer": true - }, - "node_modules/through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "dependencies": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "peer": true, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "peer": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/typescript": { - "version": "4.5.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz", - "integrity": "sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/untildify": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", - "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/update-browserslist-db": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", - "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true - }, - "node_modules/watchpack": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", - "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", - "dev": true, - "dependencies": { - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.1.2" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/webpack": { - "version": "5.88.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.88.0.tgz", - "integrity": "sha512-O3jDhG5e44qIBSi/P6KpcCcH7HD+nYIHVBhdWFxcLOcIGN8zGo5nqF3BjyNCxIh4p1vFdNnreZv2h2KkoAw3lw==", - "dev": true, - "dependencies": { - "@types/eslint-scope": "^3.7.3", - "@types/estree": "^1.0.0", - "@webassemblyjs/ast": "^1.11.5", - "@webassemblyjs/wasm-edit": "^1.11.5", - "@webassemblyjs/wasm-parser": "^1.11.5", - "acorn": "^8.7.1", - "acorn-import-assertions": "^1.9.0", - "browserslist": "^4.14.5", - "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.15.0", - "es-module-lexer": "^1.2.1", - "eslint-scope": "5.1.1", - "events": "^3.2.0", - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.9", - "json-parse-even-better-errors": "^2.3.1", - "loader-runner": "^4.2.0", - "mime-types": "^2.1.27", - "neo-async": "^2.6.2", - "schema-utils": "^3.2.0", - "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.3.7", - "watchpack": "^2.4.0", - "webpack-sources": "^3.2.3" - }, - "bin": { - "webpack": "bin/webpack.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependenciesMeta": { - "webpack-cli": { - "optional": true - } - } - }, - "node_modules/webpack-sources": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", - "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", - "dev": true, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/webpack/node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/webpack/node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/webpack/node_modules/schema-utils": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", - "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "peer": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true, - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "node_modules/xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "dev": true, - "engines": { - "node": ">=0.4" - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "peer": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - }, - "dependencies": { - "@babel/helper-string-parser": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", - "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", - "dev": true - }, - "@babel/helper-validator-identifier": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz", - "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==", - "dev": true - }, - "@babel/types": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.5.tgz", - "integrity": "sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA==", - "dev": true, - "requires": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.5", - "to-fast-properties": "^2.0.0" - } - }, - "@craco/types": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@craco/types/-/types-7.1.0.tgz", - "integrity": "sha512-zdyk2G9UfEItrvnB+sd3xDHB5Mf3dsD6wE+Ex6V+Nch+GSXdFGQfXD/l+ZX9hO03R1rmnJPCxrIRPJUib8Q/MQ==", - "dev": true, - "requires": { - "@babel/types": "^7.19.3", - "@jest/types": "^27.5.1", - "@types/eslint": "^8.4.6", - "autoprefixer": "^10.4.12", - "eslint-webpack-plugin": "^3.2.0", - "webpack": "^5.74.0" - } - }, - "@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", - "dev": true, - "peer": true, - "requires": { - "eslint-visitor-keys": "^3.3.0" - } - }, - "@eslint-community/regexpp": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.1.tgz", - "integrity": "sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ==", - "dev": true, - "peer": true - }, - "@eslint/eslintrc": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.3.tgz", - "integrity": "sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==", - "dev": true, - "peer": true, - "requires": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.5.2", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - } - }, - "@eslint/js": { - "version": "8.43.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.43.0.tgz", - "integrity": "sha512-s2UHCoiXfxMvmfzqoN+vrQ84ahUSYde9qNO1MdxmoEhyHWsfmwOpFlwYV+ePJEVc7gFnATGUi376WowX1N7tFg==", - "dev": true, - "peer": true - }, - "@humanwhocodes/config-array": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", - "integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==", - "dev": true, - "peer": true, - "requires": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.5" - } - }, - "@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "peer": true - }, - "@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", - "dev": true, - "peer": true - }, - "@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", - "dev": true, - "requires": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, - "@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", - "dev": true - }, - "@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "dev": true - }, - "@jridgewell/source-map": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.3.tgz", - "integrity": "sha512-b+fsZXeLYi9fEULmfBrhxn4IrPlINf8fiNarzTof004v3lFdntdwa9PF7vFJqm3mg7s+ScJMxXaE3Acp1irZcg==", - "dev": true, - "requires": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, - "@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", - "dev": true - }, - "@jridgewell/trace-mapping": { - "version": "0.3.18", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", - "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", - "dev": true, - "requires": { - "@jridgewell/resolve-uri": "3.1.0", - "@jridgewell/sourcemap-codec": "1.4.14" - } - }, - "@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "peer": true, - "requires": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - } - }, - "@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "peer": true - }, - "@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "peer": true, - "requires": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - } - }, - "@types/eslint": { - "version": "8.40.2", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.40.2.tgz", - "integrity": "sha512-PRVjQ4Eh9z9pmmtaq8nTjZjQwKFk7YIHIud3lRoKRBgUQjgjRmoGxxGEPXQkF+lH7QkHJRNr5F4aBgYCW0lqpQ==", - "dev": true, - "requires": { - "@types/estree": "*", - "@types/json-schema": "*" - } - }, - "@types/eslint-scope": { - "version": "3.7.4", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz", - "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==", - "dev": true, - "requires": { - "@types/eslint": "*", - "@types/estree": "*" - } - }, - "@types/estree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz", - "integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==", - "dev": true - }, - "@types/istanbul-lib-coverage": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", - "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", - "dev": true - }, - "@types/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "*" - } - }, - "@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "requires": { - "@types/istanbul-lib-report": "*" - } - }, - "@types/json-schema": { - "version": "7.0.12", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz", - "integrity": "sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==", - "dev": true - }, - "@types/node": { - "version": "20.3.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.3.1.tgz", - "integrity": "sha512-EhcH/wvidPy1WeML3TtYFGR83UzjxeWRen9V402T8aUGYsCHOmfoisV3ZSg03gAFIbLq8TnWOJ0f4cALtnSEUg==", - "dev": true - }, - "@types/prop-types": { - "version": "15.7.5", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", - "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==", - "dev": true - }, - "@types/react": { - "version": "18.2.13", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.13.tgz", - "integrity": "sha512-vJ+zElvi/Zn9cVXB5slX2xL8PZodPCwPRDpittQdw43JR2AJ5k3vKdgJJyneV/cYgIbLQUwXa9JVDvUZXGba+Q==", - "dev": true, - "requires": { - "@types/prop-types": "*", - "@types/scheduler": "*", - "csstype": "^3.0.2" - } - }, - "@types/scheduler": { - "version": "0.16.3", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz", - "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==", - "dev": true - }, - "@types/yargs": { - "version": "16.0.5", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", - "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "@types/yargs-parser": { - "version": "21.0.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", - "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", - "dev": true - }, - "@webassemblyjs/ast": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz", - "integrity": "sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==", - "dev": true, - "requires": { - "@webassemblyjs/helper-numbers": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6" - } - }, - "@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", - "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", - "dev": true - }, - "@webassemblyjs/helper-api-error": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", - "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", - "dev": true - }, - "@webassemblyjs/helper-buffer": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz", - "integrity": "sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA==", - "dev": true - }, - "@webassemblyjs/helper-numbers": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", - "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", - "dev": true, - "requires": { - "@webassemblyjs/floating-point-hex-parser": "1.11.6", - "@webassemblyjs/helper-api-error": "1.11.6", - "@xtuc/long": "4.2.2" - } - }, - "@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", - "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", - "dev": true - }, - "@webassemblyjs/helper-wasm-section": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz", - "integrity": "sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.11.6", - "@webassemblyjs/helper-buffer": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/wasm-gen": "1.11.6" - } - }, - "@webassemblyjs/ieee754": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", - "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", - "dev": true, - "requires": { - "@xtuc/ieee754": "^1.2.0" - } - }, - "@webassemblyjs/leb128": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", - "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", - "dev": true, - "requires": { - "@xtuc/long": "4.2.2" - } - }, - "@webassemblyjs/utf8": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", - "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", - "dev": true - }, - "@webassemblyjs/wasm-edit": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz", - "integrity": "sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.11.6", - "@webassemblyjs/helper-buffer": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/helper-wasm-section": "1.11.6", - "@webassemblyjs/wasm-gen": "1.11.6", - "@webassemblyjs/wasm-opt": "1.11.6", - "@webassemblyjs/wasm-parser": "1.11.6", - "@webassemblyjs/wast-printer": "1.11.6" - } - }, - "@webassemblyjs/wasm-gen": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz", - "integrity": "sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/ieee754": "1.11.6", - "@webassemblyjs/leb128": "1.11.6", - "@webassemblyjs/utf8": "1.11.6" - } - }, - "@webassemblyjs/wasm-opt": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz", - "integrity": "sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.11.6", - "@webassemblyjs/helper-buffer": "1.11.6", - "@webassemblyjs/wasm-gen": "1.11.6", - "@webassemblyjs/wasm-parser": "1.11.6" - } - }, - "@webassemblyjs/wasm-parser": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz", - "integrity": "sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.11.6", - "@webassemblyjs/helper-api-error": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/ieee754": "1.11.6", - "@webassemblyjs/leb128": "1.11.6", - "@webassemblyjs/utf8": "1.11.6" - } - }, - "@webassemblyjs/wast-printer": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz", - "integrity": "sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.11.6", - "@xtuc/long": "4.2.2" - } - }, - "@xtuc/ieee754": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "dev": true - }, - "@xtuc/long": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", - "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "dev": true - }, - "acorn": { - "version": "8.9.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.9.0.tgz", - "integrity": "sha512-jaVNAFBHNLXspO543WnNNPZFRtavh3skAkITqD0/2aeMkKZTN+254PyhwxFYrk3vQ1xfY+2wbesJMs/JC8/PwQ==", - "dev": true - }, - "acorn-import-assertions": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", - "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", - "dev": true, - "requires": {} - }, - "acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "peer": true, - "requires": {} - }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ajv-formats": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", - "dev": true, - "requires": { - "ajv": "^8.0.0" - }, - "dependencies": { - "ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - } - }, - "json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - } - } - }, - "ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "requires": {} - }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, - "peer": true - }, - "autoprefixer": { - "version": "10.4.14", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.14.tgz", - "integrity": "sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==", - "dev": true, - "requires": { - "browserslist": "^4.21.5", - "caniuse-lite": "^1.0.30001464", - "fraction.js": "^4.2.0", - "normalize-range": "^0.1.2", - "picocolors": "^1.0.0", - "postcss-value-parser": "^4.2.0" - } - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "browserslist": { - "version": "4.21.9", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.9.tgz", - "integrity": "sha512-M0MFoZzbUrRU4KNfCrDLnvyE7gub+peetoTid3TBIqtunaDJyXlwhakT+/VkvSXcfIzFfK/nkCs4nmyTmxdNSg==", - "dev": true, - "requires": { - "caniuse-lite": "^1.0.30001503", - "electron-to-chromium": "^1.4.431", - "node-releases": "^2.0.12", - "update-browserslist-db": "^1.0.11" - } - }, - "buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true - }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "peer": true - }, - "caniuse-lite": { - "version": "1.0.30001506", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001506.tgz", - "integrity": "sha512-6XNEcpygZMCKaufIcgpQNZNf00GEqc7VQON+9Rd0K1bMYo8xhMZRAo5zpbnbMNizi4YNgIDAFrdykWsvY3H4Hw==", - "dev": true - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "chrome-trace-event": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", - "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", - "dev": true - }, - "cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "copyfiles": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/copyfiles/-/copyfiles-2.4.1.tgz", - "integrity": "sha512-fereAvAvxDrQDOXybk3Qu3dPbOoKoysFMWtkY3mv5BsL8//OSZVL5DCLYqgRfY5cWirgRzlC+WSrxp6Bo3eNZg==", - "dev": true, - "requires": { - "glob": "^7.0.5", - "minimatch": "^3.0.3", - "mkdirp": "^1.0.4", - "noms": "0.0.0", - "through2": "^2.0.1", - "untildify": "^4.0.0", - "yargs": "^16.1.0" - }, - "dependencies": { - "mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true - } - } - }, - "core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "dev": true - }, - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "peer": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "csstype": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", - "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==", - "dev": true - }, - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "peer": true, - "requires": { - "ms": "2.1.2" - } - }, - "deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true, - "peer": true - }, - "doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "peer": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "electron-to-chromium": { - "version": "1.4.437", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.437.tgz", - "integrity": "sha512-ZFekRuBOHUXp21wrR5lshT6pZa/KmjkhKBAtmZz4NN5sCWlHOk3kdhiwFINrDBsRLX6FjyBAb1TRN+KBeNlyzQ==", - "dev": true - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "enhanced-resolve": { - "version": "5.15.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", - "integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==", - "dev": true, - "requires": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" - } - }, - "es-module-lexer": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.3.0.tgz", - "integrity": "sha512-vZK7T0N2CBmBOixhmjdqx2gWVbFZ4DXZ/NyRMZVlJXPa7CyFS+/a4QQsDGDQy9ZfEzxFuNEsMLeQJnKP2p5/JA==", - "dev": true - }, - "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true - }, - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "peer": true - }, - "eslint": { - "version": "8.43.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.43.0.tgz", - "integrity": "sha512-aaCpf2JqqKesMFGgmRPessmVKjcGXqdlAYLLC3THM8t5nBRZRQ+st5WM/hoJXkdioEXLLbXgclUpM0TXo5HX5Q==", - "dev": true, - "peer": true, - "requires": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.4.0", - "@eslint/eslintrc": "^2.0.3", - "@eslint/js": "8.43.0", - "@humanwhocodes/config-array": "^0.11.10", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.0", - "eslint-visitor-keys": "^3.4.1", - "espree": "^9.5.2", - "esquery": "^1.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0" - } - }, - "eslint-scope": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.0.tgz", - "integrity": "sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==", - "dev": true, - "peer": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - } - }, - "eslint-visitor-keys": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz", - "integrity": "sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==", - "dev": true, - "peer": true - }, - "eslint-webpack-plugin": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/eslint-webpack-plugin/-/eslint-webpack-plugin-3.2.0.tgz", - "integrity": "sha512-avrKcGncpPbPSUHX6B3stNGzkKFto3eL+DKM4+VyMrVnhPc3vRczVlCq3uhuFOdRvDHTVXuzwk1ZKUrqDQHQ9w==", - "dev": true, - "requires": { - "@types/eslint": "^7.29.0 || ^8.4.1", - "jest-worker": "^28.0.2", - "micromatch": "^4.0.5", - "normalize-path": "^3.0.0", - "schema-utils": "^4.0.0" - } - }, - "espree": { - "version": "9.5.2", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.2.tgz", - "integrity": "sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==", - "dev": true, - "peer": true, - "requires": { - "acorn": "^8.8.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - } - }, - "esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", - "dev": true, - "peer": true, - "requires": { - "estraverse": "^5.1.0" - } - }, - "esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "requires": { - "estraverse": "^5.2.0" - } - }, - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "peer": true - }, - "events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "dev": true - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true, - "peer": true - }, - "fastq": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", - "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", - "dev": true, - "peer": true, - "requires": { - "reusify": "^1.0.4" - } - }, - "file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "peer": true, - "requires": { - "flat-cache": "^3.0.4" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "peer": true, - "requires": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - } - }, - "flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "dev": true, - "peer": true, - "requires": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - } - }, - "flatted": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", - "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", - "dev": true, - "peer": true - }, - "fraction.js": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz", - "integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==", - "dev": true - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true - }, - "glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "peer": true, - "requires": { - "is-glob": "^4.0.3" - } - }, - "glob-to-regexp": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", - "dev": true - }, - "globals": { - "version": "13.20.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", - "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", - "dev": true, - "peer": true, - "requires": { - "type-fest": "^0.20.2" - } - }, - "graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true - }, - "graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true, - "peer": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", - "dev": true, - "peer": true - }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "peer": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "peer": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "peer": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "peer": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, - "is-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, - "peer": true - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, - "peer": true - }, - "jest-worker": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.1.3.tgz", - "integrity": "sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g==", - "dev": true, - "requires": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "dependencies": { - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "peer": true, - "requires": { - "argparse": "^2.0.1" - } - }, - "json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true, - "peer": true - }, - "levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "peer": true, - "requires": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - } - }, - "loader-runner": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", - "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", - "dev": true - }, - "locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "peer": true, - "requires": { - "p-locate": "^5.0.0" - } - }, - "lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true, - "peer": true - }, - "merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, - "requires": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - } - }, - "mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true - }, - "mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, - "requires": { - "mime-db": "1.52.0" - } - }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true, - "peer": true - }, - "nanoid": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", - "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", - "dev": true, - "peer": true - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true, - "peer": true - }, - "neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true - }, - "node-releases": { - "version": "2.0.12", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.12.tgz", - "integrity": "sha512-QzsYKWhXTWx8h1kIvqfnC++o0pEmpRQA/aenALsL2F4pqNVr7YzcdMlDij5WBnwftRbJCNJL/O7zdKaxKPHqgQ==", - "dev": true - }, - "noms": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/noms/-/noms-0.0.0.tgz", - "integrity": "sha1-2o69nzr51nYJGbJ9nNyAkqczKFk=", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "readable-stream": "~1.0.31" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true - }, - "readable-stream": { - "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", - "dev": true - } - } - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true - }, - "normalize-range": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", - "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", - "dev": true - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "dev": true, - "peer": true, - "requires": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - } - }, - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "peer": true, - "requires": { - "yocto-queue": "^0.1.0" - } - }, - "p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "peer": true, - "requires": { - "p-limit": "^3.0.2" - } - }, - "parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "peer": true, - "requires": { - "callsites": "^3.0.0" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "peer": true - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "peer": true - }, - "picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true - }, - "picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true - }, - "postcss": { - "version": "8.4.24", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.24.tgz", - "integrity": "sha512-M0RzbcI0sO/XJNucsGjvWU9ERWxb/ytp1w6dKtxTKgixdtQDq4rmx/g8W1hnaheq9jgwL/oyEdH5Bc4WwJKMqg==", - "dev": true, - "peer": true, - "requires": { - "nanoid": "^3.3.6", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - } - }, - "postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true - }, - "prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "peer": true - }, - "process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true - }, - "punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", - "dev": true - }, - "queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "peer": true - }, - "randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "requires": { - "safe-buffer": "^5.1.0" - } - }, - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true - }, - "require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true - }, - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "peer": true - }, - "reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "peer": true - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "peer": true, - "requires": { - "queue-microtask": "^1.2.2" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "schema-utils": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", - "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" - }, - "dependencies": { - "ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - } - }, - "ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.3" - } - }, - "json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - } - } - }, - "serialize-javascript": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", - "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", - "dev": true, - "requires": { - "randombytes": "^2.1.0" - } - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "peer": true, - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "peer": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, - "source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", - "dev": true, - "peer": true - }, - "source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1" - } - }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "peer": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - }, - "tapable": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", - "dev": true - }, - "terser": { - "version": "5.18.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.18.1.tgz", - "integrity": "sha512-j1n0Ao919h/Ai5r43VAnfV/7azUYW43GPxK7qSATzrsERfW7+y2QW9Cp9ufnRF5CQUWbnLSo7UJokSWCqg4tsQ==", - "dev": true, - "requires": { - "@jridgewell/source-map": "^0.3.3", - "acorn": "^8.8.2", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - } - }, - "terser-webpack-plugin": { - "version": "5.3.9", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.9.tgz", - "integrity": "sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA==", - "dev": true, - "requires": { - "@jridgewell/trace-mapping": "^0.3.17", - "jest-worker": "^27.4.5", - "schema-utils": "^3.1.1", - "serialize-javascript": "^6.0.1", - "terser": "^5.16.8" - }, - "dependencies": { - "jest-worker": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", - "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", - "dev": true, - "requires": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - } - }, - "schema-utils": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", - "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - } - }, - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true, - "peer": true - }, - "through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "requires": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, - "to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "dev": true - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } - }, - "type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "peer": true, - "requires": { - "prelude-ls": "^1.2.1" - } - }, - "type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "peer": true - }, - "typescript": { - "version": "4.5.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz", - "integrity": "sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==", - "dev": true - }, - "untildify": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", - "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", - "dev": true - }, - "update-browserslist-db": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", - "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==", - "dev": true, - "requires": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" - } - }, - "uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true - }, - "watchpack": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", - "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", - "dev": true, - "requires": { - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.1.2" - } - }, - "webpack": { - "version": "5.88.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.88.0.tgz", - "integrity": "sha512-O3jDhG5e44qIBSi/P6KpcCcH7HD+nYIHVBhdWFxcLOcIGN8zGo5nqF3BjyNCxIh4p1vFdNnreZv2h2KkoAw3lw==", - "dev": true, - "requires": { - "@types/eslint-scope": "^3.7.3", - "@types/estree": "^1.0.0", - "@webassemblyjs/ast": "^1.11.5", - "@webassemblyjs/wasm-edit": "^1.11.5", - "@webassemblyjs/wasm-parser": "^1.11.5", - "acorn": "^8.7.1", - "acorn-import-assertions": "^1.9.0", - "browserslist": "^4.14.5", - "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.15.0", - "es-module-lexer": "^1.2.1", - "eslint-scope": "5.1.1", - "events": "^3.2.0", - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.9", - "json-parse-even-better-errors": "^2.3.1", - "loader-runner": "^4.2.0", - "mime-types": "^2.1.27", - "neo-async": "^2.6.2", - "schema-utils": "^3.2.0", - "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.3.7", - "watchpack": "^2.4.0", - "webpack-sources": "^3.2.3" - }, - "dependencies": { - "eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - } - }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true - }, - "schema-utils": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", - "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - } - } - } - }, - "webpack-sources": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", - "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", - "dev": true - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "peer": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true, - "peer": true - }, - "wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "dev": true - }, - "y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true - }, - "yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "requires": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - } - }, - "yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true - }, - "yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "peer": true - } - } -} diff --git a/packages/oidc-client/package.json b/packages/oidc-client/package.json index b566b1bfd..ee04fbb07 100644 --- a/packages/oidc-client/package.json +++ b/packages/oidc-client/package.json @@ -1,6 +1,6 @@ { - "name": "@axa-fr/vanilla-oidc", - "version": "6.24.1", + "name": "@axa-fr/oidc-client", + "version": "7.26.0", "private": false, "type": "module", "main": "./dist/index.umd.cjs", @@ -17,28 +17,23 @@ ], "repository": { "type": "git", - "url": "https://github.com/AxaGuilDEv/react-oidc.git" + "url": "https://github.com/AxaFrance/oidc-client.git" + }, + "dependencies": { + "@axa-fr/oidc-client-service-worker": "workspace:*" }, "devDependencies": { - "@axa-fr/oidc-client-service-worker": "workspace:*", - "@testing-library/dom": "^9.3.1", - "@testing-library/jest-dom": "^5.16.5", - "@testing-library/react": "13.3.0", - "@vitest/coverage-v8": "^0.33.0", - "base64-js": "^1.5.1", - "cpy": "^10.1.0", + "@testing-library/dom": "10.4.0", + "@testing-library/jest-dom": "6.6.3", + "@testing-library/react": "16.3.0", + "@vitest/coverage-v8": "3.1.3", + "cpy": "11.1.0", "cpy-cli": "^5.0.0", - "eslint": "^8.26.0", - "eslint-config-standard": "^17.1.0", - "eslint-config-standard-with-typescript": "^36.1.0", - "eslint-import-resolver-typescript": "^3.5.5", - "eslint-plugin-react": "^7.32.2", - "eslint-plugin-simple-import-sort": "^10.0.0", - "rimraf": "5.0.1", - "typescript": "5.1.6", - "vite": "^4.4.4", - "vite-plugin-dts": "^3.3.0", - "vitest": "^0.33.0" + "rimraf": "6.0.1", + "typescript": "5.8.3", + "vite": "6.3.5", + "vite-plugin-dts": "4.5.3", + "vitest": "3.1.3" }, "keywords": [ "oidc", @@ -46,7 +41,8 @@ "openid", "oauth2", "oauth", - "vanilla" + "vanilla", + "vanillajs" ], "scripts": { "clean": "rimraf dist", @@ -54,7 +50,7 @@ "build": "tsc && vite build", "test": "vitest --root . --coverage", "prepare": "pnpm run clean && pnpm run copy-service-worker && pnpm run build", - "postinstall": "node ./bin/post-install.mjs" + "postinstall": "echo 'WARNING keep sink OidcServiceWorker.js version file'" }, "license": "MIT", "publishConfig": { diff --git a/packages/oidc-client/public/OidcServiceWorker.js b/packages/oidc-client/public/OidcServiceWorker.js deleted file mode 100644 index b70fc4b42..000000000 --- a/packages/oidc-client/public/OidcServiceWorker.js +++ /dev/null @@ -1,559 +0,0 @@ -const scriptFilename = "OidcTrustedDomains.js"; -const acceptAnyDomainToken = "*"; -const TOKEN = { - REFRESH_TOKEN: "REFRESH_TOKEN_SECURED_BY_OIDC_SERVICE_WORKER", - ACCESS_TOKEN: "ACCESS_TOKEN_SECURED_BY_OIDC_SERVICE_WORKER", - NONCE_TOKEN: "NONCE_SECURED_BY_OIDC_SERVICE_WORKER", - CODE_VERIFIER: "CODE_VERIFIER_SECURED_BY_OIDC_SERVICE_WORKER" -}; -const TokenRenewMode = { - access_token_or_id_token_invalid: "access_token_or_id_token_invalid", - access_token_invalid: "access_token_invalid", - id_token_invalid: "id_token_invalid" -}; -const openidWellknownUrlEndWith = "/.well-known/openid-configuration"; -function checkDomain(domains, endpoint) { - if (!endpoint) { - return; - } - const domain = domains.find((domain2) => { - var _a; - let testable; - if (typeof domain2 === "string") { - testable = new RegExp(`^${domain2}`); - } else { - testable = domain2; - } - return (_a = testable.test) == null ? void 0 : _a.call(testable, endpoint); - }); - if (!domain) { - throw new Error( - "Domain " + endpoint + " is not trusted, please add domain in " + scriptFilename - ); - } -} -const getDomains = (trustedDomain, type) => { - if (Array.isArray(trustedDomain)) { - return trustedDomain; - } - return trustedDomain[`${type}Domains`] ?? trustedDomain.domains ?? []; -}; -const getCurrentDatabaseDomain = (database2, url, trustedDomains2) => { - var _a; - if (url.endsWith(openidWellknownUrlEndWith)) { - return null; - } - for (const [key, currentDatabase] of Object.entries(database2)) { - const oidcServerConfiguration = currentDatabase.oidcServerConfiguration; - if (!oidcServerConfiguration) { - continue; - } - if (oidcServerConfiguration.tokenEndpoint && url === oidcServerConfiguration.tokenEndpoint) { - continue; - } - if (oidcServerConfiguration.revocationEndpoint && url === oidcServerConfiguration.revocationEndpoint) { - continue; - } - const trustedDomain = trustedDomains2 == null ? [] : trustedDomains2[key]; - const domains = getDomains(trustedDomain, "accessToken"); - const domainsToSendTokens = oidcServerConfiguration.userInfoEndpoint ? [oidcServerConfiguration.userInfoEndpoint, ...domains] : [...domains]; - let hasToSendToken = false; - if (domainsToSendTokens.find((f) => f === acceptAnyDomainToken)) { - hasToSendToken = true; - } else { - for (let i = 0; i < domainsToSendTokens.length; i++) { - let domain = domainsToSendTokens[i]; - if (typeof domain === "string") { - domain = new RegExp(`^${domain}`); - } - if ((_a = domain.test) == null ? void 0 : _a.call(domain, url)) { - hasToSendToken = true; - break; - } - } - } - if (hasToSendToken) { - if (!currentDatabase.tokens) { - return null; - } - return currentDatabase; - } - } - return null; -}; -function serializeHeaders(headers) { - const headersObj = {}; - for (const key of headers.keys()) { - if (headers.has(key)) { - headersObj[key] = headers.get(key); - } - } - return headersObj; -} -const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); -function countLetter(str, find) { - return str.split(find).length - 1; -} -function parseJwt(token) { - return JSON.parse( - b64DecodeUnicode(token.split(".")[1].replace("-", "+").replace("_", "/")) - ); -} -function b64DecodeUnicode(str) { - return decodeURIComponent( - Array.prototype.map.call( - atob(str), - (c) => "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2) - ).join("") - ); -} -function computeTimeLeft(refreshTimeBeforeTokensExpirationInSecond, expiresAt) { - const currentTimeUnixSecond = (/* @__PURE__ */ new Date()).getTime() / 1e3; - return Math.round( - expiresAt - refreshTimeBeforeTokensExpirationInSecond - currentTimeUnixSecond - ); -} -function isTokensValid(tokens) { - if (!tokens) { - return false; - } - return computeTimeLeft(0, tokens.expiresAt) > 0; -} -const extractTokenPayload = (token) => { - try { - if (!token) { - return null; - } - if (countLetter(token, ".") === 2) { - return parseJwt(token); - } else { - return null; - } - } catch (e) { - console.warn(e); - } - return null; -}; -const isTokensOidcValid = (tokens, nonce, oidcServerConfiguration) => { - if (tokens.idTokenPayload) { - const idTokenPayload = tokens.idTokenPayload; - if (oidcServerConfiguration.issuer !== idTokenPayload.iss) { - return { isValid: false, reason: "Issuer does not match" }; - } - const currentTimeUnixSecond = (/* @__PURE__ */ new Date()).getTime() / 1e3; - if (idTokenPayload.exp && idTokenPayload.exp < currentTimeUnixSecond) { - return { isValid: false, reason: "Token expired" }; - } - const timeInSevenDays = 60 * 60 * 24 * 7; - if (idTokenPayload.iat && idTokenPayload.iat + timeInSevenDays < currentTimeUnixSecond) { - return { isValid: false, reason: "Token is used from too long time" }; - } - if (nonce && idTokenPayload.nonce && idTokenPayload.nonce !== nonce) { - return { isValid: false, reason: "Nonce does not match" }; - } - } - return { isValid: true, reason: "" }; -}; -function _hideTokens(tokens, currentDatabaseElement, configurationName) { - if (!tokens.issued_at) { - const currentTimeUnixSecond = (/* @__PURE__ */ new Date()).getTime() / 1e3; - tokens.issued_at = currentTimeUnixSecond; - } - const accessTokenPayload = extractTokenPayload(tokens.access_token); - const secureTokens = { - ...tokens, - accessTokenPayload - }; - if (currentDatabaseElement.hideAccessToken) { - secureTokens.access_token = TOKEN.ACCESS_TOKEN + "_" + configurationName; - } - tokens.accessTokenPayload = accessTokenPayload; - let _idTokenPayload = null; - if (tokens.id_token) { - _idTokenPayload = extractTokenPayload(tokens.id_token); - tokens.idTokenPayload = { ..._idTokenPayload }; - if (_idTokenPayload.nonce && currentDatabaseElement.nonce != null) { - const keyNonce = TOKEN.NONCE_TOKEN + "_" + currentDatabaseElement.configurationName; - _idTokenPayload.nonce = keyNonce; - } - secureTokens.idTokenPayload = _idTokenPayload; - } - if (tokens.refresh_token) { - secureTokens.refresh_token = TOKEN.REFRESH_TOKEN + "_" + configurationName; - } - const idTokenExpiresAt = _idTokenPayload && _idTokenPayload.exp ? _idTokenPayload.exp : Number.MAX_VALUE; - const accessTokenExpiresAt = accessTokenPayload && accessTokenPayload.exp ? accessTokenPayload.exp : tokens.issued_at + tokens.expires_in; - let expiresAt; - const tokenRenewMode = currentDatabaseElement.oidcConfiguration.token_renew_mode; - if (tokenRenewMode === TokenRenewMode.access_token_invalid) { - expiresAt = accessTokenExpiresAt; - } else if (tokenRenewMode === TokenRenewMode.id_token_invalid) { - expiresAt = idTokenExpiresAt; - } else { - expiresAt = idTokenExpiresAt < accessTokenExpiresAt ? idTokenExpiresAt : accessTokenExpiresAt; - } - secureTokens.expiresAt = expiresAt; - tokens.expiresAt = expiresAt; - const nonce = currentDatabaseElement.nonce ? currentDatabaseElement.nonce.nonce : null; - const { isValid, reason } = isTokensOidcValid( - tokens, - nonce, - currentDatabaseElement.oidcServerConfiguration - ); - if (!isValid) { - throw Error(`Tokens are not OpenID valid, reason: ${reason}`); - } - if (currentDatabaseElement.tokens != null && "refresh_token" in currentDatabaseElement.tokens && !("refresh_token" in tokens)) { - const refreshToken = currentDatabaseElement.tokens.refresh_token; - currentDatabaseElement.tokens = { - ...tokens, - refresh_token: refreshToken - }; - } else { - currentDatabaseElement.tokens = tokens; - } - currentDatabaseElement.status = "LOGGED_IN"; - return secureTokens; -} -function hideTokens(currentDatabaseElement) { - const configurationName = currentDatabaseElement.configurationName; - return (response) => { - if (response.status !== 200) { - return response; - } - return response.json().then((tokens) => { - const secureTokens = _hideTokens(tokens, currentDatabaseElement, configurationName); - const body = JSON.stringify(secureTokens); - return new Response(body, response); - }); - }; -} -function replaceCodeVerifier(codeVerifier, newCodeVerifier) { - const regex = /code_verifier=[A-Za-z0-9_-]+/i; - return codeVerifier.replace(regex, `code_verifier=${newCodeVerifier}`); -} -const _self = self; -_self.importScripts(scriptFilename); -const id = Math.round((/* @__PURE__ */ new Date()).getTime() / 1e3).toString(); -const keepAliveJsonFilename = "OidcKeepAliveServiceWorker.json"; -const handleInstall = (event) => { - console.log("[OidcServiceWorker] service worker installed " + id); - event.waitUntil(_self.skipWaiting()); -}; -const handleActivate = (event) => { - console.log("[OidcServiceWorker] service worker activated " + id); - event.waitUntil(_self.clients.claim()); -}; -let currentLoginCallbackConfigurationName = null; -const database = { - default: { - configurationName: "default", - tokens: null, - status: null, - state: null, - codeVerifier: null, - nonce: null, - oidcServerConfiguration: null, - hideAccessToken: true - } -}; -const getCurrentDatabasesTokenEndpoint = (database2, url) => { - const databases = []; - for (const [, value] of Object.entries(database2)) { - if (value.oidcServerConfiguration != null && url.startsWith(value.oidcServerConfiguration.tokenEndpoint)) { - databases.push(value); - } else if (value.oidcServerConfiguration != null && value.oidcServerConfiguration.revocationEndpoint && url.startsWith(value.oidcServerConfiguration.revocationEndpoint)) { - databases.push(value); - } - } - return databases; -}; -const keepAliveAsync = async (event) => { - const originalRequest = event.request; - const isFromVanilla = originalRequest.headers.has("oidc-vanilla"); - const init = { status: 200, statusText: "oidc-service-worker" }; - const response = new Response("{}", init); - if (!isFromVanilla) { - const originalRequestUrl = new URL(originalRequest.url); - const minSleepSeconds = Number(originalRequestUrl.searchParams.get("minSleepSeconds")) || 240; - for (let i = 0; i < minSleepSeconds; i++) { - await sleep(1e3 + Math.floor(Math.random() * 1e3)); - const cache = await caches.open("oidc_dummy_cache"); - await cache.put(event.request, response.clone()); - } - } - return response; -}; -const handleFetch = async (event) => { - const originalRequest = event.request; - const url = originalRequest.url; - if (originalRequest.url.includes(keepAliveJsonFilename)) { - event.respondWith(keepAliveAsync(event)); - return; - } - const currentDatabaseForRequestAccessToken = getCurrentDatabaseDomain( - database, - originalRequest.url, - trustedDomains - ); - if (currentDatabaseForRequestAccessToken && currentDatabaseForRequestAccessToken.tokens && currentDatabaseForRequestAccessToken.tokens.access_token) { - while (currentDatabaseForRequestAccessToken.tokens && !isTokensValid(currentDatabaseForRequestAccessToken.tokens)) { - await sleep(200); - } - const newRequest = originalRequest.mode === "navigate" ? new Request(originalRequest, { - headers: { - ...serializeHeaders(originalRequest.headers), - authorization: "Bearer " + currentDatabaseForRequestAccessToken.tokens.access_token - } - }) : new Request(originalRequest, { - headers: { - ...serializeHeaders(originalRequest.headers), - authorization: "Bearer " + currentDatabaseForRequestAccessToken.tokens.access_token - }, - mode: currentDatabaseForRequestAccessToken.oidcConfiguration.service_worker_convert_all_requests_to_cors ? "cors" : originalRequest.mode - }); - event.waitUntil(event.respondWith(fetch(newRequest))); - return; - } - if (event.request.method !== "POST") { - return; - } - let currentDatabase = null; - const currentDatabases = getCurrentDatabasesTokenEndpoint( - database, - originalRequest.url - ); - const numberDatabase = currentDatabases.length; - if (numberDatabase > 0) { - const maPromesse = new Promise((resolve, reject) => { - const clonedRequest = originalRequest.clone(); - const response = clonedRequest.text().then((actualBody) => { - if (actualBody.includes(TOKEN.REFRESH_TOKEN) || actualBody.includes(TOKEN.ACCESS_TOKEN)) { - let newBody = actualBody; - for (let i = 0; i < numberDatabase; i++) { - const currentDb = currentDatabases[i]; - if (currentDb && currentDb.tokens != null) { - const keyRefreshToken = TOKEN.REFRESH_TOKEN + "_" + currentDb.configurationName; - if (actualBody.includes(keyRefreshToken)) { - newBody = newBody.replace( - keyRefreshToken, - encodeURIComponent(currentDb.tokens.refresh_token) - ); - currentDatabase = currentDb; - break; - } - const keyAccessToken = TOKEN.ACCESS_TOKEN + "_" + currentDb.configurationName; - if (actualBody.includes(keyAccessToken)) { - newBody = newBody.replace( - keyAccessToken, - encodeURIComponent(currentDb.tokens.access_token) - ); - currentDatabase = currentDb; - break; - } - } - } - const fetchPromise = fetch(originalRequest, { - body: newBody, - method: clonedRequest.method, - headers: { - ...serializeHeaders(originalRequest.headers) - }, - mode: clonedRequest.mode, - cache: clonedRequest.cache, - redirect: clonedRequest.redirect, - referrer: clonedRequest.referrer, - credentials: clonedRequest.credentials, - integrity: clonedRequest.integrity - }); - if (currentDatabase && currentDatabase.oidcServerConfiguration != null && currentDatabase.oidcServerConfiguration.revocationEndpoint && url.startsWith( - currentDatabase.oidcServerConfiguration.revocationEndpoint - )) { - return fetchPromise.then(async (response2) => { - const text = await response2.text(); - return new Response(text, response2); - }); - } - return fetchPromise.then(hideTokens(currentDatabase)); - } else if (actualBody.includes("code_verifier=") && currentLoginCallbackConfigurationName) { - currentDatabase = database[currentLoginCallbackConfigurationName]; - currentLoginCallbackConfigurationName = null; - let newBody = actualBody; - if (currentDatabase && currentDatabase.codeVerifier != null) { - newBody = replaceCodeVerifier(newBody, currentDatabase.codeVerifier); - } - return fetch(originalRequest, { - body: newBody, - method: clonedRequest.method, - headers: { - ...serializeHeaders(originalRequest.headers) - }, - mode: clonedRequest.mode, - cache: clonedRequest.cache, - redirect: clonedRequest.redirect, - referrer: clonedRequest.referrer, - credentials: clonedRequest.credentials, - integrity: clonedRequest.integrity - }).then(hideTokens(currentDatabase)); - } - return void 0; - }); - response.then((r) => { - if (r !== void 0) { - resolve(r); - } else { - console.log("success undefined"); - reject(new Error("Response is undefined inside a success")); - } - }).catch((err) => { - if (err !== void 0) { - reject(err); - } else { - console.log("error undefined"); - reject(new Error("Response is undefined inside a error")); - } - }); - }); - event.waitUntil(event.respondWith(maPromesse)); - } -}; -const trustedDomainsShowAccessToken = {}; -const handleMessage = (event) => { - const port = event.ports[0]; - const data = event.data; - const configurationName = data.configurationName; - let currentDatabase = database[configurationName]; - if (trustedDomains == null) { - trustedDomains = {}; - } - if (!currentDatabase) { - if (trustedDomainsShowAccessToken[configurationName] === void 0) { - const trustedDomain = trustedDomains[configurationName]; - trustedDomainsShowAccessToken[configurationName] = Array.isArray(trustedDomain) ? false : trustedDomain.showAccessToken; - } - database[configurationName] = { - tokens: null, - state: null, - codeVerifier: null, - oidcServerConfiguration: null, - oidcConfiguration: void 0, - nonce: null, - status: null, - configurationName, - hideAccessToken: !trustedDomainsShowAccessToken[configurationName] - }; - currentDatabase = database[configurationName]; - if (!trustedDomains[configurationName]) { - trustedDomains[configurationName] = []; - } - } - switch (data.type) { - case "clear": - currentDatabase.tokens = null; - currentDatabase.state = null; - currentDatabase.codeVerifier = null; - currentDatabase.status = data.data.status; - port.postMessage({ configurationName }); - return; - case "init": { - const oidcServerConfiguration = data.data.oidcServerConfiguration; - const trustedDomain = trustedDomains[configurationName]; - const domains = getDomains(trustedDomain, "oidc"); - if (!domains.find((f) => f === acceptAnyDomainToken)) { - [ - oidcServerConfiguration.tokenEndpoint, - oidcServerConfiguration.revocationEndpoint, - oidcServerConfiguration.userInfoEndpoint, - oidcServerConfiguration.issuer - ].forEach((url) => { - checkDomain(domains, url); - }); - } - currentDatabase.oidcServerConfiguration = oidcServerConfiguration; - currentDatabase.oidcConfiguration = data.data.oidcConfiguration; - const where = data.data.where; - if (where === "loginCallbackAsync" || where === "tryKeepExistingSessionAsync") { - currentLoginCallbackConfigurationName = configurationName; - } else { - currentLoginCallbackConfigurationName = null; - } - if (!currentDatabase.tokens) { - port.postMessage({ - tokens: null, - status: currentDatabase.status, - configurationName - }); - } else { - const tokens = { - ...currentDatabase.tokens - }; - if (currentDatabase.hideAccessToken) { - tokens.access_token = TOKEN.ACCESS_TOKEN + "_" + configurationName; - } - if (tokens.refresh_token) { - tokens.refresh_token = TOKEN.REFRESH_TOKEN + "_" + configurationName; - } - if (tokens.idTokenPayload && tokens.idTokenPayload.nonce && currentDatabase.nonce != null) { - tokens.idTokenPayload.nonce = TOKEN.NONCE_TOKEN + "_" + configurationName; - } - port.postMessage({ - tokens, - status: currentDatabase.status, - configurationName - }); - } - return; - } - case "setState": - currentDatabase.state = data.data.state; - port.postMessage({ configurationName }); - return; - case "getState": { - const state = currentDatabase.state; - port.postMessage({ configurationName, state }); - return; - } - case "setCodeVerifier": - currentDatabase.codeVerifier = data.data.codeVerifier; - port.postMessage({ configurationName }); - return; - case "getCodeVerifier": { - port.postMessage({ - configurationName, - codeVerifier: currentDatabase.codeVerifier != null ? TOKEN.CODE_VERIFIER + "_" + configurationName : null - }); - return; - } - case "setSessionState": - currentDatabase.sessionState = data.data.sessionState; - port.postMessage({ configurationName }); - return; - case "getSessionState": { - const sessionState = currentDatabase.sessionState; - port.postMessage({ configurationName, sessionState }); - return; - } - case "setNonce": { - const nonce = data.data.nonce; - if (nonce) { - currentDatabase.nonce = nonce; - } - port.postMessage({ configurationName }); - return; - } - case "getNonce": { - const keyNonce = TOKEN.NONCE_TOKEN + "_" + configurationName; - const nonce = currentDatabase.nonce ? keyNonce : null; - port.postMessage({ configurationName, nonce }); - return; - } - default: - currentDatabase.items = { ...data.data }; - port.postMessage({ configurationName }); - } -}; -_self.addEventListener("install", handleInstall); -_self.addEventListener("activate", handleActivate); -_self.addEventListener("fetch", handleFetch); -_self.addEventListener("message", handleMessage); -//# sourceMappingURL=OidcServiceWorker.js.map diff --git a/packages/oidc-client/public/OidcTrustedDomains.js b/packages/oidc-client/public/OidcTrustedDomains.js index 25851f75e..4447b02f6 100644 --- a/packages/oidc-client/public/OidcTrustedDomains.js +++ b/packages/oidc-client/public/OidcTrustedDomains.js @@ -5,23 +5,26 @@ // Domains used by OIDC server must be also declared here // eslint-disable-next-line @typescript-eslint/no-unused-vars const trustedDomains = { - default: ['https://demo.duendesoftware.com', 'https://kdhttps.auth0.com'], - config_classic: ['https://demo.duendesoftware.com'], - config_without_silent_login: ['https://demo.duendesoftware.com'], - config_without_refresh_token: ['https://demo.duendesoftware.com'], - config_without_refresh_token_silent_login: ['https://demo.duendesoftware.com'], - config_google: ['https://oauth2.googleapis.com', 'https://openidconnect.googleapis.com'], - config_with_hash: ['https://demo.duendesoftware.com'], + default: ['https://demo.duendesoftware.com', 'https://kdhttps.auth0.com'], + config_classic: ['https://demo.duendesoftware.com'], + config_with_monitor_session: ['https://demo.duendesoftware.com'], + config_without_silent_login: ['https://demo.duendesoftware.com'], + config_without_refresh_token: ['https://demo.duendesoftware.com'], + config_without_refresh_token_silent_login: ['https://demo.duendesoftware.com'], + config_google: ['https://oauth2.googleapis.com', 'https://openidconnect.googleapis.com'], + config_with_hash: ['https://demo.duendesoftware.com'], }; // Service worker will continue to give access token to the JavaScript client // Ideal to hide refresh token from client JavaScript, but to retrieve access_token for some // scenarios which require it. For example, to send it via websocket connection. -trustedDomains.config_show_access_token = { domains : ["https://demo.duendesoftware.com"], showAccessToken: true }; - +trustedDomains.config_show_access_token = { + domains: ['https://demo.duendesoftware.com'], + showAccessToken: true, +}; // This example defines domains used by OIDC server separately from domains to which access tokens will be injected. trustedDomains.config_separate_oidc_access_token_domains = { - oidcDomains: ["https://demo.duendesoftware.com"], - accessTokenDomains: ["https://myapi"] -}; \ No newline at end of file + oidcDomains: ['https://demo.duendesoftware.com'], + accessTokenDomains: ['https://myapi'], +}; diff --git a/packages/oidc-client/src/cache.ts b/packages/oidc-client/src/cache.ts index d25aa62d2..7a49cc16f 100644 --- a/packages/oidc-client/src/cache.ts +++ b/packages/oidc-client/src/cache.ts @@ -1,26 +1,29 @@ const fetchFromIssuerCache = {}; export const getFromCache = (localStorageKey, storage = window.sessionStorage, timeCacheSecond) => { - if (!fetchFromIssuerCache[localStorageKey]) { - if (storage) { - const cacheJson = storage.getItem(localStorageKey); - if (cacheJson) { - fetchFromIssuerCache[localStorageKey] = JSON.parse(cacheJson); - } - } - } - const oneHourMinisecond = 1000 * timeCacheSecond; - // @ts-ignore - if (fetchFromIssuerCache[localStorageKey] && (fetchFromIssuerCache[localStorageKey].timestamp + oneHourMinisecond) > Date.now()) { - return fetchFromIssuerCache[localStorageKey].result; + if (!fetchFromIssuerCache[localStorageKey]) { + if (storage) { + const cacheJson = storage.getItem(localStorageKey); + if (cacheJson) { + fetchFromIssuerCache[localStorageKey] = JSON.parse(cacheJson); + } } - return null; + } + const oneHourMinisecond = 1000 * timeCacheSecond; + // @ts-ignore + if ( + fetchFromIssuerCache[localStorageKey] && + fetchFromIssuerCache[localStorageKey].timestamp + oneHourMinisecond > Date.now() + ) { + return fetchFromIssuerCache[localStorageKey].result; + } + return null; }; export const setCache = (localStorageKey, result, storage = window.sessionStorage) => { - const timestamp = Date.now(); - fetchFromIssuerCache[localStorageKey] = { result, timestamp }; - if (storage) { - storage.setItem(localStorageKey, JSON.stringify({ result, timestamp })); - } + const timestamp = Date.now(); + fetchFromIssuerCache[localStorageKey] = { result, timestamp }; + if (storage) { + storage.setItem(localStorageKey, JSON.stringify({ result, timestamp })); + } }; diff --git a/packages/oidc-client/src/checkSession.ts b/packages/oidc-client/src/checkSession.ts index 66124d9e9..4e33a3d7f 100644 --- a/packages/oidc-client/src/checkSession.ts +++ b/packages/oidc-client/src/checkSession.ts @@ -1,60 +1,99 @@ import { CheckSessionIFrame } from './checkSessionIFrame.js'; +import Oidc from './oidc'; import { _silentLoginAsync, SilentLoginResponse } from './silentLogin.js'; import { OidcConfiguration } from './types.js'; -// eslint-disable-next-line @typescript-eslint/ban-types -export const startCheckSessionAsync = (oidc:any, oidcDatabase:any, configuration :OidcConfiguration) => (checkSessionIFrameUri, clientId, sessionState, isSilentSignin = false) => { - const silentLoginAsync = (extras, state = undefined, scope = undefined):Promise => { - return _silentLoginAsync(oidc.configurationName, configuration, oidc.publishEvent.bind(oidc))(extras, state, scope); +export const startCheckSessionAsync = + (oidc: Oidc, oidcDatabase: any, configuration: OidcConfiguration) => + (checkSessionIFrameUri, clientId, sessionState, isSilentSignin = false) => { + const silentLoginAsync = ( + extras, + state = undefined, + scope = undefined, + ): Promise => { + return _silentLoginAsync(oidc.configurationName, configuration, oidc.publishEvent.bind(oidc))( + extras, + state, + scope, + ); }; return new Promise((resolve, reject): void => { - if (configuration.silent_login_uri && configuration.silent_redirect_uri && configuration.monitor_session && checkSessionIFrameUri && sessionState && !isSilentSignin) { - const checkSessionCallback = () => { - oidc.checkSessionIFrame.stop(); - const tokens = oidc.tokens; - if (tokens === null) { - return; + if ( + configuration.silent_login_uri && + configuration.silent_redirect_uri && + configuration.monitor_session && + checkSessionIFrameUri && + sessionState && + !isSilentSignin + ) { + const checkSessionCallback = () => { + oidc.checkSessionIFrame.stop(); + const tokens = oidc.tokens; + if (tokens === null) { + return; + } + const idToken = tokens.idToken; + const idTokenPayload = tokens.idTokenPayload; + return silentLoginAsync({ + prompt: 'none', + id_token_hint: idToken, + scope: configuration.scope || 'openid', + }) + .then(silentSigninResponse => { + if (silentSigninResponse.error) { + throw new Error(silentSigninResponse.error); + } + const iFrameIdTokenPayload = silentSigninResponse.tokens.idTokenPayload; + if (idTokenPayload.sub === iFrameIdTokenPayload.sub) { + const sessionState = silentSigninResponse.sessionState; + oidc.checkSessionIFrame.start(silentSigninResponse.sessionState); + if (idTokenPayload.sid === iFrameIdTokenPayload.sid) { + console.debug( + 'SessionMonitor._callback: Same sub still logged in at OP, restarting check session iframe; session_state:', + sessionState, + ); + } else { + console.debug( + 'SessionMonitor._callback: Same sub still logged in at OP, session state has changed, restarting check session iframe; session_state:', + sessionState, + ); } - const idToken = tokens.idToken; - const idTokenPayload = tokens.idTokenPayload; - return silentLoginAsync({ - prompt: 'none', - id_token_hint: idToken, - scope: configuration.scope || 'openid', - }).then((silentSigninResponse) => { - const iFrameIdTokenPayload = silentSigninResponse.tokens.idTokenPayload; - if (idTokenPayload.sub === iFrameIdTokenPayload.sub) { - const sessionState = silentSigninResponse.sessionState; - oidc.checkSessionIFrame.start(silentSigninResponse.sessionState); - if (idTokenPayload.sid === iFrameIdTokenPayload.sid) { - console.debug('SessionMonitor._callback: Same sub still logged in at OP, restarting check session iframe; session_state:', sessionState); - } else { - console.debug('SessionMonitor._callback: Same sub still logged in at OP, session state has changed, restarting check session iframe; session_state:', sessionState); - } - } else { - console.debug('SessionMonitor._callback: Different subject signed into OP:', iFrameIdTokenPayload.sub); - } - // eslint-disable-next-line @typescript-eslint/no-unused-vars - }).catch(async (e) => { - console.warn('SessionMonitor._callback: Silent login failed, logging out other tabs:', e); - // eslint-disable-next-line @typescript-eslint/no-unused-vars - for (const [key, oidc] of Object.entries(oidcDatabase)) { - // @ts-ignore - await oidc.logoutOtherTabAsync(configuration.client_id, idTokenPayload.sub); - } - }); - }; - - oidc.checkSessionIFrame = new CheckSessionIFrame(checkSessionCallback, clientId, checkSessionIFrameUri); - oidc.checkSessionIFrame.load().then(() => { - oidc.checkSessionIFrame.start(sessionState); - resolve(oidc.checkSessionIFrame); - }).catch((e) => { - reject(e); + } else { + console.debug( + 'SessionMonitor._callback: Different subject signed into OP:', + iFrameIdTokenPayload.sub, + ); + } + }) + .catch(async e => { + console.warn( + 'SessionMonitor._callback: Silent login failed, logging out other tabs:', + e, + ); + for (const [, oidc] of Object.entries(oidcDatabase)) { + // @ts-ignore + await oidc.logoutOtherTabAsync(configuration.client_id, idTokenPayload.sub); + } }); - } else { - resolve(null); - } + }; + + oidc.checkSessionIFrame = new CheckSessionIFrame( + checkSessionCallback, + clientId, + checkSessionIFrameUri, + ); + oidc.checkSessionIFrame + .load() + .then(() => { + oidc.checkSessionIFrame.start(sessionState); + resolve(oidc.checkSessionIFrame); + }) + .catch(e => { + reject(e); + }); + } else { + resolve(null); + } }); -}; + }; diff --git a/packages/oidc-client/src/checkSessionIFrame.ts b/packages/oidc-client/src/checkSessionIFrame.ts index 247cbb24e..c82191415 100644 --- a/packages/oidc-client/src/checkSessionIFrame.ts +++ b/packages/oidc-client/src/checkSessionIFrame.ts @@ -3,81 +3,82 @@ const DefaultInterval = 2000; const Log = console; export class CheckSessionIFrame { - private readonly _client_id: any; - private readonly _callback: any; - private _url: any; - private readonly _interval: number; - private readonly _stopOnError: boolean; - private readonly _frame_origin: string; - private readonly _frame: HTMLIFrameElement; - private _boundMessageEvent: any; - private _timer: number; - constructor(callback, client_id, url, interval = DefaultInterval, stopOnError = true) { - this._callback = callback; - this._client_id = client_id; - this._url = url; - this._interval = interval || DefaultInterval; - this._stopOnError = stopOnError; - const idx = url.indexOf('/', url.indexOf('//') + 2); - this._frame_origin = url.substr(0, idx); - this._frame = window.document.createElement('iframe'); - this._frame.style.visibility = 'hidden'; - this._frame.style.position = 'absolute'; - this._frame.style.display = 'none'; - // @ts-ignore - this._frame.width = 0; - // @ts-ignore - this._frame.height = 0; + private readonly _client_id: any; + private readonly _callback: any; + private _url: any; + private readonly _interval: number; + private readonly _stopOnError: boolean; + private readonly _frame_origin: string; + private readonly _frame: HTMLIFrameElement; + private _boundMessageEvent: any; + private _timer: number; + constructor(callback, client_id, url, interval = DefaultInterval, stopOnError = true) { + this._callback = callback; + this._client_id = client_id; + this._url = url; + this._interval = interval || DefaultInterval; + this._stopOnError = stopOnError; + const idx = url.indexOf('/', url.indexOf('//') + 2); + this._frame_origin = url.substring(0, idx); + this._frame = window.document.createElement('iframe'); + this._frame.style.visibility = 'hidden'; + this._frame.style.position = 'absolute'; + this._frame.style.display = 'none'; + // @ts-ignore + this._frame.width = 0; + // @ts-ignore + this._frame.height = 0; - this._frame.src = url; - } + this._frame.src = url; + } - load() { - return new Promise((resolve) => { - this._frame.onload = () => { - resolve(); - }; - window.document.body.appendChild(this._frame); - this._boundMessageEvent = this._message.bind(this); - window.addEventListener('message', this._boundMessageEvent, false); - }); - } + load() { + return new Promise(resolve => { + this._frame.onload = () => { + resolve(); + }; + window.document.body.appendChild(this._frame); + this._boundMessageEvent = this._message.bind(this); + window.addEventListener('message', this._boundMessageEvent, false); + }); + } - _message(e) { - if (e.origin === this._frame_origin && - e.source === this._frame.contentWindow - ) { - if (e.data === 'error') { - Log.error('CheckSessionIFrame: error message from check session op iframe'); - if (this._stopOnError) { - this.stop(); - } - } else if (e.data === 'changed') { - Log.debug(e); - Log.debug('CheckSessionIFrame: changed message from check session op iframe'); - this.stop(); - this._callback(); - } else { - Log.debug('CheckSessionIFrame: ' + e.data + ' message from check session op iframe'); - } + _message(e) { + if (e.origin === this._frame_origin && e.source === this._frame.contentWindow) { + if (e.data === 'error') { + Log.error('CheckSessionIFrame: error message from check session op iframe'); + if (this._stopOnError) { + this.stop(); } + } else if (e.data === 'changed') { + Log.debug(e); + Log.debug('CheckSessionIFrame: changed message from check session op iframe'); + this.stop(); + this._callback(); + } else { + Log.debug('CheckSessionIFrame: ' + e.data + ' message from check session op iframe'); + } } + } - start(session_state) { - Log.debug('CheckSessionIFrame.start :' + session_state); - this.stop(); - const send = () => { - this._frame.contentWindow.postMessage(this._client_id + ' ' + session_state, this._frame_origin); - }; - send(); - this._timer = window.setInterval(send, this._interval); - } + start(session_state) { + Log.debug('CheckSessionIFrame.start :' + session_state); + this.stop(); + const send = () => { + this._frame.contentWindow.postMessage( + this._client_id + ' ' + session_state, + this._frame_origin, + ); + }; + send(); + this._timer = window.setInterval(send, this._interval); + } - stop() { - if (this._timer) { - Log.debug('CheckSessionIFrame.stop'); - window.clearInterval(this._timer); - this._timer = null; - } + stop() { + if (this._timer) { + Log.debug('CheckSessionIFrame.stop'); + window.clearInterval(this._timer); + this._timer = null; } + } } diff --git a/packages/oidc-client/src/crypto.ts b/packages/oidc-client/src/crypto.ts index e99391035..17ea8e45d 100644 --- a/packages/oidc-client/src/crypto.ts +++ b/packages/oidc-client/src/crypto.ts @@ -1,4 +1,4 @@ -import * as base64 from 'base64-js'; +import { uint8ToUrlBase64 } from './jwt'; const cryptoInfo = () => { const hasCrypto = typeof window !== 'undefined' && !!(window.crypto as any); @@ -16,24 +16,19 @@ const bufferToString = (buffer: Uint8Array) => { return state.join(''); }; -const urlSafe = (buffer: Uint8Array): string => { - const encoded = base64.fromByteArray(new Uint8Array(buffer)); - return encoded.replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, ''); -}; - export const generateRandom = (size: number) => { - const buffer = new Uint8Array(size); - const { hasCrypto } = cryptoInfo(); - if (hasCrypto) { - window.crypto.getRandomValues(buffer); - } else { - // fall back to Math.random() if nothing else is available - for (let i = 0; i < size; i += 1) { - buffer[i] = (Math.random() * charset.length) | 0; - } + const buffer = new Uint8Array(size); + const { hasCrypto } = cryptoInfo(); + if (hasCrypto) { + window.crypto.getRandomValues(buffer); + } else { + // fall back to Math.random() if nothing else is available + for (let i = 0; i < size; i += 1) { + buffer[i] = (Math.random() * charset.length) | 0; } - return bufferToString(buffer); - }; + } + return bufferToString(buffer); +}; export function textEncodeLite(str: string) { const buf = new ArrayBuffer(str.length); @@ -44,18 +39,26 @@ export function textEncodeLite(str: string) { } return bufView; } - export const deriveChallengeAsync = (code: string): Promise => { - if (code.length < 43 || code.length > 128) { - return Promise.reject(new Error('Invalid code length.')); - } - const { hasSubtleCrypto } = cryptoInfo(); - if (!hasSubtleCrypto) { - return Promise.reject(new Error('window.crypto.subtle is unavailable.')); - } - return new Promise((resolve, reject) => { - crypto.subtle.digest('SHA-256', textEncodeLite(code)).then(buffer => { - return resolve(urlSafe(new Uint8Array(buffer))); - }, error => reject(error)); - }); +export function base64urlOfHashOfASCIIEncodingAsync(code: string): Promise { + return new Promise((resolve, reject) => { + crypto.subtle.digest('SHA-256', textEncodeLite(code)).then( + buffer => { + return resolve(uint8ToUrlBase64(new Uint8Array(buffer))); + }, + error => reject(error), + ); + }); +} + +export const deriveChallengeAsync = (code: string): Promise => { + if (code.length < 43 || code.length > 128) { + return Promise.reject(new Error('Invalid code length.')); + } + const { hasSubtleCrypto } = cryptoInfo(); + if (!hasSubtleCrypto) { + return Promise.reject(new Error('window.crypto.subtle is unavailable.')); + } + + return base64urlOfHashOfASCIIEncodingAsync(code); }; diff --git a/packages/oidc-client/src/events.ts b/packages/oidc-client/src/events.ts index ac2690113..bd36726c9 100644 --- a/packages/oidc-client/src/events.ts +++ b/packages/oidc-client/src/events.ts @@ -1,28 +1,30 @@ export const eventNames = { - service_worker_not_supported_by_browser: 'service_worker_not_supported_by_browser', - token_aquired: 'token_aquired', - logout_from_another_tab: 'logout_from_another_tab', - logout_from_same_tab: 'logout_from_same_tab', - token_renewed: 'token_renewed', - token_timer: 'token_timer', - loginAsync_begin: 'loginAsync_begin', - loginAsync_error: 'loginAsync_error', - loginCallbackAsync_begin: 'loginCallbackAsync_begin', - loginCallbackAsync_end: 'loginCallbackAsync_end', - loginCallbackAsync_error: 'loginCallbackAsync_error', - refreshTokensAsync_begin: 'refreshTokensAsync_begin', - refreshTokensAsync: 'refreshTokensAsync', - refreshTokensAsync_end: 'refreshTokensAsync_end', - refreshTokensAsync_error: 'refreshTokensAsync_error', - refreshTokensAsync_silent_error: 'refreshTokensAsync_silent_error', - tryKeepExistingSessionAsync_begin: 'tryKeepExistingSessionAsync_begin', - tryKeepExistingSessionAsync_end: 'tryKeepExistingSessionAsync_end', - tryKeepExistingSessionAsync_error: 'tryKeepExistingSessionAsync_error', - silentLoginAsync_begin: 'silentLoginAsync_begin', - silentLoginAsync: 'silentLoginAsync', - silentLoginAsync_end: 'silentLoginAsync_end', - silentLoginAsync_error: 'silentLoginAsync_error', - syncTokensAsync_begin: 'syncTokensAsync_begin', - syncTokensAsync_end: 'syncTokensAsync_end', - syncTokensAsync_error: 'syncTokensAsync_error', + service_worker_not_supported_by_browser: 'service_worker_not_supported_by_browser', + token_acquired: 'token_acquired', + logout_from_another_tab: 'logout_from_another_tab', + logout_from_same_tab: 'logout_from_same_tab', + token_renewed: 'token_renewed', + token_timer: 'token_timer', + loginAsync_begin: 'loginAsync_begin', + loginAsync_error: 'loginAsync_error', + loginCallbackAsync_begin: 'loginCallbackAsync_begin', + loginCallbackAsync_end: 'loginCallbackAsync_end', + loginCallbackAsync_error: 'loginCallbackAsync_error', + refreshTokensAsync_begin: 'refreshTokensAsync_begin', + refreshTokensAsync: 'refreshTokensAsync', + refreshTokensAsync_end: 'refreshTokensAsync_end', + refreshTokensAsync_error: 'refreshTokensAsync_error', + refreshTokensAsync_silent_error: 'refreshTokensAsync_silent_error', + tryKeepExistingSessionAsync_begin: 'tryKeepExistingSessionAsync_begin', + tryKeepExistingSessionAsync_end: 'tryKeepExistingSessionAsync_end', + tryKeepExistingSessionAsync_error: 'tryKeepExistingSessionAsync_error', + silentLoginAsync_begin: 'silentLoginAsync_begin', + silentLoginAsync: 'silentLoginAsync', + silentLoginAsync_end: 'silentLoginAsync_end', + silentLoginAsync_error: 'silentLoginAsync_error', + syncTokensAsync_begin: 'syncTokensAsync_begin', + syncTokensAsync_lock_not_available: 'syncTokensAsync_lock_not_available', + syncTokensAsync_end: 'syncTokensAsync_end', + syncTokensAsync_error: 'syncTokensAsync_error', + tokensInvalidAndWaitingActionsToRefresh: 'tokensInvalidAndWaitingActionsToRefresh', }; diff --git a/packages/oidc-client/src/fetch.ts b/packages/oidc-client/src/fetch.ts new file mode 100644 index 000000000..5edd196fd --- /dev/null +++ b/packages/oidc-client/src/fetch.ts @@ -0,0 +1,66 @@ +import Oidc from './oidc'; +import { getValidTokenAsync, OidcToken } from './parseTokens'; +import { syncTokensInfoAsync } from './renewTokens'; +import { Fetch } from './types'; + +// @ts-ignore +export const fetchWithTokens = + (fetch: Fetch, oidc: Oidc | null, demonstrating_proof_of_possession: boolean = false): Fetch => + async (...params: Parameters): Promise => { + const [url, options, ...rest] = params; + const optionTmp = options ? { ...options } : { method: 'GET' }; + let headers = new Headers(); + if (optionTmp.headers) { + headers = !(optionTmp.headers instanceof Headers) + ? new Headers(optionTmp.headers) + : optionTmp.headers; + } + const oidcToken: OidcToken = { + getTokens: () => oidc.tokens, + configuration: { + token_automatic_renew_mode: oidc.configuration.token_automatic_renew_mode, + refresh_time_before_tokens_expiration_in_second: + oidc.configuration.refresh_time_before_tokens_expiration_in_second, + }, + + syncTokensInfoAsync: async () => { + const { status } = await syncTokensInfoAsync(oidc)( + oidc.configuration, + oidc.configurationName, + oidc.tokens, + false, + ); + return status; + }, + renewTokensAsync: oidc.renewTokensAsync.bind(oidc), + }; + + // @ts-ignore + const getValidToken = await getValidTokenAsync(oidcToken); + const accessToken = getValidToken?.tokens?.accessToken; + if (!headers.has('Accept')) { + headers.set('Accept', 'application/json'); + } + if (accessToken) { + if ( + oidc.configuration.demonstrating_proof_of_possession && + demonstrating_proof_of_possession + ) { + const demonstrationOdProofOfPossession = + await oidc.generateDemonstrationOfProofOfPossessionAsync( + accessToken, + url.toString(), + optionTmp.method, + ); + headers.set('Authorization', `DPoP ${accessToken}`); + headers.set('DPoP', demonstrationOdProofOfPossession); + } else { + headers.set('Authorization', `Bearer ${accessToken}`); + } + if (!optionTmp.credentials) { + optionTmp.credentials = 'same-origin'; + } + } + const newOptions = { ...optionTmp, headers }; + return await fetch(url, newOptions, ...rest); + }; diff --git a/packages/oidc-client/src/index.ts b/packages/oidc-client/src/index.ts index 8e6bbd857..af6dea8a3 100644 --- a/packages/oidc-client/src/index.ts +++ b/packages/oidc-client/src/index.ts @@ -1,10 +1,10 @@ +export type { ILOidcLocation } from './location.js'; +export { OidcLocation } from './location.js'; export { getFetchDefault } from './oidc.js'; +export type { OidcUserInfo } from './oidcClient.js'; +export { OidcClient } from './oidcClient.js'; +export type { Tokens } from './parseTokens.js'; export { TokenRenewMode } from './parseTokens.js'; export { getParseQueryStringFromLocation, getPath } from './route-utils'; -export type { - AuthorityConfiguration, - Fetch, - OidcConfiguration, - StringMap, -} from './types.js'; -export { type OidcUserInfo, VanillaOidc } from './vanillaOidc.js'; +export type { AuthorityConfiguration, Fetch, OidcConfiguration, StringMap } from './types.js'; +export { TokenAutomaticRenewMode } from './types.js'; diff --git a/packages/oidc-client/src/iniWorker.spec.ts b/packages/oidc-client/src/iniWorker.spec.ts index a9b00b2a2..ac21fccb6 100644 --- a/packages/oidc-client/src/iniWorker.spec.ts +++ b/packages/oidc-client/src/iniWorker.spec.ts @@ -1,21 +1,31 @@ -import { excludeOs, getOperatingSystem } from './initWorker'; +import { describe, expect, it } from 'vitest'; -import { describe, it, expect } from 'vitest'; +import { excludeOs, getOperatingSystem } from './initWorkerOption'; describe('initWorker test Suite', () => { + it.each([ + [ + 'Mozilla/5.0 (iPhone; CPU iPhone OS 12_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 Mobile/15E148 Safari/604.1', + 'iOS', + '12.1.0', + ], + [ + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/69.0.3497.105 Mobile/15E148 Safari/605.1', + 'Mac OS X', + '10_15_6', + ], + ])( + 'getOperatingSystem should return OS for Version', + (userAgent, expectedOs, expectedVersion) => { + const operatingSystem = getOperatingSystem({ + userAgent, + appVersion: 'OS ' + expectedVersion.replaceAll('.', '_'), + }); + expect(expectedOs).toBe(operatingSystem.os); + expect(expectedVersion).toBe(operatingSystem.osVersion); - it.each([['Mozilla/5.0 (iPhone; CPU iPhone OS 12_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 Mobile/15E148 Safari/604.1', 'iOS', '12.1.0'], - ['Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/69.0.3497.105 Mobile/15E148 Safari/605.1', 'Mac OS X', '10_15_6'], - ])( - 'getOperatingSystem should return OS for Version', - (userAgent, expectedOs, expectedVersion) => { - const operatingSystem = getOperatingSystem({ userAgent, appVersion: 'OS ' + expectedVersion.replaceAll('.', '_') }); - expect(expectedOs).toBe(operatingSystem.os); - expect(expectedVersion).toBe(operatingSystem.osVersion); - - const isExcluded = excludeOs(operatingSystem); - expect(isExcluded).toBe(true); - }, - ); - -}); \ No newline at end of file + const isExcluded = excludeOs(operatingSystem); + expect(isExcluded).toBe(true); + }, + ); +}); diff --git a/packages/oidc-client/src/initSession.ts b/packages/oidc-client/src/initSession.ts index e3b96efb0..897b9bbd3 100644 --- a/packages/oidc-client/src/initSession.ts +++ b/packages/oidc-client/src/initSession.ts @@ -1,89 +1,118 @@ export const initSession = (configurationName, storage = sessionStorage) => { - const clearAsync = (status) => { - storage[`oidc.${configurationName}`] = JSON.stringify({ tokens: null, status }); - return Promise.resolve(); - }; - - const initAsync = async () => { - if (!storage[`oidc.${configurationName}`]) { - storage[`oidc.${configurationName}`] = JSON.stringify({ tokens: null, status: null }); - return { tokens: null, status: null }; - } - const data = JSON.parse(storage[`oidc.${configurationName}`]); - return Promise.resolve({ tokens: data.tokens, status: data.status }); - }; - - const setTokens = (tokens) => { - storage[`oidc.${configurationName}`] = JSON.stringify({ tokens }); - }; - - const setSessionStateAsync = async (sessionState) => { - storage[`oidc.session_state.${configurationName}`] = sessionState; - }; - - const getSessionStateAsync = async () => { - return storage[`oidc.session_state.${configurationName}`]; - }; - - const setNonceAsync = (nonce) => { - localStorage[`oidc.nonce.${configurationName}`] = nonce.nonce; - }; - - const getNonceAsync = async () => { - // @ts-ignore - return { nonce: localStorage[`oidc.nonce.${configurationName}`] }; - }; - - const getTokens = () => { - if (!storage[`oidc.${configurationName}`]) { - return null; - } - return JSON.stringify({ tokens: JSON.parse(storage[`oidc.${configurationName}`]).tokens }); - }; - - let getLoginParamsCache = null; - const setLoginParams = (configurationName:string, data) => { - getLoginParamsCache = data; - storage[`oidc.login.${configurationName}`] = JSON.stringify(data); - }; - const getLoginParams = (configurationName) => { - const dataString = storage[`oidc.login.${configurationName}`]; - if (!getLoginParamsCache) { - getLoginParamsCache = JSON.parse(dataString); - } - return getLoginParamsCache; - }; - - const getStateAsync = async () => { - return storage[`oidc.state.${configurationName}`]; - }; - - const setStateAsync = async (state:string) => { - storage[`oidc.state.${configurationName}`] = state; - }; - - const getCodeVerifierAsync = async () => { - return storage[`oidc.code_verifier.${configurationName}`]; - }; - - const setCodeVerifierAsync = async (codeVerifier) => { - storage[`oidc.code_verifier.${configurationName}`] = codeVerifier; - }; - - return { - clearAsync, - initAsync, - setTokens, - getTokens, - setSessionStateAsync, - getSessionStateAsync, - setNonceAsync, - getNonceAsync, - setLoginParams, - getLoginParams, - getStateAsync, - setStateAsync, - getCodeVerifierAsync, - setCodeVerifierAsync, - }; + const clearAsync = status => { + storage[`oidc.${configurationName}`] = JSON.stringify({ tokens: null, status }); + delete storage[`oidc.${configurationName}.userInfo`]; + return Promise.resolve(); + }; + + const initAsync = async () => { + if (!storage[`oidc.${configurationName}`]) { + storage[`oidc.${configurationName}`] = JSON.stringify({ tokens: null, status: null }); + return { tokens: null, status: null }; + } + const data = JSON.parse(storage[`oidc.${configurationName}`]); + return Promise.resolve({ tokens: data.tokens, status: data.status }); + }; + + const setTokens = tokens => { + storage[`oidc.${configurationName}`] = JSON.stringify({ tokens }); + }; + + const setSessionStateAsync = async sessionState => { + storage[`oidc.session_state.${configurationName}`] = sessionState; + }; + + const getSessionStateAsync = async () => { + return storage[`oidc.session_state.${configurationName}`]; + }; + + const setNonceAsync = nonce => { + storage[`oidc.nonce.${configurationName}`] = nonce.nonce; + }; + + const setDemonstratingProofOfPossessionJwkAsync = (jwk: JsonWebKey) => { + storage[`oidc.jwk.${configurationName}`] = JSON.stringify(jwk); + }; + + const getDemonstratingProofOfPossessionJwkAsync = () => { + return JSON.parse(storage[`oidc.jwk.${configurationName}`]); + }; + + const getNonceAsync = async () => { + // @ts-ignore + return { nonce: storage[`oidc.nonce.${configurationName}`] }; + }; + + const setDemonstratingProofOfPossessionNonce = async (dpopNonce: string) => { + storage[`oidc.dpop_nonce.${configurationName}`] = dpopNonce; + }; + + const getDemonstratingProofOfPossessionNonce = (): string => { + return storage[`oidc.dpop_nonce.${configurationName}`]; + }; + + const getTokens = () => { + if (!storage[`oidc.${configurationName}`]) { + return null; + } + return JSON.stringify({ tokens: JSON.parse(storage[`oidc.${configurationName}`]).tokens }); + }; + + const getLoginParamsCache = {}; + const setLoginParams = data => { + getLoginParamsCache[configurationName] = data; + storage[`oidc.login.${configurationName}`] = JSON.stringify(data); + }; + const getLoginParams = () => { + const dataString = storage[`oidc.login.${configurationName}`]; + + if (!dataString) { + console.warn( + `storage[oidc.login.${configurationName}] is empty, you should have an bad OIDC or code configuration somewhere.`, + ); + return null; + } + + if (!getLoginParamsCache[configurationName]) { + getLoginParamsCache[configurationName] = JSON.parse(dataString); + } + return getLoginParamsCache[configurationName]; + }; + + const getStateAsync = async () => { + return storage[`oidc.state.${configurationName}`]; + }; + + const setStateAsync = async (state: string) => { + storage[`oidc.state.${configurationName}`] = state; + }; + + const getCodeVerifierAsync = async () => { + return storage[`oidc.code_verifier.${configurationName}`]; + }; + + const setCodeVerifierAsync = async codeVerifier => { + storage[`oidc.code_verifier.${configurationName}`] = codeVerifier; + }; + + return { + clearAsync, + initAsync, + setTokens, + getTokens, + setSessionStateAsync, + getSessionStateAsync, + setNonceAsync, + getNonceAsync, + setLoginParams, + getLoginParams, + getStateAsync, + setStateAsync, + getCodeVerifierAsync, + setCodeVerifierAsync, + setDemonstratingProofOfPossessionNonce, + getDemonstratingProofOfPossessionNonce, + setDemonstratingProofOfPossessionJwkAsync, + getDemonstratingProofOfPossessionJwkAsync, + }; }; diff --git a/packages/oidc-client/src/initWorker.ts b/packages/oidc-client/src/initWorker.ts index e38f718c8..2bb44694b 100644 --- a/packages/oidc-client/src/initWorker.ts +++ b/packages/oidc-client/src/initWorker.ts @@ -1,321 +1,362 @@ +import { ILOidcLocation } from './location'; import { parseOriginalTokens } from './parseTokens.js'; import timer from './timer.js'; import { OidcConfiguration } from './types.js'; +import codeVersion from './version.js'; -export const getOperatingSystem = (navigator) => { - const nVer = navigator.appVersion; - const nAgt = navigator.userAgent; - const unknown = '-'; - // system - let os = unknown; - const clientStrings = [ - { s: 'Windows 10', r: /(Windows 10.0|Windows NT 10.0)/ }, - { s: 'Windows 8.1', r: /(Windows 8.1|Windows NT 6.3)/ }, - { s: 'Windows 8', r: /(Windows 8|Windows NT 6.2)/ }, - { s: 'Windows 7', r: /(Windows 7|Windows NT 6.1)/ }, - { s: 'Windows Vista', r: /Windows NT 6.0/ }, - { s: 'Windows Server 2003', r: /Windows NT 5.2/ }, - { s: 'Windows XP', r: /(Windows NT 5.1|Windows XP)/ }, - { s: 'Windows 2000', r: /(Windows NT 5.0|Windows 2000)/ }, - { s: 'Windows ME', r: /(Win 9x 4.90|Windows ME)/ }, - { s: 'Windows 98', r: /(Windows 98|Win98)/ }, - { s: 'Windows 95', r: /(Windows 95|Win95|Windows_95)/ }, - { s: 'Windows NT 4.0', r: /(Windows NT 4.0|WinNT4.0|WinNT|Windows NT)/ }, - { s: 'Windows CE', r: /Windows CE/ }, - { s: 'Windows 3.11', r: /Win16/ }, - { s: 'Android', r: /Android/ }, - { s: 'Open BSD', r: /OpenBSD/ }, - { s: 'Sun OS', r: /SunOS/ }, - { s: 'Chrome OS', r: /CrOS/ }, - { s: 'Linux', r: /(Linux|X11(?!.*CrOS))/ }, - { s: 'iOS', r: /(iPhone|iPad|iPod)/ }, - { s: 'Mac OS X', r: /Mac OS X/ }, - { s: 'Mac OS', r: /(Mac OS|MacPPC|MacIntel|Mac_PowerPC|Macintosh)/ }, - { s: 'QNX', r: /QNX/ }, - { s: 'UNIX', r: /UNIX/ }, - { s: 'BeOS', r: /BeOS/ }, - { s: 'OS/2', r: /OS\/2/ }, - { s: 'Search Bot', r: /(nuhk|Googlebot|Yammybot|Openbot|Slurp|MSNBot|Ask Jeeves\/Teoma|ia_archiver)/ }, - ]; - for (const id in clientStrings) { - const cs = clientStrings[id]; - if (cs.r.test(nAgt)) { - os = cs.s; - break; - } - } - - let osVersion = unknown; +let keepAliveServiceWorkerTimeoutId = null; +let keepAliveController; +export const sleepAsync = ({ milliseconds }: { milliseconds: any }) => { + return new Promise(resolve => timer.setTimeout(resolve, milliseconds)); +}; - if (/Windows/.test(os)) { - osVersion = /Windows (.*)/.exec(os)[1]; - os = 'Windows'; - } +const keepAlive = (service_worker_keep_alive_path = '/') => { + try { + const minSleepSeconds = 150; + keepAliveController = new AbortController(); + const promise = fetch( + `${service_worker_keep_alive_path}OidcKeepAliveServiceWorker.json?minSleepSeconds=${minSleepSeconds}`, + { signal: keepAliveController.signal }, + ); + promise.catch(error => { + console.log(error); + }); + sleepAsync({ milliseconds: minSleepSeconds * 1000 }).then(keepAlive); + } catch (error) { + console.log(error); + } +}; - switch (os) { - case 'Mac OS': - case 'Mac OS X': - case 'Android': - osVersion = /(?:Android|Mac OS|Mac OS X|MacPPC|MacIntel|Mac_PowerPC|Macintosh) ([._\d]+)/.exec(nAgt)[1]; - break; - - case 'iOS': { - const osVersionArray = /OS (\d+)_(\d+)_?(\d+)?/.exec(nVer); - osVersion = osVersionArray[1] + '.' + osVersionArray[2] + '.' + (parseInt(osVersionArray[3]) | 0); - break; - } - } - return { - os, - osVersion, - }; +const stopKeepAlive = () => { + if (keepAliveController) { + keepAliveController.abort(); + } }; -function getBrowser() { - const ua = navigator.userAgent; let tem; - let M = ua.match(/(opera|chrome|safari|firefox|msie|trident(?=\/))\/?\s*(\d+)/i) || []; - if (/trident/i.test(M[1])) { - tem = /\brv[ :]+(\d+)/g.exec(ua) || []; - return { name: 'ie', version: (tem[1] || '') }; - } - if (M[1] === 'Chrome') { - tem = ua.match(/\bOPR|Edge\/(\d+)/); - - if (tem != null) { - let version = tem[1]; - if (!version) { - const splits = ua.split(tem[0] + '/'); - if (splits.length > 1) { - version = splits[1]; - } - } - - return { name: 'opera', version }; - } - } - M = M[2] ? [M[1], M[2]] : [navigator.appName, navigator.appVersion, '-?']; - if ((tem = ua.match(/version\/(\d+)/i)) != null) { M.splice(1, 1, tem[1]); } - return { - name: M[0].toLowerCase(), - version: M[1], - }; -} +export const defaultServiceWorkerUpdateRequireCallback = + (location: ILOidcLocation) => async (registration: any, stopKeepAlive: () => void) => { + stopKeepAlive(); + await registration.update(); + const isSuccess = await registration.unregister(); + console.log(`Service worker unregistration ${isSuccess ? 'successful' : 'failed'}`); + await sleepAsync({ milliseconds: 2000 }); + location.reload(); + }; -let keepAliveServiceWorkerTimeoutId = null; +export const getTabId = (configurationName: string) => { + const tabId = sessionStorage.getItem(`oidc.tabId.${configurationName}`); -export const sleepAsync = (milliseconds) => { - return new Promise(resolve => timer.setTimeout(resolve, milliseconds)); -}; + if (tabId) { + return tabId; + } -const keepAlive = () => { - try { - const operatingSystem = getOperatingSystem(navigator); - const minSleepSeconds = operatingSystem.os === 'Android' ? 240 : 150; - const promise = fetch(`/OidcKeepAliveServiceWorker.json?minSleepSeconds=${minSleepSeconds}`); - promise.catch(error => { console.log(error); }); - sleepAsync(minSleepSeconds * 1000).then(keepAlive); - } catch (error) { console.log(error); } + const newTabId = globalThis.crypto.randomUUID(); + sessionStorage.setItem(`oidc.tabId.${configurationName}`, newTabId); + return newTabId; }; -const isServiceWorkerProxyActiveAsync = () => { - return fetch('/OidcKeepAliveServiceWorker.json', { - headers: { - 'oidc-vanilla': 'true', - }, - }).then((response) => { - return response.statusText === 'oidc-service-worker'; - }).catch(error => { console.log(error); }); -}; +const sendMessageAsync = + registration => + (data): Promise => { + return new Promise(function (resolve, reject) { + const messageChannel = new MessageChannel(); + messageChannel.port1.onmessage = function (event) { + if (event?.data.error) { + reject(event.data.error); + } else { + resolve(event.data); + } -export const excludeOs = (operatingSystem) => { - if (operatingSystem.os === 'iOS' && operatingSystem.osVersion.startsWith('12')) { - return true; - } - if (operatingSystem.os === 'Mac OS X' && operatingSystem.osVersion.startsWith('10_15_6')) { - return true; - } - return false; -}; + messageChannel.port1.close(); + messageChannel.port2.close(); + }; + registration.active.postMessage({ ...data, tabId: getTabId(data.configurationName) }, [ + messageChannel.port2, + ]); + }); + }; + +export const initWorkerAsync = async ( + configuration: OidcConfiguration, + configurationName: string, +) => { + const serviceWorkerRelativeUrl = configuration.service_worker_relative_url; + if ( + typeof window === 'undefined' || + typeof navigator === 'undefined' || + !navigator.serviceWorker || + !serviceWorkerRelativeUrl + ) { + return null; + } + + if (configuration.service_worker_activate() === false) { + return null; + } -const sendMessageAsync = (registration) => (data) => { - return new Promise(function(resolve, reject) { - const messageChannel = new MessageChannel(); - messageChannel.port1.onmessage = function (event) { - if (event.data && event.data.error) { - reject(event.data.error); - } else { - resolve(event.data); - } - }; - registration.active.postMessage(data, [messageChannel.port2]); + const swUrl = `${serviceWorkerRelativeUrl}?v=${codeVersion}`; + let registration: ServiceWorkerRegistration = null; + if (configuration.service_worker_register) { + registration = await configuration.service_worker_register(serviceWorkerRelativeUrl); + } else { + registration = await navigator.serviceWorker.register(swUrl, { + updateViaCache: 'none', }); -}; + } -export const initWorkerAsync = async(serviceWorkerRelativeUrl, configurationName) => { - if (typeof window === 'undefined' || typeof navigator === 'undefined' || !navigator.serviceWorker || !serviceWorkerRelativeUrl) { - return null; - } - const { name, version } = getBrowser(); - if (name === 'chrome' && parseInt(version) < 90) { - return null; - } - if (name === 'opera') { - if (!version) { - return null; - } - if (parseInt(version.split('.')[0]) < 80) { - return null; - } - } - if (name === 'ie') { - return null; - } + // 1) Détection updatefound + registration.addEventListener('updatefound', () => { + const newSW = registration.installing; + stopKeepAlive(); + newSW?.addEventListener('statechange', () => { + if (newSW.state === 'installed' && navigator.serviceWorker.controller) { + stopKeepAlive(); + console.log('New SW waiting – skipWaiting()'); + newSW.postMessage({ type: 'SKIP_WAITING' }); + } + }); + }); - const operatingSystem = getOperatingSystem(navigator); - if (excludeOs(operatingSystem)) { - return null; + // 2) Quand le SW actif change, on reload + navigator.serviceWorker.addEventListener('controllerchange', () => { + console.log('SW controller changed – reloading page'); + stopKeepAlive(); + window.location.reload(); + }); + + // 3) Claim + init classique + try { + await navigator.serviceWorker.ready; + if (!navigator.serviceWorker.controller) { + await sendMessageAsync(registration)({ type: 'claim' }); } + } catch (err) { + console.warn(`Failed init ServiceWorker ${err.toString()}`); + return null; + } - const registration = await navigator.serviceWorker.register(serviceWorkerRelativeUrl); + const clearAsync = async status => { + return sendMessageAsync(registration)({ type: 'clear', data: { status }, configurationName }); + }; + const initAsync = async ( + oidcServerConfiguration, + where, + oidcConfiguration: OidcConfiguration, + ) => { + const result = await sendMessageAsync(registration)({ + type: 'init', + data: { + oidcServerConfiguration, + where, + oidcConfiguration: { + token_renew_mode: oidcConfiguration.token_renew_mode, + service_worker_convert_all_requests_to_cors: + oidcConfiguration.service_worker_convert_all_requests_to_cors, + }, + }, + configurationName, + }); - try { - await navigator.serviceWorker.ready; - } catch (err) { - return null; + // @ts-ignore + const serviceWorkerVersion = result.version; + if (serviceWorkerVersion !== codeVersion) { + console.warn( + `Service worker ${serviceWorkerVersion} version mismatch with js client version ${codeVersion}, unregistering and reloading`, + ); } - const unregisterAsync = async () => { - return await registration.unregister(); + // @ts-ignore + return { + tokens: parseOriginalTokens(result.tokens, null, oidcConfiguration.token_renew_mode), + status: result.status, }; + }; - registration.addEventListener('updatefound', () => { - const newWorker = registration.installing; - newWorker.addEventListener('statechange', () => { - switch (newWorker.state) { - case 'installed': - if (navigator.serviceWorker.controller) { - registration.unregister().then(() => { - window.location.reload(); - }); - } - break; - } - }); + const startKeepAliveServiceWorker = (service_worker_keep_alive_path = '/') => { + if (keepAliveServiceWorkerTimeoutId == null) { + keepAliveServiceWorkerTimeoutId = 'not_null'; + keepAlive(service_worker_keep_alive_path); + } + }; + + const setSessionStateAsync = (sessionState: string) => { + return sendMessageAsync(registration)({ + type: 'setSessionState', + data: { sessionState }, + configurationName, }); + }; - const clearAsync = async (status) => { - return sendMessageAsync(registration)({ type: 'clear', data: { status }, configurationName }); - }; - const initAsync = async (oidcServerConfiguration, where, oidcConfiguration:OidcConfiguration) => { - const result = await sendMessageAsync(registration)({ - type: 'init', - data: { - oidcServerConfiguration, - where, - oidcConfiguration: { - token_renew_mode: oidcConfiguration.token_renew_mode, - service_worker_convert_all_requests_to_cors: oidcConfiguration.service_worker_convert_all_requests_to_cors, - }, - }, - configurationName, - }); + const getSessionStateAsync = async () => { + const result = await sendMessageAsync(registration)({ + type: 'getSessionState', + data: null, + configurationName, + }); + // @ts-ignore + return result.sessionState; + }; + + const setNonceAsync = nonce => { + sessionStorage[`oidc.nonce.${configurationName}`] = nonce.nonce; + return sendMessageAsync(registration)({ + type: 'setNonce', + data: { nonce }, + configurationName, + }); + }; + const getNonceAsync = async (fallback: boolean = true) => { + // @ts-ignore + const result = await sendMessageAsync(registration)({ + type: 'getNonce', + data: null, + configurationName, + }); + // @ts-ignore + let nonce = result.nonce; + if (!nonce) { + nonce = sessionStorage[`oidc.nonce.${configurationName}`]; + console.warn('nonce not found in service worker, using sessionStorage'); + if (fallback) { + await setNonceAsync(nonce); + const data = await getNonceAsync(false); // @ts-ignore - return { tokens: parseOriginalTokens(result.tokens, null, oidcConfiguration.token_renew_mode), status: result.status }; - }; + nonce = data.nonce; + } + } + return { nonce }; + }; - const startKeepAliveServiceWorker = () => { - if (keepAliveServiceWorkerTimeoutId == null) { - keepAliveServiceWorkerTimeoutId = 'not_null'; - keepAlive(); - } - }; + const getLoginParamsCache = {}; + const setLoginParams = data => { + getLoginParamsCache[configurationName] = data; + localStorage[`oidc.login.${configurationName}`] = JSON.stringify(data); + }; - const setSessionStateAsync = (sessionState:string) => { - return sendMessageAsync(registration)({ type: 'setSessionState', data: { sessionState }, configurationName }); - }; + const getLoginParams = () => { + const dataString = localStorage[`oidc.login.${configurationName}`]; + if (!getLoginParamsCache[configurationName]) { + getLoginParamsCache[configurationName] = JSON.parse(dataString); + } + return getLoginParamsCache[configurationName]; + }; - const getSessionStateAsync = async () => { - const result = await sendMessageAsync(registration)({ type: 'getSessionState', data: null, configurationName }); - // @ts-ignore - return result.sessionState; - }; + const setDemonstratingProofOfPossessionNonce = async ( + demonstratingProofOfPossessionNonce: string, + ) => { + await sendMessageAsync(registration)({ + type: 'setDemonstratingProofOfPossessionNonce', + data: { demonstratingProofOfPossessionNonce }, + configurationName, + }); + }; - const setNonceAsync = (nonce) => { - sessionStorage['oidc.nonce'] = nonce.nonce; - return sendMessageAsync(registration)({ type: 'setNonce', data: { nonce }, configurationName }); - }; - const getNonceAsync = async () => { - // @ts-ignore - const result = await sendMessageAsync(registration)({ type: 'getNonce', data: null, configurationName }); - // @ts-ignore - let nonce = result.nonce; - if (!nonce) { - nonce = sessionStorage['oidc.nonce']; - console.warn('nonce not found in service worker, using sessionStorage'); - } - return { nonce }; - }; + const getDemonstratingProofOfPossessionNonce = async () => { + const result = await sendMessageAsync(registration)({ + type: 'getDemonstratingProofOfPossessionNonce', + data: null, + configurationName, + }); + return result.demonstratingProofOfPossessionNonce; + }; - let getLoginParamsCache = null; - const setLoginParams = (configurationName:string, data) => { - getLoginParamsCache = data; - localStorage[`oidc.login.${configurationName}`] = JSON.stringify(data); - }; - const getLoginParams = (configurationName) => { - const dataString = localStorage[`oidc.login.${configurationName}`]; - if (!getLoginParamsCache) { - getLoginParamsCache = JSON.parse(dataString); - } - return getLoginParamsCache; - }; + const setDemonstratingProofOfPossessionJwkAsync = async ( + demonstratingProofOfPossessionJwk: JsonWebKey, + ) => { + const demonstratingProofOfPossessionJwkJson = JSON.stringify(demonstratingProofOfPossessionJwk); + await sendMessageAsync(registration)({ + type: 'setDemonstratingProofOfPossessionJwk', + data: { demonstratingProofOfPossessionJwkJson }, + configurationName, + }); + }; - const getStateAsync = async () => { - const result = await sendMessageAsync(registration)({ type: 'getState', data: null, configurationName }); - // @ts-ignore - let state = result.state; - if (!state) { - state = sessionStorage[`oidc.state.${configurationName}`]; - console.warn('state not found in service worker, using sessionStorage'); - } - return state; - }; + const getDemonstratingProofOfPossessionJwkAsync = async () => { + const result = await sendMessageAsync(registration)({ + type: 'getDemonstratingProofOfPossessionJwk', + data: null, + configurationName, + }); + if (!result.demonstratingProofOfPossessionJwkJson) { + return null; + } + return JSON.parse(result.demonstratingProofOfPossessionJwkJson); + }; - const setStateAsync = async (state:string) => { - sessionStorage[`oidc.state.${configurationName}`] = state; - return sendMessageAsync(registration)({ type: 'setState', data: { state }, configurationName }); - }; + const getStateAsync = async (fallback: boolean = true) => { + const result = await sendMessageAsync(registration)({ + type: 'getState', + data: null, + configurationName, + }); + // @ts-ignore + let state = result.state; + if (!state) { + state = sessionStorage[`oidc.state.${configurationName}`]; + console.warn('state not found in service worker, using sessionStorage'); + if (fallback) { + await setStateAsync(state); + state = await getStateAsync(false); + } + } + return state; + }; - const getCodeVerifierAsync = async () => { - const result = await sendMessageAsync(registration)({ type: 'getCodeVerifier', data: null, configurationName }); - // @ts-ignore - let codeVerifier = result.codeVerifier; - if (!codeVerifier) { - codeVerifier = sessionStorage[`oidc.code_verifier.${configurationName}`]; - console.warn('codeVerifier not found in service worker, using sessionStorage'); - } - return codeVerifier; - }; + const setStateAsync = async (state: string) => { + sessionStorage[`oidc.state.${configurationName}`] = state; + return sendMessageAsync(registration)({ + type: 'setState', + data: { state }, + configurationName, + }); + }; - const setCodeVerifierAsync = async (codeVerifier:string) => { - sessionStorage[`oidc.code_verifier.${configurationName}`] = codeVerifier; - return sendMessageAsync(registration)({ type: 'setCodeVerifier', data: { codeVerifier }, configurationName }); - }; + const getCodeVerifierAsync = async (fallback: boolean = true) => { + const result = await sendMessageAsync(registration)({ + type: 'getCodeVerifier', + data: null, + configurationName, + }); + // @ts-ignore + let codeVerifier = result.codeVerifier; + if (!codeVerifier) { + codeVerifier = sessionStorage[`oidc.code_verifier.${configurationName}`]; + console.warn('codeVerifier not found in service worker, using sessionStorage'); + if (fallback) { + await setCodeVerifierAsync(codeVerifier); + codeVerifier = await getCodeVerifierAsync(false); + } + } + return codeVerifier; + }; - return { - clearAsync, - initAsync, - startKeepAliveServiceWorker, - isServiceWorkerProxyActiveAsync, - setSessionStateAsync, - getSessionStateAsync, - setNonceAsync, - getNonceAsync, - unregisterAsync, - setLoginParams, - getLoginParams, - getStateAsync, - setStateAsync, - getCodeVerifierAsync, - setCodeVerifierAsync, - }; + const setCodeVerifierAsync = async (codeVerifier: string) => { + sessionStorage[`oidc.code_verifier.${configurationName}`] = codeVerifier; + return sendMessageAsync(registration)({ + type: 'setCodeVerifier', + data: { codeVerifier }, + configurationName, + }); + }; + + return { + clearAsync, + initAsync, + startKeepAliveServiceWorker: () => + startKeepAliveServiceWorker(configuration.service_worker_keep_alive_path), + setSessionStateAsync, + getSessionStateAsync, + setNonceAsync, + getNonceAsync, + setLoginParams, + getLoginParams, + getStateAsync, + setStateAsync, + getCodeVerifierAsync, + setCodeVerifierAsync, + setDemonstratingProofOfPossessionNonce, + getDemonstratingProofOfPossessionNonce, + setDemonstratingProofOfPossessionJwkAsync, + getDemonstratingProofOfPossessionJwkAsync, + }; }; diff --git a/packages/oidc-client/src/initWorkerOption.ts b/packages/oidc-client/src/initWorkerOption.ts new file mode 100644 index 000000000..3a9bfd37c --- /dev/null +++ b/packages/oidc-client/src/initWorkerOption.ts @@ -0,0 +1,140 @@ +import { ServiceWorkerActivate } from './types'; + +export const excludeOs = operatingSystem => { + if (operatingSystem.os === 'iOS' && operatingSystem.osVersion.startsWith('12')) { + return true; + } + if (operatingSystem.os === 'Mac OS X' && operatingSystem.osVersion.startsWith('10_15_6')) { + return true; + } + return false; +}; +export const getOperatingSystem = navigator => { + const nVer = navigator.appVersion; + const nAgt = navigator.userAgent; + const unknown = '-'; + // system + let os = unknown; + const clientStrings = [ + { s: 'Windows 10', r: /(Windows 10.0|Windows NT 10.0)/ }, + { s: 'Windows 8.1', r: /(Windows 8.1|Windows NT 6.3)/ }, + { s: 'Windows 8', r: /(Windows 8|Windows NT 6.2)/ }, + { s: 'Windows 7', r: /(Windows 7|Windows NT 6.1)/ }, + { s: 'Windows Vista', r: /Windows NT 6.0/ }, + { s: 'Windows Server 2003', r: /Windows NT 5.2/ }, + { s: 'Windows XP', r: /(Windows NT 5.1|Windows XP)/ }, + { s: 'Windows 2000', r: /(Windows NT 5.0|Windows 2000)/ }, + { s: 'Windows ME', r: /(Win 9x 4.90|Windows ME)/ }, + { s: 'Windows 98', r: /(Windows 98|Win98)/ }, + { s: 'Windows 95', r: /(Windows 95|Win95|Windows_95)/ }, + { s: 'Windows NT 4.0', r: /(Windows NT 4.0|WinNT4.0|WinNT|Windows NT)/ }, + { s: 'Windows CE', r: /Windows CE/ }, + { s: 'Windows 3.11', r: /Win16/ }, + { s: 'Android', r: /Android/ }, + { s: 'Open BSD', r: /OpenBSD/ }, + { s: 'Sun OS', r: /SunOS/ }, + { s: 'Chrome OS', r: /CrOS/ }, + { s: 'Linux', r: /(Linux|X11(?!.*CrOS))/ }, + { s: 'iOS', r: /(iPhone|iPad|iPod)/ }, + { s: 'Mac OS X', r: /Mac OS X/ }, + { s: 'Mac OS', r: /(Mac OS|MacPPC|MacIntel|Mac_PowerPC|Macintosh)/ }, + { s: 'QNX', r: /QNX/ }, + { s: 'UNIX', r: /UNIX/ }, + { s: 'BeOS', r: /BeOS/ }, + { s: 'OS/2', r: /OS\/2/ }, + { + s: 'Search Bot', + r: /(nuhk|Googlebot|Yammybot|Openbot|Slurp|MSNBot|Ask Jeeves\/Teoma|ia_archiver)/, + }, + ]; + for (const id in clientStrings) { + const cs = clientStrings[id]; + if (cs.r.test(nAgt)) { + os = cs.s; + break; + } + } + + let osVersion = unknown; + + if (/Windows/.test(os)) { + osVersion = /Windows (.*)/.exec(os)[1]; + os = 'Windows'; + } + + switch (os) { + case 'Mac OS': + case 'Mac OS X': + case 'Android': + osVersion = + /(?:Android|Mac OS|Mac OS X|MacPPC|MacIntel|Mac_PowerPC|Macintosh) ([._\d]+)/.exec(nAgt)[1]; + break; + + case 'iOS': { + const osVersionArray = /OS (\d+)_(\d+)_?(\d+)?/.exec(nVer); + if (osVersionArray != null && osVersionArray.length > 2) { + osVersion = + osVersionArray[1] + '.' + osVersionArray[2] + '.' + (parseInt(osVersionArray[3]) | 0); + } + break; + } + } + return { + os, + osVersion, + }; +}; + +function getBrowser() { + const ua = navigator.userAgent; + let tem; + let M = ua.match(/(opera|chrome|safari|firefox|msie|trident(?=\/))\/?\s*(\d+)/i) || []; + if (/trident/i.test(M[1])) { + tem = /\brv[ :]+(\d+)/g.exec(ua) || []; + return { name: 'ie', version: tem[1] || '' }; + } + if (M[1] === 'Chrome') { + tem = ua.match(/\bOPR|Edge\/(\d+)/); + + if (tem != null) { + let version = tem[1]; + if (!version) { + const splits = ua.split(tem[0] + '/'); + if (splits.length > 1) { + version = splits[1]; + } + } + + return { name: 'opera', version }; + } + } + M = M[2] ? [M[1], M[2]] : [navigator.appName, navigator.appVersion, '-?']; + if ((tem = ua.match(/version\/(\d+)/i)) != null) { + M.splice(1, 1, tem[1]); + } + return { + name: M[0].toLowerCase(), + version: M[1], + }; +} + +export const activateServiceWorker: ServiceWorkerActivate = (): boolean => { + const { name, version } = getBrowser(); + if (name === 'chrome' && parseInt(version) <= 70) { + return false; + } + if (name === 'opera') { + if (!version) { + return false; + } + if (parseInt(version.split('.')[0]) < 80) { + return false; + } + } + if (name === 'ie') { + return false; + } + + const operatingSystem = getOperatingSystem(navigator); + return !excludeOs(operatingSystem); +}; diff --git a/packages/oidc-client/src/jwt.ts b/packages/oidc-client/src/jwt.ts new file mode 100644 index 000000000..11c233989 --- /dev/null +++ b/packages/oidc-client/src/jwt.ts @@ -0,0 +1,278 @@ +// code base on https://coolaj86.com/articles/sign-jwt-webcrypto-vanilla-js/ + +// String (UCS-2) to Uint8Array +// +// because... JavaScript, Strings, and Buffers +// @ts-ignore +import { DemonstratingProofOfPossessionConfiguration } from './types'; + +function strToUint8(str) { + return new TextEncoder().encode(str); +} + +// Binary String to URL-Safe Base64 +// +// btoa (Binary-to-Ascii) means "binary string" to base64 +// @ts-ignore +function binToUrlBase64(bin) { + return btoa(bin).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+/g, ''); +} + +// UTF-8 to Binary String +// +// Because JavaScript has a strange relationship with strings +// https://coolaj86.com/articles/base64-unicode-utf-8-javascript-and-you/ +// @ts-ignore +function utf8ToBinaryString(str) { + const escstr = encodeURIComponent(str); + // replaces any uri escape sequence, such as %0A, + // with binary escape, such as 0x0A + return escstr.replace(/%([0-9A-F]{2})/g, function (match, p1) { + return String.fromCharCode(parseInt(p1, 16)); + }); +} + +// Uint8Array to URL Safe Base64 +// +// the shortest distant between two encodings... binary string +// @ts-ignore +export const uint8ToUrlBase64 = (uint8: Uint8Array) => { + let bin = ''; + // @ts-ignore + uint8.forEach(function (code) { + bin += String.fromCharCode(code); + }); + return binToUrlBase64(bin); +}; + +// UCS-2 String to URL-Safe Base64 +// +// btoa doesn't work on UTF-8 strings +// @ts-ignore +function strToUrlBase64(str) { + return binToUrlBase64(utf8ToBinaryString(str)); +} + +export const defaultDemonstratingProofOfPossessionConfiguration: DemonstratingProofOfPossessionConfiguration = + { + importKeyAlgorithm: { + name: 'ECDSA', + namedCurve: 'P-256', + hash: { name: 'ES256' }, + }, + signAlgorithm: { name: 'ECDSA', hash: { name: 'SHA-256' } }, + generateKeyAlgorithm: { + name: 'ECDSA', + namedCurve: 'P-256', + }, + digestAlgorithm: { name: 'SHA-256' }, + jwtHeaderAlgorithm: 'ES256', + }; + +// @ts-ignore +const sign = + (w: any) => + async ( + jwk, + headers, + claims, + demonstratingProofOfPossessionConfiguration: DemonstratingProofOfPossessionConfiguration, + jwtHeaderType = 'dpop+jwt', + ) => { + // Make a shallow copy of the key + // (to set ext if it wasn't already set) + jwk = Object.assign({}, jwk); + + // The headers should probably be empty + headers.typ = jwtHeaderType; + headers.alg = demonstratingProofOfPossessionConfiguration.jwtHeaderAlgorithm; + switch (headers.alg) { + case 'ES256': //if (!headers.kid) { + // alternate: see thumbprint function below + headers.jwk = { kty: jwk.kty, crv: jwk.crv, x: jwk.x, y: jwk.y }; + //} + break; + case 'RS256': + headers.jwk = { kty: jwk.kty, n: jwk.n, e: jwk.e, kid: headers.kid }; + break; + default: + throw new Error('Unknown or not implemented JWS algorithm'); + } + + const jws = { + // @ts-ignore + // JWT "headers" really means JWS "protected headers" + protected: strToUrlBase64(JSON.stringify(headers)), + // @ts-ignore + // JWT "claims" are really a JSON-defined JWS "payload" + payload: strToUrlBase64(JSON.stringify(claims)), + }; + + // To import as EC (ECDSA, P-256, SHA-256, ES256) + const keyType = demonstratingProofOfPossessionConfiguration.importKeyAlgorithm; + + // To make re-exportable as JSON (or DER/PEM) + const exportable = true; + + // Import as a private key that isn't black-listed from signing + const privileges = ['sign']; + + // Actually do the import, which comes out as an abstract key type + // @ts-ignore + const privateKey = await w.crypto.subtle.importKey('jwk', jwk, keyType, exportable, privileges); + // Convert UTF-8 to Uint8Array ArrayBuffer + // @ts-ignore + const data = strToUint8(`${jws.protected}.${jws.payload}`); + + // The signature and hash should match the bit-entropy of the key + // https://tools.ietf.org/html/rfc7518#section-3 + const signatureType = demonstratingProofOfPossessionConfiguration.signAlgorithm; + + const signature = await w.crypto.subtle.sign(signatureType, privateKey, data); + // returns an ArrayBuffer containing a JOSE (not X509) signature, + // which must be converted to Uint8 to be useful + // @ts-ignore + jws.signature = uint8ToUrlBase64(new Uint8Array(signature)); + // JWT is just a "compressed", "protected" JWS + // @ts-ignore + return `${jws.protected}.${jws.payload}.${jws.signature}`; + }; + +export const JWT = { sign }; + +// @ts-ignore +const generate = + (w: any) => async (generateKeyAlgorithm: RsaHashedKeyGenParams | EcKeyGenParams) => { + const keyType = generateKeyAlgorithm; + const exportable = true; + const privileges = ['sign', 'verify']; + // @ts-ignore + const key = await w.crypto.subtle.generateKey(keyType, exportable, privileges); + // returns an abstract and opaque WebCrypto object, + // which in most cases you'll want to export as JSON to be able to save + return await w.crypto.subtle.exportKey('jwk', key.privateKey); + }; + +// Create a Public Key from a Private Key +// +// chops off the private parts +// @ts-ignore +const neuter = jwk => { + const copy = Object.assign({}, jwk); + delete copy.d; + copy.key_ops = ['verify']; + return copy; +}; + +const EC = { + generate, + neuter, +}; +// @ts-ignore +const thumbprint = (w: any) => async (jwk, digestAlgorithm: AlgorithmIdentifier) => { + let sortedPub; + // lexigraphically sorted, no spaces + switch (jwk.kty) { + case 'EC': + sortedPub = '{"crv":"CRV","kty":"EC","x":"X","y":"Y"}' + .replace('CRV', jwk.crv) + .replace('X', jwk.x) + .replace('Y', jwk.y); + break; + case 'RSA': + sortedPub = '{"e":"E","kty":"RSA","n":"N"}'.replace('E', jwk.e).replace('N', jwk.n); + break; + default: + throw new Error('Unknown or not implemented JWK type'); + } + // The hash should match the size of the key, + // but we're only dealing with P-256 + const hash = await w.crypto.subtle.digest(digestAlgorithm, strToUint8(sortedPub)); + return uint8ToUrlBase64(new Uint8Array(hash)); +}; + +export const JWK = { thumbprint }; + +export const generateJwkAsync = + (w: any) => async (generateKeyAlgorithm: RsaHashedKeyGenParams | EcKeyGenParams) => { + // @ts-ignore + const jwk = await EC.generate(w)(generateKeyAlgorithm); + // console.info('Private Key:', JSON.stringify(jwk)); + // @ts-ignore + // console.info('Public Key:', JSON.stringify(EC.neuter(jwk))); + return jwk; + }; + +export const generateJwtDemonstratingProofOfPossessionAsync = + (w: any) => + (demonstratingProofOfPossessionConfiguration: DemonstratingProofOfPossessionConfiguration) => + async (jwk, method = 'POST', url: string, extrasClaims = {}) => { + const claims = { + // https://www.rfc-editor.org/rfc/rfc9449.html#name-concept + jti: btoa(guid()), + htm: method, + htu: url, + iat: Math.round(Date.now() / 1000), + ...extrasClaims, + }; + // @ts-ignore + const kid = await JWK.thumbprint(w)( + jwk, + demonstratingProofOfPossessionConfiguration.digestAlgorithm, + ); + // @ts-ignore + const jwt = await JWT.sign(w)( + jwk, + { kid: kid }, + claims, + demonstratingProofOfPossessionConfiguration, + ); + // console.info('JWT:', jwt); + return jwt; + }; + +const guid = () => { + // RFC4122: The version 4 UUID is meant for generating UUIDs from truly-random or + // pseudo-random numbers. + // The algorithm is as follows: + // Set the two most significant bits (bits 6 and 7) of the + // clock_seq_hi_and_reserved to zero and one, respectively. + // Set the four most significant bits (bits 12 through 15) of the + // time_hi_and_version field to the 4-bit version number from + // Section 4.1.3. Version4 + // Set all the other bits to randomly (or pseudo-randomly) chosen + // values. + // UUID = time-low "-" time-mid "-"time-high-and-version "-"clock-seq-reserved and low(2hexOctet)"-" node + // time-low = 4hexOctet + // time-mid = 2hexOctet + // time-high-and-version = 2hexOctet + // clock-seq-and-reserved = hexOctet: + // clock-seq-low = hexOctet + // node = 6hexOctet + // Format: xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx + // y could be 1000, 1001, 1010, 1011 since most significant two bits needs to be 10 + // y values are 8, 9, A, B + const guidHolder = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'; + const hex = '0123456789abcdef'; + let r = 0; + let guidResponse = ''; + for (let i = 0; i < 36; i++) { + if (guidHolder[i] !== '-' && guidHolder[i] !== '4') { + // each x and y needs to be random + r = (Math.random() * 16) | 0; + } + + if (guidHolder[i] === 'x') { + guidResponse += hex[r]; + } else if (guidHolder[i] === 'y') { + // clock-seq-and-reserved first hex is filtered and remaining hex values are random + r &= 0x3; // bit and with 0011 to set pos 2 to zero ?0?? + r |= 0x8; // set pos 3 to 1 as 1??? + guidResponse += hex[r]; + } else { + guidResponse += guidHolder[i]; + } + } + + return guidResponse; +}; diff --git a/packages/oidc-client/src/keepSession.ts b/packages/oidc-client/src/keepSession.ts new file mode 100644 index 000000000..a3133fdfb --- /dev/null +++ b/packages/oidc-client/src/keepSession.ts @@ -0,0 +1,113 @@ +import { eventNames } from './events'; +import { initSession } from './initSession'; +import { initWorkerAsync } from './initWorker'; +import Oidc from './oidc'; +import { setTokens } from './parseTokens'; +import { autoRenewTokens } from './renewTokens'; + +export const tryKeepSessionAsync = async (oidc: Oidc) => { + let serviceWorker; + if (oidc.tokens != null) { + return false; + } + oidc.publishEvent(eventNames.tryKeepExistingSessionAsync_begin, {}); + try { + const configuration = oidc.configuration; + const oidcServerConfiguration = await oidc.initAsync( + configuration.authority, + configuration.authority_configuration, + ); + serviceWorker = await initWorkerAsync(configuration, oidc.configurationName); + if (serviceWorker) { + const { tokens } = await serviceWorker.initAsync( + oidcServerConfiguration, + 'tryKeepExistingSessionAsync', + configuration, + ); + if (tokens) { + serviceWorker.startKeepAliveServiceWorker(); + // @ts-ignore + oidc.tokens = tokens; + const getLoginParams = serviceWorker.getLoginParams(oidc.configurationName); + // @ts-ignore + oidc.timeoutId = autoRenewTokens( + oidc, + oidc.tokens.expiresAt, + getLoginParams.extras, + getLoginParams.scope, + ); + const sessionState = await serviceWorker.getSessionStateAsync(); + // @ts-ignore + await oidc.startCheckSessionAsync( + oidcServerConfiguration.checkSessionIframe, + configuration.client_id, + sessionState, + ); + if (configuration.preload_user_info) { + await oidc.userInfoAsync(); + } + oidc.publishEvent(eventNames.tryKeepExistingSessionAsync_end, { + success: true, + message: 'tokens inside ServiceWorker are valid', + }); + return true; + } + oidc.publishEvent(eventNames.tryKeepExistingSessionAsync_end, { + success: false, + message: 'no exiting session found', + }); + } else { + if (configuration.service_worker_relative_url) { + oidc.publishEvent(eventNames.service_worker_not_supported_by_browser, { + message: 'service worker is not supported by this browser', + }); + } + const session = initSession(oidc.configurationName, configuration.storage ?? sessionStorage); + const { tokens } = await session.initAsync(); + if (tokens) { + // @ts-ignore + oidc.tokens = setTokens(tokens, null, configuration.token_renew_mode); + const getLoginParams = session.getLoginParams(); + // @ts-ignore + oidc.timeoutId = autoRenewTokens( + oidc, + oidc.tokens.expiresAt, + getLoginParams.extras, + getLoginParams.scope, + ); + const sessionState = await session.getSessionStateAsync(); + // @ts-ignore + await oidc.startCheckSessionAsync( + oidcServerConfiguration.checkSessionIframe, + configuration.client_id, + sessionState, + ); + if (configuration.preload_user_info) { + await oidc.userInfoAsync(); + } + oidc.publishEvent(eventNames.tryKeepExistingSessionAsync_end, { + success: true, + message: 'tokens inside storage are valid', + }); + return true; + } + } + oidc.publishEvent(eventNames.tryKeepExistingSessionAsync_end, { + success: false, + message: serviceWorker + ? 'service worker sessions not retrieved' + : 'session storage sessions not retrieved', + }); + return false; + } catch (exception) { + console.error(exception); + if (serviceWorker) { + await serviceWorker.clearAsync(); + } + oidc.publishEvent( + eventNames.tryKeepExistingSessionAsync_error, + 'tokens inside ServiceWorker are invalid', + ); + return false; + } +}; diff --git a/packages/oidc-client/src/location.ts b/packages/oidc-client/src/location.ts new file mode 100644 index 000000000..b3cd5808a --- /dev/null +++ b/packages/oidc-client/src/location.ts @@ -0,0 +1,30 @@ +export interface ILOidcLocation { + open(url: string): void; + reload(): void; + getCurrentHref(): string; + getPath(): string; + getOrigin(): string; +} + +export class OidcLocation implements ILOidcLocation { + open(url: string) { + window.location.href = url; + } + + reload() { + window.location.reload(); + } + + getCurrentHref() { + return window.location.href; + } + + getPath() { + const location = window.location; + return location.pathname + (location.search || '') + (location.hash || ''); + } + + getOrigin(): string { + return window.origin; + } +} diff --git a/packages/oidc-client/src/login.ts b/packages/oidc-client/src/login.ts index f738b1791..d4bec6852 100644 --- a/packages/oidc-client/src/login.ts +++ b/packages/oidc-client/src/login.ts @@ -2,173 +2,279 @@ import { generateRandom } from './crypto.js'; import { eventNames } from './events.js'; import { initSession } from './initSession.js'; import { initWorkerAsync } from './initWorker.js'; +import { generateJwkAsync, generateJwtDemonstratingProofOfPossessionAsync } from './jwt'; +import { ILOidcLocation } from './location'; +import Oidc from './oidc'; import { isTokensOidcValid } from './parseTokens.js'; import { performAuthorizationRequestAsync, performFirstTokenRequestAsync } from './requests.js'; import { getParseQueryStringFromLocation } from './route-utils.js'; import { OidcConfiguration, StringMap } from './types.js'; -// eslint-disable-next-line @typescript-eslint/ban-types -export const defaultLoginAsync = (window, configurationName, configuration:OidcConfiguration, publishEvent :(string, any)=>void, initAsync:Function) => (callbackPath:string = undefined, extras:StringMap = null, isSilentSignin = false, scope:string = undefined) => { +export type InitAsyncFunction = (authority: string, authorityConfiguration: any) => Promise; + +export const defaultLoginAsync = + ( + configurationName: string, + configuration: OidcConfiguration, + publishEvent: (string, any) => void, + initAsync: InitAsyncFunction, + oidcLocation: ILOidcLocation, + ) => + ( + callbackPath: string = undefined, + extras: StringMap = null, + isSilentSignin = false, + scope: string = undefined, + ): Promise => { const originExtras = extras; extras = { ...extras }; const loginLocalAsync = async () => { - const location = window.location; - const url = callbackPath || location.pathname + (location.search || '') + (location.hash || ''); + const url = callbackPath || oidcLocation.getPath(); - if (!('state' in extras)) { - extras.state = generateRandom(16); - } + if (!('state' in extras)) { + extras.state = generateRandom(16); + } - publishEvent(eventNames.loginAsync_begin, {}); - if (extras) { - for (const key of Object.keys(extras)) { - if (key.endsWith(':token_request')) { - delete extras[key]; - } - } + publishEvent(eventNames.loginAsync_begin, {}); + if (extras) { + for (const key of Object.keys(extras)) { + if (key.endsWith(':token_request')) { + delete extras[key]; + } } - try { - const redirectUri = isSilentSignin ? configuration.silent_redirect_uri : configuration.redirect_uri; - if (!scope) { - scope = configuration.scope; - } - - const extraFinal = !configuration.extras ? extras : { ...configuration.extras, ...extras }; - if (!extraFinal.nonce) { - extraFinal.nonce = generateRandom(12); - } - const nonce = { nonce: extraFinal.nonce }; - const serviceWorker = await initWorkerAsync(configuration.service_worker_relative_url, configurationName); - const oidcServerConfiguration = await initAsync(configuration.authority, configuration.authority_configuration); - let storage; - if (serviceWorker) { - serviceWorker.setLoginParams(configurationName, { callbackPath: url, extras: originExtras }); - serviceWorker.startKeepAliveServiceWorker(); - await serviceWorker.initAsync(oidcServerConfiguration, 'loginAsync', configuration); - await serviceWorker.setNonceAsync(nonce); - storage = serviceWorker; - } else { - const session = initSession(configurationName, configuration.storage ?? sessionStorage); - session.setLoginParams(configurationName, { callbackPath: url, extras: originExtras }); - await session.setNonceAsync(nonce); - storage = session; - } - - // @ts-ignore - const extraInternal = { - client_id: configuration.client_id, - redirect_uri: redirectUri, - scope, - response_type: 'code', - ...extraFinal, - }; - await performAuthorizationRequestAsync(storage)(oidcServerConfiguration.authorizationEndpoint, extraInternal); - } catch (exception) { - publishEvent(eventNames.loginAsync_error, exception); - throw exception; + } + try { + const redirectUri = isSilentSignin + ? configuration.silent_redirect_uri + : configuration.redirect_uri; + if (!scope) { + scope = configuration.scope; } - }; - return loginLocalAsync(); -}; -export const loginCallbackAsync = (oidc) => async (isSilentSignin = false) => { - try { - oidc.publishEvent(eventNames.loginCallbackAsync_begin, {}); - const configuration = oidc.configuration; - const clientId = configuration.client_id; - const redirectUri = isSilentSignin ? configuration.silent_redirect_uri : configuration.redirect_uri; - const authority = configuration.authority; - const tokenRequestTimeout = configuration.token_request_timeout; - const oidcServerConfiguration = await oidc.initAsync(authority, configuration.authority_configuration); - const queryParams = getParseQueryStringFromLocation(window.location.href); - const sessionState = queryParams.session_state; - const serviceWorker = await initWorkerAsync(configuration.service_worker_relative_url, oidc.configurationName); + const extraFinal = !configuration.extras ? extras : { ...configuration.extras, ...extras }; + if (!extraFinal.nonce) { + extraFinal.nonce = generateRandom(12); + } + const nonce = { nonce: extraFinal.nonce }; + const serviceWorker = await initWorkerAsync(configuration, configurationName); + const oidcServerConfiguration = await initAsync( + configuration.authority, + configuration.authority_configuration, + ); let storage; - let nonceData; - let getLoginParams; - let state; if (serviceWorker) { - serviceWorker.startKeepAliveServiceWorker(); - await serviceWorker.initAsync(oidcServerConfiguration, 'loginCallbackAsync', configuration); - await serviceWorker.setSessionStateAsync(sessionState); - nonceData = await serviceWorker.getNonceAsync(); - getLoginParams = serviceWorker.getLoginParams(oidc.configurationName); - state = await serviceWorker.getStateAsync(); - storage = serviceWorker; + serviceWorker.setLoginParams({ callbackPath: url, extras: originExtras, scope: scope }); + await serviceWorker.initAsync(oidcServerConfiguration, 'loginAsync', configuration); + await serviceWorker.setNonceAsync(nonce); + serviceWorker.startKeepAliveServiceWorker(); + storage = serviceWorker; } else { - const session = initSession(oidc.configurationName, configuration.storage ?? sessionStorage); - await session.setSessionStateAsync(sessionState); - nonceData = await session.getNonceAsync(); - getLoginParams = session.getLoginParams(oidc.configurationName); - state = await session.getStateAsync(); - storage = session; + const session = initSession(configurationName, configuration.storage ?? sessionStorage); + session.setLoginParams({ callbackPath: url, extras: originExtras, scope: scope }); + await session.setNonceAsync(nonce); + storage = session; } - const params = getParseQueryStringFromLocation(window.location.toString()); + // @ts-ignore + const extraInternal = { + client_id: configuration.client_id, + redirect_uri: redirectUri, + scope, + response_type: 'code', + ...extraFinal, + }; + await performAuthorizationRequestAsync(storage, oidcLocation)( + oidcServerConfiguration.authorizationEndpoint, + extraInternal, + ); + } catch (exception) { + publishEvent(eventNames.loginAsync_error, exception); + throw exception; + } + }; + return loginLocalAsync(); + }; - if (params.iss && params.iss !== oidcServerConfiguration.issuer) { - throw new Error('issuer not valid'); - } - if (params.state && params.state !== state) { - throw new Error('state not valid'); - } +export const loginCallbackAsync = + (oidc: Oidc) => + async (isSilentSignin = false) => { + try { + oidc.publishEvent(eventNames.loginCallbackAsync_begin, {}); + const configuration = oidc.configuration; + const clientId = configuration.client_id; + const redirectUri = isSilentSignin + ? configuration.silent_redirect_uri + : configuration.redirect_uri; + const authority = configuration.authority; + const tokenRequestTimeout = configuration.token_request_timeout; + const oidcServerConfiguration = await oidc.initAsync( + authority, + configuration.authority_configuration, + ); + const href = oidc.location.getCurrentHref(); + const queryParams = getParseQueryStringFromLocation(href); + const sessionState = queryParams.session_state; + const serviceWorker = await initWorkerAsync(configuration, oidc.configurationName); + let storage; + let nonceData; + let getLoginParams; + let state; + if (serviceWorker) { + await serviceWorker.initAsync(oidcServerConfiguration, 'loginCallbackAsync', configuration); + await serviceWorker.setSessionStateAsync(sessionState); + nonceData = await serviceWorker.getNonceAsync(); + getLoginParams = serviceWorker.getLoginParams(); + state = await serviceWorker.getStateAsync(); + serviceWorker.startKeepAliveServiceWorker(); + storage = serviceWorker; + } else { + const session = initSession( + oidc.configurationName, + configuration.storage ?? sessionStorage, + ); + await session.setSessionStateAsync(sessionState); + nonceData = await session.getNonceAsync(); + getLoginParams = session.getLoginParams(); + state = await session.getStateAsync(); + storage = session; + } - const data = { - code: params.code, - grant_type: 'authorization_code', - client_id: configuration.client_id, - redirect_uri: redirectUri, - }; + if (queryParams.error || queryParams.error_description) { + throw new Error( + `Error from OIDC server: ${queryParams.error} - ${queryParams.error_description}`, + ); + } - const extras = {}; - // @ts-ignore - if (configuration.token_request_extras) { - for (const [key, value] of Object.entries(configuration.token_request_extras)) { - extras[key] = value; - } - } - if (getLoginParams && getLoginParams.extras) { - for (const [key, value] of Object.entries(getLoginParams.extras)) { - if (key.endsWith(':token_request')) { - extras[key.replace(':token_request', '')] = value; - } - } - } + if (queryParams.iss && queryParams.iss !== oidcServerConfiguration.issuer) { + console.error(); + throw new Error( + `Issuer not valid (expected: ${oidcServerConfiguration.issuer}, received: ${queryParams.iss})`, + ); + } + if (queryParams.state && queryParams.state !== state) { + throw new Error(`State not valid (expected: ${state}, received: ${queryParams.state})`); + } - const tokenResponse = await performFirstTokenRequestAsync(storage)(oidcServerConfiguration.tokenEndpoint, { ...data, ...extras }, oidc.configuration.token_renew_mode, tokenRequestTimeout); + const data = { + code: queryParams.code, + grant_type: 'authorization_code', + client_id: configuration.client_id, + redirect_uri: redirectUri, + }; - if (!tokenResponse.success) { - throw new Error('Token request failed'); + const extras = {}; + // @ts-ignore + if (configuration.token_request_extras) { + for (const [key, value] of Object.entries(configuration.token_request_extras)) { + extras[key] = value; } + } + if (getLoginParams?.extras) { + for (const [key, value] of Object.entries(getLoginParams.extras)) { + if (key.endsWith(':token_request')) { + extras[key.replace(':token_request', '')] = value; + } + } + } - let loginParams; - const formattedTokens = tokenResponse.data.tokens; + const url = oidcServerConfiguration.tokenEndpoint; + const headersExtras = {}; + if (configuration.demonstrating_proof_of_possession) { if (serviceWorker) { - await serviceWorker.initAsync(redirectUri, 'syncTokensAsync', configuration); - loginParams = serviceWorker.getLoginParams(oidc.configurationName); + headersExtras['DPoP'] = `DPOP_SECURED_BY_OIDC_SERVICE_WORKER_${oidc.configurationName}`; } else { - const session = initSession(oidc.configurationName, configuration.storage); - loginParams = session.getLoginParams(oidc.configurationName); + const jwk = await generateJwkAsync(window)( + configuration.demonstrating_proof_of_possession_configuration.generateKeyAlgorithm, + ); + const session = initSession(oidc.configurationName, configuration.storage); + await session.setDemonstratingProofOfPossessionJwkAsync(jwk); + headersExtras['DPoP'] = await generateJwtDemonstratingProofOfPossessionAsync(window)( + configuration.demonstrating_proof_of_possession_configuration, + )(jwk, 'POST', url); } - // @ts-ignore - if (tokenResponse.data.state !== extras.state) { - throw new Error('state is not valid'); + } + + const tokenResponse = await performFirstTokenRequestAsync(storage)( + url, + { ...data, ...extras }, + headersExtras, + oidc.configuration.token_renew_mode, + tokenRequestTimeout, + ); + + if (!tokenResponse.success) { + throw new Error('Token request failed'); + } + + let loginParams; + const formattedTokens = tokenResponse.data.tokens; + const demonstratingProofOfPossessionNonce = + tokenResponse.data.demonstratingProofOfPossessionNonce; + + // @ts-ignore + if (tokenResponse.data.state !== extras.state) { + throw new Error('state is not valid'); + } + const { isValid, reason } = isTokensOidcValid( + formattedTokens, + nonceData.nonce, + oidcServerConfiguration, + ); + if (!isValid) { + throw new Error(`Tokens are not OpenID valid, reason: ${reason}`); + } + + if (serviceWorker) { + if ( + formattedTokens.refreshToken && + !formattedTokens.refreshToken.includes('SECURED_BY_OIDC_SERVICE_WORKER') + ) { + throw new Error('Refresh token should be hidden by service worker'); } - const { isValid, reason } = isTokensOidcValid(formattedTokens, nonceData.nonce, oidcServerConfiguration); - if (!isValid) { - throw new Error(`Tokens are not OpenID valid, reason: ${reason}`); + + if ( + demonstratingProofOfPossessionNonce && + formattedTokens?.accessToken.includes('SECURED_BY_OIDC_SERVICE_WORKER') + ) { + throw new Error( + 'Demonstration of proof of possession require Access token not hidden by service worker', + ); } + } - await oidc.startCheckSessionAsync(oidcServerConfiguration.checkSessionIframe, clientId, sessionState, isSilentSignin); - oidc.publishEvent(eventNames.loginCallbackAsync_end, {}); - return { - tokens: formattedTokens, - state: 'request.state', - callbackPath: loginParams.callbackPath, - }; + if (serviceWorker) { + await serviceWorker.initAsync(oidcServerConfiguration, 'syncTokensAsync', configuration); + loginParams = serviceWorker.getLoginParams(); + if (demonstratingProofOfPossessionNonce) { + await serviceWorker.setDemonstratingProofOfPossessionNonce( + demonstratingProofOfPossessionNonce, + ); + } + } else { + const session = initSession(oidc.configurationName, configuration.storage); + loginParams = session.getLoginParams(); + if (demonstratingProofOfPossessionNonce) { + await session.setDemonstratingProofOfPossessionNonce(demonstratingProofOfPossessionNonce); + } + } + + await oidc.startCheckSessionAsync( + oidcServerConfiguration.checkSessionIframe, + clientId, + sessionState, + isSilentSignin, + ); + oidc.publishEvent(eventNames.loginCallbackAsync_end, {}); + return { + tokens: formattedTokens, + state: 'request.state', + callbackPath: loginParams.callbackPath, + scope: queryParams.scope, + extras: loginParams.extras, + }; } catch (exception) { - console.error(exception); - oidc.publishEvent(eventNames.loginCallbackAsync_error, exception); - throw exception; + console.error(exception); + oidc.publishEvent(eventNames.loginCallbackAsync_error, exception); + throw exception; } -}; + }; diff --git a/packages/oidc-client/src/logout.spec.ts b/packages/oidc-client/src/logout.spec.ts index 82035047c..65469f0fc 100644 --- a/packages/oidc-client/src/logout.spec.ts +++ b/packages/oidc-client/src/logout.spec.ts @@ -1,63 +1,141 @@ -import '@testing-library/jest-dom' -import { logoutAsync } from "./logout"; -import { describe, it, expect, vi } from 'vitest'; +// import '@testing-library/jest-dom'; + +import { describe, expect, it, vi } from 'vitest'; + +import { ILOidcLocation } from './location'; +import { logoutAsync } from './logout'; describe('Logout test suite', () => { + const expectedFinalUrl = + 'http://api/connect/endsession?id_token_hint=abcd&post_logout_redirect_uri=http%3A%2F%2Flocalhost%3A4200%2Flogged_out'; + it.each([ + { + logout_tokens_to_invalidate: ['access_token', 'refresh_token'], + extras: null, + expectedResults: [ + 'token=abcd&token_type_hint=access_token&client_id=interactive.public.short', + 'token=abdc&token_type_hint=refresh_token&client_id=interactive.public.short', + ], + expectedFinalUrl, + }, + { + logout_tokens_to_invalidate: ['refresh_token'], + extras: null, + expectedResults: [ + 'token=abdc&token_type_hint=refresh_token&client_id=interactive.public.short', + ], + expectedFinalUrl, + }, + { + logout_tokens_to_invalidate: ['access_token'], + extras: null, + expectedResults: [ + 'token=abcd&token_type_hint=access_token&client_id=interactive.public.short', + ], + expectedFinalUrl, + }, + { logout_tokens_to_invalidate: [], extras: null, expectedResults: [], expectedFinalUrl }, + { + logout_tokens_to_invalidate: [], + extras: { id_token_hint: undefined }, + expectedResults: [], + expectedFinalUrl: + 'http://api/connect/endsession?post_logout_redirect_uri=http%3A%2F%2Flocalhost%3A4200%2Flogged_out', + }, + { + logout_tokens_to_invalidate: [], + extras: { 'no_reload:oidc': 'true' }, + expectedResults: [], + expectedFinalUrl: '', + }, + { + logout_tokens_to_invalidate: ['refresh_token'], + extras: { 'client_secret:revoke_refresh_token': 'secret' }, + expectedResults: [ + 'token=abdc&token_type_hint=refresh_token&client_id=interactive.public.short&client_secret=secret', + ], + expectedFinalUrl, + }, + { + logout_tokens_to_invalidate: ['access_token'], + extras: { 'client_secret:revoke_access_token': 'secret' }, + expectedResults: [ + 'token=abcd&token_type_hint=access_token&client_id=interactive.public.short&client_secret=secret', + ], + expectedFinalUrl, + }, + ])( + 'Logout should revoke tokens $logout_tokens_to_invalidate', + async ({ logout_tokens_to_invalidate, extras = null, expectedResults, expectedFinalUrl }) => { + const configuration = { + client_id: 'interactive.public.short', + redirect_uri: 'http://localhost:4200/authentication/callback', + scope: 'openid profile email api offline_access', + authority: 'http://api', + refresh_time_before_tokens_expiration_in_second: 70, + logout_tokens_to_invalidate, + }; + + const fetch = (url, data) => { + if (url === 'http://api/connect/revocation') { + return Promise.resolve({ status: 200 }); + } + return Promise.resolve({ + status: 200, + }); + }; + + const mockFetchFn = vi.fn().mockImplementation(fetch); + + const oidc = { + configuration, + tokens: { idToken: 'abcd', accessToken: 'abcd', refreshToken: 'abdc' }, + initAsync: () => + Promise.resolve({ + revocationEndpoint: 'http://api/connect/revocation', + endSessionEndpoint: 'http://api/connect/endsession', + }), + destroyAsync: () => Promise.resolve(), + logoutSameTabAsync: () => Promise.resolve(), + }; + + const oidcDatabase = { default: () => oidc }; + + let finalUrl = ''; + class OidcLocationMock implements ILOidcLocation { + open(url: string): void { + finalUrl = url; + } + + getCurrentHref(): string { + return ''; + } + + getPath(): string { + return ''; + } + + reload(): void {} - it.each([ - {logout_tokens_to_invalidate:['access_token', 'refresh_token'], expectedResults: ["token=abcd&token_type_hint=access_token&client_id=interactive.public.short","token=abdc&token_type_hint=refresh_token&client_id=interactive.public.short"]}, - {logout_tokens_to_invalidate:['refresh_token'], expectedResults: ["token=abdc&token_type_hint=refresh_token&client_id=interactive.public.short"]}, - {logout_tokens_to_invalidate:['access_token'], expectedResults: ["token=abcd&token_type_hint=access_token&client_id=interactive.public.short"]}, - {logout_tokens_to_invalidate:[], expectedResults: []}, - ])('Logout should revoke tokens $logout_tokens_to_invalidate', async ({ logout_tokens_to_invalidate, expectedResults}) => { - - const configuration = { - client_id: 'interactive.public.short', - redirect_uri: 'http://localhost:4200/authentication/callback', - scope: 'openid profile email api offline_access', - authority: 'http://api', - refresh_time_before_tokens_expiration_in_second: 70, - logout_tokens_to_invalidate - }; - - const fetch = (url, data) => { - if(url === "http://api/connect/revocation") { - return Promise.resolve({status: 200}); - } - return Promise.resolve({ - status : 200, - }); - }; - - const mockFetchFn = vi.fn().mockImplementation(fetch) - - const oidc = { - configuration, - tokens : {idToken: "abcd", accessToken: "abcd", refreshToken: "abdc" }, - initAsync: () => Promise.resolve({ - revocationEndpoint: "http://api/connect/revocation", - endSessionEndpoint: "http://api/connect/endsession", - }), - destroyAsync: () => Promise.resolve(), - logoutSameTabAsync: () => Promise.resolve(), - }; - - const oidcDatabase = {default: () => oidc}; - - const window = { - location: { - href: "", - origin: "http://localhost:4200" - } + getOrigin(): string { + return 'http://localhost:4200'; } + } + + await logoutAsync( + oidc, + oidcDatabase, + mockFetchFn, + console, + new OidcLocationMock(), + )('/logged_out', extras); + + // @ts-ignore - await logoutAsync(oidc, oidcDatabase, mockFetchFn, window, console)("/logged_out"); - - // @ts-ignore + const results = mockFetchFn.mock.calls.map((call, index) => call[1].body); - const results = mockFetchFn.mock.calls.map((call, index) => call[1].body) - - expect(results).toEqual(expectedResults); - expect(window.location.href).toBe("http://api/connect/endsession?id_token_hint=abcd&post_logout_redirect_uri=http%3A%2F%2Flocalhost%3A4200%2Flogged_out"); - }); + expect(results).toEqual(expectedResults); + expect(finalUrl).toBe(expectedFinalUrl); + }, + ); }); diff --git a/packages/oidc-client/src/logout.ts b/packages/oidc-client/src/logout.ts index 76296ecfb..6c3007197 100644 --- a/packages/oidc-client/src/logout.ts +++ b/packages/oidc-client/src/logout.ts @@ -1,101 +1,168 @@ +import { eventNames } from './events'; import { initSession } from './initSession.js'; import { initWorkerAsync } from './initWorker.js'; +import { ILOidcLocation } from './location'; import { performRevocationRequestAsync, TOKEN_TYPE } from './requests.js'; import timer from './timer.js'; import { StringMap } from './types.js'; export const oidcLogoutTokens = { - access_token: 'access_token', - refresh_token: 'refresh_token', + access_token: 'access_token', + refresh_token: 'refresh_token', }; -export const destroyAsync = (oidc) => async (status) => { - timer.clearTimeout(oidc.timeoutId); - oidc.timeoutId = null; - if (oidc.checkSessionIFrame) { - oidc.checkSessionIFrame.stop(); +const extractExtras = (extras: StringMap, postKey: string): StringMap => { + const postExtras: StringMap = {}; + if (extras) { + for (const [key, value] of Object.entries(extras)) { + if (key.endsWith(postKey)) { + const newKey = key.replace(postKey, ''); + postExtras[newKey] = value; + } } - const serviceWorker = await initWorkerAsync(oidc.configuration.service_worker_relative_url, oidc.configurationName); - if (!serviceWorker) { - const session = initSession(oidc.configurationName, oidc.configuration.storage); - await session.clearAsync(status); - } else { - await serviceWorker.clearAsync(status); + return postExtras; + } + return postExtras; +}; + +const keepExtras = (extras: StringMap): StringMap => { + const postExtras: StringMap = {}; + if (extras) { + for (const [key, value] of Object.entries(extras)) { + if (!key.includes(':')) { + postExtras[key] = value; + } } - oidc.tokens = null; - oidc.userInfo = null; + return postExtras; + } + return postExtras; +}; + +export const destroyAsync = oidc => async status => { + timer.clearTimeout(oidc.timeoutId); + oidc.timeoutId = null; + if (oidc.checkSessionIFrame) { + oidc.checkSessionIFrame.stop(); + } + const serviceWorker = await initWorkerAsync(oidc.configuration, oidc.configurationName); + if (!serviceWorker) { + const session = initSession(oidc.configurationName, oidc.configuration.storage); + await session.clearAsync(status); + } else { + await serviceWorker.clearAsync(status); + } + oidc.tokens = null; + oidc.userInfo = null; }; -export const logoutAsync = (oidc, oidcDatabase, fetch, window, console) => async (callbackPathOrUrl: string | null | undefined = undefined, extras: StringMap = null) => { +export const logoutAsync = + (oidc, oidcDatabase, fetch, console, oicLocation: ILOidcLocation) => + async (callbackPathOrUrl: string | null | undefined = undefined, extras: StringMap = null) => { const configuration = oidc.configuration; - const oidcServerConfiguration = await oidc.initAsync(configuration.authority, configuration.authority_configuration); - if (callbackPathOrUrl && (typeof callbackPathOrUrl !== 'string')) { - callbackPathOrUrl = undefined; - console.warn('callbackPathOrUrl path is not a string'); + const oidcServerConfiguration = await oidc.initAsync( + configuration.authority, + configuration.authority_configuration, + ); + if (callbackPathOrUrl && typeof callbackPathOrUrl !== 'string') { + callbackPathOrUrl = undefined; + console.warn('callbackPathOrUrl path is not a string'); } - const path = (callbackPathOrUrl === null || callbackPathOrUrl === undefined) ? location.pathname + (location.search || '') + (location.hash || '') : callbackPathOrUrl; + const path = + callbackPathOrUrl === null || callbackPathOrUrl === undefined + ? oicLocation.getPath() + : callbackPathOrUrl; let isUri = false; if (callbackPathOrUrl) { - isUri = callbackPathOrUrl.includes('https://') || callbackPathOrUrl.includes('http://'); + isUri = callbackPathOrUrl.includes('https://') || callbackPathOrUrl.includes('http://'); } - const url = isUri ? callbackPathOrUrl : window.location.origin + path; + const url = isUri ? callbackPathOrUrl : oicLocation.getOrigin() + path; // @ts-ignore const idToken = oidc.tokens ? oidc.tokens.idToken : ''; try { - const revocationEndpoint = oidcServerConfiguration.revocationEndpoint; - if (revocationEndpoint) { - const promises = []; - const accessToken = oidc.tokens.accessToken; - if (accessToken && configuration.logout_tokens_to_invalidate.includes(oidcLogoutTokens.access_token)) { - const revokeAccessTokenPromise = performRevocationRequestAsync(fetch)(revocationEndpoint, accessToken, TOKEN_TYPE.access_token, configuration.client_id); - promises.push(revokeAccessTokenPromise); - } - const refreshToken = oidc.tokens.refreshToken; - if (refreshToken && configuration.logout_tokens_to_invalidate.includes(oidcLogoutTokens.refresh_token)) { - const revokeRefreshTokenPromise = performRevocationRequestAsync(fetch)(revocationEndpoint, refreshToken, TOKEN_TYPE.refresh_token, configuration.client_id); - promises.push(revokeRefreshTokenPromise); - } - if (promises.length > 0) { - await Promise.all(promises); - } + const revocationEndpoint = oidcServerConfiguration.revocationEndpoint; + if (revocationEndpoint) { + const promises = []; + const accessToken = oidc.tokens ? oidc.tokens.accessToken : null; + if ( + accessToken && + configuration.logout_tokens_to_invalidate.includes(oidcLogoutTokens.access_token) + ) { + const revokeAccessTokenExtras = extractExtras(extras, ':revoke_access_token'); + const revokeAccessTokenPromise = performRevocationRequestAsync(fetch)( + revocationEndpoint, + accessToken, + TOKEN_TYPE.access_token, + configuration.client_id, + revokeAccessTokenExtras, + ); + promises.push(revokeAccessTokenPromise); + } + const refreshToken = oidc.tokens ? oidc.tokens.refreshToken : null; + if ( + refreshToken && + configuration.logout_tokens_to_invalidate.includes(oidcLogoutTokens.refresh_token) + ) { + const revokeAccessTokenExtras = extractExtras(extras, ':revoke_refresh_token'); + const revokeRefreshTokenPromise = performRevocationRequestAsync(fetch)( + revocationEndpoint, + refreshToken, + TOKEN_TYPE.refresh_token, + configuration.client_id, + revokeAccessTokenExtras, + ); + promises.push(revokeRefreshTokenPromise); } + if (promises.length > 0) { + await Promise.all(promises); + } + } } catch (exception) { - console.warn('logoutAsync: error when revoking tokens, if the error persist, you ay configure property logout_tokens_to_invalidate from configuration to avoid this error'); - console.warn(exception); + console.warn( + 'logoutAsync: error when revoking tokens, if the error persist, you ay configure property logout_tokens_to_invalidate from configuration to avoid this error', + ); + console.warn(exception); } - // @ts-ignore - const sub = oidc.tokens && oidc.tokens.idTokenPayload ? oidc.tokens.idTokenPayload.sub : null; + const sub = oidc.tokens?.idTokenPayload?.sub ?? null; + await oidc.destroyAsync('LOGGED_OUT'); - // eslint-disable-next-line @typescript-eslint/no-unused-vars - for (const [key, itemOidc] of Object.entries(oidcDatabase)) { - if (itemOidc !== oidc) { - // @ts-ignore - await oidc.logoutSameTabAsync(oidc.configuration.client_id, sub); - } + for (const [, itemOidc] of Object.entries(oidcDatabase)) { + if (itemOidc !== oidc) { + // @ts-ignore + await oidc.logoutSameTabAsync(oidc.configuration.client_id, sub); + } else { + oidc.publishEvent(eventNames.logout_from_same_tab, {}); + } + } + + const oidcExtras = extractExtras(extras, ':oidc'); + const noReload = oidcExtras && oidcExtras['no_reload'] === 'true'; + + if (noReload) { + return; } + const endPointExtras = keepExtras(extras); + if (oidcServerConfiguration.endSessionEndpoint) { - if (!extras) { - extras = { - id_token_hint: idToken, - }; - if (callbackPathOrUrl !== null) { - extras.post_logout_redirect_uri = url; - } + if (!('id_token_hint' in endPointExtras)) { + endPointExtras['id_token_hint'] = idToken; + } + if (!('post_logout_redirect_uri' in endPointExtras) && callbackPathOrUrl !== null) { + endPointExtras['post_logout_redirect_uri'] = url; + } + let queryString = ''; + for (const [key, value] of Object.entries(endPointExtras)) { + if (value !== null && value !== undefined) { + if (queryString === '') { + queryString += '?'; + } else { + queryString += '&'; + } + queryString += `${key}=${encodeURIComponent(value)}`; } - let queryString = ''; - if (extras) { - for (const [key, value] of Object.entries(extras)) { - if (queryString === '') { - queryString += '?'; - } else { - queryString += '&'; - } - queryString += `${key}=${encodeURIComponent(value)}`; - } - } - window.location.href = `${oidcServerConfiguration.endSessionEndpoint}${queryString}`; + } + oicLocation.open(`${oidcServerConfiguration.endSessionEndpoint}${queryString}`); } else { - window.location.reload(); + oicLocation.reload(); } -}; + }; diff --git a/packages/oidc-client/src/oidc.ts b/packages/oidc-client/src/oidc.ts index 318cd51cf..f86e4a1e1 100644 --- a/packages/oidc-client/src/oidc.ts +++ b/packages/oidc-client/src/oidc.ts @@ -1,613 +1,498 @@ import { startCheckSessionAsync as defaultStartCheckSessionAsync } from './checkSession.js'; import { CheckSessionIFrame } from './checkSessionIFrame.js'; +import { base64urlOfHashOfASCIIEncodingAsync } from './crypto'; import { eventNames } from './events.js'; import { initSession } from './initSession.js'; -import { initWorkerAsync, sleepAsync } from './initWorker.js'; +import { getTabId, initWorkerAsync } from './initWorker.js'; +import { activateServiceWorker } from './initWorkerOption'; +import { + defaultDemonstratingProofOfPossessionConfiguration, + generateJwtDemonstratingProofOfPossessionAsync, +} from './jwt'; +import { tryKeepSessionAsync } from './keepSession'; +import { ILOidcLocation, OidcLocation } from './location'; import { defaultLoginAsync, loginCallbackAsync } from './login.js'; import { destroyAsync, logoutAsync } from './logout.js'; -import { - computeTimeLeft, - isTokensOidcValid, - setTokens, TokenRenewMode, - Tokens, -} from './parseTokens.js'; +import { TokenRenewMode, Tokens } from './parseTokens.js'; import { autoRenewTokens, renewTokensAndStartTimerAsync } from './renewTokens.js'; -import { fetchFromIssuer, performTokenRequestAsync } from './requests.js'; +import { fetchFromIssuer } from './requests.js'; import { getParseQueryStringFromLocation } from './route-utils.js'; -import defaultSilentLoginAsync, { _silentLoginAsync } from './silentLogin.js'; +import defaultSilentLoginAsync from './silentLogin.js'; import timer from './timer.js'; -import { AuthorityConfiguration, Fetch, OidcConfiguration, StringMap } from './types.js'; +import { + AuthorityConfiguration, + Fetch, + OidcConfiguration, + StringMap, + TokenAutomaticRenewMode, +} from './types.js'; import { userInfoAsync } from './user.js'; export const getFetchDefault = () => { - return fetch; + return fetch; }; export interface OidcAuthorizationServiceConfigurationJson { - check_session_iframe?: string; - issuer:string; + check_session_iframe?: string; + issuer: string; } export class OidcAuthorizationServiceConfiguration { - private checkSessionIframe: string; - private issuer: string; - private authorizationEndpoint: string; - private tokenEndpoint: string; - private revocationEndpoint: string; - private userInfoEndpoint: string; - private endSessionEndpoint: string; - - constructor(request: any) { - this.authorizationEndpoint = request.authorization_endpoint; - this.tokenEndpoint = request.token_endpoint; - this.revocationEndpoint = request.revocation_endpoint; - this.userInfoEndpoint = request.userinfo_endpoint; - this.checkSessionIframe = request.check_session_iframe; - this.issuer = request.issuer; - this.endSessionEndpoint = request.end_session_endpoint; - } + private checkSessionIframe: string; + private issuer: string; + private authorizationEndpoint: string; + private tokenEndpoint: string; + private revocationEndpoint: string; + private userInfoEndpoint: string; + private endSessionEndpoint: string; + + constructor(request: any) { + this.authorizationEndpoint = request.authorization_endpoint; + this.tokenEndpoint = request.token_endpoint; + this.revocationEndpoint = request.revocation_endpoint; + this.userInfoEndpoint = request.userinfo_endpoint; + this.checkSessionIframe = request.check_session_iframe; + this.issuer = request.issuer; + this.endSessionEndpoint = request.end_session_endpoint; + } } const oidcDatabase = {}; -const oidcFactory = (getFetch : () => Fetch) => (configuration: OidcConfiguration, name = 'default') => { +const oidcFactory = + (getFetch: () => Fetch, location: ILOidcLocation = new OidcLocation()) => + (configuration: OidcConfiguration, name = 'default') => { if (oidcDatabase[name]) { - return oidcDatabase[name]; + return oidcDatabase[name]; } - oidcDatabase[name] = new Oidc(configuration, name, getFetch); + oidcDatabase[name] = new Oidc(configuration, name, getFetch, location); return oidcDatabase[name]; -}; + }; export type LoginCallback = { - callbackPath:string; -} + callbackPath: string; +}; export type InternalLoginCallback = { - callbackPath:string; - parsedTokens:Tokens; -} + callbackPath: string; + state: string; + parsedTokens: Tokens; + scope: string; + extras: StringMap; +}; -const loginCallbackWithAutoTokensRenewAsync = async (oidc) : Promise => { - const { parsedTokens, callbackPath } = await oidc.loginCallbackAsync(); - oidc.timeoutId = autoRenewTokens(oidc, parsedTokens.refreshToken, parsedTokens.expiresAt); - return { callbackPath }; +const loginCallbackWithAutoTokensRenewAsync = async (oidc): Promise => { + const { parsedTokens, callbackPath, extras, scope } = await oidc.loginCallbackAsync(); + oidc.timeoutId = autoRenewTokens(oidc, parsedTokens.expiresAt, extras, scope); + return { callbackPath }; }; -const getRandomInt = (max) => { - return Math.floor(Math.random() * max); +const getRandomInt = max => { + return Math.floor(Math.random() * max); }; export class Oidc { - public configuration: OidcConfiguration; - public userInfo: null; - public tokens?: Tokens; - public events: Array; - private timeoutId: NodeJS.Timeout; - public configurationName: string; - private checkSessionIFrame: CheckSessionIFrame; - private getFetch: () => Fetch; - constructor(configuration:OidcConfiguration, configurationName = 'default', getFetch : () => Fetch) { - let silent_login_uri = configuration.silent_login_uri; - if (configuration.silent_redirect_uri && !configuration.silent_login_uri) { - silent_login_uri = `${configuration.silent_redirect_uri.replace('-callback', '').replace('callback', '')}-login`; - } - let refresh_time_before_tokens_expiration_in_second = configuration.refresh_time_before_tokens_expiration_in_second ?? 120; - if (refresh_time_before_tokens_expiration_in_second > 60) { - refresh_time_before_tokens_expiration_in_second = refresh_time_before_tokens_expiration_in_second - Math.floor(Math.random() * 40); - } - if (!configuration.logout_tokens_to_invalidate) { - configuration.logout_tokens_to_invalidate = ['access_token', 'refresh_token']; - } - if (!configuration.authority_timeout_wellknowurl_in_millisecond) { - configuration.authority_timeout_wellknowurl_in_millisecond = 10000; - } - this.configuration = { - ...configuration, - silent_login_uri, - monitor_session: configuration.monitor_session ?? false, - refresh_time_before_tokens_expiration_in_second, - silent_login_timeout: configuration.silent_login_timeout ?? 12000, - token_renew_mode: configuration.token_renew_mode ?? TokenRenewMode.access_token_or_id_token_invalid, - }; - this.getFetch = getFetch ?? getFetchDefault; - this.configurationName = configurationName; - this.tokens = null; - this.userInfo = null; - this.events = []; - this.timeoutId = null; - this.synchroniseTokensAsync.bind(this); - this.loginCallbackWithAutoTokensRenewAsync.bind(this); - this.initAsync.bind(this); - this.loginCallbackAsync.bind(this); - this.subscribeEvents.bind(this); - this.removeEventSubscription.bind(this); - this.publishEvent.bind(this); - this.destroyAsync.bind(this); - this.logoutAsync.bind(this); - this.renewTokensAsync.bind(this); - this.initAsync(this.configuration.authority, this.configuration.authority_configuration); + public configuration: OidcConfiguration; + public userInfo: null; + public tokens?: Tokens; + public events: Array; + public timeoutId: NodeJS.Timeout | number; + public configurationName: string; + public checkSessionIFrame: CheckSessionIFrame; + public getFetch: () => Fetch; + public location: ILOidcLocation; + constructor( + configuration: OidcConfiguration, + configurationName = 'default', + getFetch: () => Fetch, + location: ILOidcLocation = new OidcLocation(), + ) { + let silent_login_uri = configuration.silent_login_uri; + if (configuration.silent_redirect_uri && !configuration.silent_login_uri) { + silent_login_uri = `${configuration.silent_redirect_uri.replace('-callback', '').replace('callback', '')}-login`; } + let refresh_time_before_tokens_expiration_in_second = + configuration.refresh_time_before_tokens_expiration_in_second ?? 120; + if (refresh_time_before_tokens_expiration_in_second > 60) { + refresh_time_before_tokens_expiration_in_second = + refresh_time_before_tokens_expiration_in_second - Math.floor(Math.random() * 40); + } + this.location = location ?? new OidcLocation(); + + this.configuration = { + ...configuration, + silent_login_uri, + token_automatic_renew_mode: + configuration.token_automatic_renew_mode ?? + TokenAutomaticRenewMode.AutomaticBeforeTokenExpiration, + monitor_session: configuration.monitor_session ?? false, + refresh_time_before_tokens_expiration_in_second, + silent_login_timeout: configuration.silent_login_timeout ?? 12000, + token_renew_mode: + configuration.token_renew_mode ?? TokenRenewMode.access_token_or_id_token_invalid, + demonstrating_proof_of_possession: configuration.demonstrating_proof_of_possession ?? false, + authority_timeout_wellknowurl_in_millisecond: + configuration.authority_timeout_wellknowurl_in_millisecond ?? 10000, + logout_tokens_to_invalidate: configuration.logout_tokens_to_invalidate ?? [ + 'access_token', + 'refresh_token', + ], + service_worker_activate: configuration.service_worker_activate ?? activateServiceWorker, + demonstrating_proof_of_possession_configuration: + configuration.demonstrating_proof_of_possession_configuration ?? + defaultDemonstratingProofOfPossessionConfiguration, + preload_user_info: configuration.preload_user_info ?? false, + }; + + this.getFetch = getFetch ?? getFetchDefault; + this.configurationName = configurationName; + this.tokens = null; + this.userInfo = null; + this.events = []; + this.timeoutId = null; + this.loginCallbackWithAutoTokensRenewAsync.bind(this); + this.initAsync.bind(this); + this.loginCallbackAsync.bind(this); + this.subscribeEvents.bind(this); + this.removeEventSubscription.bind(this); + this.publishEvent.bind(this); + this.destroyAsync.bind(this); + this.logoutAsync.bind(this); + this.renewTokensAsync.bind(this); + this.initAsync(this.configuration.authority, this.configuration.authority_configuration); + } - subscribeEvents(func):string { - const id = getRandomInt(9999999999999).toString(); - this.events.push({ id, func }); - return id; + subscribeEvents(func): string { + const id = getRandomInt(9999999999999).toString(); + this.events.push({ id, func }); + return id; + } + + removeEventSubscription(id): void { + const newEvents = this.events.filter(e => e.id !== id); + this.events = newEvents; + } + + publishEvent(eventName, data) { + this.events.forEach(event => { + event.func(eventName, data); + }); + } + + static getOrCreate = + (getFetch: () => Fetch, location: ILOidcLocation) => + (configuration, name = 'default') => { + return oidcFactory(getFetch, location)(configuration, name); + }; + + static get(name = 'default') { + const isInsideBrowser = typeof process === 'undefined'; + if (!Object.prototype.hasOwnProperty.call(oidcDatabase, name) && isInsideBrowser) { + throw Error(`OIDC library does seem initialized. +Please checkout that you are using OIDC hook inside a component.`); + } + return oidcDatabase[name]; + } + + static eventNames = eventNames; + + _silentLoginCallbackFromIFrame() { + if (this.configuration.silent_redirect_uri && this.configuration.silent_login_uri) { + const location = this.location; + const queryParams = getParseQueryStringFromLocation(location.getCurrentHref()); + window.parent.postMessage( + `${this.configurationName}_oidc_tokens:${JSON.stringify({ tokens: this.tokens, sessionState: queryParams.session_state })}`, + location.getOrigin(), + ); } + } - removeEventSubscription(id) :void { - const newEvents = this.events.filter(e => e.id !== id); - this.events = newEvents; + _silentLoginErrorCallbackFromIFrame(exception = null) { + if (this.configuration.silent_redirect_uri && this.configuration.silent_login_uri) { + const location = this.location; + const queryParams = getParseQueryStringFromLocation(location.getCurrentHref()); + if (queryParams.error) { + window.parent.postMessage( + `${this.configurationName}_oidc_error:${JSON.stringify({ error: queryParams.error })}`, + location.getOrigin(), + ); + } else { + window.parent.postMessage( + `${this.configurationName}_oidc_exception:${JSON.stringify({ error: exception == null ? '' : exception.toString() })}`, + location.getOrigin(), + ); + } } + } - publishEvent(eventName, data) { - this.events.forEach(event => { - event.func(eventName, data); - }); + async silentLoginCallbackAsync() { + try { + await this.loginCallbackAsync(true); + this._silentLoginCallbackFromIFrame(); + } catch (exception) { + console.error(exception); + this._silentLoginErrorCallbackFromIFrame(exception); } + } - static getOrCreate = (getFetch : () => Fetch) => (configuration, name = 'default') => { - return oidcFactory(getFetch)(configuration, name); + initPromise = null; + async initAsync(authority: string, authorityConfiguration: AuthorityConfiguration) { + if (this.initPromise !== null) { + return this.initPromise; + } + const localFuncAsync = async () => { + if (authorityConfiguration != null) { + return new OidcAuthorizationServiceConfiguration({ + authorization_endpoint: authorityConfiguration.authorization_endpoint, + end_session_endpoint: authorityConfiguration.end_session_endpoint, + revocation_endpoint: authorityConfiguration.revocation_endpoint, + token_endpoint: authorityConfiguration.token_endpoint, + userinfo_endpoint: authorityConfiguration.userinfo_endpoint, + check_session_iframe: authorityConfiguration.check_session_iframe, + issuer: authorityConfiguration.issuer, + }); + } + + const serviceWorker = await initWorkerAsync(this.configuration, this.configurationName); + const storage = serviceWorker + ? this.configuration.storage || window.sessionStorage + : this.configuration.storage; + return await fetchFromIssuer(this.getFetch())( + authority, + this.configuration.authority_time_cache_wellknowurl_in_second ?? 60 * 60, + storage, + this.configuration.authority_timeout_wellknowurl_in_millisecond, + ); }; + this.initPromise = localFuncAsync(); + return this.initPromise.finally(() => { + // in case if anything went wrong with the promise, we should reset the initPromise to null too + // otherwise client can't re-init the OIDC client + // as the promise is already fulfilled with rejected state, so could not ever reach this point again, + // so that leads to infinite loop of calls, when client tries to re-init the OIDC client after error + this.initPromise = null; + }); + } - static get(name = 'default') { - const isInsideBrowser = (typeof process === 'undefined'); - if (!Object.prototype.hasOwnProperty.call(oidcDatabase, name) && isInsideBrowser) { - throw Error(`OIDC library does seem initialized. -Please checkout that you are using OIDC hook inside a compoment.`); - } - return oidcDatabase[name]; + tryKeepExistingSessionPromise = null; + async tryKeepExistingSessionAsync(): Promise { + if (this.tryKeepExistingSessionPromise !== null) { + return this.tryKeepExistingSessionPromise; } + this.tryKeepExistingSessionPromise = tryKeepSessionAsync(this); + return this.tryKeepExistingSessionPromise.finally(() => { + this.tryKeepExistingSessionPromise = null; + }); + } - static eventNames = eventNames; + async startCheckSessionAsync( + checkSessionIFrameUri, + clientId, + sessionState, + isSilentSignin = false, + ) { + await defaultStartCheckSessionAsync(this, oidcDatabase, this.configuration)( + checkSessionIFrameUri, + clientId, + sessionState, + isSilentSignin, + ); + } - _silentLoginCallbackFromIFrame() { - if (this.configuration.silent_redirect_uri && this.configuration.silent_login_uri) { - const queryParams = getParseQueryStringFromLocation(window.location.href); - window.top.postMessage(`${this.configurationName}_oidc_tokens:${JSON.stringify({ tokens: this.tokens, sessionState: queryParams.session_state })}`, window.location.origin); - } + loginPromise: Promise = null; + async loginAsync( + callbackPath: string = undefined, + extras: StringMap = null, + isSilentSignin = false, + scope: string = undefined, + silentLoginOnly = false, + ) { + if (this.logoutPromise) { + await this.logoutPromise; } - _silentLoginErrorCallbackFromIFrame() { - if (this.configuration.silent_redirect_uri && this.configuration.silent_login_uri) { - const queryParams = getParseQueryStringFromLocation(window.location.href); - window.top.postMessage(`${this.configurationName}_oidc_error:${JSON.stringify({ error: queryParams.error })}`, window.location.origin); - } + if (this.loginPromise !== null) { + return this.loginPromise; } + if (silentLoginOnly) { + this.loginPromise = defaultSilentLoginAsync( + window, + this.configurationName, + this.configuration, + this.publishEvent.bind(this), + this, + )(extras, scope); + } else { + this.loginPromise = defaultLoginAsync( + this.configurationName, + this.configuration, + this.publishEvent.bind(this), + this.initAsync.bind(this), + this.location, + )(callbackPath, extras, isSilentSignin, scope); + } + return this.loginPromise.finally(() => { + this.loginPromise = null; + }); + } - async silentLoginCallbackAsync() { - try { - await this.loginCallbackAsync(true); - this._silentLoginCallbackFromIFrame(); - } catch (error) { - console.error(error); - this._silentLoginErrorCallbackFromIFrame(); - } + loginCallbackPromise: Promise = null; + async loginCallbackAsync(isSilenSignin = false) { + if (this.loginCallbackPromise !== null) { + return this.loginCallbackPromise; } - initPromise = null; - async initAsync(authority:string, authorityConfiguration:AuthorityConfiguration) { - if (this.initPromise !== null) { - return this.initPromise; - } - const localFuncAsync = async () => { - if (authorityConfiguration != null) { - return new OidcAuthorizationServiceConfiguration({ - authorization_endpoint: authorityConfiguration.authorization_endpoint, - end_session_endpoint: authorityConfiguration.end_session_endpoint, - revocation_endpoint: authorityConfiguration.revocation_endpoint, - token_endpoint: authorityConfiguration.token_endpoint, - userinfo_endpoint: authorityConfiguration.userinfo_endpoint, - check_session_iframe: authorityConfiguration.check_session_iframe, - issuer: authorityConfiguration.issuer, - }); - } - - const serviceWorker = await initWorkerAsync(this.configuration.service_worker_relative_url, this.configurationName); - const storage = serviceWorker ? window.localStorage : null; - return await fetchFromIssuer(this.getFetch())(authority, this.configuration.authority_time_cache_wellknowurl_in_second ?? 60 * 60, storage, this.configuration.authority_timeout_wellknowurl_in_millisecond); - }; - this.initPromise = localFuncAsync(); - return this.initPromise.then((result) => { - this.initPromise = null; - return result; - }); + const loginCallbackLocalAsync = async (): Promise => { + const response = await loginCallbackAsync(this)(isSilenSignin); + // @ts-ignore + const parsedTokens = response.tokens; + // @ts-ignore + this.tokens = parsedTokens; + const serviceWorker = await initWorkerAsync(this.configuration, this.configurationName); + if (!serviceWorker) { + const session = initSession(this.configurationName, this.configuration.storage); + session.setTokens(parsedTokens); + } + this.publishEvent(Oidc.eventNames.token_acquired, parsedTokens); + if (this.configuration.preload_user_info) { + await this.userInfoAsync(); + } + // @ts-ignore + return { + parsedTokens, + state: response.state, + callbackPath: response.callbackPath, + scope: response.scope, + extras: response.extras, + }; + }; + this.loginCallbackPromise = loginCallbackLocalAsync(); + return this.loginCallbackPromise.finally(() => { + this.loginCallbackPromise = null; + }); + } + + async generateDemonstrationOfProofOfPossessionAsync( + accessToken: string, + url: string, + method: string, + extras: StringMap = {}, + ): Promise { + const configuration = this.configuration; + const claimsExtras = { + ath: await base64urlOfHashOfASCIIEncodingAsync(accessToken), + ...extras, + }; + + const serviceWorker = await initWorkerAsync(configuration, this.configurationName); + + if (serviceWorker) { + return `DPOP_SECURED_BY_OIDC_SERVICE_WORKER_${this.configurationName}#tabId=${getTabId(this.configurationName)}`; } - tryKeepExistingSessionPromise = null; - async tryKeepExistingSessionAsync() :Promise { - if (this.tryKeepExistingSessionPromise !== null) { - return this.tryKeepExistingSessionPromise; - } - const funcAsync = async () => { - let serviceWorker; - if (this.tokens != null) { - return false; - } - this.publishEvent(eventNames.tryKeepExistingSessionAsync_begin, {}); - try { - const configuration = this.configuration; - const oidcServerConfiguration = await this.initAsync(configuration.authority, configuration.authority_configuration); - serviceWorker = await initWorkerAsync(configuration.service_worker_relative_url, this.configurationName); - if (serviceWorker) { - const { tokens } = await serviceWorker.initAsync(oidcServerConfiguration, 'tryKeepExistingSessionAsync', configuration); - if (tokens) { - serviceWorker.startKeepAliveServiceWorker(); - // @ts-ignore - this.tokens = tokens; - const getLoginParams = serviceWorker.getLoginParams(this.configurationName); - // @ts-ignore - this.timeoutId = autoRenewTokens(this, this.tokens.refreshToken, this.tokens.expiresAt, getLoginParams.extras); - const sessionState = await serviceWorker.getSessionStateAsync(); - // @ts-ignore - await this.startCheckSessionAsync(oidcServerConfiguration.check_session_iframe, configuration.client_id, sessionState); - this.publishEvent(eventNames.tryKeepExistingSessionAsync_end, { - success: true, - message: 'tokens inside ServiceWorker are valid', - }); - return true; - } - this.publishEvent(eventNames.tryKeepExistingSessionAsync_end, { - success: false, - message: 'no exiting session found', - }); - } else { - if (configuration.service_worker_relative_url) { - this.publishEvent(eventNames.service_worker_not_supported_by_browser, { - message: 'service worker is not supported by this browser', - }); - } - const session = initSession(this.configurationName, configuration.storage ?? sessionStorage); - const { tokens } = await session.initAsync(); - if (tokens) { - // @ts-ignore - this.tokens = setTokens(tokens, null, configuration.token_renew_mode); - const getLoginParams = session.getLoginParams(this.configurationName); - // @ts-ignore - this.timeoutId = autoRenewTokens(this, tokens.refreshToken, this.tokens.expiresAt, getLoginParams.extras); - const sessionState = await session.getSessionStateAsync(); - // @ts-ignore - await this.startCheckSessionAsync(oidcServerConfiguration.check_session_iframe, configuration.client_id, sessionState); - this.publishEvent(eventNames.tryKeepExistingSessionAsync_end, { - success: true, - message: 'tokens inside storage are valid', - }); - return true; - } - } - this.publishEvent(eventNames.tryKeepExistingSessionAsync_end, { - success: false, - message: serviceWorker ? 'service worker sessions not retrieved' : 'session storage sessions not retrieved', - }); - return false; - } catch (exception) { - console.error(exception); - if (serviceWorker) { - await serviceWorker.clearAsync(); - } - this.publishEvent(eventNames.tryKeepExistingSessionAsync_error, 'tokens inside ServiceWorker are invalid'); - return false; - } - }; - - this.tryKeepExistingSessionPromise = funcAsync(); - return this.tryKeepExistingSessionPromise.then((result) => { - this.tryKeepExistingSessionPromise = null; - return result; - }); + const session = initSession(this.configurationName, configuration.storage); + const jwk = await session.getDemonstratingProofOfPossessionJwkAsync(); + const demonstratingProofOfPossessionNonce = session.getDemonstratingProofOfPossessionNonce(); + + if (demonstratingProofOfPossessionNonce) { + claimsExtras['nonce'] = demonstratingProofOfPossessionNonce; } - async startCheckSessionAsync(checkSessionIFrameUri, clientId, sessionState, isSilentSignin = false) { - await defaultStartCheckSessionAsync(this, oidcDatabase, this.configuration)(checkSessionIFrameUri, clientId, sessionState, isSilentSignin); + return await generateJwtDemonstratingProofOfPossessionAsync(window)( + configuration.demonstrating_proof_of_possession_configuration, + )(jwk, method, url, claimsExtras); + } + + loginCallbackWithAutoTokensRenewPromise: Promise = null; + loginCallbackWithAutoTokensRenewAsync(): Promise { + if (this.loginCallbackWithAutoTokensRenewPromise !== null) { + return this.loginCallbackWithAutoTokensRenewPromise; } + this.loginCallbackWithAutoTokensRenewPromise = loginCallbackWithAutoTokensRenewAsync(this); + return this.loginCallbackWithAutoTokensRenewPromise.finally(() => { + this.loginCallbackWithAutoTokensRenewPromise = null; + }); + } - loginPromise: Promise = null; - async loginAsync(callbackPath:string = undefined, extras:StringMap = null, isSilentSignin = false, scope:string = undefined, silentLoginOnly = false) { - if (this.loginPromise !== null) { - return this.loginPromise; - } - if (silentLoginOnly) { - return defaultSilentLoginAsync(window, this.configurationName, this.configuration, this.publishEvent.bind(this), this)(extras, scope); - } - this.loginPromise = defaultLoginAsync(window, this.configurationName, this.configuration, this.publishEvent.bind(this), this.initAsync.bind(this))(callbackPath, extras, isSilentSignin, scope); - return this.loginPromise.then(result => { - this.loginPromise = null; - return result; - }); + userInfoPromise: Promise = null; + userInfoAsync(noCache = false, demonstrating_proof_of_possession = false) { + if (this.userInfoPromise !== null) { + return this.userInfoPromise; } + this.userInfoPromise = userInfoAsync(this)(noCache, demonstrating_proof_of_possession); + return this.userInfoPromise.finally(() => { + this.userInfoPromise = null; + }); + } - loginCallbackPromise : Promise = null; - async loginCallbackAsync(isSilenSignin = false) { - if (this.loginCallbackPromise !== null) { - return this.loginCallbackPromise; - } - - const loginCallbackLocalAsync = async():Promise => { - const response = await loginCallbackAsync(this)(isSilenSignin); - // @ts-ignore - const parsedTokens = response.tokens; - // @ts-ignore - this.tokens = parsedTokens; - const serviceWorker = await initWorkerAsync(this.configuration.service_worker_relative_url, this.configurationName); - if (!serviceWorker) { - const session = initSession(this.configurationName, this.configuration.storage); - session.setTokens(parsedTokens); - } - this.publishEvent(Oidc.eventNames.token_aquired, parsedTokens); - // @ts-ignore - return { parsedTokens, state: response.state, callbackPath: response.callbackPath }; - }; - this.loginCallbackPromise = loginCallbackLocalAsync(); - return this.loginCallbackPromise.then(result => { - this.loginCallbackPromise = null; - return result; - }); + renewTokensPromise: Promise = null; + + async renewTokensAsync(extras: StringMap = null, scope: string = null) { + if (this.renewTokensPromise !== null) { + return this.renewTokensPromise; + } + if (!this.timeoutId) { + return; } + timer.clearTimeout(this.timeoutId); + // @ts-ignore + this.renewTokensPromise = renewTokensAndStartTimerAsync(this, true, extras, scope); + return this.renewTokensPromise.finally(() => { + this.renewTokensPromise = null; + }); + } + + async destroyAsync(status) { + return await destroyAsync(this)(status); + } - async synchroniseTokensAsync(refreshToken, index = 0, forceRefresh = false, extras:StringMap = null, updateTokens) { - while (!navigator.onLine && document.hidden) { - await sleepAsync(1000); - this.publishEvent(eventNames.refreshTokensAsync, { message: 'wait because navigator is offline and hidden' }); - } - let numberTryOnline = 6; - while (!navigator.onLine && numberTryOnline > 0) { - await sleepAsync(1000); - numberTryOnline--; - this.publishEvent(eventNames.refreshTokensAsync, { message: `wait because navigator is offline try ${numberTryOnline}` }); - } - let numberTryHidden = Math.floor(Math.random() * 15) + 10; - while (document.hidden && numberTryHidden > 0) { - await sleepAsync(1000); - numberTryHidden--; - this.publishEvent(eventNames.refreshTokensAsync, { message: `wait because navigator is hidden try ${numberTryHidden}` }); - } - const isDocumentHidden = document.hidden; - const nextIndex = isDocumentHidden ? index : index + 1; - if (!extras) { - extras = {}; - } - const configuration = this.configuration; - - const silentLoginAsync = (extras: StringMap, state:string, scope:string = null) => { - return _silentLoginAsync(this.configurationName, this.configuration, this.publishEvent.bind(this))(extras, state, scope); - }; - const localsilentLoginAsync = async () => { - try { - let loginParams; - const serviceWorker = await initWorkerAsync(configuration.service_worker_relative_url, this.configurationName); - if (serviceWorker) { - loginParams = serviceWorker.getLoginParams(this.configurationName); - } else { - const session = initSession(this.configurationName, configuration.storage); - loginParams = session.getLoginParams(this.configurationName); - } - const silent_token_response = await silentLoginAsync({ - ...loginParams.extras, - ...extras, - prompt: 'none', - }, loginParams.state); - if (silent_token_response) { - updateTokens(silent_token_response.tokens); - this.publishEvent(Oidc.eventNames.token_renewed, {}); - return { tokens: silent_token_response.tokens, status: 'LOGGED' }; - } - } catch (exceptionSilent: any) { - console.error(exceptionSilent); - this.publishEvent(eventNames.refreshTokensAsync_silent_error, { message: 'exceptionSilent', exception: exceptionSilent.message }); - if (exceptionSilent && exceptionSilent.message && exceptionSilent.message.startsWith('oidc')) { - updateTokens(null); - this.publishEvent(eventNames.refreshTokensAsync_error, { message: 'refresh token silent' }); - return { tokens: null, status: 'SESSION_LOST' }; - } - } - this.publishEvent(eventNames.refreshTokensAsync_error, { message: 'refresh token silent return' }); - return await this.synchroniseTokensAsync(null, nextIndex, forceRefresh, extras, updateTokens); - }; - - if (index > 4) { - updateTokens(null); - this.publishEvent(eventNames.refreshTokensAsync_error, { message: 'refresh token' }); - return { tokens: null, status: 'SESSION_LOST' }; - } - try { - const { status, tokens, nonce } = await this.syncTokensInfoAsync(configuration, this.configurationName, this.tokens, forceRefresh); - switch (status) { - case 'SESSION_LOST': - updateTokens(null); - this.publishEvent(eventNames.refreshTokensAsync_error, { message: 'refresh token session lost' }); - return { tokens: null, status: 'SESSION_LOST' }; - case 'NOT_CONNECTED': - updateTokens(null); - return { tokens: null, status: null }; - case 'TOKENS_VALID': - updateTokens(tokens); - return { tokens, status: 'LOGGED_IN' }; - case 'TOKEN_UPDATED_BY_ANOTHER_TAB_TOKENS_VALID': - updateTokens(tokens); - this.publishEvent(Oidc.eventNames.token_renewed, { reason: 'TOKEN_UPDATED_BY_ANOTHER_TAB_TOKENS_VALID' }); - return { tokens, status: 'LOGGED_IN' }; - case 'LOGOUT_FROM_ANOTHER_TAB': - updateTokens(null); - this.publishEvent(eventNames.logout_from_another_tab, { status: 'session syncTokensAsync' }); - return { tokens: null, status: 'LOGGED_OUT' }; - case 'REQUIRE_SYNC_TOKENS': - this.publishEvent(eventNames.refreshTokensAsync_begin, { refreshToken, status, tryNumber: index }); - return await localsilentLoginAsync(); - default: { - this.publishEvent(eventNames.refreshTokensAsync_begin, { refreshToken, status, tryNumber: index }); - if (!refreshToken) { - return await localsilentLoginAsync(); - } - - const clientId = configuration.client_id; - const redirectUri = configuration.redirect_uri; - const authority = configuration.authority; - const tokenExtras = configuration.token_request_extras ? configuration.token_request_extras : {}; - const finalExtras = { ...tokenExtras }; - - for (const [key, value] of Object.entries(extras)) { - if (key.endsWith(':token_request')) { - finalExtras[key.replace(':token_request', '')] = value; - } - } - const localFunctionAsync = async () => { - const details = { - client_id: clientId, - redirect_uri: redirectUri, - grant_type: 'refresh_token', - refresh_token: tokens.refreshToken, - }; - const oidcServerConfiguration = await this.initAsync(authority, configuration.authority_configuration); - const timeoutMs = document.hidden ? 10000 : 30000 * 10; - const tokenResponse = await performTokenRequestAsync(this.getFetch())(oidcServerConfiguration.tokenEndpoint, details, finalExtras, tokens, configuration.token_renew_mode, timeoutMs); - if (tokenResponse.success) { - const { isValid, reason } = isTokensOidcValid(tokenResponse.data, nonce.nonce, oidcServerConfiguration); - if (!isValid) { - updateTokens(null); - this.publishEvent(eventNames.refreshTokensAsync_error, { message: `refresh token return not valid tokens, reason: ${reason}` }); - return { tokens: null, status: 'SESSION_LOST' }; - } - updateTokens(tokenResponse.data); - this.publishEvent(eventNames.refreshTokensAsync_end, { success: tokenResponse.success }); - this.publishEvent(Oidc.eventNames.token_renewed, { reason: 'REFRESH_TOKEN' }); - return { tokens: tokenResponse.data, status: 'LOGGED_IN' }; - } else { - this.publishEvent(eventNames.refreshTokensAsync_silent_error, { - message: 'bad request', - tokenResponse, - }); - return await this.synchroniseTokensAsync(refreshToken, nextIndex, forceRefresh, extras, updateTokens); - } - }; - return await localFunctionAsync(); - } - } - } catch (exception: any) { - console.error(exception); - this.publishEvent(eventNames.refreshTokensAsync_silent_error, { message: 'exception', exception: exception.message }); - return this.synchroniseTokensAsync(refreshToken, nextIndex, forceRefresh, extras, updateTokens); - } - } - - async syncTokensInfoAsync(configuration, configurationName, currentTokens, forceRefresh = false) { - // Service Worker can be killed by the browser (when it wants,for example after 10 seconds of inactivity, so we retreieve the session if it happen) - // const configuration = this.configuration; - const nullNonce = { nonce: null }; - if (!currentTokens) { - return { tokens: null, status: 'NOT_CONNECTED', nonce: nullNonce }; - } - let nonce = nullNonce; - const oidcServerConfiguration = await this.initAsync(configuration.authority, configuration.authority_configuration); - const serviceWorker = await initWorkerAsync(configuration.service_worker_relative_url, configurationName); - if (serviceWorker) { - const { status, tokens } = await serviceWorker.initAsync(oidcServerConfiguration, 'syncTokensAsync', configuration); - if (status === 'LOGGED_OUT') { - return { tokens: null, status: 'LOGOUT_FROM_ANOTHER_TAB', nonce: nullNonce }; - } else if (status === 'SESSIONS_LOST') { - return { tokens: null, status: 'SESSIONS_LOST', nonce: nullNonce }; - } else if (!status || !tokens) { - return { tokens: null, status: 'REQUIRE_SYNC_TOKENS', nonce: nullNonce }; - } else if (tokens.issuedAt !== currentTokens.issuedAt) { - const timeLeft = computeTimeLeft(configuration.refresh_time_before_tokens_expiration_in_second, tokens.expiresAt); - const status = (timeLeft > 0) ? 'TOKEN_UPDATED_BY_ANOTHER_TAB_TOKENS_VALID' : 'TOKEN_UPDATED_BY_ANOTHER_TAB_TOKENS_INVALID'; - const nonce = await serviceWorker.getNonceAsync(); - return { tokens, status, nonce }; - } - nonce = await serviceWorker.getNonceAsync(); - } else { - const session = initSession(configurationName, configuration.storage ?? sessionStorage); - const { tokens, status } = await session.initAsync(); - if (!tokens) { - return { tokens: null, status: 'LOGOUT_FROM_ANOTHER_TAB', nonce: nullNonce }; - } else if (status === 'SESSIONS_LOST') { - return { tokens: null, status: 'SESSIONS_LOST', nonce: nullNonce }; - } else if (tokens.issuedAt !== currentTokens.issuedAt) { - const timeLeft = computeTimeLeft(configuration.refresh_time_before_tokens_expiration_in_second, tokens.expiresAt); - const status = (timeLeft > 0) ? 'TOKEN_UPDATED_BY_ANOTHER_TAB_TOKENS_VALID' : 'TOKEN_UPDATED_BY_ANOTHER_TAB_TOKENS_INVALID'; - const nonce = await session.getNonceAsync(); - return { tokens, status, nonce }; - } - nonce = await session.getNonceAsync(); - } - - const timeLeft = computeTimeLeft(configuration.refresh_time_before_tokens_expiration_in_second, currentTokens.expiresAt); - const status = (timeLeft > 0) ? 'TOKENS_VALID' : 'TOKENS_INVALID'; - if (forceRefresh) { - return { tokens: currentTokens, status: 'FORCE_REFRESH', nonce }; - } - return { tokens: currentTokens, status, nonce }; + async logoutSameTabAsync(clientId: string, sub: any) { + // @ts-ignore + if ( + this.configuration.monitor_session && + this.configuration.client_id === clientId && + sub && + this.tokens && + this.tokens.idTokenPayload && + this.tokens.idTokenPayload.sub === sub + ) { + await this.destroyAsync('LOGGED_OUT'); + this.publishEvent(eventNames.logout_from_same_tab, { mmessage: 'SessionMonitor', sub }); } + } - loginCallbackWithAutoTokensRenewPromise:Promise = null; - loginCallbackWithAutoTokensRenewAsync():Promise { - if (this.loginCallbackWithAutoTokensRenewPromise !== null) { - return this.loginCallbackWithAutoTokensRenewPromise; - } - this.loginCallbackWithAutoTokensRenewPromise = loginCallbackWithAutoTokensRenewAsync(this); - return this.loginCallbackWithAutoTokensRenewPromise.then(result => { - this.loginCallbackWithAutoTokensRenewPromise = null; - return result; - }); - } - - userInfoPromise:Promise = null; - userInfoAsync(noCache = false) { - if (this.userInfoPromise !== null) { - return this.userInfoPromise; - } - this.userInfoPromise = userInfoAsync(this)(noCache); - return this.userInfoPromise.then(result => { - this.userInfoPromise = null; - return result; - }); - } - - renewTokensPromise:Promise = null; - - async renewTokensAsync (extras:StringMap = null) { - if (this.renewTokensPromise !== null) { - return this.renewTokensPromise; - } - if (!this.timeoutId) { - return; - } - timer.clearTimeout(this.timeoutId); - // @ts-ignore - this.renewTokensPromise = renewTokensAndStartTimerAsync(this, this.tokens.refreshToken, true, extras); - return this.renewTokensPromise.then(result => { - this.renewTokensPromise = null; - return result; - }); - } - - async destroyAsync(status) { - return await destroyAsync(this)(status); - } - - async logoutSameTabAsync(clientId: string, sub: any) { - // @ts-ignore - if (this.configuration.monitor_session && this.configuration.client_id === clientId && sub && this.tokens && this.tokens.idTokenPayload && this.tokens.idTokenPayload.sub === sub) { - this.publishEvent(eventNames.logout_from_same_tab, { message: sub }); - await this.destroyAsync('LOGGED_OUT'); - } - } - - async logoutOtherTabAsync(clientId: string, sub: any) { - // @ts-ignore - if (this.configuration.monitor_session && this.configuration.client_id === clientId && sub && this.tokens && this.tokens.idTokenPayload && this.tokens.idTokenPayload.sub === sub) { - await this.destroyAsync('LOGGED_OUT'); - this.publishEvent(eventNames.logout_from_another_tab, { message: 'SessionMonitor', sub }); - } + async logoutOtherTabAsync(clientId: string, sub: any) { + // @ts-ignore + if ( + this.configuration.monitor_session && + this.configuration.client_id === clientId && + sub && + this.tokens && + this.tokens.idTokenPayload && + this.tokens.idTokenPayload.sub === sub + ) { + await this.destroyAsync('LOGGED_OUT'); + this.publishEvent(eventNames.logout_from_another_tab, { message: 'SessionMonitor', sub }); } + } - logoutPromise:Promise = null; - async logoutAsync(callbackPathOrUrl: string | null | undefined = undefined, extras: StringMap = null) { - if (this.logoutPromise) { - return this.logoutPromise; - } - this.logoutPromise = logoutAsync(this, oidcDatabase, this.getFetch(), window, console)(callbackPathOrUrl, extras); - return this.logoutPromise.then(result => { - this.logoutPromise = null; - return result; - }); + logoutPromise: Promise = null; + async logoutAsync( + callbackPathOrUrl: string | null | undefined = undefined, + extras: StringMap = null, + ) { + if (this.logoutPromise) { + return this.logoutPromise; } + this.logoutPromise = logoutAsync( + this, + oidcDatabase, + this.getFetch(), + console, + this.location, + )(callbackPathOrUrl, extras); + return this.logoutPromise.finally(() => { + this.logoutPromise = null; + }); } +} - export default Oidc; +export default Oidc; diff --git a/packages/oidc-client/src/oidcClient.ts b/packages/oidc-client/src/oidcClient.ts new file mode 100644 index 000000000..d70ee2463 --- /dev/null +++ b/packages/oidc-client/src/oidcClient.ts @@ -0,0 +1,166 @@ +import { fetchWithTokens } from './fetch'; +import { ILOidcLocation, OidcLocation } from './location'; +import { LoginCallback, Oidc } from './oidc.js'; +import { getValidTokenAsync, OidcToken, Tokens, ValidToken } from './parseTokens.js'; +import { syncTokensInfoAsync } from './renewTokens'; +import { Fetch, OidcConfiguration, StringMap } from './types.js'; + +export interface EventSubscriber { + (name: string, data: any); +} + +export class OidcClient { + private readonly _oidc: Oidc; + constructor(oidc: Oidc) { + this._oidc = oidc; + } + + subscribeEvents(func: EventSubscriber): string { + return this._oidc.subscribeEvents(func); + } + + removeEventSubscription(id: string): void { + this._oidc.removeEventSubscription(id); + } + + publishEvent(eventName: string, data: any): void { + this._oidc.publishEvent(eventName, data); + } + + static getOrCreate = + (getFetch: () => Fetch, location: ILOidcLocation = new OidcLocation()) => + (configuration: OidcConfiguration, name = 'default'): OidcClient => { + return new OidcClient(Oidc.getOrCreate(getFetch, location)(configuration, name)); + }; + + static get(name = 'default'): OidcClient { + return new OidcClient(Oidc.get(name)); + } + + static eventNames = Oidc.eventNames; + tryKeepExistingSessionAsync(): Promise { + return this._oidc.tryKeepExistingSessionAsync(); + } + + loginAsync( + callbackPath: string = undefined, + extras: StringMap = null, + isSilentSignin = false, + scope: string = undefined, + silentLoginOnly = false, + ): Promise { + return this._oidc.loginAsync(callbackPath, extras, isSilentSignin, scope, silentLoginOnly); + } + + logoutAsync( + callbackPathOrUrl: string | null | undefined = undefined, + extras: StringMap = null, + ): Promise { + return this._oidc.logoutAsync(callbackPathOrUrl, extras); + } + + silentLoginCallbackAsync(): Promise { + return this._oidc.silentLoginCallbackAsync(); + } + + renewTokensAsync(extras: StringMap = null, scope: string = null): Promise { + return this._oidc.renewTokensAsync(extras, scope); + } + + loginCallbackAsync(): Promise { + return this._oidc.loginCallbackWithAutoTokensRenewAsync(); + } + + get tokens(): Tokens { + return this._oidc.tokens; + } + + get configuration(): OidcConfiguration { + return this._oidc.configuration; + } + + async generateDemonstrationOfProofOfPossessionAsync( + accessToken: string, + url: string, + method: string, + extras: StringMap = {}, + ): Promise { + return this._oidc.generateDemonstrationOfProofOfPossessionAsync( + accessToken, + url, + method, + extras, + ); + } + + async getValidTokenAsync(waitMs = 200, numberWait = 50): Promise { + const oidc = this._oidc; + const oidcToken: OidcToken = { + getTokens: () => oidc.tokens, + configuration: { + token_automatic_renew_mode: oidc.configuration.token_automatic_renew_mode, + refresh_time_before_tokens_expiration_in_second: + oidc.configuration.refresh_time_before_tokens_expiration_in_second, + }, + syncTokensInfoAsync: async () => { + const { status } = await syncTokensInfoAsync(oidc)( + oidc.configuration, + oidc.configurationName, + oidc.tokens, + false, + ); + return status; + }, + renewTokensAsync: oidc.renewTokensAsync.bind(oidc), + }; + return getValidTokenAsync(oidcToken, waitMs, numberWait); + } + + fetchWithTokens(fetch: Fetch, demonstratingProofOfPossession: boolean = false): Fetch { + return fetchWithTokens(fetch, this._oidc, demonstratingProofOfPossession); + } + + async userInfoAsync( + noCache = false, + demonstratingProofOfPossession: boolean = false, + ): Promise { + return this._oidc.userInfoAsync(noCache, demonstratingProofOfPossession); + } + + userInfo(): T { + return this._oidc.userInfo; + } +} + +export interface OidcUserInfo { + sub: string; + name?: string; + given_name?: string; + family_name?: string; + middle_name?: string; + nickname?: string; + preferred_username?: string; + profile?: string; + picture?: string; + website?: string; + email?: string; + email_verified?: boolean; + gender?: string; + birthdate?: string; + zoneinfo?: string; + locale?: string; + phone_number?: string; + phone_number_verified?: boolean; + address?: OidcAddressClaim; + updated_at?: number; + groups?: string[]; +} + +export interface OidcAddressClaim { + formatted?: string; + street_address?: string; + locality?: string; + region?: string; + postal_code?: string; + country?: string; +} diff --git a/packages/oidc-client/src/parseTokens.spec.ts b/packages/oidc-client/src/parseTokens.spec.ts index a18db08be..be8b46f14 100644 --- a/packages/oidc-client/src/parseTokens.spec.ts +++ b/packages/oidc-client/src/parseTokens.spec.ts @@ -1,49 +1,217 @@ -import {getValidTokenAsync, isTokensOidcValid} from "./parseTokens"; -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; + +import { sleepAsync } from './initWorker'; +import { + getValidTokenAsync, + isTokensOidcValid, + parseJwt, + parseOriginalTokens, + setTokens, + TokenRenewMode, +} from './parseTokens'; +import { synchroniseTokensStatus } from './renewTokens'; +import { StringMap, TokenAutomaticRenewMode } from './types'; describe('ParseTokens test Suite', () => { - const currentTimeUnixSecond = new Date().getTime() / 1000; - describe.each([ - [currentTimeUnixSecond + 120, currentTimeUnixSecond - 10, true], - [currentTimeUnixSecond - 20, currentTimeUnixSecond - 50, false], - ])('getValidTokenAsync', (expiresAt, issuedAt, expectIsValidToken) => { - it('should getValidTokenAsync wait and return value', async () => { - const oidc = { - tokens: { - refreshToken: 'youhou', - idTokenPayload: null, - idToken: 'youhou', - accessTokenPayload: null, - accessToken: 'youhou', - expiresAt: expiresAt, - issuedAt: issuedAt, - } - } - const result = await getValidTokenAsync(oidc, 1, 1); - expect(result.isTokensValid).toEqual(expectIsValidToken); - }); + const currentTimeUnixSecond = new Date().getTime() / 1000; + describe.each([ + [currentTimeUnixSecond + 120, currentTimeUnixSecond - 10, true], + [currentTimeUnixSecond - 20, currentTimeUnixSecond - 50, false], + ])('getValidTokenAsync', (expiresAt, issuedAt, expectIsValidToken) => { + it('should getValidTokenAsync wait and return value', async () => { + const oidc = { + getTokens: () => { + return { + refreshToken: 'youhou', + idTokenPayload: null, + idToken: 'youhou', + accessTokenPayload: null, + accessToken: 'youhou', + expiresAt, + issuedAt, + }; + }, + configuration: { + token_automatic_renew_mode: TokenAutomaticRenewMode.AutomaticBeforeTokenExpiration, + refresh_time_before_tokens_expiration_in_second: 0, + }, + syncTokensInfoAsync: async () => synchroniseTokensStatus.TOKENS_VALID, + renewTokensAsync: async (_extras: StringMap) => { + await sleepAsync({ milliseconds: 10 }); + }, + }; + const result = await getValidTokenAsync(oidc, 1, 1); + expect(result.isTokensValid).toEqual(expectIsValidToken); + }); + }); + + describe.each([ + [ + 'eyJzZXNzaW9uX3N0YXRlIjoiNzVjYzVlZDItZGYyZC00NTY5LWJmYzUtMThhOThlNjhiZTExIiwic2NvcGUiOiJvcGVuaWQgZW1haWwgcHJvZmlsZSIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJuYW1lIjoixrTHosOBw6zDhyDlsI_lkI0t44Ob44Or44OYIiwicHJlZmVycmVkX3VzZXJuYW1lIjoidGVzdGluZ2NoYXJhY3RlcnNAaW52ZW50ZWRtYWlsLmNvbSIsImdpdmVuX25hbWUiOiLGtMeiw4HDrMOHIiwiZmFtaWx5X25hbWUiOiLlsI_lkI0t44Ob44Or44OYIn0', + { + session_state: '75cc5ed2-df2d-4569-bfc5-18a98e68be11', + scope: 'openid email profile', + email_verified: true, + name: 'ƴǢÁìÇ 小名-ホルヘ', + preferred_username: 'testingcharacters@inventedmail.com', + given_name: 'ƴǢÁìÇ', + family_name: '小名-ホルヘ', + }, + ], + [ + 'eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCI_IjoiYWE_In0', + { + '?': 'aa?', + iat: 1516239022, + name: 'John Doe', + sub: '1234567890', + }, + ], + ])('parseJwtShouldExtractData', (claimsPart, expectedResult) => { + it('should parseJwtShouldExtractData ', async () => { + const result = parseJwt(claimsPart); + expect(expectedResult).toStrictEqual(result); }); + }); + + const id_token = + 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IjUwNWZkODljLTM4YzktNGI2Mi04ZjQ3LWI4MGQ0ZTNhYjYxNSJ9.eyJpc3MiOiJodHRwOlwvXC9sb2NhbGhvc3Q6ODA4MCIsInN1YiI6ImFkbWluIiwiYXVkIjoiM2FTbk5XUGxZQWQwOGVES3c1UUNpSWVMcWpIdHkxTTVzSGFzcDJDZWREcWYzbmJkZm8xUFo1cXhmbWoyaFhkUyIsImV4cCI6MTY5MDk4NzQ1NCwiYXV0aF90aW1lIjoxNjkwOTg2NTUxLCJpYXQiOjE2OTA5ODY1NTQsImFjciI6IjAiLCJhenAiOiIzYVNuTldQbFlBZDA4ZURLdzVRQ2lJZUxxakh0eTFNNXNIYXNwMkNlZERxZjNuYmRmbzFQWjVxeGZtajJoWGRTIiwicHJlZmVycmVkX3VzZXJuYW1lIjoiYWRtaW4iLCJzY29wZSI6Im9wZW5pZCBwcm9maWxlIGdyb3VwcyBvZmZsaW5lX2FjY2VzcyIsIm5iZiI6MTY5MDk4NjU1NCwianRpIjoiNjMiLCJub25jZSI6ImNpQkVVOTdaVmRWVSIsImdyb3VwcyI6WyJhZG1pbiJdLCJuYW1lIjoiQWRtaW5pc3RyYXRvciIsInVwZGF0ZWRfYXQiOjE2OTA5ODY1NDV9.2MUdtQR_QtzDY9BTMctG8C4uvg92DgMIUUoJed2cI7WTd5_VEPFW87esDQLw4snVdAJM1_Wf3wB88B2MXFDMCnMTNn0TMnzetRDiG3xlr2LL-geL5SNgwD0Y6RPK_aITjrC9uiQCTj3LPEENrBulNRZPURwaVon9WUVNuuBmMTKd7QKEuFN0zYDoRs0HnXo6WKnFy1rldLGh_JpA3PBUuXt4VMjfGQ7yYEuNn7MkFVDX6OnTffR8jTQp74hREvuRLFjYxfgfgu547X7yIcboOl81D0ZQlP-gfvBOeypZolRLScuqAA3fHBYvE0vCtOM6ObekfeeTDfms75csMLUuZtTR07x32xYC8vdoFsY0sRpMByTqlhsae9VX_rETJ7PIWEfruojzcj47WN9dG0K3pdPiJHEwZ1CKgZfU_cY0gtuAGaIcIjKL0txXCevaiIiIsrgSU_HTjNVybp4WHSAs3h6x0XLz4_91luCylsaoMQbwKOQNwAfr2L74jF6DOg-8DIPb-WClRQzaQtrkx_iv6FtqCB3ogFoZwi6xljdYUc2EHUmoAo-LXal-QAgUXGGzfFU2YOpxV3RyAbMGPm7PfkMVzDsDJwORJNhh38QQ6o88GgNnV28BT-d2G0n7okc0QC6o2IW0jpyCrI6v0hWOBUX2EqiJ5Wao-4LYZfCaRgU'; + const refresh_token = + 'DEsqDca7nDGSgT6tJPkCwbPy98B8VOC4AA55lOPs03G3hqhZ8WH08REBcwTZg1s0jZyVoA3iCXzm4PPJ096gjV7ZKYyN8vnFKw6P6KLV3tUI6mWFaSROoh1LipThFrkS'; + const access_token = 'opqavdgHEYx8nhCdc3iByd1HD0jiYN30LevhJy4f5wIavINXKdh4lQ9C3kA49QF0OH0XeA02'; + describe.each([ + [ + { + access_token: access_token, + token_type: 'Bearer', + expires_in: '900', // Here a string instead of a number + refresh_token: refresh_token, + id_token: id_token, + }, + ], + [ + { + access_token: access_token, + token_type: 'Bearer', + expires_in: 900, + refresh_token: refresh_token, + id_token: id_token, + }, + ], + [ + { + access_token: access_token, + token_type: 'Bearer', + expires_in: 900, + expiresAt: 1609987454, // Here expiresAt that come from Service Worker + refresh_token: refresh_token, + id_token: id_token, + }, + ], + ])('getValidTokenAsync', tokens => { + it('should parseOriginalTokens', async () => { + // @ts-ignore + const result = parseOriginalTokens(tokens); + expect(typeof result.issuedAt).toEqual('number'); + }); + }); + + const idTokenPayload = { + iss: 'toto', + exp: currentTimeUnixSecond + 900, + iat: currentTimeUnixSecond - 900, + nonce: 'nonce', + }; + const oidcServerConfiguration = { issuer: 'toto' }; + const idTokenPayloadExpired = { ...idTokenPayload, exp: currentTimeUnixSecond - 20 }; + const idTokenPayloadIssuedTooLongTimeAgo = { + ...idTokenPayload, + iat: currentTimeUnixSecond - 20000000, + }; + + describe.each([ + [idTokenPayload, 'nonce', oidcServerConfiguration, true, 'success'], + [idTokenPayload, 'other_nonce', oidcServerConfiguration, false, 'bad nonce'], + [idTokenPayload, 'nonce', { issuer: 'tutu' }, false, 'different issuer'], + [idTokenPayloadExpired, 'nonce', oidcServerConfiguration, false, 'id token expired issuer'], + [ + idTokenPayloadIssuedTooLongTimeAgo, + 'nonce', + oidcServerConfiguration, + false, + 'id token expired issuer', + ], + ])( + 'isTokensOidcValid', + (idTokenPayload, nonce, oidcServerConfiguration, expectIsValidToken, status) => { + it('should isTokensOidcValid return ' + status, async () => { + const oidc = { + idTokenPayload, + }; + const { isValid } = isTokensOidcValid(oidc, nonce, oidcServerConfiguration); + expect(isValid).toEqual(expectIsValidToken); + }); + }, + ); + const testTokens = { + id_token: + 'eyJhbGciOiJSUzI1NiIsImtpZCI6IkMyNTJGOUNBQjc3Q0MxNTQwNTBFMTg1NTk5MjJCMTJGIiwidHlwIjoiSldUIn0.eyJpc3MiOiJodHRwczovL2RlbW8uZHVlbmRlc29mdHdhcmUuY29tIiwibmJmIjoxNzA2NTQwMjU4LCJpYXQiOjE3MDY1NDAyNTgsImV4cCI6MTcwNjU0MDU1OCwiYXVkIjoiaW50ZXJhY3RpdmUucHVibGljLnNob3J0IiwiYW1yIjpbInB3ZCJdLCJub25jZSI6IlA5dEo5eGxHZE05NiIsImF0X2hhc2giOiJOWnZhR0dZYlhoelRNWlVxUjlNYk5nIiwic2lkIjoiMzQ1QUJDODhFNkU1MEFGMTI3M0VENDE1QTdGRDZBMjMiLCJzdWIiOiIyIiwiYXV0aF90aW1lIjoxNzA2NTMxNjY1LCJpZHAiOiJsb2NhbCJ9.MVtXrCkshJFBplbOw7az3fdWB1Ewqixb2fuHXpx7KbGWUY6qgT9ijlldeD-ZV7JGA958AKqmGwfNjovAJE89pQsCFKkNft6fRO8eM9qKif6eRUqMMPiQrawARpuJOs1NvJ-SyeRs_jSNLwPVzI8NlZyFWHoyQ4DZnFoQLSQMy5UaHaCtWhC_FrWMFLQvbE3RuMlnJGzrsoMewFyVAZctMCTE1MOI3Akvhe1IGc1hmxzwNg3OkxwzHLinsDlDw8UVn8vX5iNI18GFuyTuJlawOq5OHHJH3LdKQD_RbwRF-9BFjKRZfWzGpdpxTD2lIPf1Irc3U_R6xCNuXYUwzrHp6Q', + access_token: 'ACCESS_TOKEN_SECURED_BY_OIDC_SERVICE_WORKER_default', + expires_in: 75, + token_type: 'Bearer', + refresh_token: 'REFRESH_TOKEN_SECURED_BY_OIDC_SERVICE_WORKER_default', + scope: 'openid profile email api offline_access', + issued_at: 1706540256.465, + accessTokenPayload: { + iss: 'https://demo.duendesoftware.com', + nbf: 1706540258, + iat: 1706540258, + exp: 1706540333, + aud: 'api', + scope: ['openid', 'profile', 'email', 'api', 'offline_access'], + amr: ['pwd'], + client_id: 'interactive.public.short', + sub: '2', + auth_time: 1706531665, + idp: 'local', + name: 'Bob Smith', + email: 'BobSmith@email.com', + sid: '345ABC88E6E50AF1273ED415A7FD6A23', + jti: 'E3CF3853D77AC90ABC774266CD381C43', + }, + idTokenPayload: { + iss: 'https://demo.duendesoftware.com', + nbf: 1706540258, + iat: 1706540258, + exp: 1706540558, + aud: 'interactive.public.short', + amr: ['pwd'], + nonce: 'NONCE_SECURED_BY_OIDC_SERVICE_WORKER_default', + at_hash: 'NZvaGGYbXhzTMZUqR9MbNg', + sid: '345ABC88E6E50AF1273ED415A7FD6A23', + sub: '2', + auth_time: 1706531665, + idp: 'local', + }, + expiresAt: 1706540333, + }; - const idTokenPayload = {iss: "toto", exp: currentTimeUnixSecond +900, iat: currentTimeUnixSecond -900, nonce: "nonce"}; - const oidcServerConfiguration = {issuer:"toto"}; - const idTokenPayloadExpired = {...idTokenPayload, exp: currentTimeUnixSecond-20}; - const idTokenPayloadIssuedTooLongTimeAgo = {...idTokenPayload, iat: currentTimeUnixSecond-20000000}; - - describe.each([ - [idTokenPayload, "nonce", oidcServerConfiguration, true, "success"], - [idTokenPayload, "other_nonce", oidcServerConfiguration, false, "bad nonce"], - [idTokenPayload, "nonce", {issuer:"tutu"}, false, "different issuer"], - [idTokenPayloadExpired, "nonce", oidcServerConfiguration, false, "id token expired issuer"], - [idTokenPayloadIssuedTooLongTimeAgo, "nonce", oidcServerConfiguration, false, "id token expired issuer"], - ])('isTokensOidcValid', (idTokenPayload, nonce, oidcServerConfiguration, expectIsValidToken, status) => { - it('should isTokensOidcValid return ' + status, async () => { - const oidc = { - idTokenPayload - } - const {isValid} = await isTokensOidcValid(oidc, nonce, oidcServerConfiguration); - expect(isValid).toEqual(expectIsValidToken); - }); + describe.each([ + [testTokens, null, TokenRenewMode.access_token_invalid, () => {}], + [ + testTokens, + { testTokens, idTokenPayload: undefined, id_token: undefined }, + TokenRenewMode.access_token_invalid, + (newTokens: any) => { + expect(newTokens.idTokenPayload).toBeDefined(); + expect(newTokens.id_token).toBeDefined(); + }, + ], + ])('setTokens', (tokens, oldTokens, tokenRenewMode, validationFunction) => { + it('should setTokens return updatedTokens', async () => { + const newTokens = setTokens(tokens, oldTokens, tokenRenewMode); + validationFunction(newTokens); }); - + }); }); diff --git a/packages/oidc-client/src/parseTokens.ts b/packages/oidc-client/src/parseTokens.ts index c5ddd8ab9..ad1eb374e 100644 --- a/packages/oidc-client/src/parseTokens.ts +++ b/packages/oidc-client/src/parseTokens.ts @@ -1,194 +1,284 @@ import { sleepAsync } from './initWorker.js'; +import { synchroniseTokensStatus } from './renewTokens'; +import { StringMap, TokenAutomaticRenewMode } from './types'; -const b64DecodeUnicode = (str) => - decodeURIComponent(Array.prototype.map.call(atob(str), (c) => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)).join('')); -const parseJwt = (token) => JSON.parse(b64DecodeUnicode(token.split('.')[1].replace('-', '+').replace('_', '/'))); - -const extractTokenPayload = (token) => { - try { - if (!token) { - return null; - } - if (countLetter(token, '.') === 2) { - return parseJwt(token); - } else { - return null; - } - } catch (e) { - console.warn(e); +const b64DecodeUnicode = str => + decodeURIComponent( + Array.prototype.map + .call(atob(str), c => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)) + .join(''), + ); +export const parseJwt = (payload: string) => + JSON.parse(b64DecodeUnicode(payload.replaceAll(/-/g, '+').replaceAll(/_/g, '/'))); + +const extractTokenPayload = (token: string) => { + try { + if (!token) { + return null; } - return null; + if (countLetter(token, '.') === 2) { + return parseJwt(token.split('.')[1]); + } else { + return null; + } + } catch (e) { + console.warn(e); + } + return null; }; -const countLetter = (str, find) => { - return (str.split(find)).length - 1; +const countLetter = (str: string, find) => { + return str.split(find).length - 1; }; export type Tokens = { - refreshToken: string; - idTokenPayload:any; - idToken:string; - accessTokenPayload:any; - accessToken:string; - expiresAt: number; - issuedAt: number; + refreshToken: string; + idTokenPayload: any; + idToken: string; + accessTokenPayload: any; + accessToken: string; + expiresAt: number; + issuedAt: number; }; export type TokenRenewModeType = { - access_token_or_id_token_invalid: string; - access_token_invalid:string; - id_token_invalid: string; -} + access_token_or_id_token_invalid: string; + access_token_invalid: string; + id_token_invalid: string; +}; export const TokenRenewMode = { - access_token_or_id_token_invalid: 'access_token_or_id_token_invalid', - access_token_invalid: 'access_token_invalid', - id_token_invalid: 'id_token_invalid', + access_token_or_id_token_invalid: 'access_token_or_id_token_invalid', + access_token_invalid: 'access_token_invalid', + id_token_invalid: 'id_token_invalid', }; -export const setTokens = (tokens, oldTokens = null, tokenRenewMode: string):Tokens => { - if (!tokens) { - return null; +function extractedIssueAt(tokens, accessTokenPayload, _idTokenPayload) { + if (!tokens.issuedAt) { + if (accessTokenPayload && accessTokenPayload.iat) { + return accessTokenPayload.iat; + } else if (_idTokenPayload && _idTokenPayload.iat) { + return _idTokenPayload.iat; + } else { + const currentTimeUnixSecond = new Date().getTime() / 1000; + return currentTimeUnixSecond; } - let accessTokenPayload; + } else if (typeof tokens.issuedAt == 'string') { + return parseInt(tokens.issuedAt, 10); + } + return tokens.issuedAt; +} - if (!tokens.issuedAt) { - const currentTimeUnixSecond = new Date().getTime() / 1000; - tokens.issuedAt = currentTimeUnixSecond; - } +export const setTokens = (tokens, oldTokens = null, tokenRenewMode: string): Tokens => { + if (!tokens) { + return null; + } + let accessTokenPayload; + const expireIn = + typeof tokens.expiresIn == 'string' ? parseInt(tokens.expiresIn, 10) : tokens.expiresIn; - if (tokens.accessTokenPayload !== undefined) { - accessTokenPayload = tokens.accessTokenPayload; - } else { - accessTokenPayload = extractTokenPayload(tokens.accessToken); - } - const _idTokenPayload = tokens.idTokenPayload ? tokens.idTokenPayload : extractTokenPayload(tokens.idToken); + if (tokens.accessTokenPayload !== undefined) { + accessTokenPayload = tokens.accessTokenPayload; + } else { + accessTokenPayload = extractTokenPayload(tokens.accessToken); + } + + // When id_token is not rotated we reuse old id_token + let idToken: string; + if (oldTokens != null && 'idToken' in oldTokens && !('idToken' in tokens)) { + idToken = oldTokens.idToken; + } else { + idToken = tokens.idToken; + } - const idTokenExpireAt = (_idTokenPayload && _idTokenPayload.exp) ? _idTokenPayload.exp : Number.MAX_VALUE; - const accessTokenExpiresAt = (accessTokenPayload && accessTokenPayload.exp) ? accessTokenPayload.exp : tokens.issuedAt + tokens.expiresIn; + const _idTokenPayload = tokens.idTokenPayload + ? tokens.idTokenPayload + : extractTokenPayload(idToken); - let expiresAt; + const idTokenExpireAt = + _idTokenPayload && _idTokenPayload.exp ? _idTokenPayload.exp : Number.MAX_VALUE; + const accessTokenExpiresAt = + accessTokenPayload && accessTokenPayload.exp + ? accessTokenPayload.exp + : tokens.issuedAt + expireIn; + tokens.issuedAt = extractedIssueAt(tokens, accessTokenPayload, _idTokenPayload); + + let expiresAt; + if (tokens.expiresAt) { + expiresAt = tokens.expiresAt; + } else { if (tokenRenewMode === TokenRenewMode.access_token_invalid) { - expiresAt = accessTokenExpiresAt; + expiresAt = accessTokenExpiresAt; } else if (tokenRenewMode === TokenRenewMode.id_token_invalid) { - expiresAt = idTokenExpireAt; + expiresAt = idTokenExpireAt; } else { - expiresAt = idTokenExpireAt < accessTokenExpiresAt ? idTokenExpireAt : accessTokenExpiresAt; + expiresAt = idTokenExpireAt < accessTokenExpiresAt ? idTokenExpireAt : accessTokenExpiresAt; } + } - const newTokens = { ...tokens, idTokenPayload: _idTokenPayload, accessTokenPayload, expiresAt }; - // When refresh_token is not rotated we reuse ald refresh_token - if (oldTokens != null && 'refreshToken' in oldTokens && !('refreshToken' in tokens)) { - const refreshToken = oldTokens.refreshToken; - return { ...newTokens, refreshToken }; - } + const newTokens = { + ...tokens, + idTokenPayload: _idTokenPayload, + accessTokenPayload, + expiresAt, + idToken, + }; + // When refresh_token is not rotated we reuse old refresh_token + if (oldTokens != null && 'refreshToken' in oldTokens && !('refreshToken' in tokens)) { + const refreshToken = oldTokens.refreshToken; + return { ...newTokens, refreshToken }; + } - return newTokens; + return newTokens; }; export const parseOriginalTokens = (tokens, oldTokens, tokenRenewMode: string) => { - if (!tokens) { - return null; - } - if (!tokens.issued_at) { - const currentTimeUnixSecond = new Date().getTime() / 1000; - tokens.issued_at = currentTimeUnixSecond; - } + if (!tokens) { + return null; + } + if (!tokens.issued_at) { + const currentTimeUnixSecond = new Date().getTime() / 1000; + tokens.issued_at = currentTimeUnixSecond; + } - const data = { - accessToken: tokens.access_token, - expiresIn: tokens.expires_in, - idToken: tokens.id_token, - scope: tokens.scope, - tokenType: tokens.token_type, - issuedAt: tokens.issued_at, - }; - - if ('refresh_token' in tokens) { - // @ts-ignore - data.refreshToken = tokens.refresh_token; - } + const data = { + accessToken: tokens.access_token, + expiresIn: tokens.expires_in, + idToken: tokens.id_token, + scope: tokens.scope, + tokenType: tokens.token_type, + issuedAt: tokens.issued_at, + }; - if (tokens.accessTokenPayload !== undefined) { - // @ts-ignore - data.accessTokenPayload = tokens.accessTokenPayload; - } + if ('refresh_token' in tokens) { + // @ts-ignore + data.refreshToken = tokens.refresh_token; + } - if (tokens.idTokenPayload !== undefined) { - // @ts-ignore - data.idTokenPayload = tokens.idTokenPayload; - } + if (tokens.accessTokenPayload !== undefined) { + // @ts-ignore + data.accessTokenPayload = tokens.accessTokenPayload; + } + + if (tokens.idTokenPayload !== undefined) { + // @ts-ignore + data.idTokenPayload = tokens.idTokenPayload; + } - return setTokens(data, oldTokens, tokenRenewMode); + return setTokens(data, oldTokens, tokenRenewMode); }; -export const computeTimeLeft = (refreshTimeBeforeTokensExpirationInSecond, expiresAt) => { - const currentTimeUnixSecond = new Date().getTime() / 1000; - return Math.round(((expiresAt - refreshTimeBeforeTokensExpirationInSecond) - currentTimeUnixSecond)); +export const computeTimeLeft = ( + refreshTimeBeforeTokensExpirationInSecond: number, + expiresAt: number, +) => { + const currentTimeUnixSecond = new Date().getTime() / 1000; + + const timeLeftSecond = expiresAt - currentTimeUnixSecond; + + return Math.round(timeLeftSecond - refreshTimeBeforeTokensExpirationInSecond); }; -export const isTokensValid = (tokens) => { - if (!tokens) { - return false; - } - return computeTimeLeft(0, tokens.expiresAt) > 0; +export const isTokensValid = (tokens, refreshTimeBeforeTokensExpirationInSecond: number = 0) => { + if (!tokens) { + return false; + } + return computeTimeLeft(refreshTimeBeforeTokensExpirationInSecond, tokens.expiresAt) > 0; }; export type ValidToken = { - isTokensValid: boolean; - tokens: Tokens; - numberWaited: number; -} + isTokensValid: boolean; + tokens: Tokens; + numberWaited: number; +}; -export interface OidcToken{ - tokens?: Tokens; +export interface OidcToken { + getTokens: () => Tokens | null; + syncTokensInfoAsync: () => Promise; + configuration: { + token_automatic_renew_mode?: TokenAutomaticRenewMode; + refresh_time_before_tokens_expiration_in_second?: number; + }; + renewTokensAsync: (extras: StringMap) => Promise; } -export const getValidTokenAsync = async (oidc: OidcToken, waitMs = 200, numberWait = 50): Promise => { - let numberWaitTemp = numberWait; - if (!oidc.tokens) { - return null; - } - while (!isTokensValid(oidc.tokens) && numberWaitTemp > 0) { - await sleepAsync(waitMs); - numberWaitTemp = numberWaitTemp - 1; +export const getValidTokenAsync = async ( + oidc: OidcToken, + waitMs = 200, + numberWait = 50, +): Promise => { + let numberWaitTemp = numberWait; + + let status = await oidc.syncTokensInfoAsync(); + while ( + [ + synchroniseTokensStatus.REQUIRE_SYNC_TOKENS, + synchroniseTokensStatus.TOKEN_UPDATED_BY_ANOTHER_TAB_TOKENS_INVALID, + synchroniseTokensStatus.TOKENS_INVALID, + ].includes(status) && + numberWaitTemp > 0 + ) { + if ( + oidc.configuration.token_automatic_renew_mode == + TokenAutomaticRenewMode.AutomaticOnlyWhenFetchExecuted + ) { + await oidc.renewTokensAsync({}); + break; + } else { + await sleepAsync({ milliseconds: waitMs }); } - const isValid = isTokensValid(oidc.tokens); - return { - isTokensValid: isValid, - tokens: oidc.tokens, - numberWaited: numberWaitTemp - numberWait, - }; + numberWaitTemp = numberWaitTemp - 1; + + status = await oidc.syncTokensInfoAsync(); + } + const isValid = isTokensValid(oidc.getTokens()); + return { + isTokensValid: isValid, + tokens: oidc.getTokens(), + numberWaited: numberWaitTemp - numberWait, + }; }; // https://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation (excluding rules #1, #4, #5, #7, #8, #12, and #13 which did not apply). // https://github.com/openid/AppAuth-JS/issues/65 export const isTokensOidcValid = (tokens, nonce, oidcServerConfiguration) => { - if (tokens.idTokenPayload) { - const idTokenPayload = tokens.idTokenPayload; - // 2: The Issuer Identifier for the OpenID Provider (which is typically obtained during Discovery) MUST exactly match the value of the iss (issuer) Claim. - if (oidcServerConfiguration.issuer !== idTokenPayload.iss) { - return { isValid: false, reason: 'Issuer does not match' }; - } - // 3: The Client MUST validate that the aud (audience) Claim contains its client_id value registered at the Issuer identified by the iss (issuer) Claim as an audience. The aud (audience) Claim MAY contain an array with more than one element. The ID Token MUST be rejected if the ID Token does not list the Client as a valid audience, or if it contains additional audiences not trusted by the Client. - - // 6: If the ID Token is received via direct communication between the Client and the Token Endpoint (which it is in this flow), the TLS server validation MAY be used to validate the issuer in place of checking the token signature. The Client MUST validate the signature of all other ID Tokens according to JWS [JWS] using the algorithm specified in the JWT alg Header Parameter. The Client MUST use the keys provided by the Issuer. - - // 9: The current time MUST be before the time represented by the exp Claim. - const currentTimeUnixSecond = new Date().getTime() / 1000; - if (idTokenPayload.exp && idTokenPayload.exp < currentTimeUnixSecond) { - return { isValid: false, reason: 'Token expired' }; - } - // 10: The iat Claim can be used to reject tokens that were issued too far away from the current time, limiting the amount of time that nonces need to be stored to prevent attacks. The acceptable range is Client specific. - const timeInSevenDays = 60 * 60 * 24 * 7; - if (idTokenPayload.iat && (idTokenPayload.iat + timeInSevenDays) < currentTimeUnixSecond) { - return { isValid: false, reason: 'Token is used from too long time' }; - } - // 11: If a nonce value was sent in the Authentication Request, a nonce Claim MUST be present and its value checked to verify that it is the same value as the one that was sent in the Authentication Request. The Client SHOULD check the nonce value for replay attacks. The precise method for detecting replay attacks is Client specific. - if (idTokenPayload.nonce && idTokenPayload.nonce !== nonce) { - return { isValid: false, reason: 'Nonce does not match' }; - } + if (tokens.idTokenPayload) { + const idTokenPayload = tokens.idTokenPayload; + // 2: The Issuer Identifier for the OpenID Provider (which is typically obtained during Discovery) MUST exactly match the value of the iss (issuer) Claim. + if (oidcServerConfiguration.issuer !== idTokenPayload.iss) { + return { + isValid: false, + reason: `Issuer does not match (oidcServerConfiguration issuer) ${oidcServerConfiguration.issuer} !== (idTokenPayload issuer) ${idTokenPayload.iss}`, + }; + } + // 3: The Client MUST validate that the aud (audience) Claim contains its client_id value registered at the Issuer identified by the iss (issuer) Claim as an audience. The aud (audience) Claim MAY contain an array with more than one element. The ID Token MUST be rejected if the ID Token does not list the Client as a valid audience, or if it contains additional audiences not trusted by the Client. + + // 6: If the ID Token is received via direct communication between the Client and the Token Endpoint (which it is in this flow), the TLS server validation MAY be used to validate the issuer in place of checking the token signature. The Client MUST validate the signature of all other ID Tokens according to JWS [JWS] using the algorithm specified in the JWT alg Header Parameter. The Client MUST use the keys provided by the Issuer. + + // 9: The current time MUST be before the time represented by the exp Claim. + const currentTimeUnixSecond = new Date().getTime() / 1000; + if (idTokenPayload.exp && idTokenPayload.exp < currentTimeUnixSecond) { + return { + isValid: false, + reason: `Token expired (idTokenPayload exp) ${idTokenPayload.exp} < (currentTimeUnixSecond) ${currentTimeUnixSecond}`, + }; + } + // 10: The iat Claim can be used to reject tokens that were issued too far away from the current time, limiting the amount of time that nonces need to be stored to prevent attacks. The acceptable range is Client specific. + const timeInSevenDays = 60 * 60 * 24 * 7; + if (idTokenPayload.iat && idTokenPayload.iat + timeInSevenDays < currentTimeUnixSecond) { + return { + isValid: false, + reason: `Token is used from too long time (idTokenPayload iat + timeInSevenDays) ${idTokenPayload.iat + timeInSevenDays} < (currentTimeUnixSecond) ${currentTimeUnixSecond}`, + }; + } + // 11: If a nonce value was sent in the Authentication Request, a nonce Claim MUST be present and its value checked to verify that it is the same value as the one that was sent in the Authentication Request. The Client SHOULD check the nonce value for replay attacks. The precise method for detecting replay attacks is Client specific. + if (idTokenPayload.nonce && idTokenPayload.nonce !== nonce) { + return { + isValid: false, + reason: `Nonce does not match (idTokenPayload nonce) ${idTokenPayload.nonce} !== (nonce) ${nonce}`, + }; } - return { isValid: true, reason: '' }; + } + return { isValid: true, reason: '' }; }; diff --git a/packages/oidc-client/src/renewTokens.ts b/packages/oidc-client/src/renewTokens.ts index a0e23d0c4..4e296e102 100644 --- a/packages/oidc-client/src/renewTokens.ts +++ b/packages/oidc-client/src/renewTokens.ts @@ -1,37 +1,516 @@ +import { eventNames } from './events'; import { initSession } from './initSession.js'; -import { initWorkerAsync } from './initWorker.js'; +import { initWorkerAsync, sleepAsync } from './initWorker.js'; import Oidc from './oidc.js'; -import { computeTimeLeft } from './parseTokens.js'; +import { computeTimeLeft, isTokensOidcValid, setTokens, Tokens } from './parseTokens.js'; +import { performTokenRequestAsync } from './requests'; +import { _silentLoginAsync } from './silentLogin'; import timer from './timer.js'; -import { StringMap } from './types.js'; +import { OidcConfiguration, StringMap, TokenAutomaticRenewMode } from './types.js'; -export async function renewTokensAndStartTimerAsync(oidc, refreshToken, forceRefresh = false, extras:StringMap = null) { - const updateTokens = (tokens) => { oidc.tokens = tokens; }; - const { tokens, status } = await oidc.synchroniseTokensAsync(refreshToken, 0, forceRefresh, extras, updateTokens); +async function syncTokens( + oidc: Oidc, + forceRefresh: boolean, + extras: StringMap, + scope: string = null, +) { + const updateTokens = tokens => { + oidc.tokens = tokens; + }; + const { tokens, status } = await synchroniseTokensAsync(oidc)( + updateTokens, + 0, + 0, + forceRefresh, + extras, + scope, + ); - const serviceWorker = await initWorkerAsync(oidc.configuration.service_worker_relative_url, oidc.configurationName); - if (!serviceWorker) { - const session = initSession(oidc.configurationName, oidc.configuration.storage); - await session.setTokens(oidc.tokens); - } + const serviceWorker = await initWorkerAsync(oidc.configuration, oidc.configurationName); + if (!serviceWorker) { + const session = initSession(oidc.configurationName, oidc.configuration.storage); + session.setTokens(oidc.tokens); + } - if (!oidc.tokens) { - await oidc.destroyAsync(status); - return; - } + if (!oidc.tokens) { + await oidc.destroyAsync(status); + return null; + } + return tokens; +} - if (oidc.timeoutId) { - oidc.timeoutId = autoRenewTokens(oidc, tokens.refreshToken, oidc.tokens.expiresAt, extras); +export async function renewTokensAndStartTimerAsync( + oidc, + forceRefresh = false, + extras: StringMap = null, + scope: string = null, +) { + const configuration = oidc.configuration; + const lockResourcesName = `${configuration.client_id}_${oidc.configurationName}_${configuration.authority}`; + + let tokens: null; + const serviceWorker = await initWorkerAsync(oidc.configuration, oidc.configurationName); + if ((configuration?.storage === window?.sessionStorage && !serviceWorker) || !navigator.locks) { + tokens = await syncTokens(oidc, forceRefresh, extras, scope); + } else { + let status: any = 'retry'; + while (status === 'retry') { + status = await navigator.locks.request( + lockResourcesName, + { ifAvailable: true }, + async lock => { + if (!lock) { + oidc.publishEvent(Oidc.eventNames.syncTokensAsync_lock_not_available, { + lock: 'lock not available', + }); + return 'retry'; + } + return await syncTokens(oidc, forceRefresh, extras, scope); + }, + ); } - return oidc.tokens; + tokens = status; + } + + if (!tokens) { + return null; + } + + if (oidc.timeoutId) { + // @ts-ignore + oidc.timeoutId = autoRenewTokens(oidc, oidc.tokens.expiresAt, extras, scope); + } + + return oidc.tokens; } -export const autoRenewTokens = (oidc, refreshToken, expiresAt, extras:StringMap = null) => { - const refreshTimeBeforeTokensExpirationInSecond = oidc.configuration.refresh_time_before_tokens_expiration_in_second; - return timer.setTimeout(async () => { - const timeLeft = computeTimeLeft(refreshTimeBeforeTokensExpirationInSecond, expiresAt); - const timeInfo = { timeLeft }; - oidc.publishEvent(Oidc.eventNames.token_timer, timeInfo); - await renewTokensAndStartTimerAsync(oidc, refreshToken, false, extras); - }, 1000); +export const autoRenewTokens = ( + oidc: Oidc, + expiresAt, + extras: StringMap = null, + scope: string = null, +) => { + const refreshTimeBeforeTokensExpirationInSecond = + oidc.configuration.refresh_time_before_tokens_expiration_in_second; + if (oidc.timeoutId) { + timer.clearTimeout(oidc.timeoutId); + } + return timer.setTimeout(async () => { + const timeLeft = computeTimeLeft(refreshTimeBeforeTokensExpirationInSecond, expiresAt); + const timeInfo = { timeLeft }; + oidc.publishEvent(Oidc.eventNames.token_timer, timeInfo); + await renewTokensAndStartTimerAsync(oidc, false, extras, scope); + }, 1000); }; + +export const synchroniseTokensStatus = { + FORCE_REFRESH: 'FORCE_REFRESH', + SESSION_LOST: 'SESSION_LOST', + NOT_CONNECTED: 'NOT_CONNECTED', + TOKENS_VALID: 'TOKENS_VALID', + TOKEN_UPDATED_BY_ANOTHER_TAB_TOKENS_VALID: 'TOKEN_UPDATED_BY_ANOTHER_TAB_TOKENS_VALID', + TOKEN_UPDATED_BY_ANOTHER_TAB_TOKENS_INVALID: 'TOKEN_UPDATED_BY_ANOTHER_TAB_TOKENS_INVALID', + LOGOUT_FROM_ANOTHER_TAB: 'LOGOUT_FROM_ANOTHER_TAB', + REQUIRE_SYNC_TOKENS: 'REQUIRE_SYNC_TOKENS', + TOKENS_INVALID: 'TOKENS_INVALID', +}; + +export const syncTokensInfoAsync = + (oidc: Oidc) => + async ( + configuration: OidcConfiguration, + configurationName: string, + currentTokens: Tokens, + forceRefresh = false, + ) => { + // Service Worker can be killed by the browser (when it wants,for example after 10 seconds of inactivity, so we retreieve the session if it happen) + // const configuration = this.configuration; + const nullNonce = { nonce: null }; + if (!currentTokens) { + return { tokens: null, status: synchroniseTokensStatus.NOT_CONNECTED, nonce: nullNonce }; + } + let nonce = nullNonce; + const oidcServerConfiguration = await oidc.initAsync( + configuration.authority, + configuration.authority_configuration, + ); + const serviceWorker = await initWorkerAsync(configuration, configurationName); + if (serviceWorker) { + const { status, tokens } = await serviceWorker.initAsync( + oidcServerConfiguration, + 'syncTokensAsync', + configuration, + ); + if (status === 'LOGGED_OUT') { + return { + tokens: null, + status: synchroniseTokensStatus.LOGOUT_FROM_ANOTHER_TAB, + nonce: nullNonce, + }; + } else if (status === 'SESSIONS_LOST') { + return { tokens: null, status: synchroniseTokensStatus.SESSION_LOST, nonce: nullNonce }; + } else if (!status || !tokens) { + return { + tokens: null, + status: synchroniseTokensStatus.REQUIRE_SYNC_TOKENS, + nonce: nullNonce, + }; + } else if (tokens.issuedAt !== currentTokens.issuedAt) { + const timeLeft = computeTimeLeft( + configuration.refresh_time_before_tokens_expiration_in_second, + tokens.expiresAt, + ); + const status = + timeLeft > 0 + ? synchroniseTokensStatus.TOKEN_UPDATED_BY_ANOTHER_TAB_TOKENS_VALID + : synchroniseTokensStatus.TOKEN_UPDATED_BY_ANOTHER_TAB_TOKENS_INVALID; + const nonce = await serviceWorker.getNonceAsync(); + return { tokens, status, nonce }; + } + nonce = await serviceWorker.getNonceAsync(); + } else { + const session = initSession(configurationName, configuration.storage ?? sessionStorage); + const initAsyncResponse = await session.initAsync(); + let { tokens } = initAsyncResponse; + const { status } = initAsyncResponse; + if (tokens) { + tokens = setTokens(tokens, oidc.tokens, configuration.token_renew_mode); + } + if (!tokens) { + return { + tokens: null, + status: synchroniseTokensStatus.LOGOUT_FROM_ANOTHER_TAB, + nonce: nullNonce, + }; + } else if (status === 'SESSIONS_LOST') { + return { tokens: null, status: synchroniseTokensStatus.SESSION_LOST, nonce: nullNonce }; + } else if (tokens.issuedAt !== currentTokens.issuedAt) { + const timeLeft = computeTimeLeft( + configuration.refresh_time_before_tokens_expiration_in_second, + tokens.expiresAt, + ); + const status = + timeLeft > 0 + ? synchroniseTokensStatus.TOKEN_UPDATED_BY_ANOTHER_TAB_TOKENS_VALID + : synchroniseTokensStatus.TOKEN_UPDATED_BY_ANOTHER_TAB_TOKENS_INVALID; + const nonce = await session.getNonceAsync(); + return { tokens, status, nonce }; + } + nonce = await session.getNonceAsync(); + } + + const timeLeft = computeTimeLeft( + configuration.refresh_time_before_tokens_expiration_in_second, + currentTokens.expiresAt, + ); + const status = timeLeft > 0 ? 'TOKENS_VALID' : 'TOKENS_INVALID'; + if (forceRefresh) { + return { tokens: currentTokens, status: 'FORCE_REFRESH', nonce }; + } + return { tokens: currentTokens, status, nonce }; + }; + +const synchroniseTokensAsync = + (oidc: Oidc) => + async ( + updateTokens, + tryNumber = 0, + backgroundTry = 0, + forceRefresh = false, + extras: StringMap = null, + scope: string = null, + ) => { + if (!navigator.onLine && document.hidden) { + return { tokens: oidc.tokens, status: 'GIVE_UP' }; + } + let numberTryOnline = 6; + const maxTries = forceRefresh ? 2 : 5; + const maxBackgroundTries = 5; + + while (!navigator.onLine && numberTryOnline > 0) { + await sleepAsync({ milliseconds: 1000 }); + numberTryOnline--; + oidc.publishEvent(eventNames.refreshTokensAsync, { + message: `wait because navigator is offline try ${numberTryOnline}`, + }); + } + const isDocumentHidden = document.hidden; + const nextTry = isDocumentHidden ? tryNumber : tryNumber + 1; + const nextBackgroundTry = isDocumentHidden ? backgroundTry + 1 : backgroundTry; + + if (tryNumber >= maxTries || backgroundTry >= maxBackgroundTries) { + updateTokens(null); + oidc.publishEvent(eventNames.refreshTokensAsync_error, { message: 'refresh token' }); + return { tokens: null, status: 'SESSION_LOST' }; + } + + if (!extras) { + extras = {}; + } + const configuration = oidc.configuration; + + const silentLoginAsync = (extras: StringMap, state: string = null, scope: string = null) => { + return _silentLoginAsync( + oidc.configurationName, + oidc.configuration, + oidc.publishEvent.bind(oidc), + )(extras, state, scope); + }; + const localSilentLoginAsync = async () => { + try { + let loginParams; + const serviceWorker = await initWorkerAsync(configuration, oidc.configurationName); + if (serviceWorker) { + loginParams = serviceWorker.getLoginParams(); + } else { + const session = initSession(oidc.configurationName, configuration.storage); + loginParams = session.getLoginParams(); + } + const silentLoginInput = {}; + + if (loginParams && loginParams.extras) { + for (const [key, value] of Object.entries(loginParams.extras)) { + silentLoginInput[key] = value; + } + } + if (extras) { + for (const [key, value] of Object.entries(extras)) { + silentLoginInput[key] = value; + } + } + silentLoginInput['prompt'] = 'none'; + if (scope) { + silentLoginInput['scope'] = scope; + } + + const silent_token_response = await silentLoginAsync(silentLoginInput); + if (!silent_token_response) { + updateTokens(null); + oidc.publishEvent(eventNames.refreshTokensAsync_error, { + message: 'refresh token silent not active', + }); + return { tokens: null, status: 'SESSION_LOST' }; + } + if (silent_token_response.error) { + updateTokens(null); + oidc.publishEvent(eventNames.refreshTokensAsync_error, { + message: 'refresh token silent', + }); + return { tokens: null, status: 'SESSION_LOST' }; + } + + updateTokens(silent_token_response.tokens); + oidc.publishEvent(Oidc.eventNames.token_renewed, {}); + return { tokens: silent_token_response.tokens, status: 'LOGGED' }; + } catch (exceptionSilent: any) { + console.error(exceptionSilent); + oidc.publishEvent(eventNames.refreshTokensAsync_silent_error, { + message: 'exceptionSilent', + exception: exceptionSilent.message, + }); + return await synchroniseTokensAsync(oidc)( + updateTokens, + nextTry, + nextBackgroundTry, + forceRefresh, + extras, + scope, + ); + } + }; + + try { + const { status, tokens, nonce } = await syncTokensInfoAsync(oidc)( + configuration, + oidc.configurationName, + oidc.tokens, + forceRefresh, + ); + + switch (status) { + case synchroniseTokensStatus.SESSION_LOST: + updateTokens(null); + oidc.publishEvent(eventNames.refreshTokensAsync_error, { + message: 'refresh token session lost', + }); + return { tokens: null, status: 'SESSION_LOST' }; + case synchroniseTokensStatus.NOT_CONNECTED: + updateTokens(null); + return { tokens: null, status: null }; + case synchroniseTokensStatus.TOKENS_VALID: + updateTokens(tokens); + return { tokens, status: 'LOGGED_IN' }; + case synchroniseTokensStatus.TOKEN_UPDATED_BY_ANOTHER_TAB_TOKENS_VALID: + updateTokens(tokens); + oidc.publishEvent(Oidc.eventNames.token_renewed, { + reason: 'TOKEN_UPDATED_BY_ANOTHER_TAB_TOKENS_VALID', + }); + return { tokens, status: 'LOGGED_IN' }; + case synchroniseTokensStatus.LOGOUT_FROM_ANOTHER_TAB: + updateTokens(null); + oidc.publishEvent(eventNames.logout_from_another_tab, { + status: 'session syncTokensAsync', + }); + return { tokens: null, status: 'LOGGED_OUT' }; + case synchroniseTokensStatus.REQUIRE_SYNC_TOKENS: + if ( + configuration.token_automatic_renew_mode == + TokenAutomaticRenewMode.AutomaticOnlyWhenFetchExecuted && + !forceRefresh + ) { + oidc.publishEvent(eventNames.tokensInvalidAndWaitingActionsToRefresh, {}); + return { tokens: oidc.tokens, status: 'GIVE_UP' }; + } + + oidc.publishEvent(eventNames.refreshTokensAsync_begin, { tryNumber: tryNumber }); + return await localSilentLoginAsync(); + default: { + if ( + configuration.token_automatic_renew_mode == + TokenAutomaticRenewMode.AutomaticOnlyWhenFetchExecuted && + synchroniseTokensStatus.FORCE_REFRESH !== status + ) { + oidc.publishEvent(eventNames.tokensInvalidAndWaitingActionsToRefresh, {}); + return { tokens: oidc.tokens, status: 'GIVE_UP' }; + } + + oidc.publishEvent(eventNames.refreshTokensAsync_begin, { + refreshToken: tokens.refreshToken, + status, + tryNumber: tryNumber, + backgroundTry: backgroundTry, + }); + + if (!tokens.refreshToken) { + return await localSilentLoginAsync(); + } + + const clientId = configuration.client_id; + const redirectUri = configuration.redirect_uri; + const authority = configuration.authority; + const tokenExtras = configuration.token_request_extras + ? configuration.token_request_extras + : {}; + const finalExtras = { ...tokenExtras }; + + for (const [key, value] of Object.entries(extras)) { + if (key.endsWith(':token_request')) { + finalExtras[key.replace(':token_request', '')] = value; + } + } + const localFunctionAsync = async () => { + const details = { + client_id: clientId, + redirect_uri: redirectUri, + grant_type: 'refresh_token', + refresh_token: tokens.refreshToken, + }; + const oidcServerConfiguration = await oidc.initAsync( + authority, + configuration.authority_configuration, + ); + const timeoutMs = document.hidden ? 10000 : 30000 * 10; + const url = oidcServerConfiguration.tokenEndpoint; + const headersExtras = {}; + if (configuration.demonstrating_proof_of_possession) { + headersExtras['DPoP'] = await oidc.generateDemonstrationOfProofOfPossessionAsync( + tokens.accessToken, + url, + 'POST', + ); + } + const tokenResponse = await performTokenRequestAsync(oidc.getFetch())( + url, + details, + finalExtras, + tokens, + headersExtras, + configuration.token_renew_mode, + timeoutMs, + ); + + if (tokenResponse.success) { + const { isValid, reason } = isTokensOidcValid( + tokenResponse.data, + nonce.nonce, + oidcServerConfiguration, + ); + if (!isValid) { + updateTokens(null); + oidc.publishEvent(eventNames.refreshTokensAsync_error, { + message: `refresh token return not valid tokens, reason: ${reason}`, + }); + return { tokens: null, status: 'SESSION_LOST' }; + } + updateTokens(tokenResponse.data); + if (tokenResponse.demonstratingProofOfPossessionNonce) { + const serviceWorker = await initWorkerAsync(configuration, oidc.configurationName); + if (serviceWorker) { + await serviceWorker.setDemonstratingProofOfPossessionNonce( + tokenResponse.demonstratingProofOfPossessionNonce, + ); + } else { + const session = initSession(oidc.configurationName, configuration.storage); + await session.setDemonstratingProofOfPossessionNonce( + tokenResponse.demonstratingProofOfPossessionNonce, + ); + } + } + oidc.publishEvent(eventNames.refreshTokensAsync_end, { + success: tokenResponse.success, + }); + oidc.publishEvent(Oidc.eventNames.token_renewed, { reason: 'REFRESH_TOKEN' }); + return { tokens: tokenResponse.data, status: 'LOGGED_IN' }; + } else { + oidc.publishEvent(eventNames.refreshTokensAsync_silent_error, { + message: 'bad request', + tokenResponse, + }); + + if (tokenResponse.status >= 400 && tokenResponse.status < 500) { + updateTokens(null); + oidc.publishEvent(eventNames.refreshTokensAsync_error, { + message: `session lost: ${tokenResponse.status}`, + }); + return { tokens: null, status: 'SESSION_LOST' }; + } + + return await synchroniseTokensAsync(oidc)( + updateTokens, + nextTry, + nextBackgroundTry, + forceRefresh, + extras, + scope, + ); + } + }; + return await localFunctionAsync(); + } + } + } catch (exception: any) { + console.error(exception); + + oidc.publishEvent(eventNames.refreshTokensAsync_silent_error, { + message: 'exception', + exception: exception.message, + }); + // we need to break the loop or errors, as direct call of synchroniseTokensAsync + // inside of synchroniseTokensAsync will cause an infinite loop and kill the browser stack + // so we need to brake calls chain and delay next call + return new Promise((resolve, reject) => { + setTimeout(() => { + synchroniseTokensAsync(oidc)( + updateTokens, + nextTry, + nextBackgroundTry, + forceRefresh, + extras, + scope, + ) + .then(resolve) + .catch(reject); + }, 1000); + }); + } + }; diff --git a/packages/oidc-client/src/requests.spec.ts b/packages/oidc-client/src/requests.spec.ts index 7d3271d7d..32c7f879d 100644 --- a/packages/oidc-client/src/requests.spec.ts +++ b/packages/oidc-client/src/requests.spec.ts @@ -1,9 +1,7 @@ - -import { describe, it, expect } from 'vitest'; - +import { describe, expect, it } from 'vitest'; describe('Requests test Suite', () => { - it('performAuthorizationRequestAsync', async () => { - expect(true).toBe(true); - }); -}); \ No newline at end of file + it('performAuthorizationRequestAsync', async () => { + expect(true).toBe(true); + }); +}); diff --git a/packages/oidc-client/src/requests.ts b/packages/oidc-client/src/requests.ts index 7bf644f00..8c61f47cb 100644 --- a/packages/oidc-client/src/requests.ts +++ b/packages/oidc-client/src/requests.ts @@ -1,121 +1,183 @@ import { getFromCache, setCache } from './cache.js'; import { deriveChallengeAsync, generateRandom } from './crypto.js'; +import { ILOidcLocation } from './location'; import { OidcAuthorizationServiceConfiguration } from './oidc.js'; import { parseOriginalTokens } from './parseTokens.js'; import { Fetch, StringMap } from './types.js'; const oneHourSecond = 60 * 60; -export const fetchFromIssuer = (fetch) => async (openIdIssuerUrl: string, timeCacheSecond = oneHourSecond, storage = window.sessionStorage, timeoutMs = 10000): - Promise => { +export const fetchFromIssuer = + fetch => + async ( + openIdIssuerUrl: string, + timeCacheSecond = oneHourSecond, + storage = window.sessionStorage, + timeoutMs = 10000, + ): Promise => { const fullUrl = `${openIdIssuerUrl}/.well-known/openid-configuration`; const localStorageKey = `oidc.server:${openIdIssuerUrl}`; const data = getFromCache(localStorageKey, storage, timeCacheSecond); if (data) { - return new OidcAuthorizationServiceConfiguration(data); + return new OidcAuthorizationServiceConfiguration(data); } const response = await internalFetch(fetch)(fullUrl, {}, timeoutMs); if (response.status !== 200) { - return null; + return null; } const result = await response.json(); setCache(localStorageKey, result, storage); return new OidcAuthorizationServiceConfiguration(result); -}; + }; -const internalFetch = (fetch) => async (url, headers = {}, timeoutMs = 10000, numberRetry = 0) : Promise => { +const internalFetch = + fetch => + async (url: string, headers = {}, timeoutMs = 10000, numberRetry = 0): Promise => { let response; try { - const controller = new AbortController(); - setTimeout(() => controller.abort(), timeoutMs); - response = await fetch(url, { ...headers, signal: controller.signal }); + const controller = new AbortController(); + setTimeout(() => controller.abort(), timeoutMs); + response = await fetch(url, { ...headers, signal: controller.signal }); } catch (e: any) { - if (e.name === 'AbortError' || - e.message === 'Network request failed') { - if (numberRetry <= 1) { - return await internalFetch(fetch)(url, headers, timeoutMs, numberRetry + 1); - } else { - throw e; - } + if (e.name === 'AbortError' || e.message === 'Network request failed') { + if (numberRetry <= 1) { + return await internalFetch(fetch)(url, headers, timeoutMs, numberRetry + 1); } else { - console.error(e.message); - throw e; // rethrow other unexpected errors + throw e; } + } else { + console.error(e.message); + throw e; // rethrow other unexpected errors + } } return response; -}; + }; export const TOKEN_TYPE = { - refresh_token: 'refresh_token', - access_token: 'access_token', + refresh_token: 'refresh_token', + access_token: 'access_token', }; -export const performRevocationRequestAsync = (fetch) => async (url, token, token_type = TOKEN_TYPE.refresh_token, client_id, timeoutMs = 10000) => { +export const performRevocationRequestAsync = + fetch => + async ( + url, + token, + token_type = TOKEN_TYPE.refresh_token, + client_id, + extras: StringMap = {}, + timeoutMs = 10000, + ) => { const details = { - token, - token_type_hint: token_type, - client_id, + token, + token_type_hint: token_type, + client_id, }; + for (const [key, value] of Object.entries(extras)) { + if (details[key] === undefined) { + details[key] = value; + } + } const formBody = []; for (const property in details) { - const encodedKey = encodeURIComponent(property); - const encodedValue = encodeURIComponent(details[property]); - formBody.push(`${encodedKey}=${encodedValue}`); + const encodedKey = encodeURIComponent(property); + const encodedValue = encodeURIComponent(details[property]); + formBody.push(`${encodedKey}=${encodedValue}`); } const formBodyString = formBody.join('&'); - const response = await internalFetch(fetch)(url, { + const response = await internalFetch(fetch)( + url, + { method: 'POST', headers: { - 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8', + 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8', }, body: formBodyString, - }, timeoutMs); + }, + timeoutMs, + ); if (response.status !== 200) { - return { success: false }; + return { success: false }; } return { - success: true, + success: true, }; + }; + +type PerformTokenRequestResponse = { + success: boolean; + status?: number; + data?: any; + demonstratingProofOfPossessionNonce?: string; }; -export const performTokenRequestAsync = (fetch:Fetch) => async (url, details, extras, oldTokens, tokenRenewMode: string, timeoutMs = 10000) => { +export const performTokenRequestAsync = + (fetch: Fetch) => + async ( + url: string, + details, + extras, + oldTokens, + headersExtras = {}, + tokenRenewMode: string, + timeoutMs = 10000, + ): Promise => { for (const [key, value] of Object.entries(extras)) { - if (details[key] === undefined) { - details[key] = value; - } + if (details[key] === undefined) { + details[key] = value; + } } const formBody = []; for (const property in details) { - const encodedKey = encodeURIComponent(property); - const encodedValue = encodeURIComponent(details[property]); - formBody.push(`${encodedKey}=${encodedValue}`); + const encodedKey = encodeURIComponent(property); + const encodedValue = encodeURIComponent(details[property]); + formBody.push(`${encodedKey}=${encodedValue}`); } const formBodyString = formBody.join('&'); - const response = await internalFetch(fetch)(url, { + const response = await internalFetch(fetch)( + url, + { method: 'POST', headers: { - 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8', + 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8', + ...headersExtras, }, body: formBodyString, - }, timeoutMs); + }, + timeoutMs, + ); if (response.status !== 200) { - return { success: false, status: response.status }; + return { + success: false, + status: response.status, + demonstratingProofOfPossessionNonce: null, + }; } const tokens = await response.json(); + + let demonstratingProofOfPossessionNonce = null; + if (response.headers.has(demonstratingProofOfPossessionNonceResponseHeader)) { + demonstratingProofOfPossessionNonce = response.headers.get( + demonstratingProofOfPossessionNonceResponseHeader, + ); + } return { - success: true, - data: parseOriginalTokens(tokens, oldTokens, tokenRenewMode), + success: true, + status: response.status, + data: parseOriginalTokens(tokens, oldTokens, tokenRenewMode), + demonstratingProofOfPossessionNonce: demonstratingProofOfPossessionNonce, }; -}; + }; -export const performAuthorizationRequestAsync = (storage: any) => async (url, extras: StringMap) => { +export const performAuthorizationRequestAsync = + (storage: any, oidcLocation: ILOidcLocation) => async (url, extras: StringMap) => { extras = extras ? { ...extras } : {}; const codeVerifier = generateRandom(128); const codeChallenge = await deriveChallengeAsync(codeVerifier); @@ -125,45 +187,60 @@ export const performAuthorizationRequestAsync = (storage: any) => async (url, ex extras.code_challenge_method = 'S256'; let queryString = ''; if (extras) { - for (const [key, value] of Object.entries(extras)) { - if (queryString === '') { - queryString += '?'; - } else { - queryString += '&'; - } - queryString += `${key}=${encodeURIComponent(value)}`; + for (const [key, value] of Object.entries(extras)) { + if (queryString === '') { + queryString += '?'; + } else { + queryString += '&'; } + queryString += `${key}=${encodeURIComponent(value)}`; + } } - window.location.href = `${url}${queryString}`; -}; + oidcLocation.open(`${url}${queryString}`); + }; -export const performFirstTokenRequestAsync = (storage:any) => async (url, extras, tokenRenewMode: string, timeoutMs = 10000) => { - extras = extras ? { ...extras } : {}; - extras.code_verifier = await storage.getCodeVerifierAsync(); +const demonstratingProofOfPossessionNonceResponseHeader = 'DPoP-Nonce'; +export const performFirstTokenRequestAsync = + (storage: any) => + async (url, formBodyExtras, headersExtras, tokenRenewMode: string, timeoutMs = 10000) => { + formBodyExtras = formBodyExtras ? { ...formBodyExtras } : {}; + formBodyExtras.code_verifier = await storage.getCodeVerifierAsync(); const formBody = []; - for (const property in extras) { - const encodedKey = encodeURIComponent(property); - const encodedValue = encodeURIComponent(extras[property]); - formBody.push(`${encodedKey}=${encodedValue}`); + for (const property in formBodyExtras) { + const encodedKey = encodeURIComponent(property); + const encodedValue = encodeURIComponent(formBodyExtras[property]); + formBody.push(`${encodedKey}=${encodedValue}`); } const formBodyString = formBody.join('&'); - const response = await internalFetch(fetch)(url, { + const response = await internalFetch(fetch)( + url, + { method: 'POST', headers: { - 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8', + 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8', + ...headersExtras, }, body: formBodyString, - }, timeoutMs); + }, + timeoutMs, + ); await Promise.all([storage.setCodeVerifierAsync(null), storage.setStateAsync(null)]); if (response.status !== 200) { - return { success: false, status: response.status }; + return { success: false, status: response.status }; + } + let demonstratingProofOfPossessionNonce: string = null; + if (response.headers.has(demonstratingProofOfPossessionNonceResponseHeader)) { + demonstratingProofOfPossessionNonce = response.headers.get( + demonstratingProofOfPossessionNonceResponseHeader, + ); } const tokens = await response.json(); return { - success: true, - data: { - state: extras.state, - tokens: parseOriginalTokens(tokens, null, tokenRenewMode), - }, + success: true, + data: { + state: formBodyExtras.state, + tokens: parseOriginalTokens(tokens, null, tokenRenewMode), + demonstratingProofOfPossessionNonce, + }, }; -}; + }; diff --git a/packages/oidc-client/src/route-utils.spec.ts b/packages/oidc-client/src/route-utils.spec.ts index 30a1dc60a..2f41e3950 100644 --- a/packages/oidc-client/src/route-utils.spec.ts +++ b/packages/oidc-client/src/route-utils.spec.ts @@ -1,23 +1,22 @@ +import { describe, expect, it } from 'vitest'; + import { getPath } from './route-utils'; -import { describe, it, expect } from 'vitest'; describe('Route test Suite', () => { - it.each([['http://example.com/pathname', '/pathname'], - ['http://example.com:3000/pathname/?search=test#hash', '/pathname#hash'], - ['http://example.com:3000/pathname/#hash?search=test', '/pathname#hash'], - ['http://example.com:3000/pathname#hash?search=test', '/pathname#hash'], - ['capacitor://localhost/index.html', '/index.html'], - ['capacitor://localhost/pathname#hash?search=test', '/pathname#hash'], - ['http://example.com:3000/', ''],])( - 'getPath should return the full path of an url', - (uri, expected) => { - - const path = getPath(uri); - expect(path).toBe(expected); - }, - ); + it.each([ + ['http://example.com/pathname', '/pathname'], + ['http://example.com:3000/pathname/?search=test#hash', '/pathname#hash'], + ['http://example.com:3000/pathname/#hash?search=test', '/pathname#hash'], + ['http://example.com:3000/pathname#hash?search=test', '/pathname#hash'], + ['capacitor://localhost/index.html', '/index.html'], + ['capacitor://localhost/pathname#hash?search=test', '/pathname#hash'], + ['http://example.com:3000/', ''], + ])('getPath should return the full path of an url', (uri, expected) => { + const path = getPath(uri); + expect(path).toBe(expected); + }); - it('wrong uri format', () => { - expect(() => getPath("urimybad/toto.com")).toThrowError(); - }); -}); \ No newline at end of file + it('wrong uri format', () => { + expect(() => getPath('urimybad/toto.com')).toThrowError(); + }); +}); diff --git a/packages/oidc-client/src/route-utils.ts b/packages/oidc-client/src/route-utils.ts index 3d8b0a46c..e3d30897a 100644 --- a/packages/oidc-client/src/route-utils.ts +++ b/packages/oidc-client/src/route-utils.ts @@ -1,26 +1,26 @@ export const getLocation = (href: string) => { const match = href.match( // eslint-disable-next-line no-useless-escape - /^([a-z][\w-]+\:)\/\/(([^:\/?#]*)(?:\:([0-9]+))?)([\/]{0,1}[^?#]*)(\?[^#]*|)(#.*|)$/, + /^([a-z][\w-]+\:)\/\/(([^:\/?#]*)(?:\:([0-9]+))?)([\/]{0,1}[^?#]*)(\?[^#]*|)(#.*|)$/, ); if (!match) { - throw new Error('Invalid URL'); + throw new Error('Invalid URL'); } let search = match[6]; let hash = match[7]; - if (hash) { - const splits = hash.split('?'); - if (splits.length === 2) { - hash = splits[0]; - search = splits[1]; - } + if (hash) { + const splits = hash.split('?'); + if (splits.length === 2) { + hash = splits[0]; + search = splits[1]; } + } - if (search.startsWith('?')) { - search = search.slice(1); - } + if (search.startsWith('?')) { + search = search.slice(1); + } return ( match && { @@ -41,12 +41,12 @@ export const getPath = (href: string) => { let { path } = location; if (path.endsWith('/')) { - path = path.slice(0, -1); + path = path.slice(0, -1); } let { hash } = location; if (hash === '#_=_') { - hash = ''; + hash = ''; } if (hash) { @@ -57,23 +57,26 @@ export const getPath = (href: string) => { }; export const getParseQueryStringFromLocation = (href: string) => { - const location = getLocation(href); - const { search } = location; + const location = getLocation(href); + const { search } = location; - return parseQueryString(search); + return parseQueryString(search); }; -const parseQueryString = (queryString:string) => { - const params:any = {}; let temp; let i; let l; +const parseQueryString = (queryString: string) => { + const params: any = {}; + let temp; + let i; + let l; - // Split into key/value pairs - const queries = queryString.split('&'); + // Split into key/value pairs + const queries = queryString.split('&'); - // Convert the array of strings into an object - for (i = 0, l = queries.length; i < l; i++) { - temp = queries[i].split('='); - params[decodeURIComponent(temp[0])] = decodeURIComponent(temp[1]); - } + // Convert the array of strings into an object + for (i = 0, l = queries.length; i < l; i++) { + temp = queries[i].split('='); + params[decodeURIComponent(temp[0])] = decodeURIComponent(temp[1]); + } - return params; + return params; }; diff --git a/packages/oidc-client/src/silentLogin.ts b/packages/oidc-client/src/silentLogin.ts index 70932a974..286bb5f5e 100644 --- a/packages/oidc-client/src/silentLogin.ts +++ b/packages/oidc-client/src/silentLogin.ts @@ -4,141 +4,180 @@ import { autoRenewTokens } from './renewTokens.js'; import timer from './timer.js'; import { OidcConfiguration, StringMap } from './types.js'; export type SilentLoginResponse = { - tokens:Tokens; - sessionState:string; + tokens: Tokens; + sessionState: string; + error: string; }; -// eslint-disable-next-line @typescript-eslint/ban-types -export const _silentLoginAsync = (configurationName:string, configuration:OidcConfiguration, publishEvent:Function) => (extras:StringMap = null, state:string = null, scope:string = null):Promise => { +export type PublishEventFunction = (eventName: string, eventData: any) => void; + +export const _silentLoginAsync = + ( + configurationName: string, + configuration: OidcConfiguration, + publishEvent: PublishEventFunction, + ) => + ( + extras: StringMap = null, + state: string = null, + scope: string = null, + ): Promise => { if (!configuration.silent_redirect_uri || !configuration.silent_login_uri) { - return Promise.resolve(null); + return Promise.resolve(null); } - try { - publishEvent(eventNames.silentLoginAsync_begin, {}); - let queries = ''; + publishEvent(eventNames.silentLoginAsync_begin, {}); + let queries = ''; - if (state) { - if (extras == null) { - extras = {}; - } - extras.state = state; + if (state) { + if (extras == null) { + extras = {}; } + extras.state = state; + } - if (scope) { - if (extras == null) { - extras = {}; - } - extras.scope = scope; + if (scope != null) { + if (extras == null) { + extras = {}; + } + extras.scope = scope; + } + + if (extras != null) { + for (const [key, value] of Object.entries(extras)) { + if (queries === '') { + queries = `?${encodeURIComponent(key)}=${encodeURIComponent(value)}`; + } else { + queries += `&${encodeURIComponent(key)}=${encodeURIComponent(value)}`; + } } + } + const link = configuration.silent_login_uri + queries; + const idx = link.indexOf('/', link.indexOf('//') + 2); + const iFrameOrigin = link.substring(0, idx); + const iframe = document.createElement('iframe'); + iframe.width = '0px'; + iframe.height = '0px'; - if (extras != null) { - for (const [key, value] of Object.entries(extras)) { - if (queries === '') { - queries = `?${encodeURIComponent(key)}=${encodeURIComponent(value)}`; - } else { - queries += `&${encodeURIComponent(key)}=${encodeURIComponent(value)}`; + iframe.id = `${configurationName}_oidc_iframe`; + iframe.setAttribute('src', link); + iframe.style.display = 'none'; + document.body.appendChild(iframe); + return new Promise((resolve, reject) => { + let isResolved = false; + + const clear = () => { + window.removeEventListener('message', listener); + iframe.remove(); + isResolved = true; + }; + + const listener = (e: MessageEvent) => { + if (e.origin === iFrameOrigin && e.source === iframe.contentWindow) { + const key = `${configurationName}_oidc_tokens:`; + const key_error = `${configurationName}_oidc_error:`; + const key_exception = `${configurationName}_oidc_exception:`; + const data = e.data; + + if (data && typeof data === 'string') { + if (!isResolved) { + if (data.startsWith(key)) { + const result = JSON.parse(e.data.replace(key, '')); + publishEvent(eventNames.silentLoginAsync_end, {}); + resolve(result); + clear(); + } else if (data.startsWith(key_error)) { + const result = JSON.parse(e.data.replace(key_error, '')); + publishEvent(eventNames.silentLoginAsync_error, result); + resolve({ error: 'oidc_' + result.error, tokens: null, sessionState: null }); + clear(); + } else if (data.startsWith(key_exception)) { + const result = JSON.parse(e.data.replace(key_exception, '')); + publishEvent(eventNames.silentLoginAsync_error, result); + reject(new Error(result.error)); + clear(); } + } } - } - const link = configuration.silent_login_uri + queries; - const idx = link.indexOf('/', link.indexOf('//') + 2); - const iFrameOrigin = link.substr(0, idx); - const iframe = document.createElement('iframe'); - iframe.width = '0px'; - iframe.height = '0px'; - - iframe.id = `${configurationName}_oidc_iframe`; - iframe.setAttribute('src', link); - document.body.appendChild(iframe); - return new Promise((resolve, reject) => { - try { - let isResolved = false; - window.onmessage = (e: MessageEvent) => { - if (e.origin === iFrameOrigin && - e.source === iframe.contentWindow - ) { - const key = `${configurationName}_oidc_tokens:`; - const key_error = `${configurationName}_oidc_error:`; - const data = e.data; - if (data && typeof (data) === 'string') { - if (!isResolved) { - if (data.startsWith(key)) { - const result = JSON.parse(e.data.replace(key, '')); - publishEvent(eventNames.silentLoginAsync_end, {}); - iframe.remove(); - isResolved = true; - resolve(result); - } else if (data.startsWith(key_error)) { - const result = JSON.parse(e.data.replace(key_error, '')); - publishEvent(eventNames.silentLoginAsync_error, result); - iframe.remove(); - isResolved = true; - reject(new Error('oidc_' + result.error)); - } - } - } - } - }; - const silentSigninTimeout = configuration.silent_login_timeout; - setTimeout(() => { - if (!isResolved) { - publishEvent(eventNames.silentLoginAsync_error, { reason: 'timeout' }); - iframe.remove(); - isResolved = true; - reject(new Error('timeout')); - } - }, silentSigninTimeout); - } catch (e) { - iframe.remove(); - publishEvent(eventNames.silentLoginAsync_error, e); - reject(e); + } + }; + + try { + window.addEventListener('message', listener); + + const silentSigninTimeout = configuration.silent_login_timeout; + setTimeout(() => { + if (!isResolved) { + clear(); + publishEvent(eventNames.silentLoginAsync_error, { reason: 'timeout' }); + reject(new Error('timeout')); } - }); + }, silentSigninTimeout); + } catch (e) { + clear(); + publishEvent(eventNames.silentLoginAsync_error, e); + reject(e); + } + }); } catch (e) { - publishEvent(eventNames.silentLoginAsync_error, e); - throw e; + publishEvent(eventNames.silentLoginAsync_error, e); + throw e; } -}; + }; -// eslint-disable-next-line @typescript-eslint/ban-types -export const defaultSilentLoginAsync = (window, configurationName, configuration:OidcConfiguration, publishEvent :(string, any)=>void, oidc:any) => (extras:StringMap = null, scope:string = undefined) => { +export const defaultSilentLoginAsync = + ( + window, + configurationName, + configuration: OidcConfiguration, + publishEvent: (string, any) => void, + oidc: any, + ) => + (extras: StringMap = null, scope: string = undefined) => { extras = { ...extras }; - const silentLoginAsync = (extras, state, scope) => { - return _silentLoginAsync(configurationName, configuration, publishEvent.bind(oidc))(extras, state, scope); + const silentLoginAsync = (extras, state, scopeInternal) => { + return _silentLoginAsync(configurationName, configuration, publishEvent.bind(oidc))( + extras, + state, + scopeInternal, + ); }; const loginLocalAsync = async () => { - if (oidc.timeoutId) { - timer.clearTimeout(oidc.timeoutId); - } + if (oidc.timeoutId) { + timer.clearTimeout(oidc.timeoutId); + } - let state; - if (extras && 'state' in extras) { - state = extras.state; - delete extras.state; - } + let state; + if (extras && 'state' in extras) { + state = extras.state; + delete extras.state; + } - try { - const extraFinal = !configuration.extras ? extras : { ...configuration.extras, ...extras }; - const silentResult = await silentLoginAsync({ - ...extraFinal, - prompt: 'none', - }, state, scope); - - if (silentResult) { - oidc.tokens = silentResult.tokens; - publishEvent(eventNames.token_aquired, {}); - // @ts-ignore - oidc.timeoutId = autoRenewTokens(oidc, oidc.tokens.refreshToken, oidc.tokens.expiresAt, extras); - return {}; - } - } catch (e) { - return e; + try { + const extraFinal = !configuration.extras ? extras : { ...configuration.extras, ...extras }; + const silentResult = await silentLoginAsync( + { + ...extraFinal, + prompt: 'none', + }, + state, + scope, + ); + + if (silentResult) { + oidc.tokens = silentResult.tokens; + publishEvent(eventNames.token_acquired, {}); + // @ts-ignore + oidc.timeoutId = autoRenewTokens(oidc, oidc.tokens.expiresAt, extras, scope); + return {}; } + } catch (e) { + return e; + } }; return loginLocalAsync(); -}; + }; export default defaultSilentLoginAsync; diff --git a/packages/oidc-client/src/timer.ts b/packages/oidc-client/src/timer.ts index cd088f52b..6f6e2cfec 100644 --- a/packages/oidc-client/src/timer.ts +++ b/packages/oidc-client/src/timer.ts @@ -1,163 +1,13 @@ const timer = (function () { - const workerPort = (function () { - let worker; - let blobURL; - - const workerCode = function () { - const innerIdsByOuterIds = {}; - - const methods = { - setTimeout: function (port, id, timeout) { - innerIdsByOuterIds[id] = setTimeout(function () { - port.postMessage(id); - innerIdsByOuterIds[id] = null; - }, timeout); - }, - - setInterval: function (port, id, timeout) { - innerIdsByOuterIds[id] = setInterval(function () { - port.postMessage(id); - }, timeout); - }, - - clearTimeout: function (port, id) { - clearTimeout(innerIdsByOuterIds[id]); - innerIdsByOuterIds[id] = null; - }, - - clearInterval: function (port, id) { - clearInterval(innerIdsByOuterIds[id]); - innerIdsByOuterIds[id] = null; - }, - }; - - function onMessage(port, event) { - const method = event.data[0]; - const id = event.data[1]; - const option = event.data[2]; - - if (methods[method]) { - methods[method](port, id, option); - } - } - - // For Dedicated Worker - this.onmessage = function (event) { - onMessage(self, event); - }; - - // For Shared Worker - this.onconnect = function (event) { - const port = event.ports[0]; - - port.onmessage = function (event) { - onMessage(port, event); - }; - }; - }.toString(); - - try { - const blob = new Blob(['(', workerCode, ')()'], { type: 'application/javascript' }); - blobURL = URL.createObjectURL(blob); - } catch (error) { - return null; - } - const isInsideBrowser = (typeof process === 'undefined'); - try { - if (SharedWorker) { - worker = new SharedWorker(blobURL); - return worker.port; - } - } catch (error) { - if (isInsideBrowser) { - console.warn('SharedWorker not available'); - } - } - try { - if (Worker) { - worker = new Worker(blobURL); - return worker; - } - } catch (error) { - if (isInsideBrowser) { - console.warn('Worker not available'); - } - } - - return null; - }()); - - if (!workerPort) { - // In NextJS with SSR (Server Side Rendering) during rending in Node JS, the window object is undefined, - // the global object is used instead as it is the closest approximation of a browsers window object. - const bindContext = (typeof window === 'undefined') ? global : window; - - return { - setTimeout: setTimeout.bind(bindContext), - clearTimeout: clearTimeout.bind(bindContext), - setInterval: setInterval.bind(bindContext), - clearInterval: clearInterval.bind(bindContext), - }; - } - - const getId = (function () { - let currentId = 0; - - return function () { - currentId++; - return currentId; - }; - }()); - - const timeoutCallbacksById = {}; - const intervalCallbacksById = {}; - - workerPort.onmessage = function (event) { - const id = event.data; - - const timeoutCallback = timeoutCallbacksById[id]; - if (timeoutCallback) { - timeoutCallback(); - timeoutCallbacksById[id] = null; - return; - } - - const intervalCallback = intervalCallbacksById[id]; - if (intervalCallback) { - intervalCallback(); - } - }; - - function setTimeoutWorker(callback, timeout) { - const id = getId(); - workerPort.postMessage(['setTimeout', id, timeout]); - timeoutCallbacksById[id] = callback; - return id; - } - - function clearTimeoutWorker(id) { - workerPort.postMessage(['clearTimeout', id]); - timeoutCallbacksById[id] = null; - } - - function setIntervalWorker(callback, timeout) { - const id = getId(); - workerPort.postMessage(['setInterval', id, timeout]); - intervalCallbacksById[id] = callback; - return id; - } - - function clearIntervalWorker(id) { - workerPort.postMessage(['clearInterval', id]); - intervalCallbacksById[id] = null; - } - - return { - setTimeout: setTimeoutWorker, - clearTimeout: clearTimeoutWorker, - setInterval: setIntervalWorker, - clearInterval: clearIntervalWorker, - }; -}()); + // In NextJS with SSR (Server Side Rendering) during rending in Node JS, the window object is undefined, + // the global object is used instead as it is the closest approximation of a browsers window object. + const bindContext = typeof window === 'undefined' ? global : window; + return { + setTimeout: setTimeout.bind(bindContext), + clearTimeout: clearTimeout.bind(bindContext), + setInterval: setInterval.bind(bindContext), + clearInterval: clearInterval.bind(bindContext), + }; +})(); export default timer; diff --git a/packages/oidc-client/src/types.ts b/packages/oidc-client/src/types.ts index 7ac7c58ea..ccea19d34 100644 --- a/packages/oidc-client/src/types.ts +++ b/packages/oidc-client/src/types.ts @@ -2,40 +2,74 @@ export type Fetch = typeof window.fetch; export type LogoutToken = 'access_token' | 'refresh_token'; +export type ServiceWorkerUpdateRequireCallback = ( + registration: any, + stopKeepAlive: () => void, +) => Promise; +export type ServiceWorkerRegister = ( + serviceWorkerRelativeUrl: string, +) => Promise; +export type ServiceWorkerActivate = () => boolean; + +export enum TokenAutomaticRenewMode { + AutomaticBeforeTokenExpiration = 'AutomaticBeforeTokensExpiration', + AutomaticOnlyWhenFetchExecuted = 'AutomaticOnlyWhenFetchExecuted', +} + export type OidcConfiguration = { - client_id: string; - redirect_uri: string; - silent_redirect_uri?:string; - silent_login_uri?:string; - silent_login_timeout?:number; - scope: string; - authority: string; - authority_time_cache_wellknowurl_in_second?: number; - authority_timeout_wellknowurl_in_millisecond?: number; - authority_configuration?: AuthorityConfiguration; - refresh_time_before_tokens_expiration_in_second?: number; - token_request_timeout?: number; - service_worker_relative_url?:string; - service_worker_only?:boolean; - service_worker_convert_all_requests_to_cors?:boolean; - extras?:StringMap; - token_request_extras?:StringMap; - storage?: Storage; - monitor_session?: boolean; - token_renew_mode?: string; - logout_tokens_to_invalidate?:Array; + client_id: string; + redirect_uri: string; + silent_redirect_uri?: string; + silent_login_uri?: string; + silent_login_timeout?: number; + scope: string; + authority: string; + authority_time_cache_wellknowurl_in_second?: number; + authority_timeout_wellknowurl_in_millisecond?: number; + authority_configuration?: AuthorityConfiguration; + refresh_time_before_tokens_expiration_in_second?: number; + token_automatic_renew_mode?: TokenAutomaticRenewMode; + token_request_timeout?: number; + service_worker_relative_url?: string; + service_worker_register?: ServiceWorkerRegister; + service_worker_keep_alive_path?: string; + service_worker_activate?: ServiceWorkerActivate; + service_worker_only?: boolean; + service_worker_convert_all_requests_to_cors?: boolean; + extras?: StringMap; + token_request_extras?: StringMap; + storage?: Storage; + monitor_session?: boolean; + token_renew_mode?: string; + logout_tokens_to_invalidate?: Array; + demonstrating_proof_of_possession?: boolean; + demonstrating_proof_of_possession_configuration?: DemonstratingProofOfPossessionConfiguration; + preload_user_info?: boolean; }; +export interface DemonstratingProofOfPossessionConfiguration { + generateKeyAlgorithm: RsaHashedKeyGenParams | EcKeyGenParams; + digestAlgorithm: AlgorithmIdentifier; + importKeyAlgorithm: + | AlgorithmIdentifier + | RsaHashedImportParams + | EcKeyImportParams + | HmacImportParams + | AesKeyAlgorithm; + signAlgorithm: AlgorithmIdentifier | RsaPssParams | EcdsaParams; + jwtHeaderAlgorithm: string; +} + export interface StringMap { - [key: string]: string; + [key: string]: string; } export interface AuthorityConfiguration { - authorization_endpoint: string; - token_endpoint: string; - revocation_endpoint: string; - end_session_endpoint?: string; - userinfo_endpoint?: string; - check_session_iframe?:string; - issuer:string; + authorization_endpoint: string; + token_endpoint: string; + revocation_endpoint: string; + end_session_endpoint?: string; + userinfo_endpoint?: string; + check_session_iframe?: string; + issuer: string; } diff --git a/packages/oidc-client/src/user.ts b/packages/oidc-client/src/user.ts index e23f7407c..29d01aebb 100644 --- a/packages/oidc-client/src/user.ts +++ b/packages/oidc-client/src/user.ts @@ -1,40 +1,41 @@ -import { sleepAsync } from './initWorker.js'; -import { isTokensValid } from './parseTokens.js'; +import { fetchWithTokens } from './fetch'; +import Oidc from './oidc'; -export const userInfoAsync = (oidc) => async (noCache = false) => { +export const userInfoAsync = + (oidc: Oidc) => + async (noCache = false, demonstrating_proof_of_possession = false) => { if (oidc.userInfo != null && !noCache) { - return oidc.userInfo; + return oidc.userInfo; } - - // We wait the synchronisation before making a request - while (oidc.tokens && !isTokensValid(oidc.tokens)) { - await sleepAsync(200); - } - - if (!oidc.tokens) { - return null; - } - const accessToken = oidc.tokens.accessToken; - if (!accessToken) { - return null; + // Check storage cache + const stored = + !noCache && oidc.configuration.storage?.getItem(`oidc.${oidc.configurationName}.userInfo`); + if (stored) { + oidc.userInfo = JSON.parse(stored); + return oidc.userInfo; } - - const oidcServerConfiguration = await oidc.initAsync(oidc.configuration.authority, oidc.configuration.authority_configuration); + const configuration = oidc.configuration; + const oidcServerConfiguration = await oidc.initAsync( + configuration.authority, + configuration.authority_configuration, + ); const url = oidcServerConfiguration.userInfoEndpoint; - const fetchUserInfo = async (accessToken) => { - const res = await fetch(url, { - headers: { - authorization: `Bearer ${accessToken}`, - }, - }); - - if (res.status !== 200) { - return null; - } - - return res.json(); + const fetchUserInfo = async () => { + const oidcFetch = fetchWithTokens(fetch, oidc, demonstrating_proof_of_possession); + const response = await oidcFetch(url); + if (response.status !== 200) { + return null; + } + return response.json(); }; - const userInfo = await fetchUserInfo(accessToken); + const userInfo = await fetchUserInfo(); oidc.userInfo = userInfo; + // Store in cache + if (userInfo) { + oidc.configuration.storage?.setItem( + `oidc.${oidc.configurationName}.userInfo`, + JSON.stringify(userInfo), + ); + } return userInfo; -}; + }; diff --git a/packages/oidc-client/src/vanillaOidc.ts b/packages/oidc-client/src/vanillaOidc.ts deleted file mode 100644 index e2f3c7477..000000000 --- a/packages/oidc-client/src/vanillaOidc.ts +++ /dev/null @@ -1,108 +0,0 @@ -import { LoginCallback, Oidc } from './oidc.js'; -import { getValidTokenAsync, Tokens, ValidToken } from './parseTokens.js'; -import { Fetch, OidcConfiguration, StringMap } from './types.js'; - -export interface EventSubscriber { - (name: string, data:any); -} - -export class VanillaOidc { - private _oidc: Oidc; - constructor(oidc: Oidc) { - this._oidc = oidc; - } - - subscribeEvents(func:EventSubscriber):string { - return this._oidc.subscribeEvents(func); - } - - removeEventSubscription(id:string):void { - this._oidc.removeEventSubscription(id); - } - - publishEvent(eventName:string, data:any) : void { - this._oidc.publishEvent(eventName, data); - } - - static getOrCreate = (getFetch : () => Fetch) => (configuration:OidcConfiguration, name = 'default'): VanillaOidc => { - return new VanillaOidc(Oidc.getOrCreate(getFetch)(configuration, name)); - }; - - static get(name = 'default'):VanillaOidc { - return new VanillaOidc(Oidc.get(name)); - } - - static eventNames = Oidc.eventNames; - tryKeepExistingSessionAsync():Promise { - return this._oidc.tryKeepExistingSessionAsync(); - } - - loginAsync(callbackPath:string = undefined, extras:StringMap = null, isSilentSignin = false, scope:string = undefined, silentLoginOnly = false):Promise { - return this._oidc.loginAsync(callbackPath, extras, isSilentSignin, scope, silentLoginOnly); - } - - logoutAsync(callbackPathOrUrl: string | null | undefined = undefined, extras: StringMap = null):Promise { - return this._oidc.logoutAsync(callbackPathOrUrl, extras); - } - - silentLoginCallbackAsync():Promise { - return this._oidc.silentLoginCallbackAsync(); - } - - renewTokensAsync(extras:StringMap = null):Promise { - return this._oidc.renewTokensAsync(extras); - } - - loginCallbackAsync():Promise { - return this._oidc.loginCallbackWithAutoTokensRenewAsync(); - } - - get tokens():Tokens { - return this._oidc.tokens; - } - - get configuration():OidcConfiguration { - return this._oidc.configuration; - } - - async getValidTokenAsync(waitMs = 200, numberWait = 50): Promise { - return getValidTokenAsync(this._oidc, waitMs, numberWait); - } - - async userInfoAsync(noCache = false):Promise { - return this._oidc.userInfoAsync(noCache); - } -} - -export interface OidcUserInfo { - sub: string; - name?: string; - given_name?: string; - family_name?: string; - middle_name?: string; - nickname?: string; - preferred_username?: string; - profile?: string; - picture?: string; - website?: string; - email?: string; - email_verified?: boolean; - gender?: string; - birthdate?: string; - zoneinfo?: string; - locale?: string; - phone_number?: string; - phone_number_verified?: boolean; - address?: OidcAddressClaim; - updated_at?: number; - groups?: string[]; -} - -export interface OidcAddressClaim { - formatted?: string; - street_address?: string; - locality?: string; - region?: string; - postal_code?: string; - country?: string; -} diff --git a/packages/oidc-client/src/version.ts b/packages/oidc-client/src/version.ts new file mode 100644 index 000000000..1fe2b83bd --- /dev/null +++ b/packages/oidc-client/src/version.ts @@ -0,0 +1 @@ +export default '7.26.0'; diff --git a/packages/oidc-client/tests/setup.js b/packages/oidc-client/tests/setup.js index e022aaa60..8476fd748 100644 --- a/packages/oidc-client/tests/setup.js +++ b/packages/oidc-client/tests/setup.js @@ -1,11 +1,8 @@ -import { expect, afterEach } from 'vitest'; -import { cleanup } from '@testing-library/react'; -import matchers from '@testing-library/jest-dom/matchers'; +import { defineConfig } from 'vite'; +import { configDefaults } from 'vitest/config'; -// extends Vitest's expect method with methods from react-testing-library -expect.extend(matchers); - -// runs a cleanup after each test case (e.g. clearing jsdom) -afterEach(() => { - cleanup(); -}); \ No newline at end of file +export default defineConfig({ + test: { + exclude: [...configDefaults.exclude, 'public/*'], + }, +}); diff --git a/packages/oidc-client/tsconfig.eslint.json b/packages/oidc-client/tsconfig.eslint.json index e9041fd6b..b90fc83e0 100644 --- a/packages/oidc-client/tsconfig.eslint.json +++ b/packages/oidc-client/tsconfig.eslint.json @@ -1,4 +1,4 @@ { "extends": "./tsconfig.json", "include": ["src"] -} \ No newline at end of file +} diff --git a/packages/oidc-client/tsconfig.json b/packages/oidc-client/tsconfig.json index 32493f492..3337cacd7 100644 --- a/packages/oidc-client/tsconfig.json +++ b/packages/oidc-client/tsconfig.json @@ -27,12 +27,7 @@ "allowJs": true, "rootDir": "src" }, - "exclude": [ - "node_modules", - "**/*.spec.tsx", - ], - "include": [ - "src/**/*" - ], + "exclude": ["node_modules", "**/*.spec.tsx"], + "include": ["src/**/*"] // "files": ["./src/index.ts"] } diff --git a/packages/oidc-client/vite.config.ts b/packages/oidc-client/vite.config.ts index 07867ece3..ad02950d4 100644 --- a/packages/oidc-client/vite.config.ts +++ b/packages/oidc-client/vite.config.ts @@ -1,10 +1,6 @@ -import { defineConfig } from 'vite'; -import { resolve } from 'path'; +import { resolve } from 'path'; +import { defineConfig } from 'vite'; import dts from 'vite-plugin-dts'; -import pkg from './package.json'; - -const dependencies = externalDependencies(); -console.log('external dependencies:', dependencies); export default defineConfig({ build: { @@ -14,26 +10,12 @@ export default defineConfig({ formats: ['es', 'umd'], fileName: 'index', }, - rollupOptions: { - external: [...dependencies], - }, }, plugins: [ - dts(), //generate typescript typedefs + dts(), // generate typescript typedefs ], resolve: { - preserveSymlinks: true, //https://github.com/vitejs/vite/issues/11657 - }, - test: { - globals: true, - environment: 'jsdom', - setupFiles: './tests/setup.js', + preserveSymlinks: true, // https://github.com/vitejs/vite/issues/11657 }, }); - -function externalDependencies(): Array { - const deps = Object.keys(pkg.dependencies || {}); - const peerDeps = Object.keys(pkg.peerDependencies || {}); - return [...deps, ...peerDeps]; -} diff --git a/packages/react-oidc/.eslintrc.cjs b/packages/react-oidc/.eslintrc.cjs deleted file mode 100644 index 968c0320f..000000000 --- a/packages/react-oidc/.eslintrc.cjs +++ /dev/null @@ -1,18 +0,0 @@ -module.exports = { - extends: [__dirname+'/config/defaultEslintConfig.cjs'], - parserOptions: { - project: './tsconfig.eslint.json', - tsconfigRootDir: __dirname, - }, - rules: { - '@typescript-eslint/naming-convention': [ - 'error', - { - 'selector': 'variable', - 'types': ['boolean'], - 'format': ['PascalCase'], - 'prefix': ['is', 'with', 'should', 'has', 'can', 'did', 'will'] - } - ] - } - } \ No newline at end of file diff --git a/packages/react-oidc/README.md b/packages/react-oidc/README.md index 102b48cfa..671a99b1f 100644 --- a/packages/react-oidc/README.md +++ b/packages/react-oidc/README.md @@ -1,13 +1,17 @@ # @axa-fr/react-oidc -[![Continuous Integration](https://github.com/AxaGuilDEv/react-oidc/actions/workflows/npm-publish.yml/badge.svg)](https://github.com/AxaGuilDEv/react-oidc/actions/workflows/npm-publish.yml) +[![Continuous Integration](https://github.com/AxaFrance/react-oidc/actions/workflows/npm-publish.yml/badge.svg)](https://github.com/AxaFrance/react-oidc/actions/workflows/npm-publish.yml) [![Quality Gate](https://sonarcloud.io/api/project_badges/measure?project=AxaGuilDEv_react-oidc&metric=alert_status)](https://sonarcloud.io/dashboard?id=AxaGuilDEv_react-oidc) [![Reliability](https://sonarcloud.io/api/project_badges/measure?project=AxaGuilDEv_react-oidc&metric=reliability_rating)](https://sonarcloud.io/component_measures?id=AxaGuilDEv_react-oidc&metric=reliability_rating) [![Security](https://sonarcloud.io/api/project_badges/measure?project=AxaGuilDEv_react-oidc&metric=security_rating)](https://sonarcloud.io/component_measures?id=AxaGuilDEv_react-oidc&metric=security_rating) [![Code Corevage](https://sonarcloud.io/api/project_badges/measure?project=AxaGuilDEv_react-oidc&metric=coverage)](https://sonarcloud.io/component_measures?id=AxaGuilDEv_react-oidc&metric=Coverage) [![Twitter](https://img.shields.io/twitter/follow/GuildDEvOpen?style=social)](https://twitter.com/intent/follow?screen_name=GuildDEvOpen) -Try the demo at https://black-rock-0dc6b0d03.1.azurestaticapps.net/ +**@axa-fr/oidc-client** the lightest and securest library to manage authentication with OpenID Connect (OIDC) and OAuth2 protocol. It is compatible with all OIDC providers. +**@axa-fr/oidc-client** is a pure javascript library. It works with any JavaScript framework or library. -![Sample React OIDC](https://github.com/AxaGuilDEv/react-oidc/blob/master/docs/img/introduction.gif?raw=true) +We provide a wrapper **@axa-fr/react-oidc** for **React** (compatible next.js) and we expect soon to provide one for **Vue**, **Angular** and **Svelte**. -A set of react components to make OIDC (OpenID Connect) client easy. It aim to simplify OAuth authentication between multiples providers. +- Try the React demo at https://black-rock-0dc6b0d03.1.azurestaticapps.net/ (most advanced) +- Try the pure javascript demo at https://icy-glacier-004ab4303.2.azurestaticapps.net/ + +Sample React Oicd - [About](#about) - [Getting Started](#getting-started) @@ -20,22 +24,22 @@ A set of react components to make OIDC (OpenID Connect) client easy. It aim to s ## About -Easy set up of OIDC for react. -It is a real alternative to existing oidc-client libraries. +@axa-fr/react is: - **Secure** : - - With the use of Service Worker, your tokens (refresh_token and access_token) are not accessible to the JavaScript client code (big protection against XSRF attacks) - - OIDC using client side Code Credential Grant with PKCE only -- **Lightweight** -- **Simple** : + - With Demonstrating Proof of Possession (DPoP), your access_token and refresh_token are not usable outside your browser context (big protection) + - With the use of Service Worker, your tokens (refresh_token and/or access_token) are not accessible to the JavaScript client code (if you follow good practices from [`FAQ`](https://github.com/AxaFrance/oidc-client/blob/main/FAQ.md) section) + - OIDC using client side Code Credential Grant with pkce only +- **Lightweight** : Unpacked Size on npm is **274 kB** +- **Simple** - refresh_token and access_token are auto refreshed in background - - with the use of the Service Worker, you do not need to inject the access_token in every fetch, you have only to configure `OidcTrustedDomains.js` file -- **No cookies problem** : You can disable silent signin (that internally use an iframe). For your information, your OIDC server should be in the same domain of your website in order to be able to send OIDC server cookies from your website via an internal IFRAME, else, you may encounter COOKIES problem. + - with the use of the Service Worker, you do not need to inject the access_token in every fetch, you have only to configure OidcTrustedDomains.js file - **Multiple Authentication** : - You can authenticate many times to the same provider with different scope (for example you can acquire a new 'payment' scope for a payment) - You can authenticate to multiple different providers inside the same SPA (single page application) website - **Flexible** : - - Work with Service Worker (more secure) and without for older browser (less secure) + - Work with Service Worker (more secure) and without for older browser (less secure). + - You can disable Service Worker if you want (but less secure) and just use SessionStorage or LocalStorage mode. ![](https://github.com/AxaGuilDEv/react-oidc/blob/master/docs/img/schema_pcke_client_side_with_service_worker.png?raw=true) @@ -46,11 +50,23 @@ The service worker catch **access_token** and **refresh_token** that will never ```sh npm install @axa-fr/react-oidc --save +# To install or update OidcServiceWorker.js file, you can run +node ./node_modules/@axa-fr/react-oidc/bin/copy-service-worker-files.mjs public + # If you have a "public" folder, the 2 files will be created : # ./public/OidcServiceWorker.js <-- will be updated at each "npm install" # ./public/OidcTrustedDomains.js <-- won't be updated if already exist ``` +WARNING : If you use Service Worker mode, the OidcServiceWorker.js file should always be up to date with the version of the library. You may setup a postinstall script in your package.json file to update it at each npm install. For example : + +```sh + "scripts": { + ... + "postinstall": "node ./node_modules/@axa-fr/react-oidc/bin/copy-service-worker-files.mjs public" + }, +``` + If you need a very secure mode where refresh_token and access_token will be hide behind a service worker that will proxify requests. The only file you should edit is "OidcTrustedDomains.js". @@ -63,23 +79,62 @@ The only file you should edit is "OidcTrustedDomains.js". // Domains used by OIDC server must be also declared here const trustedDomains = { - default: ["https://demo.duendesoftware.com", "https://www.myapi.com/users"], + default: { + oidcDomains: ['https://demo.duendesoftware.com'], + accessTokenDomains: ['https://www.myapi.com/users'], + }, }; // Service worker will continue to give access token to the JavaScript client // Ideal to hide refresh token from client JavaScript, but to retrieve access_token for some // scenarios which require it. For example, to send it via websocket connection. -trustedDomains.config_show_access_token = { domains : ["https://demo.duendesoftware.com"], showAccessToken: true }; +trustedDomains.config_show_access_token = { + oidcDomains: ['https://demo.duendesoftware.com'], + accessTokenDomains: ['https://www.myapi.com/users'], + showAccessToken: true, + // convertAllRequestsToCorsExceptNavigate: false, // default value is false + // setAccessTokenToNavigateRequests: true, // default value is true +}; +// DPoP (Demonstrating Proof of Possession) will be activated for the following domains +trustedDomains.config_with_dpop = { + domains: ['https://demo.duendesoftware.com'], + demonstratingProofOfPossession: true, + demonstratingProofOfPossessionOnlyWhenDpopHeaderPresent: true, // default value is false, inject DPOP token only when DPOP header is present + // Optional, more details bellow + /*demonstratingProofOfPossessionConfiguration: { + importKeyAlgorithm: { + name: 'ECDSA', + namedCurve: 'P-256', + hash: {name: 'ES256'} + }, + signAlgorithm: {name: 'ECDSA', hash: {name: 'SHA-256'}}, + generateKeyAlgorithm: { + name: 'ECDSA', + namedCurve: 'P-256' + }, + digestAlgorithm: { name: 'SHA-256' }, + jwtHeaderAlgorithm : 'ES256' + }*/ +}; + +// Setting allowMultiTabLogin to true will enable storing login-specific parameters (state, nonce, code verifier) +// separately for each tab. This will prevent errors when logins are initiated from multiple tabs. +trustedDomains.config_multi_tab_login = { + domains: ['https://demo.duendesoftware.com'], + allowMultiTabLogin: true, +}; ``` ## Run The Demo ```sh -git clone https://github.com/AxaGuilDEv/react-oidc.git -cd react-oidc/packages/react -npm install -npm start +git clone https://github.com/AxaFrance/oidc-client.git +cd oidc-client +pnpm install +cd /examples/react-oidc-demo +pnpm install +pnpm start # then navigate to http://localhost:4200 ``` @@ -87,32 +142,32 @@ npm start ### Application startup -The library is router agnostic and use native History API. +The library is router agnostic and will use native History API. The default routes used internally : - www.your-app.fr/authentication/callback ```javascript -import React from "react"; -import { render } from "react-dom"; -import { BrowserRouter as Router } from "react-router-dom"; -import { OidcProvider } from "@axa-fr/react-oidc"; -import Header from "./Layout/Header"; -import Routes from "./Router"; +import React from 'react'; +import { render } from 'react-dom'; +import { BrowserRouter as Router } from 'react-router-dom'; +import { OidcProvider } from '@axa-fr/react-oidc'; +import Header from './Layout/Header'; +import Routes from './Router'; // This configuration use hybrid mode // ServiceWorker are used if available (more secure) else tokens are given to the client // You need to give inside your code the "access_token" when using fetch const configuration = { - client_id: "interactive.public.short", - redirect_uri: window.location.origin + "/authentication/callback", - silent_redirect_uri: - window.location.origin + "/authentication/silent-callback", - scope: "openid profile email api offline_access", // offline_access scope allow your client to retrieve the refresh_token - authority: "https://demo.duendesoftware.com", - service_worker_relative_url: "/OidcServiceWorker.js", + client_id: 'interactive.public.short', + redirect_uri: window.location.origin + '/authentication/callback', + silent_redirect_uri: window.location.origin + '/authentication/silent-callback', + scope: 'openid profile email api offline_access', // offline_access scope allow your client to retrieve the refresh_token + authority: 'https://demo.duendesoftware.com', + service_worker_relative_url: '/OidcServiceWorker.js', // just comment that line to disable service worker mode service_worker_only: false, + demonstrating_proof_of_possession: false, }; const App = () => ( @@ -124,53 +179,95 @@ const App = () => ( ); -render(, document.getElementById("root")); +render(, document.getElementById('root')); ``` +> [!WARNING] +> If you have both `redirect_uri` and `silent_redirect_uri` configured, their value must be different. + ```javascript -const propTypes = { - loadingComponent: PropTypes.elementType, // you can inject your own loading component - sessionLostComponent: PropTypes.elementType, // you can inject your own session lost component - authenticating: PropTypes.elementType, // you can inject your own authenticationg component - authenticatingErrorComponent: PropTypes.elementType, - callbackSuccessComponent: PropTypes.elementType, // you can inject your own call back success component - serviceWorkerNotSupportedComponent: PropTypes.elementType, // you can inject your page that explain your require a more modern browser - onSessionLost: PropTypes.function, // If set "sessionLostComponent" is not displayed and onSessionLost callback is called instead - configuration: PropTypes.shape({ - client_id: PropTypes.string.isRequired, // oidc client id - redirect_uri: PropTypes.string.isRequired, // oidc redirect url - silent_redirect_uri: PropTypes.string, // Optional activate silent-signin that use cookies between OIDC server and client javascript to restore sessions - silent_login_uri: PropTypes.string, // Optional, route that trigger the signin - silent_login_timeout: PropTypes.number, // Optional default is 12000 milliseconds - scope: PropTypes.string.isRequired, // oidc scope (you need to set "offline_access") - authority: PropTypes.string.isRequired, - storage: Storage, // Default sessionStorage, you can set localStorage but it is less secure to XSS attacks - authority_configuration: PropTypes.shape({ - // Optional for providers that does not implement OIDC server auto discovery via a .wellknowurl - authorization_endpoint: PropTypes.string, - token_endpoint: PropTypes.string, - userinfo_endpoint: PropTypes.string, - end_session_endpoint: PropTypes.string, - revocation_endpoint: PropTypes.string, - check_session_iframe: PropTypes.string, - issuer: PropTypes.string, - }), - refresh_time_before_tokens_expiration_in_second: PropTypes.number, // default is 120 seconds - service_worker_relative_url: PropTypes.string, - service_worker_only: PropTypes.boolean, // default false - service_worker_convert_all_requests_to_cors: PropTypes.boolean, // force all requests that servie worker upgrades to have 'cors' mode. This allows setting authentication token on requests initialted by html parsing(e.g. img tags, download links etc). - extras: StringMap | undefined, // ex: {'prompt': 'consent', 'access_type': 'offline'} list of key/value that are send to the oidc server (more info: https://github.com/openid/AppAuth-JS) - token_request_extras: StringMap | undefined, // ex: {'prompt': 'consent', 'access_type': 'offline'} list of key/value that are send to the oidc server during token request (more info: https://github.com/openid/AppAuth-JS) - withCustomHistory: PropTypes.function, // Override history modification, return instance with replaceState(url, stateHistory) implemented (like History.replaceState()) - authority_time_cache_wellknowurl_in_second: 60 * 60, // Time to cache in second of openid wellknowurl, default is 1 hour - authority_timeout_wellknowurl_in_millisecond: 10000, // Timeout in millisecond of openid wellknowurl, default is 10 seconds, then error is throwed - monitor_session: PropTypes.boolean, // Add OpenId monitor session, default is false (more information https://openid.net/specs/openid-connect-session-1_0.html), if you need to set it to true consider https://infi.nl/nieuws/spa-necromancy/ - onLogoutFromAnotherTab: Function, // Optional, can be set to override the default behavior, this function is triggered when user with the same subject is logged out from another tab when session_monitor is active - onLogoutFromSameTab: Function, // Optional, can be set to override the default behavior, this function is triggered when user is logged out from same tab when session_monitor is active - token_renew_mode: PropTypes.string, // Optional, update tokens base on the selected token(s) lifetime: "access_token_or_id_token_invalid" (default), "access_token_invalid" , "id_token_invalid" - logout_tokens_to_invalidate : Array // Optional tokens to invalidate during logout, default: ['access_token', 'refresh_token'] - }).isRequired, +const configuration = { + loadingComponent: ReactComponent, // you can inject your own loading component + sessionLostComponent: ReactComponent, // you can inject your own session lost component + authenticating: ReactComponent, // you can inject your own authenticating component + authenticatingErrorComponent: ReactComponent, + callbackSuccessComponent: ReactComponent, // you can inject your own call back success component + serviceWorkerNotSupportedComponent: ReactComponent, // you can inject your page that explains you require a more modern browser + onSessionLost: Function, // If set, "sessionLostComponent" is not displayed, and onSessionLost callback is called instead + configuration: { + client_id: String.isRequired, // oidc client id + redirect_uri: String.isRequired, // oidc redirect url + silent_redirect_uri: String, // Optional activate silent-signin that use cookies between OIDC server and client javascript to restore sessions + silent_login_uri: String, // Optional, route that triggers the signin + silent_login_timeout: Number, // Optional, default is 12000 milliseconds + scope: String.isRequired, // oidc scope (you need to set "offline_access") + authority: String.isRequired, + storage: Storage, // Default sessionStorage, you can set localStorage, but it is not secure + authority_configuration: { + // Optional for providers that do not implement OIDC server auto-discovery via a .wellknown URL + authorization_endpoint: String, + token_endpoint: String, + userinfo_endpoint: String, + end_session_endpoint: String, + revocation_endpoint: String, + check_session_iframe: String, + issuer: String, + }, + refresh_time_before_tokens_expiration_in_second: Number, // default is 120 seconds + service_worker_relative_url: String, + service_worker_keep_alive_path: String, // default is "/" + service_worker_only: Boolean, // default false + service_worker_activate: () => boolean, // you can take the control of the service worker default activation which use user agent string + service_worker_register: (url: string) => Promise, // Optional, you can take the control of the service worker registration + extras: StringMap | undefined, // ex: {'prompt': 'consent', 'access_type': 'offline'} list of key/value that is sent to the OIDC server (more info: https://github.com/openid/AppAuth-JS) + token_request_extras: StringMap | undefined, // ex: {'prompt': 'consent', 'access_type': 'offline'} list of key/value that is sent to the OIDC server during token request (more info: https://github.com/openid/AppAuth-JS) + withCustomHistory: Function, // Override history modification, return an instance with replaceState(url, stateHistory) implemented (like History.replaceState()) + authority_time_cache_wellknowurl_in_second: 60 * 60, // Time to cache in seconds of the openid well-known URL, default is 1 hour + authority_timeout_wellknowurl_in_millisecond: 10000, // Timeout in milliseconds of the openid well-known URL, default is 10 seconds, then an error is thrown + monitor_session: Boolean, // Add OpenID monitor session, default is false (more information https://openid.net/specs/openid-connect-session-1_0.html), if you need to set it to true consider https://infi.nl/nieuws/spa-necromancy/ + onLogoutFromAnotherTab: Function, // Optional, can be set to override the default behavior, this function is triggered when a user with the same subject is logged out from another tab when session_monitor is active + onLogoutFromSameTab: Function, // Optional, can be set to override the default behavior, this function is triggered when a user is logged out from the same tab when session_monitor is active + token_renew_mode: String, // Optional, update tokens based on the selected token(s) lifetime: "access_token_or_id_token_invalid" (default), "access_token_invalid", "id_token_invalid" + token_automatic_renew_mode: TokenAutomaticRenewMode.AutomaticOnlyWhenFetchExecuted, // Optional, default is TokenAutomaticRenewMode.AutomaticBeforeTokensExpiration + // TokenAutomaticRenewMode.AutomaticBeforeTokensExpiration: renew tokens automatically before they expire + // TokenAutomaticRenewMode.AutomaticOnlyWhenFetchExecuted: renew tokens automatically only when fetch is executed + // It requires you to use fetch given by hook useOidcFetch(fetch) or HOC withOidcFetch(fetch)(Component) + logout_tokens_to_invalidate: Array, // Optional tokens to invalidate during logout, default: ['access_token', 'refresh_token'] + location: ILOidcLocation, // Optional, default is window.location, you can inject your own location object respecting the ILOidcLocation interface + demonstrating_proof_of_possession: Boolean, // Optional, default is false, if true, the the Demonstrating Proof of Possession will be activated //https://www.rfc-editor.org/rfc/rfc9449.html#name-protected-resource-access + demonstrating_proof_of_possession_configuration: DemonstratingProofOfPossessionConfiguration // Optional, more details bellow + }, +}; + +demonstrating_proof_of_possession_configuration: DemonstratingProofOfPossessionConfiguration // Optional, more details bellow +}; + +interface DemonstratingProofOfPossessionConfiguration +{ + generateKeyAlgorithm: RsaHashedKeyGenParams | EcKeyGenParams, + digestAlgorithm: AlgorithmIdentifier, + importKeyAlgorithm: AlgorithmIdentifier | RsaHashedImportParams | EcKeyImportParams | HmacImportParams | AesKeyAlgorithm, + signAlgorithm: AlgorithmIdentifier | RsaPssParams | EcdsaParams, + jwtHeaderAlgorithm: string +}; + +// default value of demonstrating_proof_of_possession_configuration +const defaultDemonstratingProofOfPossessionConfiguration: DemonstratingProofOfPossessionConfiguration ={ + importKeyAlgorithm: { + name: 'ECDSA', + namedCurve: 'P-256', + hash: {name: 'ES256'} + }, + signAlgorithm: {name: 'ECDSA', hash: {name: 'SHA-256'}}, + generateKeyAlgorithm: { + name: 'ECDSA', + namedCurve: 'P-256' + }, + digestAlgorithm: { name: 'SHA-256' }, + jwtHeaderAlgorithm : 'ES256' }; + + ``` ## How to consume @@ -178,8 +275,8 @@ const propTypes = { "useOidc" returns all props from the Hook : ```javascript -import React from "react"; -import { useOidc } from "./oidc"; +import React from 'react'; +import { useOidc } from './oidc'; export const Home = () => { const { login, logout, renewTokens, isAuthenticated } = useOidc(); @@ -189,33 +286,19 @@ export const Home = () => {
Welcome !!!
-

- React Demo Application protected by OpenId Connect -

+

React Demo Application protected by OpenId Connect

{!isAuthenticated && ( - )} {isAuthenticated && ( - )} {isAuthenticated && ( - )} @@ -238,12 +321,12 @@ The Hook method exposes : `OidcSecure` component trigger authentication in case user is not authenticated. So, the children of that component can be accessible only once you are connected. ```javascript -import React from "react"; -import { OidcSecure } from "@axa-fr/react-oidc"; +import React from 'react'; +import { OidcSecure } from '@axa-fr/react-oidc'; const AdminSecure = () => ( -

My sub component

} +

My sub component

); @@ -251,17 +334,17 @@ const AdminSecure = () => ( export default AdminSecure; ``` -## How to secure a component : HOC method +## How to secure a component: HOC method -"withOidcSecure" act the same as "OidcSecure" it also trigger authentication in case user is not authenticated. +`withOidcSecure` will act the same as `OidcSecure`,it will also trigger authentication in case the user is not authenticated. ```javascript -import React from "react"; -import { Switch, Route } from "react-router-dom"; -import { withOidcSecure } from "@axa-fr/react-oidc"; -import Home from "../Pages/Home"; -import Dashboard from "../Pages/Dashboard"; -import Admin from "../Pages/Admin"; +import React from 'react'; +import { Switch, Route } from 'react-router-dom'; +import { withOidcSecure } from '@axa-fr/react-oidc'; +import Home from '../Pages/Home'; +import Dashboard from '../Pages/Dashboard'; +import Admin from '../Pages/Admin'; const Routes = () => ( @@ -275,10 +358,10 @@ const Routes = () => ( export default Routes; ``` -## How to get "Access Token" : Hook method +## How to get "Access Token": Hook method ```javascript -import { useOidcAccessToken } from "@axa-fr/react-oidc"; +import { useOidcAccessToken } from '@axa-fr/react-oidc'; const DisplayAccessToken = () => { const { accessToken, accessTokenPayload } = useOidcAccessToken(); @@ -290,11 +373,10 @@ const DisplayAccessToken = () => {
Access Token
-

- Please consider to configure the ServiceWorker in order to protect - your application from XSRF attacks. ""access_token" and - "refresh_token" will never be accessible from your client side - javascript. +

+ Please consider to configure the ServiceWorker in order to protect your application from + XSRF attacks. ""access_token" and "refresh_token" will never be accessible from your + client side javascript.

{

{JSON.stringify(accessToken)}

} {accessTokenPayload != null && ( @@ -306,10 +388,10 @@ const DisplayAccessToken = () => { }; ``` -## How to get IDToken : Hook method +## How to get IDToken: Hook method ```javascript -import { useOidcIdToken } from "@axa-fr/react-oidc"; +import { useOidcIdToken } from '@axa-fr/react-oidc'; const DisplayIdToken = () => { const { idToken, idTokenPayload } = useOidcIdToken(); @@ -323,19 +405,17 @@ const DisplayIdToken = () => {
ID Token
{

{JSON.stringify(idToken)}

} - {idTokenPayload != null && ( -

{JSON.stringify(idTokenPayload)}

- )} + {idTokenPayload != null &&

{JSON.stringify(idTokenPayload)}

}
); }; ``` -## How to get User Information : Hook method +## How to get User Information: Hook method ```javascript -import { useOidcUser, UserStatus } from "@axa-fr/react-oidc"; +import { useOidcUser, UserStatus } from '@axa-fr/react-oidc'; const DisplayUserInfo = () => { const { oidcUser, oidcUserLoadingState } = useOidcUser(); @@ -360,14 +440,14 @@ const DisplayUserInfo = () => { }; ``` -## How to get a fetch that inject Access_Token : Hook method +## How to get a fetch that inject Access_Token: Hook method -If your are not using the service worker. Fetch function need to send AccessToken. -This Hook give you a wrapped fetch that add the access token for you. +If you are not using the service worker. The Fetch function needs to send AccessToken. +This hook will give you a wrapped fetch that adds the access token for you. ```javascript -import React, { useEffect, useState } from "react"; -import { useOidcFetch, OidcSecure } from "@axa-fr/react-oidc"; +import React, { useEffect, useState } from 'react'; +import { useOidcFetch, OidcSecure } from '@axa-fr/react-oidc'; const DisplayUserInfo = ({ fetch }) => { const [oidcUser, setOidcUser] = useState(null); @@ -375,16 +455,14 @@ const DisplayUserInfo = ({ fetch }) => { useEffect(() => { const fetchUserInfoAsync = async () => { - const res = await fetch( - "https://demo.duendesoftware.com/connect/userinfo", - ); + const res = await fetch('https://demo.duendesoftware.com/connect/userinfo'); if (res.status != 200) { return null; } return res.json(); }; let isMounted = true; - fetchUserInfoAsync().then((userInfo) => { + fetchUserInfoAsync().then(userInfo => { if (isMounted) { setLoading(false); setOidcUser(userInfo); @@ -404,9 +482,7 @@ const DisplayUserInfo = ({ fetch }) => {
User information
- {oidcUser != null && ( -

{JSON.stringify(oidcUser)}

- )} + {oidcUser != null &&

{JSON.stringify(oidcUser)}

}
@@ -429,8 +505,8 @@ If your are not using the service worker. Fetch function need to send AccessToke This HOC give you a wrapped fetch that add the access token for you. ```javascript -import React, { useEffect, useState } from "react"; -import { useOidcFetch, OidcSecure } from "@axa-fr/react-oidc"; +import React, { useEffect, useState } from 'react'; +import { useOidcFetch, OidcSecure } from '@axa-fr/react-oidc'; const DisplayUserInfo = ({ fetch }) => { const [oidcUser, setOidcUser] = useState(null); @@ -438,16 +514,14 @@ const DisplayUserInfo = ({ fetch }) => { useEffect(() => { const fetchUserInfoAsync = async () => { - const res = await fetch( - "https://demo.duendesoftware.com/connect/userinfo", - ); + const res = await fetch('https://demo.duendesoftware.com/connect/userinfo'); if (res.status != 200) { return null; } return res.json(); }; let isMounted = true; - fetchUserInfoAsync().then((userInfo) => { + fetchUserInfoAsync().then(userInfo => { if (isMounted) { setLoading(false); setOidcUser(userInfo); @@ -467,9 +541,7 @@ const DisplayUserInfo = ({ fetch }) => {
User information
- {oidcUser != null && ( -

{JSON.stringify(oidcUser)}

- )} + {oidcUser != null &&

{JSON.stringify(oidcUser)}

}
@@ -490,23 +562,23 @@ You can inject your own components. All components definition receive props `configurationName`. Please checkout the demo for more complete example. ```javascript -import React from "react"; -import { render } from "react-dom"; -import { BrowserRouter as Router } from "react-router-dom"; -import { OidcProvider } from "@axa-fr/react-oidc"; -import Header from "./Layout/Header"; -import Routes from "./Router"; +import React from 'react'; +import { render } from 'react-dom'; +import { BrowserRouter as Router } from 'react-router-dom'; +import { OidcProvider } from '@axa-fr/react-oidc'; +import Header from './Layout/Header'; +import Routes from './Router'; // This configuration use hybrid mode // ServiceWorker are used if available (more secure) else tokens are given to the client // You need to give inside your code the "access_token" when using fetch const configuration = { - client_id: "interactive.public.short", - redirect_uri: "http://localhost:4200/authentication/callback", - silent_redirect_uri: "http://localhost:4200/authentication/silent-callback", - scope: "openid profile email api offline_access", - authority: "https://demo.identityserver.io", - service_worker_relative_url: "/OidcServiceWorker.js", + client_id: 'interactive.public.short', + redirect_uri: 'http://localhost:4200/authentication/callback', + silent_redirect_uri: 'http://localhost:4200/authentication/silent-callback', + scope: 'openid profile email api offline_access', + authority: 'https://demo.identityserver.io', + service_worker_relative_url: '/OidcServiceWorker.js', service_worker_only: false, }; @@ -542,7 +614,7 @@ const App = () => ( ); -render(, document.getElementById("root")); +render(, document.getElementById('root')); ``` ## How It Works @@ -554,6 +626,8 @@ More information about OIDC - [French : Augmentez la sécurité et la simplicité de votre Système d’Information OpenID Connect](https://medium.com/just-tech-it-now/augmentez-la-s%C3%A9curit%C3%A9-et-la-simplicit%C3%A9-de-votre-syst%C3%A8me-dinformation-avec-oauth-2-0-cf0732d71284) - [English : Increase the security and simplicity of your information system with openid connect](https://medium.com/just-tech-it-now/increase-the-security-and-simplicity-of-your-information-system-with-openid-connect-fa8c26b99d6d) +- [English: youtube OIDC](https://www.youtube.com/watch?v=frIJfavZkUE&list=PL8EMdIH6Mzxy2kHtsVOEWqNz-OaM_D_fB&index=1) +- [French: youtube OIDC](https://www.youtube.com/watch?v=H-mLMGzQ_y0&list=PL8EMdIH6Mzxy2kHtsVOEWqNz-OaM_D_fB&index=2) ## NextJS @@ -562,15 +636,15 @@ To work with NextJS you need to inject your own history surcharge like the sampl **component/layout.js** ```javascript -import { OidcProvider } from "@axa-fr/react-oidc"; -import { useRouter } from "next/router"; +import { OidcProvider } from '@axa-fr/react-oidc'; +import { useRouter } from 'next/router'; const configuration = { - client_id: "interactive.public.short", - redirect_uri: "http://localhost:3001/#authentication/callback", - silent_redirect_uri: "http://localhost:3001/#authentication/silent-callback", // Optional activate silent-login that use cookies between OIDC server and client javascript to restore the session - scope: "openid profile email api offline_access", - authority: "https://demo.duendesoftware.com", + client_id: 'interactive.public.short', + redirect_uri: 'http://localhost:3001/#authentication/callback', + silent_redirect_uri: 'http://localhost:3001/#authentication/silent-callback', // Optional activate silent-login that use cookies between OIDC server and client javascript to restore the session + scope: 'openid profile email api offline_access', + authority: 'https://demo.duendesoftware.com', }; const onEvent = (configurationName, eventName, data) => { @@ -581,13 +655,13 @@ export default function Layout({ children }) { const router = useRouter(); const withCustomHistory = () => { return { - replaceState: (url) => { + replaceState: url => { router .replace({ pathname: url, }) .then(() => { - window.dispatchEvent(new Event("popstate")); + window.dispatchEvent(new Event('popstate')); }); }, }; @@ -615,21 +689,13 @@ For more information checkout the [NextJS React OIDC demo](https://github.com/Ax ```javascript export const configurationIdentityServerWithHash = { - client_id: "interactive.public.short", - redirect_uri: window.location.origin + "#authentication-callback", - silent_redirect_uri: - window.location.origin + "#authentication-silent-callback", - scope: "openid profile email api offline_access", - authority: "https://demo.duendesoftware.com", + client_id: 'interactive.public.short', + redirect_uri: window.location.origin + '#authentication-callback', + silent_redirect_uri: window.location.origin + '#authentication-silent-callback', + scope: 'openid profile email api offline_access', + authority: 'https://demo.duendesoftware.com', refresh_time_before_tokens_expiration_in_second: 70, - service_worker_relative_url: "/OidcServiceWorker.js", + service_worker_relative_url: '/OidcServiceWorker.js', service_worker_only: false, }; ``` - -## Service Worker Support - -- Firefox : tested on Firefox 98.0.2 -- Chrome/Edge : tested on version upper to 90 -- Opera : tested on version upper to 80 -- Safari : tested on Safari/605.1.15 diff --git a/packages/react-oidc/bin/copy-service-worker-files.mjs b/packages/react-oidc/bin/copy-service-worker-files.mjs new file mode 100644 index 000000000..d9fdbf575 --- /dev/null +++ b/packages/react-oidc/bin/copy-service-worker-files.mjs @@ -0,0 +1,76 @@ +/* global console, process */ +/* eslint no-console: "off" */ +import fs from 'fs'; +import path from 'path'; +import { fileURLToPath } from 'url'; + +try { + /** + * Script to run after npm install + * + * Copy selected files to user's directory + */ + const script_prefix = 'react-oidc'; + + const copyFile = async (src, dest, overwrite) => { + if (!fileExists(src)) { + console.log(`[${script_prefix}:skip] file does not exist ${src}`); + return false; + } + if (!overwrite) { + if (fileExists(dest)) { + console.log(`[${script_prefix}:skip] file exists not overwriting ${dest}`); + return true; + } + } + await fs.promises.copyFile(src, dest); + console.log(`[${script_prefix}:copy] ${dest}`); + return true; + }; + + const fileExists = path => { + return !!fs.existsSync(path); + }; + + const initPath = process.cwd(); + const __dirname = path.dirname(fileURLToPath(import.meta.url)); + const srcDir = path.join(__dirname, '..', '..', 'oidc-client-service-worker', 'dist'); + const srcDirFallback = path.join( + __dirname, + '..', + 'node_modules', + '@axa-fr', + 'oidc-client-service-worker', + 'dist', + ); + const destinationFolder = process.argv.length >= 3 ? process.argv[2] : 'public'; + const destinationDir = path.join(initPath, destinationFolder); + + const files = [ + { + fileName: 'OidcServiceWorker.js', + overwrite: true, + }, + { + fileName: 'OidcTrustedDomains.js', + overwrite: false, + }, + ]; + + for await (const file of files) { + const success = await copyFile( + path.join(srcDir, file.fileName), + path.join(destinationDir, file.fileName), + file.overwrite, + ); + if (!success) { + await copyFile( + path.join(srcDirFallback, file.fileName), + path.join(destinationDir, file.fileName), + file.overwrite, + ); + } + } +} catch (err) { + console.warn(err); +} diff --git a/packages/react-oidc/bin/post-install.js b/packages/react-oidc/bin/post-install.js deleted file mode 100644 index 49f138d49..000000000 --- a/packages/react-oidc/bin/post-install.js +++ /dev/null @@ -1,35 +0,0 @@ -import cpy from 'cpy'; -import path from 'path'; - -/** - * Script to run after npm install - * - * Copy selected files to user's directory - */ - -const initPath = process.env.INIT_CWD; -// console.log('currentdir:', process.cwd()); -// console.log('userPath:', initPath); - -function copyProgress(progress) { - console.log('✓ [react-oidc:copy] ', progress.destinationPath); -} - -const srcDir = '../oidc-client-service-worker/dist/'; -const destinationDir = path.join(initPath, 'public'); - -await cpy([path.join(srcDir,'OidcServiceWorker.js')], destinationDir, { - overwrite: true, -}).on('progress', copyProgress); - -try { - await cpy([path.join(srcDir,'OidcTrustedDomains.js')], destinationDir, { - overwrite: false, - }).on('progress', copyProgress); -} catch (e) { - if (e.code === 'EEXIST') { //file exists - console.log( - `✗ [react-oidc:skip] OidcTrustedDomains.js not copied, already exists in ${destinationDir}` - ); - } else throw e; -} diff --git a/packages/react-oidc/config/defaultEslintConfig.cjs b/packages/react-oidc/config/defaultEslintConfig.cjs deleted file mode 100644 index c3fa61f5b..000000000 --- a/packages/react-oidc/config/defaultEslintConfig.cjs +++ /dev/null @@ -1,148 +0,0 @@ -module.exports = { - parser: '@typescript-eslint/parser', - extends: [ - 'standard', - 'plugin:react/recommended', - 'plugin:react-hooks/recommended', - 'plugin:@typescript-eslint/eslint-recommended', - 'plugin:@typescript-eslint/recommended', - 'plugin:import/typescript', - 'plugin:jsx-a11y/recommended', - ], - plugins: ['simple-import-sort', 'testing-library'], - env: { - node: true, - es6: true, - browser: true, - }, - parserOptions: { - ecmaVersion: 2018, - sourceType: 'module', - ecmaFeatures: { - jsx: true, - }, - // typescript-eslint specific options - warnOnUnsupportedTypeScriptVersion: true, - }, - rules: { - '@typescript-eslint/interface-name-prefix': 'off', - '@typescript-eslint/no-non-null-assertion': 'off', - '@typescript-eslint/explicit-module-boundary-types': 'off', - '@typescript-eslint/no-explicit-any': 'off', - '@typescript-eslint/ban-ts-comment': 'off', - 'no-unused-vars': 'off', - '@typescript-eslint/no-unused-vars': [ - 'error', - { - argsIgnorePattern: '^_|req|res|next|err|ctx|args|context|info', - ignoreRestSiblings: true, - }, - ], - 'no-array-constructor': 'off', - '@typescript-eslint/no-array-constructor': 'warn', - 'no-redeclare': 'off', - '@typescript-eslint/no-redeclare': 'warn', - 'no-use-before-define': 'off', - '@typescript-eslint/no-use-before-define': [ - 'warn', - { - functions: false, - classes: false, - variables: false, - typedefs: false, - }, - ], - 'no-unused-expressions': 'off', - '@typescript-eslint/no-unused-expressions': [ - 'error', - { - allowShortCircuit: true, - allowTernary: true, - allowTaggedTemplates: true, - }, - ], - '@typescript-eslint/triple-slash-reference': 'off', - '@typescript-eslint/member-delimiter-style': [ - 'error', - { - multiline: { - delimiter: 'semi', - requireLast: true, - }, - singleline: { - delimiter: 'semi', - requireLast: false, - }, - }, - ], - camelcase: 'off', - 'comma-dangle': [ - 'error', - { - arrays: 'always-multiline', - objects: 'always-multiline', - imports: 'always-multiline', - exports: 'always-multiline', - functions: 'always-multiline', - }, - ], - 'array-callback-return': 'warn', - 'jsx-quotes': ['error', 'prefer-double'], - // 'max-len': ['error', { code: 120 }], - indent: 'off', - // quotes: ['error', 'single'], - semi: ['error', 'always'], - 'space-before-function-paren': 'off', - - 'import/no-named-as-default': 'off', - 'import/no-named-as-default-member': 'off', - 'import/default': 'off', - 'import/named': 'off', - 'import/namespace': 'off', - 'import/no-unresolved': 'off', - 'simple-import-sort/imports': 'error', - 'simple-import-sort/exports': 'error', - 'react/prop-types': 'off', - 'react/jsx-wrap-multilines': 'error', - 'react/react-in-jsx-scope': 'off', - 'react/display-name': 'off', - // https://github.com/facebook/react/tree/master/packages/eslint-plugin-react-hooks - 'react-hooks/rules-of-hooks': 'error', - 'react-hooks/exhaustive-deps': 'off', - }, - - overrides: [ - { - files: ['*.js', '*.jsx'], - rules: { - '@typescript-eslint/no-var-requires': 'off', - }, - }, - { - // 3) Now we enable eslint-plugin-testing-library rules or preset only for matching files! - files: ['**/?(*.)+(spec|test).[jt]s?(x)'], - extends: ['plugin:testing-library/react'], - rules: { - 'testing-library/await-async-query': 'error', - 'testing-library/no-await-sync-query': 'error', - 'testing-library/no-debugging-utils': 'warn', - 'testing-library/no-dom-import': 'off', - 'testing-library/no-unnecessary-act': 'off', - }, - }, - ], - - settings: { - react: { - version: 'detect', - }, - 'import/parsers': { - '@typescript-eslint/parser': ['.ts', '.tsx'], - }, - 'import/resolver': { - typescript: { - alwaysTryTypes: true, - }, - }, - }, - }; \ No newline at end of file diff --git a/packages/react-oidc/package.json b/packages/react-oidc/package.json index b2d851439..e34f680bb 100644 --- a/packages/react-oidc/package.json +++ b/packages/react-oidc/package.json @@ -1,6 +1,6 @@ { "name": "@axa-fr/react-oidc", - "version": "6.24.1", + "version": "7.26.0", "private": false, "type": "module", "main": "./dist/index.umd.cjs", @@ -9,7 +9,7 @@ "description": "OpenID Connect & OAuth authentication using react", "repository": { "type": "git", - "url": "https://github.com/AxaGuilDEv/react-oidc.git" + "url": "https://github.com/AxaFrance/oidc-client.git" }, "files": [ "dist", @@ -35,46 +35,36 @@ "serve": "vite preview", "test": "vitest --root . --coverage", "clean": "rimraf dist", - "postinstall": "node ./bin/post-install.js", + "postinstall": "echo 'WARNING keep sink OidcServiceWorker.js version file'", "prepare": "pnpm run clean && pnpm run copy-service-worker && pnpm run build", "lint": "eslint src" }, "dependencies": { "@axa-fr/oidc-client-service-worker": "workspace:*", - "@axa-fr/vanilla-oidc": "workspace:*" + "@axa-fr/oidc-client": "workspace:*" }, "peerDependencies": { - "react": "^17.0.0 || ^18.0.0", - "react-dom": "^17.0.0 || ^18.0.0", - "react-router-dom": "^6.0.0" + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" }, "devDependencies": { - "@testing-library/jest-dom": "5.16.5", - "@testing-library/react": "13.3.0", - "@testing-library/user-event": "14.4.3", - "@types/react": "^18.2.15", - "@typescript-eslint/eslint-plugin": "^5.50.0", - "@typescript-eslint/parser": "^5.50.0", - "@vitejs/plugin-react": "4.0.3", - "@vitest/coverage-v8": "^0.33.0", - "cpy": "^10.1.0", + "@testing-library/jest-dom": "6.6.3", + "@testing-library/react": "16.3.0", + "@testing-library/user-event": "14.6.1", + "@types/react": "19.1.2", + "@vitejs/plugin-react": "4.4.1", + "@vitest/coverage-v8": "3.1.3", + "cpy": "11.1.0", "cpy-cli": "^5.0.0", "cross-env": "^7.0.3", - "eslint": "^8.26.0", - "eslint-config-standard": "^17.1.0", - "eslint-config-standard-with-typescript": "^36.1.0", - "eslint-import-resolver-typescript": "^3.5.5", - "eslint-plugin-react": "^7.32.2", - "eslint-plugin-simple-import-sort": "^10.0.0", - "jsdom": "22.1.0", - "msw": "1.2.2", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "rimraf": "5.0.1", - "typescript": "5.1.6", - "vite": "^4.4.4", - "vite-plugin-dts": "^3.3.0", - "vitest": "^0.33.0" + "jsdom": "26.1.0", + "msw": "2.7.6", + "react": "^19.1.0", + "react-dom": "^19.1.0", + "rimraf": "6.0.1", + "typescript": "5.8.3", + "vite": "6.3.5", + "vite-plugin-dts": "4.5.3", + "vitest": "3.1.3" }, "license": "MIT", "publishConfig": { diff --git a/packages/react-oidc/public/OidcTrustedDomains.js b/packages/react-oidc/public/OidcTrustedDomains.js index 1aea5cd1a..e72a3d143 100644 --- a/packages/react-oidc/public/OidcTrustedDomains.js +++ b/packages/react-oidc/public/OidcTrustedDomains.js @@ -5,22 +5,25 @@ // Domains used by OIDC server must be also declared here // eslint-disable-next-line @typescript-eslint/no-unused-vars const trustedDomains = { - default: ['https://demo.duendesoftware.com', 'https://kdhttps.auth0.com'], - config_classic: ['https://demo.duendesoftware.com'], - config_without_silent_login: ['https://demo.duendesoftware.com'], - config_without_refresh_token: ['https://demo.duendesoftware.com'], - config_without_refresh_token_silent_login: ['https://demo.duendesoftware.com'], - config_google: ['https://oauth2.googleapis.com', 'https://openidconnect.googleapis.com'], - config_with_hash: ['https://demo.duendesoftware.com'], + default: ['https://demo.duendesoftware.com', 'https://kdhttps.auth0.com'], + config_classic: ['https://demo.duendesoftware.com'], + config_without_silent_login: ['https://demo.duendesoftware.com'], + config_without_refresh_token: ['https://demo.duendesoftware.com'], + config_without_refresh_token_silent_login: ['https://demo.duendesoftware.com'], + config_google: ['https://oauth2.googleapis.com', 'https://openidconnect.googleapis.com'], + config_with_hash: ['https://demo.duendesoftware.com'], }; // Service worker will continue to give access token to the JavaScript client // Ideal to hide refresh token from client JavaScript, but to retrieve access_token for some // scenarios which require it. For example, to send it via websocket connection. -trustedDomains.config_show_access_token = { domains: ['https://demo.duendesoftware.com'], showAccessToken: true }; +trustedDomains.config_show_access_token = { + domains: ['https://demo.duendesoftware.com'], + showAccessToken: true, +}; // This example defines domains used by OIDC server separately from domains to which access tokens will be injected. trustedDomains.config_separate_oidc_access_token_domains = { - oidcDomains: ['https://demo.duendesoftware.com'], - accessTokenDomains: ['https://myapi'], + oidcDomains: ['https://demo.duendesoftware.com'], + accessTokenDomains: ['https://myapi'], }; diff --git a/packages/react-oidc/src/FetchToken.tsx b/packages/react-oidc/src/FetchToken.tsx index aea6d68e7..71ce80167 100644 --- a/packages/react-oidc/src/FetchToken.tsx +++ b/packages/react-oidc/src/FetchToken.tsx @@ -1,4 +1,4 @@ -import { Fetch, VanillaOidc } from '@axa-fr/vanilla-oidc'; +import { Fetch, OidcClient } from '@axa-fr/oidc-client'; import { useCallback } from 'react'; export interface ComponentWithOidcFetchProps { @@ -7,50 +7,50 @@ export interface ComponentWithOidcFetchProps { const defaultConfigurationName = 'default'; -const fetchWithToken = (fetch: Fetch, getOidcWithConfigurationName: () => VanillaOidc | null) => async (...params: Parameters) => { - const [url, options, ...rest] = params; - const optionTmp = options ? { ...options } : { method: 'GET' }; - - let headers = new Headers(); - if (optionTmp.headers) { - headers = !(optionTmp.headers instanceof Headers) - ? new Headers(optionTmp.headers) - : optionTmp.headers; - } - const oidc = getOidcWithConfigurationName(); - - // @ts-ignore - const getValidToken = await oidc.getValidTokenAsync(); - const accessToken = getValidToken?.tokens?.accessToken; - - if (!headers.has('Accept')) { - headers.set('Accept', 'application/json'); - } - if (accessToken) { - headers.set('Authorization', `Bearer ${accessToken}`); - if (!optionTmp.credentials) { - optionTmp.credentials = 'same-origin'; - } - } - const newOptions = { ...optionTmp, headers }; - return await fetch(url, newOptions, ...rest); -}; - -export const withOidcFetch = (fetch: Fetch = null, configurationName = defaultConfigurationName) => ( - WrappedComponent, -) => (props: ComponentWithOidcFetchProps) => { - const { fetch: newFetch } = useOidcFetch(fetch || props.fetch, configurationName); - return ; -}; - -export const useOidcFetch = (fetch: Fetch = null, configurationName = defaultConfigurationName) => { +const fetchWithToken = + ( + fetch: Fetch, + getOidcWithConfigurationName: () => OidcClient | null, + demonstratingProofOfPossession: boolean = false, + ) => + async (...params: Parameters) => { + const oidc = getOidcWithConfigurationName(); + const newFetch = oidc.fetchWithTokens(fetch, demonstratingProofOfPossession); + return await newFetch(...params); + }; + +export const withOidcFetch = + ( + fetch: Fetch = null, + configurationName = defaultConfigurationName, + demonstratingProofOfPossession: boolean = false, + ) => + WrappedComponent => + (props: ComponentWithOidcFetchProps) => { + const { fetch: newFetch } = useOidcFetch( + fetch || props.fetch, + configurationName, + demonstratingProofOfPossession, + ); + return ; + }; + +export const useOidcFetch = ( + fetch: Fetch = null, + configurationName = defaultConfigurationName, + demonstratingProofOfPossession: boolean = false, +) => { const previousFetch = fetch || window.fetch; - const getOidc = VanillaOidc.get; + const getOidc = OidcClient.get; const memoizedFetchCallback = useCallback( (input: RequestInfo | URL, init?: RequestInit) => { const getOidcWithConfigurationName = () => getOidc(configurationName); - const newFetch = fetchWithToken(previousFetch, getOidcWithConfigurationName); + const newFetch = fetchWithToken( + previousFetch, + getOidcWithConfigurationName, + demonstratingProofOfPossession, + ); return newFetch(input, init); }, [previousFetch, configurationName], diff --git a/packages/react-oidc/src/OidcProvider.tsx b/packages/react-oidc/src/OidcProvider.tsx index b7ca22e55..db5424ebe 100644 --- a/packages/react-oidc/src/OidcProvider.tsx +++ b/packages/react-oidc/src/OidcProvider.tsx @@ -1,207 +1,262 @@ -import { Fetch, getFetchDefault, OidcConfiguration, VanillaOidc } from '@axa-fr/vanilla-oidc'; +import { + Fetch, + getFetchDefault, + ILOidcLocation, + OidcClient, + OidcConfiguration, + OidcLocation, +} from '@axa-fr/oidc-client'; import { ComponentType, FC, PropsWithChildren, useEffect, useState } from 'react'; import AuthenticatingError from './core/default-component/AuthenticateError.component.js'; -import { Authenticating, CallBackSuccess, Loading, SessionLost } from './core/default-component/index.js'; +import { + Authenticating, + CallBackSuccess, + Loading, + SessionLost, +} from './core/default-component/index.js'; import ServiceWorkerNotSupported from './core/default-component/ServiceWorkerNotSupported.component.js'; import OidcRoutes from './core/routes/OidcRoutes.js'; import { CustomHistory } from './core/routes/withRouter.js'; export type oidcContext = { - (name?: string): VanillaOidc; + (name?: string): OidcClient; }; const defaultEventState = { name: '', data: null }; export type OidcProviderProps = { - callbackSuccessComponent?: ComponentType; - sessionLostComponent?: ComponentType; - authenticatingComponent?: ComponentType; - authenticatingErrorComponent?: ComponentType; - loadingComponent?: ComponentType; - serviceWorkerNotSupportedComponent?: ComponentType; - configurationName?: string; - configuration?: OidcConfiguration; - children: any; - onSessionLost?: () => void; - onLogoutFromAnotherTab?: () => void; - onLogoutFromSameTab?: () => void; - withCustomHistory?: () => CustomHistory; - onEvent?: (configuration: string, name: string, data: any) => void; - getFetch?: () => Fetch; + callbackSuccessComponent?: ComponentType; + sessionLostComponent?: ComponentType; + authenticatingComponent?: ComponentType; + authenticatingErrorComponent?: ComponentType; + loadingComponent?: ComponentType; + serviceWorkerNotSupportedComponent?: ComponentType; + configurationName?: string; + configuration?: OidcConfiguration; + children: any; + onSessionLost?: () => void; + onLogoutFromAnotherTab?: () => void; + onLogoutFromSameTab?: () => void; + withCustomHistory?: () => CustomHistory; + onEvent?: (configuration: string, name: string, data: any) => void; + getFetch?: () => Fetch; + location?: ILOidcLocation; }; export type OidcSessionProps = { - configurationName: string; - loadingComponent: PropsWithChildren; + configurationName: string; + loadingComponent: PropsWithChildren; }; -const OidcSession: FC> = ({ loadingComponent, children, configurationName }) => { - const [isLoading, setIsLoading] = useState(true); - const getOidc = VanillaOidc.get; - const oidc = getOidc(configurationName); - useEffect(() => { - let isMounted = true; - if (oidc) { - oidc.tryKeepExistingSessionAsync().then(() => { - if (isMounted) { - setIsLoading(false); - } - }); +const OidcSession: FC> = ({ + loadingComponent, + children, + configurationName, +}) => { + const [isLoading, setIsLoading] = useState(true); + const getOidc = OidcClient.get; + const oidc = getOidc(configurationName); + useEffect(() => { + let isMounted = true; + if (oidc) { + oidc.tryKeepExistingSessionAsync().then(() => { + if (isMounted) { + setIsLoading(false); } - return () => { - isMounted = false; - }; - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [configurationName]); - const LoadingComponent = loadingComponent; - return ( - <> - {isLoading - ? ( - - ) - : ( - <>{children} - )} - - ); + }); + } + return () => { + isMounted = false; + }; + }, [configurationName]); + const LoadingComponent = loadingComponent; + return ( + <>{isLoading ? : <>{children}} + ); }; const Switch = ({ isLoading, loadingComponent, children, configurationName }) => { - const LoadingComponent = loadingComponent; - if (isLoading) { - return {children}; - } - return <>{children}; + const LoadingComponent = loadingComponent; + if (isLoading) { + return {children}; + } + return <>{children}; }; export const OidcProvider: FC> = ({ - children, - configuration, - configurationName = 'default', - callbackSuccessComponent = CallBackSuccess, - authenticatingComponent = Authenticating, - loadingComponent = Loading, - serviceWorkerNotSupportedComponent = ServiceWorkerNotSupported, - authenticatingErrorComponent = AuthenticatingError, - sessionLostComponent = SessionLost, - onSessionLost = null, - onLogoutFromAnotherTab = null, - onLogoutFromSameTab = null, - withCustomHistory = null, - onEvent = null, - getFetch = null, + children, + configuration, + configurationName = 'default', + callbackSuccessComponent = CallBackSuccess, + authenticatingComponent = Authenticating, + loadingComponent = Loading, + serviceWorkerNotSupportedComponent = ServiceWorkerNotSupported, + authenticatingErrorComponent = AuthenticatingError, + sessionLostComponent = SessionLost, + onSessionLost = null, + onLogoutFromAnotherTab = null, + onLogoutFromSameTab = null, + withCustomHistory = null, + onEvent = null, + getFetch = null, + location = null, }) => { - const getOidc = (configurationName = 'default') => { - return VanillaOidc.getOrCreate(getFetch ?? getFetchDefault)(configuration, configurationName); + if (configuration && configuration.redirect_uri && configuration.silent_redirect_uri) { + if (configuration.redirect_uri === configuration.silent_redirect_uri) { + throw new Error('redirect_uri and silent_redirect_uri must be different'); + } + } + + const getOidc = (configurationName = 'default') => { + return OidcClient.getOrCreate(getFetch ?? getFetchDefault, location ?? new OidcLocation())( + configuration, + configurationName, + ); + }; + + const [loading, setLoading] = useState(true); + const [event, setEvent] = useState(defaultEventState); + const [currentConfigurationName, setConfigurationName] = useState('default'); + + useEffect(() => { + const oidc = getOidc(configurationName); + const newSubscriptionId = oidc.subscribeEvents((name, data) => { + if (onEvent) { + onEvent(configurationName, name, data); + } + }); + return () => { + const previousOidc = getOidc(configurationName); + previousOidc.removeEventSubscription(newSubscriptionId); }; - // eslint-disable-next-line @typescript-eslint/naming-convention - const [loading, setLoading] = useState(true); - const [event, setEvent] = useState(defaultEventState); - const [currentConfigurationName, setConfigurationName] = useState('default'); - - useEffect(() => { - const oidc = getOidc(configurationName); - const newSubscriptionId = oidc.subscribeEvents((name, data) => { - if (onEvent) { - onEvent(configurationName, name, data); - } - }); - return () => { - const previousOidc = getOidc(configurationName); - previousOidc.removeEventSubscription(newSubscriptionId); - }; - }, [configurationName, onEvent]); - - useEffect(() => { - const oidc = getOidc(configurationName); - const newSubscriptionId = oidc.subscribeEvents((name, data) => { - if (name === VanillaOidc.eventNames.refreshTokensAsync_error || name === VanillaOidc.eventNames.syncTokensAsync_error) { - if (onSessionLost != null) { - onSessionLost(); - return; - } - setEvent({ name, data }); - } else if (name === VanillaOidc.eventNames.logout_from_another_tab) { - if (onLogoutFromAnotherTab != null) { - onLogoutFromAnotherTab(); - return; - } - setEvent({ name, data }); - } else if (name === VanillaOidc.eventNames.logout_from_same_tab) { - if (onLogoutFromSameTab != null) { - onLogoutFromSameTab(); - } - // setEvent({name, data}); - } else if (name === VanillaOidc.eventNames.loginAsync_begin || - name === VanillaOidc.eventNames.loginCallbackAsync_end || - name === VanillaOidc.eventNames.loginAsync_error || - name === VanillaOidc.eventNames.loginCallbackAsync_error - ) { - setEvent({ name, data }); - } else if (name === VanillaOidc.eventNames.service_worker_not_supported_by_browser && configuration.service_worker_only === true) { - setEvent({ name, data }); - } - }); - - setConfigurationName(configurationName); - setLoading(false); - return () => { - const previousOidc = getOidc(configurationName); - previousOidc.removeEventSubscription(newSubscriptionId); - setEvent(defaultEventState); - }; - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [configuration, configurationName]); - - const SessionLostComponent = sessionLostComponent; - const AuthenticatingComponent = authenticatingComponent; - const LoadingComponent = loadingComponent; - const ServiceWorkerNotSupportedComponent = serviceWorkerNotSupportedComponent; - const AuthenticatingErrorComponent = authenticatingErrorComponent; - - const isLoading = (loading || (currentConfigurationName !== configurationName)); + }, [configurationName, onEvent]); + + useEffect(() => { const oidc = getOidc(configurationName); - const eventName = event.name; - switch (eventName) { - case VanillaOidc.eventNames.service_worker_not_supported_by_browser: - return ( - - ); - case VanillaOidc.eventNames.loginAsync_begin: - return ( - - ); - case VanillaOidc.eventNames.loginAsync_error: - case VanillaOidc.eventNames.loginCallbackAsync_error: - return ( - - ); - case VanillaOidc.eventNames.refreshTokensAsync_error: - case VanillaOidc.eventNames.syncTokensAsync_error: - case VanillaOidc.eventNames.logout_from_another_tab: - return ( - - ); - default: - return ( - - - - {children} - - - - ); - } + const newSubscriptionId = oidc.subscribeEvents((name, data) => { + if ( + name === OidcClient.eventNames.refreshTokensAsync_error || + name === OidcClient.eventNames.syncTokensAsync_error + ) { + if (onSessionLost != null) { + onSessionLost(); + return; + } + setEvent({ name, data }); + } else if (name === OidcClient.eventNames.logout_from_another_tab) { + if (onLogoutFromAnotherTab != null) { + onLogoutFromAnotherTab(); + return; + } + setEvent({ name, data }); + } else if (name === OidcClient.eventNames.logout_from_same_tab) { + if (onLogoutFromSameTab != null) { + onLogoutFromSameTab(); + } + // setEvent({name, data}); + } else if ( + name === OidcClient.eventNames.loginAsync_begin || + name === OidcClient.eventNames.loginCallbackAsync_end || + name === OidcClient.eventNames.loginAsync_error || + name === OidcClient.eventNames.loginCallbackAsync_error + ) { + setEvent({ name, data }); + } else if ( + name === OidcClient.eventNames.service_worker_not_supported_by_browser && + configuration.service_worker_only === true + ) { + setEvent({ name, data }); + } + }); + + setConfigurationName(configurationName); + setLoading(false); + return () => { + const previousOidc = getOidc(configurationName); + previousOidc.removeEventSubscription(newSubscriptionId); + setEvent(defaultEventState); + }; + }, [configuration, configurationName]); + + const SessionLostComponent = sessionLostComponent; + const AuthenticatingComponent = authenticatingComponent; + const LoadingComponent = loadingComponent; + const ServiceWorkerNotSupportedComponent = serviceWorkerNotSupportedComponent; + const AuthenticatingErrorComponent = authenticatingErrorComponent; + + const isLoading = loading || currentConfigurationName !== configurationName; + const oidc = getOidc(configurationName); + const eventName = event.name; + switch (eventName) { + case OidcClient.eventNames.service_worker_not_supported_by_browser: + return ( + + + + ); + case OidcClient.eventNames.loginAsync_begin: + return ( + + + + ); + case OidcClient.eventNames.loginAsync_error: + case OidcClient.eventNames.loginCallbackAsync_error: + return ( + + + + ); + case OidcClient.eventNames.refreshTokensAsync_error: + case OidcClient.eventNames.syncTokensAsync_error: + case OidcClient.eventNames.logout_from_another_tab: + return ( + + + + ); + default: + return ( + + + + {children} + + + + ); + } }; export default OidcProvider; diff --git a/packages/react-oidc/src/OidcSecure.tsx b/packages/react-oidc/src/OidcSecure.tsx index 0635e2f66..448959adc 100644 --- a/packages/react-oidc/src/OidcSecure.tsx +++ b/packages/react-oidc/src/OidcSecure.tsx @@ -1,32 +1,43 @@ -import { StringMap, VanillaOidc } from '@axa-fr/vanilla-oidc'; +import { OidcClient, StringMap } from '@axa-fr/oidc-client'; import { FC, PropsWithChildren, useEffect } from 'react'; export type OidcSecureProps = { - callbackPath?:string; - extras?:StringMap; - configurationName?: string; + callbackPath?: string; + extras?: StringMap; + configurationName?: string; }; -export const OidcSecure: FC> = ({ children, callbackPath = null, extras = null, configurationName = 'default' }) => { - const getOidc = VanillaOidc.get; - const oidc = getOidc(configurationName); - useEffect(() => { - if (!oidc.tokens) { - oidc.loginAsync(callbackPath, extras); - } - }, [configurationName, callbackPath, extras]); - - if (!oidc.tokens) { - return null; - } - return <>{children}; -}; - -export const withOidcSecure = ( - WrappedComponent: FC>, +export const OidcSecure: FC> = ({ + children, callbackPath = null, extras = null, configurationName = 'default', -) => (props) => { - return ; +}) => { + const getOidc = OidcClient.get; + const oidc = getOidc(configurationName); + useEffect(() => { + if (!oidc.tokens) { + oidc.loginAsync(callbackPath, extras); + } + }, [configurationName, callbackPath, extras]); + + if (!oidc.tokens) { + return null; + } + return <>{children}; }; + +export const withOidcSecure = + ( + WrappedComponent: FC>, + callbackPath = null, + extras = null, + configurationName = 'default', + ) => + props => { + return ( + + + + ); + }; diff --git a/packages/react-oidc/src/ReactOidc.tsx b/packages/react-oidc/src/ReactOidc.tsx index 367c4d085..f9ecd24f5 100644 --- a/packages/react-oidc/src/ReactOidc.tsx +++ b/packages/react-oidc/src/ReactOidc.tsx @@ -1,168 +1,221 @@ -import { StringMap, VanillaOidc } from '@axa-fr/vanilla-oidc'; +import { OidcClient, StringMap, Tokens } from '@axa-fr/oidc-client'; import { useEffect, useState } from 'react'; const defaultConfigurationName = 'default'; type GetOidcFn = { - (configurationName?: string): any; -} + (configurationName?: string): any; +}; const defaultIsAuthenticated = (getOidc: GetOidcFn, configurationName: string) => { - let isAuthenticated = false; - const oidc = getOidc(configurationName); - if (oidc) { - isAuthenticated = getOidc(configurationName).tokens != null; - } - return isAuthenticated; + let isAuthenticated = false; + const oidc = getOidc(configurationName); + if (oidc) { + isAuthenticated = getOidc(configurationName).tokens != null; + } + return isAuthenticated; }; export const useOidc = (configurationName = defaultConfigurationName) => { - const getOidc = VanillaOidc.get; - const [isAuthenticated, setIsAuthenticated] = useState(defaultIsAuthenticated(getOidc, configurationName)); - - useEffect(() => { - let isMounted = true; - const oidc = getOidc(configurationName); - setIsAuthenticated(defaultIsAuthenticated(getOidc, configurationName)); - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const newSubscriptionId = oidc.subscribeEvents((name: string, data: any) => { - if (name === VanillaOidc.eventNames.logout_from_another_tab || name === VanillaOidc.eventNames.logout_from_same_tab || name === VanillaOidc.eventNames.token_aquired) { - if (isMounted) { - setIsAuthenticated(defaultIsAuthenticated(getOidc, configurationName)); - } - } - }); - return () => { - isMounted = false; - oidc.removeEventSubscription(newSubscriptionId); - }; - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [configurationName]); - - const login = (callbackPath:string | undefined = undefined, extras:StringMap = null, silentLoginOnly = false) => { - return getOidc(configurationName).loginAsync(callbackPath, extras, false, undefined, silentLoginOnly); - }; - const logout = (callbackPath: string | null | undefined = undefined, extras:StringMap = null) => { - return getOidc(configurationName).logoutAsync(callbackPath, extras); + const getOidc = OidcClient.get; + const [isAuthenticated, setIsAuthenticated] = useState( + defaultIsAuthenticated(getOidc, configurationName), + ); + + useEffect(() => { + let isMounted = true; + const oidc = getOidc(configurationName); + setIsAuthenticated(defaultIsAuthenticated(getOidc, configurationName)); + + const newSubscriptionId = oidc.subscribeEvents((name: string, data: any) => { + if ( + name === OidcClient.eventNames.logout_from_another_tab || + name === OidcClient.eventNames.logout_from_same_tab || + name === OidcClient.eventNames.token_acquired + ) { + if (isMounted) { + setIsAuthenticated(defaultIsAuthenticated(getOidc, configurationName)); + } + } + }); + return () => { + isMounted = false; + oidc.removeEventSubscription(newSubscriptionId); }; - const renewTokens = async (extras: StringMap = null) : Promise => { - const tokens = await getOidc(configurationName).renewTokensAsync(extras); - - return { - // @ts-ignore - accessToken: tokens.accessToken, - // @ts-ignore - accessTokenPayload: tokens.accessTokenPayload, - // @ts-ignore - idToken: tokens.idToken, - // @ts-ignore - idTokenPayload: tokens.idTokenPayload, - }; + }, [configurationName]); + + const login = ( + callbackPath: string | undefined = undefined, + extras: StringMap | undefined = undefined, + silentLoginOnly = false, + scope: string = undefined, + ) => { + return getOidc(configurationName).loginAsync( + callbackPath, + extras, + false, + scope, + silentLoginOnly, + ); + }; + const logout = ( + callbackPath: string | null | undefined = undefined, + extras: StringMap | undefined = undefined, + ) => { + return getOidc(configurationName).logoutAsync(callbackPath, extras); + }; + const renewTokens = async ( + extras: StringMap | undefined = undefined, + ): Promise => { + const tokens = await getOidc(configurationName).renewTokensAsync(extras); + + return { + // @ts-ignore + accessToken: tokens.accessToken, + // @ts-ignore + accessTokenPayload: tokens.accessTokenPayload, + // @ts-ignore + idToken: tokens.idToken, + // @ts-ignore + idTokenPayload: tokens.idTokenPayload, }; - return { login, logout, renewTokens, isAuthenticated }; + }; + return { login, logout, renewTokens, isAuthenticated }; }; const accessTokenInitialState = { accessToken: null, accessTokenPayload: null }; const initTokens = (configurationName: string) => { - const getOidc = VanillaOidc.get; - const oidc = getOidc(configurationName); - if (oidc.tokens) { - const tokens = oidc.tokens; - return { - accessToken: tokens.accessToken, - accessTokenPayload: tokens.accessTokenPayload, - }; - } - return accessTokenInitialState; + const getOidc = OidcClient.get; + const oidc = getOidc(configurationName); + if (oidc.tokens) { + const tokens = oidc.tokens; + return { + accessToken: tokens.accessToken, + accessTokenPayload: tokens.accessTokenPayload, + generateDemonstrationOfProofOfPossessionAsync: oidc.configuration + .demonstrating_proof_of_possession + ? (url: string, method: string) => + oidc.generateDemonstrationOfProofOfPossessionAsync(tokens.accessToken, url, method) + : null, + }; + } + return accessTokenInitialState; }; export type OidcAccessToken = { - accessToken?: any; - accessTokenPayload?: any; + accessToken?: any; + accessTokenPayload?: any; + generateDemonstrationOfProofOfPossessionAsync?: any; +}; + +function getGenerateDemonstrationOfProofOfPossessionAsync(oidc: OidcClient, tokens: Tokens) { + return oidc.configuration.demonstrating_proof_of_possession + ? (url: string, method: string, extras: StringMap = {}) => + oidc.generateDemonstrationOfProofOfPossessionAsync(tokens.accessToken, url, method, extras) + : null; } export const useOidcAccessToken = (configurationName = defaultConfigurationName) => { - const getOidc = VanillaOidc.get; - const [state, setAccessToken] = useState(initTokens(configurationName)); - - useEffect(() => { - let isMounted = true; - const oidc = getOidc(configurationName); - if (oidc.tokens) { - const tokens = oidc.tokens; - setAccessToken({ accessToken: tokens.accessToken, accessTokenPayload: tokens.accessTokenPayload }); - } - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const newSubscriptionId = oidc.subscribeEvents((name: string, data: any) => { - if (name === VanillaOidc.eventNames.token_renewed || - name === VanillaOidc.eventNames.token_aquired || - name === VanillaOidc.eventNames.logout_from_another_tab || - name === VanillaOidc.eventNames.logout_from_same_tab || - name === VanillaOidc.eventNames.refreshTokensAsync_error || - name === VanillaOidc.eventNames.syncTokensAsync_error) { - if (isMounted) { - const tokens = oidc.tokens; - setAccessToken(tokens != null ? { accessToken: tokens.accessToken, accessTokenPayload: tokens.accessTokenPayload } : accessTokenInitialState); + const getOidc = OidcClient.get; + const [state, setAccessToken] = useState(initTokens(configurationName)); + + useEffect(() => { + let isMounted = true; + const oidc = getOidc(configurationName); + if (oidc.tokens) { + const tokens = oidc.tokens; + setAccessToken({ + accessToken: tokens.accessToken, + accessTokenPayload: tokens.accessTokenPayload, + }); + } + + const newSubscriptionId = oidc.subscribeEvents((name: string, data: any) => { + if ( + name === OidcClient.eventNames.token_renewed || + name === OidcClient.eventNames.token_acquired || + name === OidcClient.eventNames.logout_from_another_tab || + name === OidcClient.eventNames.logout_from_same_tab || + name === OidcClient.eventNames.refreshTokensAsync_error || + name === OidcClient.eventNames.syncTokensAsync_error + ) { + if (isMounted) { + const tokens = oidc.tokens; + setAccessToken( + tokens != null + ? { + accessToken: tokens.accessToken, + accessTokenPayload: tokens.accessTokenPayload, + generateDemonstrationOfProofOfPossessionAsync: + getGenerateDemonstrationOfProofOfPossessionAsync(oidc, tokens), } - } - }); - return () => { - isMounted = false; - oidc.removeEventSubscription(newSubscriptionId); - }; - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [configurationName]); - return state; + : accessTokenInitialState, + ); + } + } + }); + return () => { + isMounted = false; + oidc.removeEventSubscription(newSubscriptionId); + }; + }, [configurationName]); + return state; }; const idTokenInitialState = { idToken: null, idTokenPayload: null }; const initIdToken = (configurationName: string) => { - const getOidc = VanillaOidc.get; - const oidc = getOidc(configurationName); - if (oidc.tokens) { - const tokens = oidc.tokens; - return { idToken: tokens.idToken, idTokenPayload: tokens.idTokenPayload }; - } - return idTokenInitialState; + const getOidc = OidcClient.get; + const oidc = getOidc(configurationName); + + if (oidc.tokens) { + const tokens = oidc.tokens; + return { idToken: tokens.idToken, idTokenPayload: tokens.idTokenPayload }; + } + return idTokenInitialState; }; export type OidcIdToken = { - idToken?: any; - idTokenPayload?: any; -} + idToken?: any; + idTokenPayload?: any; +}; export const useOidcIdToken = (configurationName = defaultConfigurationName) => { - const getOidc = VanillaOidc.get; - const [state, setIDToken] = useState(initIdToken(configurationName)); - - useEffect(() => { - let isMounted = true; - const oidc = getOidc(configurationName); - if (oidc.tokens) { - const tokens = oidc.tokens; - setIDToken({ idToken: tokens.idToken, idTokenPayload: tokens.idTokenPayload }); + const getOidc = OidcClient.get; + const [state, setIDToken] = useState(initIdToken(configurationName)); + + useEffect(() => { + let isMounted = true; + const oidc = getOidc(configurationName); + if (oidc.tokens) { + const tokens = oidc.tokens; + setIDToken({ idToken: tokens.idToken, idTokenPayload: tokens.idTokenPayload }); + } + + const newSubscriptionId = oidc.subscribeEvents((name: string, data: any) => { + if ( + name === OidcClient.eventNames.token_renewed || + name === OidcClient.eventNames.token_acquired || + name === OidcClient.eventNames.logout_from_another_tab || + name === OidcClient.eventNames.logout_from_same_tab || + name === OidcClient.eventNames.refreshTokensAsync_error || + name === OidcClient.eventNames.syncTokensAsync_error + ) { + if (isMounted) { + const tokens = oidc.tokens; + setIDToken( + tokens != null + ? { idToken: tokens.idToken, idTokenPayload: tokens.idTokenPayload } + : idTokenInitialState, + ); } - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const newSubscriptionId = oidc.subscribeEvents((name: string, data: any) => { - if (name === VanillaOidc.eventNames.token_renewed || - name === VanillaOidc.eventNames.token_aquired || - name === VanillaOidc.eventNames.logout_from_another_tab || - name === VanillaOidc.eventNames.logout_from_same_tab || - name === VanillaOidc.eventNames.refreshTokensAsync_error || - name === VanillaOidc.eventNames.syncTokensAsync_error) { - if (isMounted) { - const tokens = oidc.tokens; - setIDToken(tokens != null ? { idToken: tokens.idToken, idTokenPayload: tokens.idTokenPayload } : idTokenInitialState); - } - } - }); - return () => { - isMounted = false; - oidc.removeEventSubscription(newSubscriptionId); - }; - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [configurationName]); - return state; + } + }); + return () => { + isMounted = false; + oidc.removeEventSubscription(newSubscriptionId); + }; + }, [configurationName]); + return state; }; diff --git a/packages/react-oidc/src/User.ts b/packages/react-oidc/src/User.ts index 4311e0c58..dd647ca68 100644 --- a/packages/react-oidc/src/User.ts +++ b/packages/react-oidc/src/User.ts @@ -1,45 +1,72 @@ -import { type OidcUserInfo, VanillaOidc } from '@axa-fr/vanilla-oidc'; +import { OidcClient, type OidcUserInfo } from '@axa-fr/oidc-client'; import { useEffect, useState } from 'react'; export enum OidcUserStatus { - Unauthenticated= 'Unauthenticated', - Loading = 'Loading user', - Loaded = 'User loaded', - LoadingError = 'Error loading user' + Unauthenticated = 'Unauthenticated', + Loading = 'Loading user', + Loaded = 'User loaded', + LoadingError = 'Error loading user', } export type OidcUser = { - user: T; - status: OidcUserStatus; -} + user: T | null; + status: OidcUserStatus; +}; -export const useOidcUser = (configurationName = 'default') => { - const [oidcUser, setOidcUser] = useState>({ user: null, status: OidcUserStatus.Unauthenticated }); - const [oidcUserId, setOidcUserId] = useState(''); +export const useOidcUser = ( + configurationName = 'default', + demonstrating_proof_of_possession = false, +) => { + const oidc = OidcClient.get(configurationName); + const user = oidc.userInfo(); + const [oidcUser, setOidcUser] = useState>({ + user: user, + status: user ? OidcUserStatus.Loaded : OidcUserStatus.Unauthenticated, + }); + const [oidcUserId, setOidcUserId] = useState(user ? 1 : 0); + const [oidcPreviousUserId, setPreviousOidcUserId] = useState(user ? 1 : 0); - const oidc = VanillaOidc.get(configurationName); - useEffect(() => { - let isMounted = true; - if (oidc && oidc.tokens) { - setOidcUser({ ...oidcUser, status: OidcUserStatus.Loading }); - const isNoCache = oidcUserId !== ''; - oidc.userInfoAsync(isNoCache) - .then((info) => { - if (isMounted) { - // @ts-ignore - setOidcUser({ user: info, status: OidcUserStatus.Loaded }); - } - }) - .catch(() => setOidcUser({ ...oidcUser, status: OidcUserStatus.LoadingError })); - } else { - setOidcUser({ user: null, status: OidcUserStatus.Unauthenticated }); + useEffect(() => { + const oidc = OidcClient.get(configurationName); + let isMounted = true; + if (oidc && oidc.tokens) { + const isCache = oidcUserId === oidcPreviousUserId; + if (isCache && oidc.userInfo()) { + return; + } + setOidcUser({ ...oidcUser, status: OidcUserStatus.Loading }); + oidc + .userInfoAsync(!isCache, demonstrating_proof_of_possession) + .then(info => { + if (isMounted) { + // @ts-ignore + setOidcUser({ user: info, status: OidcUserStatus.Loaded }); + } + }) + .catch(() => setOidcUser({ ...oidcUser, status: OidcUserStatus.LoadingError })); + setPreviousOidcUserId(oidcUserId); + } else { + setOidcUser({ user: null, status: OidcUserStatus.Unauthenticated }); + } + const newSubscriptionId = oidc.subscribeEvents((name: string) => { + if ( + name === OidcClient.eventNames.logout_from_another_tab || + name === OidcClient.eventNames.logout_from_same_tab + ) { + if (isMounted) { + setOidcUser({ user: null, status: OidcUserStatus.Unauthenticated }); } - return () => { isMounted = false; }; - }, [oidcUserId]); - - const reloadOidcUser = () => { - setOidcUserId(oidcUserId + ' '); + } + }); + return () => { + isMounted = false; + oidc.removeEventSubscription(newSubscriptionId); }; + }, [oidcUserId]); + + const reloadOidcUser = () => { + setOidcUserId(oidcUserId + 1); + }; - return { oidcUser: oidcUser.user, oidcUserLoadingState: oidcUser.status, reloadOidcUser }; + return { oidcUser: oidcUser.user, oidcUserLoadingState: oidcUser.status, reloadOidcUser }; }; diff --git a/packages/react-oidc/src/core/default-component/Authenticating.component.tsx b/packages/react-oidc/src/core/default-component/Authenticating.component.tsx index 5b286a95b..772d4f483 100644 --- a/packages/react-oidc/src/core/default-component/Authenticating.component.tsx +++ b/packages/react-oidc/src/core/default-component/Authenticating.component.tsx @@ -1,6 +1,6 @@ import { ComponentType } from 'react'; -const Authenticating : ComponentType = () => ( +const Authenticating: ComponentType = () => (

Authentication in progress

diff --git a/packages/react-oidc/src/core/default-component/Callback.component.tsx b/packages/react-oidc/src/core/default-component/Callback.component.tsx index 612d326b8..a9b2bc230 100644 --- a/packages/react-oidc/src/core/default-component/Callback.component.tsx +++ b/packages/react-oidc/src/core/default-component/Callback.component.tsx @@ -1,31 +1,38 @@ -import { VanillaOidc } from '@axa-fr/vanilla-oidc'; +import { OidcClient } from '@axa-fr/oidc-client'; import { ComponentType, useEffect, useState } from 'react'; import { getCustomHistory } from '../routes/withRouter.js'; import AuthenticatingError from './AuthenticateError.component.js'; -export const CallBackSuccess: ComponentType = () => (
-
-

Authentication complete

-

You will be redirected to your application.

+export const CallBackSuccess: ComponentType = () => ( +
+
+

Authentication complete

+

You will be redirected to your application.

+
-
); +); -const CallbackManager: ComponentType = ({ callBackError, callBackSuccess, configurationName, withCustomHistory }) => { +const CallbackManager: ComponentType = ({ + callBackError, + callBackSuccess, + configurationName, + withCustomHistory, +}) => { const [isError, setIsError] = useState(false); useEffect(() => { let isMounted = true; const playCallbackAsync = async () => { - const getOidc = VanillaOidc.get; + const getOidc = OidcClient.get; try { const { callbackPath } = await getOidc(configurationName).loginCallbackAsync(); - const history = (withCustomHistory) ? withCustomHistory() : getCustomHistory(); + const history = withCustomHistory ? withCustomHistory() : getCustomHistory(); history.replaceState(callbackPath || '/'); } catch (error) { - if (isMounted) { - console.warn(error); - setIsError(true); - } + if (isMounted) { + console.warn(error); + setIsError(true); + } } }; playCallbackAsync(); diff --git a/packages/react-oidc/src/core/default-component/Loading.component.tsx b/packages/react-oidc/src/core/default-component/Loading.component.tsx index e404ade19..a86b68a89 100644 --- a/packages/react-oidc/src/core/default-component/Loading.component.tsx +++ b/packages/react-oidc/src/core/default-component/Loading.component.tsx @@ -1,9 +1,5 @@ import { ComponentType } from 'react'; -const Loading : ComponentType = () => ( - - Loading - -); +const Loading: ComponentType = () => Loading; export default Loading; diff --git a/packages/react-oidc/src/core/default-component/ServiceWorkerNotSupported.component.tsx b/packages/react-oidc/src/core/default-component/ServiceWorkerNotSupported.component.tsx index 49c499f1b..649a97237 100644 --- a/packages/react-oidc/src/core/default-component/ServiceWorkerNotSupported.component.tsx +++ b/packages/react-oidc/src/core/default-component/ServiceWorkerNotSupported.component.tsx @@ -1,10 +1,13 @@ import { ComponentType } from 'react'; -const ServiceWorkerNotSupported : ComponentType = () => ( +const ServiceWorkerNotSupported: ComponentType = () => (

Unable to authenticate on this browser

-

Your browser is not secure enough to make authentication work. Try updating your browser or use a newer browser.

+

+ Your browser is not secure enough to make authentication work. Try updating your browser or + use a newer browser. +

); diff --git a/packages/react-oidc/src/core/default-component/SessionLost.component.tsx b/packages/react-oidc/src/core/default-component/SessionLost.component.tsx index 25e4c889f..c2f4ee348 100644 --- a/packages/react-oidc/src/core/default-component/SessionLost.component.tsx +++ b/packages/react-oidc/src/core/default-component/SessionLost.component.tsx @@ -5,7 +5,7 @@ export const SessionLost: ComponentType = () => (

Session timed out

- Your session has expired. Please re-authenticate. + Your session has expired. Please re-authenticate.

diff --git a/packages/react-oidc/src/core/default-component/SilentCallback.component.tsx b/packages/react-oidc/src/core/default-component/SilentCallback.component.tsx index dcef5baa4..8a3865267 100644 --- a/packages/react-oidc/src/core/default-component/SilentCallback.component.tsx +++ b/packages/react-oidc/src/core/default-component/SilentCallback.component.tsx @@ -1,17 +1,23 @@ -import { VanillaOidc } from '@axa-fr/vanilla-oidc'; -import { ComponentType, useEffect } from 'react'; +import { OidcClient } from '@axa-fr/oidc-client'; +import { FC, useEffect } from 'react'; -const SilentCallbackManager: ComponentType = ({ configurationName }) => { - useEffect(() => { - const playCallbackAsync = async () => { - const getOidc = VanillaOidc.get; - const oidc = getOidc(configurationName); - oidc.silentLoginCallbackAsync(); - }; - playCallbackAsync(); - }, []); +export interface SilentCallbackProps { + configurationName: string; +} - return <>; +const SilentCallbackManager: FC = ({ configurationName }) => { + useEffect(() => { + const playCallbackAsync = async () => { + const oidc = OidcClient.get(configurationName); + oidc.silentLoginCallbackAsync(); + }; + + playCallbackAsync().catch(error => { + console.error('Error during silent login callback:', error); + }); + }, [configurationName]); + + return null; }; export default SilentCallbackManager; diff --git a/packages/react-oidc/src/core/default-component/SilentLogin.component.tsx b/packages/react-oidc/src/core/default-component/SilentLogin.component.tsx index f12290bbd..c7255b61d 100644 --- a/packages/react-oidc/src/core/default-component/SilentLogin.component.tsx +++ b/packages/react-oidc/src/core/default-component/SilentLogin.component.tsx @@ -1,31 +1,31 @@ -import { getParseQueryStringFromLocation, VanillaOidc } from '@axa-fr/vanilla-oidc'; +import { getParseQueryStringFromLocation, OidcClient } from '@axa-fr/oidc-client'; import { ComponentType, useEffect } from 'react'; const SilentLogin: ComponentType = ({ configurationName }) => { - const queryParams = getParseQueryStringFromLocation(window.location.href); + const queryParams = getParseQueryStringFromLocation(window.location.href); - const getOidc = VanillaOidc.get; - const oidc = getOidc(configurationName); + const getOidc = OidcClient.get; + const oidc = getOidc(configurationName); - let extras = null; + let extras = null; - for (const [key, value] of Object.entries(queryParams)) { - if (key === 'state' || key === 'scope') { - continue; - } - if (extras === null) { - extras = {}; - } - extras[key] = value; + for (const [key, value] of Object.entries(queryParams)) { + if (key === 'state' || key === 'scope') { + continue; } + if (extras === null) { + extras = {}; + } + extras[key] = value; + } - useEffect(() => { - if (!oidc.tokens) { - oidc.loginAsync(null, extras, true, queryParams.scope); - } - }, []); + useEffect(() => { + if (!oidc.tokens) { + oidc.loginAsync(null, extras, true, queryParams.scope); + } + }, []); - return <>; + return <>; }; export default SilentLogin; diff --git a/packages/react-oidc/src/core/routes/OidcRoutes.spec.tsx b/packages/react-oidc/src/core/routes/OidcRoutes.spec.tsx index 79a94b540..96caf6476 100644 --- a/packages/react-oidc/src/core/routes/OidcRoutes.spec.tsx +++ b/packages/react-oidc/src/core/routes/OidcRoutes.spec.tsx @@ -1,7 +1,8 @@ +import { render } from '@testing-library/react'; import React from 'react'; +import { describe, expect, it } from 'vitest'; + import OidcRoutes from './OidcRoutes'; -import { render } from "@testing-library/react"; -import { describe, it, expect } from 'vitest'; describe('Authenticating test suite', () => { it('renders correctly', () => { @@ -9,7 +10,7 @@ describe('Authenticating test suite', () => { children: 'http://url.com', callbackComponent: () =>
tcallback component
, redirect_uri: 'http://example.com:3000/authentication/callback', - configurationName: '' + configurationName: '', }; const { asFragment } = render(); expect(asFragment()).toMatchSnapshot(); diff --git a/packages/react-oidc/src/core/routes/OidcRoutes.tsx b/packages/react-oidc/src/core/routes/OidcRoutes.tsx index 7440d5e19..7c5dc9d8f 100644 --- a/packages/react-oidc/src/core/routes/OidcRoutes.tsx +++ b/packages/react-oidc/src/core/routes/OidcRoutes.tsx @@ -1,4 +1,4 @@ -import { getPath } from '@axa-fr/vanilla-oidc'; +import { getPath, ILOidcLocation } from '@axa-fr/oidc-client'; import React, { ComponentType, FC, PropsWithChildren, useEffect, useState } from 'react'; import CallbackComponent from '../default-component/Callback.component.js'; @@ -15,6 +15,7 @@ type OidcRoutesProps = { silent_redirect_uri?: string; silent_login_uri?: string; withCustomHistory?: () => CustomHistory; + location: ILOidcLocation; }; const OidcRoutes: FC> = ({ @@ -23,7 +24,8 @@ const OidcRoutes: FC> = ({ redirect_uri, silent_redirect_uri, silent_login_uri, - children, configurationName, + children, + configurationName, withCustomHistory = null, }) => { // This exist because in next.js window outside useEffect is null @@ -54,7 +56,14 @@ const OidcRoutes: FC> = ({ switch (path) { case callbackPath: - return ; + return ( + + ); default: return <>{children}; } diff --git a/packages/react-oidc/src/core/routes/withRouter.spec.tsx b/packages/react-oidc/src/core/routes/withRouter.spec.tsx index 3cea580a0..147bdd98b 100644 --- a/packages/react-oidc/src/core/routes/withRouter.spec.tsx +++ b/packages/react-oidc/src/core/routes/withRouter.spec.tsx @@ -1,9 +1,10 @@ +import { beforeEach, describe, expect, it, vi } from 'vitest'; + import { CreateEvent, WindowInternal } from './withRouter'; -import { describe, it, expect, vi, beforeEach } from 'vitest'; describe('WithRouter test Suite', () => { const paramsMock = { bubbles: false, cancelable: false, detail: 'detail' }; - beforeEach(() => { }); + beforeEach(() => {}); it('should CreateEvent return correct Event if not on IE', () => { const windowMock = { CustomEvent: vi.fn().mockImplementation((event, params) => { @@ -11,9 +12,9 @@ describe('WithRouter test Suite', () => { }), }; const documentMock = {} as Document; - const res = CreateEvent((windowMock as unknown) as WindowInternal, documentMock)( + const res = CreateEvent(windowMock as unknown as WindowInternal, documentMock)( 'event test', - paramsMock + paramsMock, ); expect(res).toEqual({ event: 'event test', @@ -33,14 +34,13 @@ describe('WithRouter test Suite', () => { const documentMock = { createEvent: vi.fn(() => evtMock), }; - const typedDocumentMock = (documentMock as unknown) as Document; - const res = CreateEvent((windowMock as unknown) as WindowInternal, typedDocumentMock)( + const typedDocumentMock = documentMock as unknown as Document; + const res = CreateEvent(windowMock as unknown as WindowInternal, typedDocumentMock)( 'event test', - paramsMock + paramsMock, ); expect(res).toEqual({ ...evtMock }); expect(documentMock.createEvent).toHaveBeenCalledWith('CustomEvent'); expect(evtMock.initCustomEvent).toHaveBeenCalledWith('event test', false, false, 'detail'); }); - }); diff --git a/packages/react-oidc/src/core/routes/withRouter.tsx b/packages/react-oidc/src/core/routes/withRouter.tsx index dd87edb1c..5382d001c 100644 --- a/packages/react-oidc/src/core/routes/withRouter.tsx +++ b/packages/react-oidc/src/core/routes/withRouter.tsx @@ -1,7 +1,4 @@ -const generateKey = () => - Math.random() - .toString(36) - .substr(2, 6); +const generateKey = () => Math.random().toString(36).slice(2, 8); // Exported only for test export type WindowInternal = Window & { @@ -20,19 +17,23 @@ type InitCustomEventParams = { }; // IE Polyfill for CustomEvent -export const CreateEvent = (windowInternal: WindowInternal, documentInternal: Document) => ( - event: string, - params: InitCustomEventParams, -): CustomEvent => { - if (typeof windowInternal.CustomEvent === 'function') { - return new windowInternal.CustomEvent(event, params); - } - const paramsToFunction = params || { bubbles: false, cancelable: false, detail: undefined }; - const evt: CustomEvent = documentInternal.createEvent('CustomEvent'); - evt.initCustomEvent(event, paramsToFunction.bubbles, paramsToFunction.cancelable, paramsToFunction.detail); - (evt as CustomEvent & IPrototype).prototype = windowInternal.Event.prototype; - return evt; -}; +export const CreateEvent = + (windowInternal: WindowInternal, documentInternal: Document) => + (event: string, params: InitCustomEventParams): CustomEvent => { + if (typeof windowInternal.CustomEvent === 'function') { + return new windowInternal.CustomEvent(event, params); + } + const paramsToFunction = params || { bubbles: false, cancelable: false, detail: undefined }; + const evt: CustomEvent = documentInternal.createEvent('CustomEvent'); + evt.initCustomEvent( + event, + paramsToFunction.bubbles, + paramsToFunction.cancelable, + paramsToFunction.detail, + ); + (evt as CustomEvent & IPrototype).prototype = windowInternal.Event.prototype; + return evt; + }; type WindowHistoryState = typeof window.history.state; @@ -42,7 +43,7 @@ export interface ReactOidcHistory { export type CustomHistory = { replaceState(url?: string | null, stateHistory?: WindowHistoryState): void; -} +}; const getHistory = ( windowInternal: WindowInternal, @@ -59,4 +60,5 @@ const getHistory = ( }; }; -export const getCustomHistory = () => getHistory(window, CreateEvent(window, document), generateKey); +export const getCustomHistory = () => + getHistory(window, CreateEvent(window, document), generateKey); diff --git a/packages/react-oidc/src/index.ts b/packages/react-oidc/src/index.ts index 44537a8a1..6eabe6121 100644 --- a/packages/react-oidc/src/index.ts +++ b/packages/react-oidc/src/index.ts @@ -6,7 +6,14 @@ export { OidcUserStatus, useOidcUser } from './User.js'; export type { AuthorityConfiguration, Fetch, + ILOidcLocation, OidcConfiguration, StringMap, -} from '@axa-fr/vanilla-oidc'; -export { type OidcUserInfo, TokenRenewMode } from '@axa-fr/vanilla-oidc'; +} from '@axa-fr/oidc-client'; +export type { OidcUserInfo } from '@axa-fr/oidc-client'; +export { + OidcClient, + OidcLocation, + TokenAutomaticRenewMode, + TokenRenewMode, +} from '@axa-fr/oidc-client'; diff --git a/packages/react-oidc/tests/setup.js b/packages/react-oidc/tests/setup.js index e022aaa60..ebbe461d0 100644 --- a/packages/react-oidc/tests/setup.js +++ b/packages/react-oidc/tests/setup.js @@ -1,11 +1,7 @@ -import { expect, afterEach } from 'vitest'; -import { cleanup } from '@testing-library/react'; -import matchers from '@testing-library/jest-dom/matchers'; - -// extends Vitest's expect method with methods from react-testing-library -expect.extend(matchers); +import { cleanup } from '@testing-library/react'; +import { afterEach } from 'vitest'; // runs a cleanup after each test case (e.g. clearing jsdom) afterEach(() => { - cleanup(); -}); \ No newline at end of file + cleanup(); +}); diff --git a/packages/react-oidc/tsconfig.eslint.json b/packages/react-oidc/tsconfig.eslint.json index e9041fd6b..b90fc83e0 100644 --- a/packages/react-oidc/tsconfig.eslint.json +++ b/packages/react-oidc/tsconfig.eslint.json @@ -1,4 +1,4 @@ { "extends": "./tsconfig.json", "include": ["src"] -} \ No newline at end of file +} diff --git a/packages/react-oidc/tsconfig.json b/packages/react-oidc/tsconfig.json index 76f36a849..e9a40a38d 100644 --- a/packages/react-oidc/tsconfig.json +++ b/packages/react-oidc/tsconfig.json @@ -5,8 +5,8 @@ "outDir": "dist", "baseUrl": ".", "jsx": "react-jsx", - "forceConsistentCasingInFileNames":true, - "skipLibCheck":true, + "forceConsistentCasingInFileNames": true, + "skipLibCheck": true, "module": "CommonJS", "declaration": true, "declarationMap": true, @@ -27,8 +27,7 @@ "esModuleInterop": true, "allowSyntheticDefaultImports": true, "allowJs": true, - "rootDir": "src", - + "rootDir": "src" }, "exclude": [ "node_modules", @@ -39,7 +38,5 @@ "**/*.stories.tsx", "./src/setupTests.ts" ], - "include": [ - "src" - ] -} \ No newline at end of file + "include": ["src"] +} diff --git a/packages/react-oidc/vite.config.ts b/packages/react-oidc/vite.config.ts index 247d9617a..3e63539c4 100644 --- a/packages/react-oidc/vite.config.ts +++ b/packages/react-oidc/vite.config.ts @@ -1,7 +1,8 @@ -import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; import { resolve } from 'path'; -import react from '@vitejs/plugin-react'; +import { defineConfig } from 'vite'; import dts from 'vite-plugin-dts'; + import pkg from './package.json'; const dependencies = externalDependencies(); @@ -16,7 +17,7 @@ export default defineConfig({ fileName: 'index', }, rollupOptions: { - external: [...dependencies], + external: [...dependencies, 'react/jsx-runtime'], output: { globals: { react: 'React', @@ -31,7 +32,7 @@ export default defineConfig({ react(), ], resolve: { - preserveSymlinks: true, //https://github.com/vitejs/vite/issues/11657 + preserveSymlinks: true, // https://github.com/vitejs/vite/issues/11657 }, test: { globals: true, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 23941c819..bb78cfefb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,45 +1,76 @@ lockfileVersion: '6.0' +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + importers: .: devDependencies: + '@eslint/compat': + specifier: ^1.2.9 + version: 1.2.9(eslint@9.26.0) + '@typescript-eslint/eslint-plugin': + specifier: ^8.32.0 + version: 8.32.0(@typescript-eslint/parser@8.32.0)(eslint@9.26.0)(typescript@5.8.3) + '@typescript-eslint/parser': + specifier: ^8.32.0 + version: 8.32.0(eslint@9.26.0)(typescript@5.8.3) eslint: - specifier: ^8.45.0 - version: 8.45.0 + specifier: ^9.26.0 + version: 9.26.0 + eslint-config-prettier: + specifier: ^10.1.2 + version: 10.1.2(eslint@9.26.0) eslint-define-config: - specifier: ^1.21.0 - version: 1.21.0 + specifier: ^2.1.0 + version: 2.1.0 eslint-plugin-import: - specifier: ^2.27.5 - version: 2.27.5(@typescript-eslint/parser@5.62.0)(eslint-import-resolver-typescript@3.5.5)(eslint@8.45.0) + specifier: ^2.31.0 + version: 2.31.0(@typescript-eslint/parser@8.32.0)(eslint@9.26.0) eslint-plugin-jsx-a11y: - specifier: ^6.7.1 - version: 6.7.1(eslint@8.45.0) + specifier: ^6.10.2 + version: 6.10.2(eslint@9.26.0) eslint-plugin-n: - specifier: ^16.0.1 - version: 16.0.1(eslint@8.45.0) + specifier: ^17.17.0 + version: 17.17.0(eslint@9.26.0) + eslint-plugin-no-only-tests: + specifier: ^3.3.0 + version: 3.3.0 + eslint-plugin-prettier: + specifier: ^5.4.0 + version: 5.4.0(eslint-config-prettier@10.1.2)(eslint@9.26.0)(prettier@3.5.3) + eslint-plugin-react: + specifier: ^7.37.5 + version: 7.37.5(eslint@9.26.0) eslint-plugin-react-hooks: - specifier: ^4.6.0 - version: 4.6.0(eslint@8.45.0) + specifier: ^5.2.0 + version: 5.2.0(eslint@9.26.0) eslint-plugin-regexp: - specifier: ^1.15.0 - version: 1.15.0(eslint@8.45.0) + specifier: ^2.7.0 + version: 2.7.0(eslint@9.26.0) + eslint-plugin-simple-import-sort: + specifier: ^12.1.1 + version: 12.1.1(eslint@9.26.0) eslint-plugin-testing-library: - specifier: ^5.11.0 - version: 5.11.0(eslint@8.45.0)(typescript@5.1.6) + specifier: ^7.1.1 + version: 7.1.1(eslint@9.26.0)(typescript@5.8.3) + prettier: + specifier: ^3.5.3 + version: 3.5.3 tslib: - specifier: ^2.6.0 - version: 2.6.0 + specifier: ^2.8.1 + version: 2.8.1 tsx: - specifier: ^3.12.7 - version: 3.12.7 + specifier: 4.19.4 + version: 4.19.4 typescript: - specifier: ^5.1.6 - version: 5.1.6 + specifier: 5.8.3 + version: 5.8.3 vitest: - specifier: ^0.33.0 - version: 0.33.0(jsdom@22.1.0) + specifier: 3.1.3 + version: 3.1.3(@types/node@20.11.26)(jsdom@26.1.0)(msw@2.7.6)(tsx@4.19.4) examples/nextjs-demo: dependencies: @@ -48,339 +79,221 @@ importers: version: link:../../packages/react-oidc next: specifier: latest - version: 13.4.10(react-dom@18.2.0)(react@18.2.0) + version: 14.1.0(react-dom@19.1.0)(react@19.1.0) react: specifier: latest - version: 18.2.0 + version: 19.1.0 react-dom: specifier: latest - version: 18.2.0(react@18.2.0) + version: 19.1.0(react@19.1.0) examples/oidc-client-demo: dependencies: - '@axa-fr/vanilla-oidc': + '@axa-fr/oidc-client': specifier: workspace:~ version: link:../../packages/oidc-client - '@testing-library/jest-dom': - specifier: ^5.16.5 - version: 5.16.5 - '@testing-library/user-event': - specifier: ^13.5.0 - version: 13.5.0(@testing-library/dom@9.3.1) - '@types/jest': - specifier: ^27.5.2 - version: 27.5.2 typescript: - specifier: ^5.1.6 - version: 5.1.6 + specifier: 5.7.3 + version: 5.7.3 web-vitals: - specifier: ^3.4.0 - version: 3.4.0 + specifier: 4.2.4 + version: 4.2.4 devDependencies: '@types/node': - specifier: ^18.11.9 - version: 18.11.9 + specifier: 20.11.26 + version: 20.11.26 cross-env: specifier: ^7.0.3 version: 7.0.3 vite: - specifier: ^4.4.4 - version: 4.4.4(@types/node@18.11.9) + specifier: 5.1.6 + version: 5.1.6(@types/node@20.11.26) examples/react-oidc-demo: - devDependencies: - '@axa-fr/oidc-client-service-worker': - specifier: workspace:* - version: link:../../packages/oidc-client-service-worker + dependencies: '@axa-fr/react-oidc': specifier: workspace:* version: link:../../packages/react-oidc - '@axa-fr/vanilla-oidc': - specifier: workspace:* - version: link:../../packages/oidc-client + react: + specifier: ^19.0.0 + version: 19.0.0 + react-dom: + specifier: ^19.0.0 + version: 19.0.0(react@19.0.0) + react-router-dom: + specifier: ^6.22.3 + version: 6.22.3(react-dom@19.0.0)(react@19.0.0) + devDependencies: '@testing-library/jest-dom': - specifier: 5.16.5 - version: 5.16.5 + specifier: 6.6.3 + version: 6.6.3 '@testing-library/react': - specifier: 13.3.0 - version: 13.3.0(react-dom@18.2.0)(react@18.2.0) + specifier: 15.0.7 + version: 15.0.7(@types/react@19.0.5)(react-dom@19.0.0)(react@19.0.0) '@testing-library/user-event': - specifier: 14.4.3 - version: 14.4.3(@testing-library/dom@9.3.1) + specifier: 14.5.2 + version: 14.5.2(@testing-library/dom@10.4.0) '@types/react': - specifier: ^18.2.15 - version: 18.2.15 - '@typescript-eslint/eslint-plugin': - specifier: ^5.50.0 - version: 5.50.0(@typescript-eslint/parser@5.62.0)(eslint@8.45.0)(typescript@5.1.6) - '@typescript-eslint/parser': - specifier: ^5.50.0 - version: 5.62.0(eslint@8.45.0)(typescript@5.1.6) + specifier: 19.0.5 + version: 19.0.5 '@vitejs/plugin-react': - specifier: 4.0.3 - version: 4.0.3(vite@4.4.4) - '@vitest/coverage-c8': - specifier: ^0.33.0 - version: 0.33.0(vitest@0.33.0) + specifier: 4.3.4 + version: 4.3.4(vite@6.0.7) bootstrap: specifier: ^4.6.2 - version: 4.6.2(jquery@3.7.0)(popper.js@1.16.1) + version: 4.6.2(jquery@3.7.1)(popper.js@1.16.1) copyfiles: specifier: 2.4.1 version: 2.4.1 cross-env: specifier: ^7.0.3 version: 7.0.3 - eslint: - specifier: ^8.26.0 - version: 8.45.0 - eslint-config-standard: - specifier: ^17.1.0 - version: 17.1.0(eslint-plugin-import@2.27.5)(eslint-plugin-n@16.0.1)(eslint-plugin-promise@6.1.1)(eslint@8.45.0) - eslint-config-standard-with-typescript: - specifier: ^36.1.0 - version: 36.1.0(@typescript-eslint/eslint-plugin@5.50.0)(eslint-plugin-import@2.27.5)(eslint-plugin-n@16.0.1)(eslint-plugin-promise@6.1.1)(eslint@8.45.0)(typescript@5.1.6) - eslint-import-resolver-typescript: - specifier: ^3.5.5 - version: 3.5.5(@typescript-eslint/parser@5.62.0)(eslint-plugin-import@2.27.5)(eslint@8.45.0) - eslint-plugin-react: - specifier: ^7.32.2 - version: 7.32.2(eslint@8.45.0) - eslint-plugin-simple-import-sort: - specifier: ^10.0.0 - version: 10.0.0(eslint@8.45.0) jsdom: - specifier: 22.1.0 - version: 22.1.0 - msw: - specifier: 1.2.2 - version: 1.2.2(typescript@5.1.6) - react: - specifier: ^18.2.0 - version: 18.2.0 - react-dom: - specifier: ^18.2.0 - version: 18.2.0(react@18.2.0) - react-router-dom: - specifier: ^6.14.1 - version: 6.14.1(react-dom@18.2.0)(react@18.2.0) + specifier: 26.0.0 + version: 26.0.0 typescript: - specifier: 5.1.6 - version: 5.1.6 + specifier: 5.7.3 + version: 5.7.3 vite: - specifier: ^4.4.4 - version: 4.4.4(@types/node@18.11.9) + specifier: 6.0.7 + version: 6.0.7(tsx@4.19.4) vite-plugin-dts: - specifier: ^3.3.0 - version: 3.3.0(typescript@5.1.6)(vite@4.4.4) + specifier: 4.5.0 + version: 4.5.0(typescript@5.7.3)(vite@6.0.7) vitest: - specifier: ^0.33.0 - version: 0.33.0(jsdom@22.1.0) + specifier: 2.1.8 + version: 2.1.8(jsdom@26.0.0) packages/oidc-client: - devDependencies: + dependencies: '@axa-fr/oidc-client-service-worker': specifier: workspace:* version: link:../oidc-client-service-worker + devDependencies: '@testing-library/dom': - specifier: ^9.3.1 - version: 9.3.1 + specifier: 10.4.0 + version: 10.4.0 '@testing-library/jest-dom': - specifier: ^5.16.5 - version: 5.16.5 + specifier: 6.6.3 + version: 6.6.3 '@testing-library/react': - specifier: 13.3.0 - version: 13.3.0(react-dom@18.2.0)(react@18.2.0) + specifier: 16.3.0 + version: 16.3.0(@testing-library/dom@10.4.0)(@types/react@19.1.2)(react-dom@19.1.0)(react@19.1.0) '@vitest/coverage-v8': - specifier: ^0.33.0 - version: 0.33.0(vitest@0.33.0) - base64-js: - specifier: ^1.5.1 - version: 1.5.1 + specifier: 3.1.3 + version: 3.1.3(vitest@3.1.3) cpy: - specifier: ^10.1.0 - version: 10.1.0 + specifier: 11.1.0 + version: 11.1.0 cpy-cli: specifier: ^5.0.0 version: 5.0.0 - eslint: - specifier: ^8.26.0 - version: 8.45.0 - eslint-config-standard: - specifier: ^17.1.0 - version: 17.1.0(eslint-plugin-import@2.27.5)(eslint-plugin-n@16.0.1)(eslint-plugin-promise@6.1.1)(eslint@8.45.0) - eslint-config-standard-with-typescript: - specifier: ^36.1.0 - version: 36.1.0(@typescript-eslint/eslint-plugin@5.50.0)(eslint-plugin-import@2.27.5)(eslint-plugin-n@16.0.1)(eslint-plugin-promise@6.1.1)(eslint@8.45.0)(typescript@5.1.6) - eslint-import-resolver-typescript: - specifier: ^3.5.5 - version: 3.5.5(@typescript-eslint/parser@5.62.0)(eslint-plugin-import@2.27.5)(eslint@8.45.0) - eslint-plugin-react: - specifier: ^7.32.2 - version: 7.32.2(eslint@8.45.0) - eslint-plugin-simple-import-sort: - specifier: ^10.0.0 - version: 10.0.0(eslint@8.45.0) rimraf: - specifier: 5.0.1 - version: 5.0.1 + specifier: 6.0.1 + version: 6.0.1 typescript: - specifier: 5.1.6 - version: 5.1.6 + specifier: 5.8.3 + version: 5.8.3 vite: - specifier: ^4.4.4 - version: 4.4.4(@types/node@18.11.9) + specifier: 6.3.5 + version: 6.3.5(@types/node@20.11.26)(tsx@4.19.4) vite-plugin-dts: - specifier: ^3.3.0 - version: 3.3.0(typescript@5.1.6)(vite@4.4.4) + specifier: 4.5.3 + version: 4.5.3(@types/node@20.11.26)(typescript@5.8.3)(vite@6.3.5) vitest: - specifier: ^0.33.0 - version: 0.33.0(jsdom@22.1.0) + specifier: 3.1.3 + version: 3.1.3(@types/node@20.11.26)(jsdom@26.1.0)(msw@2.7.6)(tsx@4.19.4) packages/oidc-client-service-worker: devDependencies: - '@typescript-eslint/eslint-plugin': - specifier: ^5.50.0 - version: 5.50.0(@typescript-eslint/parser@5.62.0)(eslint@8.45.0)(typescript@5.1.6) - '@typescript-eslint/parser': - specifier: ^5.50.0 - version: 5.62.0(eslint@8.45.0)(typescript@5.1.6) - '@vitest/coverage-c8': - specifier: ^0.33.0 - version: 0.33.0(vitest@0.33.0) + '@vitest/coverage-v8': + specifier: 3.1.3 + version: 3.1.3(vitest@3.1.3) cpy: - specifier: ^10.1.0 - version: 10.1.0 + specifier: 11.1.0 + version: 11.1.0 cpy-cli: specifier: ^5.0.0 version: 5.0.0 - eslint: - specifier: ^8.26.0 - version: 8.45.0 - eslint-config-standard: - specifier: ^17.1.0 - version: 17.1.0(eslint-plugin-import@2.27.5)(eslint-plugin-n@16.0.1)(eslint-plugin-promise@6.1.1)(eslint@8.45.0) - eslint-config-standard-with-typescript: - specifier: ^36.1.0 - version: 36.1.0(@typescript-eslint/eslint-plugin@5.50.0)(eslint-plugin-import@2.27.5)(eslint-plugin-n@16.0.1)(eslint-plugin-promise@6.1.1)(eslint@8.45.0)(typescript@5.1.6) - eslint-import-resolver-typescript: - specifier: ^3.5.5 - version: 3.5.5(@typescript-eslint/parser@5.62.0)(eslint-plugin-import@2.27.5)(eslint@8.45.0) - eslint-plugin-react: - specifier: ^7.32.2 - version: 7.32.2(eslint@8.45.0) - eslint-plugin-simple-import-sort: - specifier: ^10.0.0 - version: 10.0.0(eslint@8.45.0) - msw: - specifier: 1.2.2 - version: 1.2.2(typescript@5.1.6) rimraf: - specifier: 5.0.1 - version: 5.0.1 + specifier: 6.0.1 + version: 6.0.1 typescript: - specifier: 5.1.6 - version: 5.1.6 + specifier: 5.8.3 + version: 5.8.3 vite: - specifier: ^4.4.4 - version: 4.4.4(@types/node@18.11.9) + specifier: 6.3.5 + version: 6.3.5(@types/node@20.11.26)(tsx@4.19.4) vite-plugin-dts: - specifier: ^3.3.0 - version: 3.3.0(typescript@5.1.6)(vite@4.4.4) + specifier: 4.5.3 + version: 4.5.3(@types/node@20.11.26)(typescript@5.8.3)(vite@6.3.5) vitest: - specifier: ^0.33.0 - version: 0.33.0(jsdom@22.1.0) + specifier: 3.1.3 + version: 3.1.3(@types/node@20.11.26)(jsdom@26.1.0)(msw@2.7.6)(tsx@4.19.4) packages/react-oidc: dependencies: + '@axa-fr/oidc-client': + specifier: workspace:* + version: link:../oidc-client '@axa-fr/oidc-client-service-worker': specifier: workspace:* version: link:../oidc-client-service-worker - '@axa-fr/vanilla-oidc': - specifier: workspace:* - version: link:../oidc-client - react-router-dom: - specifier: ^6.0.0 - version: 6.14.1(react-dom@18.2.0)(react@18.2.0) devDependencies: '@testing-library/jest-dom': - specifier: 5.16.5 - version: 5.16.5 + specifier: 6.6.3 + version: 6.6.3 '@testing-library/react': - specifier: 13.3.0 - version: 13.3.0(react-dom@18.2.0)(react@18.2.0) + specifier: 16.3.0 + version: 16.3.0(@testing-library/dom@10.4.0)(@types/react@19.1.2)(react-dom@19.1.0)(react@19.1.0) '@testing-library/user-event': - specifier: 14.4.3 - version: 14.4.3(@testing-library/dom@9.3.1) + specifier: 14.6.1 + version: 14.6.1(@testing-library/dom@10.4.0) '@types/react': - specifier: ^18.2.15 - version: 18.2.15 - '@typescript-eslint/eslint-plugin': - specifier: ^5.50.0 - version: 5.50.0(@typescript-eslint/parser@5.62.0)(eslint@8.45.0)(typescript@5.1.6) - '@typescript-eslint/parser': - specifier: ^5.50.0 - version: 5.62.0(eslint@8.45.0)(typescript@5.1.6) + specifier: 19.1.2 + version: 19.1.2 '@vitejs/plugin-react': - specifier: 4.0.3 - version: 4.0.3(vite@4.4.4) + specifier: 4.4.1 + version: 4.4.1(vite@6.3.5) '@vitest/coverage-v8': - specifier: ^0.33.0 - version: 0.33.0(vitest@0.33.0) + specifier: 3.1.3 + version: 3.1.3(vitest@3.1.3) cpy: - specifier: ^10.1.0 - version: 10.1.0 + specifier: 11.1.0 + version: 11.1.0 cpy-cli: specifier: ^5.0.0 version: 5.0.0 cross-env: specifier: ^7.0.3 version: 7.0.3 - eslint: - specifier: ^8.26.0 - version: 8.45.0 - eslint-config-standard: - specifier: ^17.1.0 - version: 17.1.0(eslint-plugin-import@2.27.5)(eslint-plugin-n@16.0.1)(eslint-plugin-promise@6.1.1)(eslint@8.45.0) - eslint-config-standard-with-typescript: - specifier: ^36.1.0 - version: 36.1.0(@typescript-eslint/eslint-plugin@5.50.0)(eslint-plugin-import@2.27.5)(eslint-plugin-n@16.0.1)(eslint-plugin-promise@6.1.1)(eslint@8.45.0)(typescript@5.1.6) - eslint-import-resolver-typescript: - specifier: ^3.5.5 - version: 3.5.5(@typescript-eslint/parser@5.62.0)(eslint-plugin-import@2.27.5)(eslint@8.45.0) - eslint-plugin-react: - specifier: ^7.32.2 - version: 7.32.2(eslint@8.45.0) - eslint-plugin-simple-import-sort: - specifier: ^10.0.0 - version: 10.0.0(eslint@8.45.0) jsdom: - specifier: 22.1.0 - version: 22.1.0 + specifier: 26.1.0 + version: 26.1.0 msw: - specifier: 1.2.2 - version: 1.2.2(typescript@5.1.6) + specifier: 2.7.6 + version: 2.7.6(@types/node@20.11.26)(typescript@5.8.3) react: - specifier: ^18.2.0 - version: 18.2.0 + specifier: ^19.1.0 + version: 19.1.0 react-dom: - specifier: ^18.2.0 - version: 18.2.0(react@18.2.0) + specifier: ^19.1.0 + version: 19.1.0(react@19.1.0) rimraf: - specifier: 5.0.1 - version: 5.0.1 + specifier: 6.0.1 + version: 6.0.1 typescript: - specifier: 5.1.6 - version: 5.1.6 + specifier: 5.8.3 + version: 5.8.3 vite: - specifier: ^4.4.4 - version: 4.4.4(@types/node@18.11.9) + specifier: 6.3.5 + version: 6.3.5(@types/node@20.11.26)(tsx@4.19.4) vite-plugin-dts: - specifier: ^3.3.0 - version: 3.3.0(typescript@5.1.6)(vite@4.4.4) + specifier: 4.5.3 + version: 4.5.3(@types/node@20.11.26)(typescript@5.8.3)(vite@6.3.5) vitest: - specifier: ^0.33.0 - version: 0.33.0(jsdom@22.1.0) + specifier: 3.1.3 + version: 3.1.3(@types/node@20.11.26)(jsdom@26.1.0)(msw@2.7.6)(tsx@4.19.4) packages: @@ -389,44 +302,80 @@ packages: engines: {node: '>=0.10.0'} dev: true - /@adobe/css-tools@4.2.0: - resolution: {integrity: sha512-E09FiIft46CmH5Qnjb0wsW54/YQd69LsxeKUOWawmws1XWvyFGURnAChH0mlr7YPFR1ofwvUQfcL0J3lMxXqPA==} + /@adobe/css-tools@4.4.0: + resolution: {integrity: sha512-Ff9+ksdQQB3rMncgqDK78uLznstjyfIf2Arnh22pW8kBpLs6rpKDwgnZT46hin5Hl1WzazzK64DOrhSwYpS7bQ==} + dev: true - /@ampproject/remapping@2.2.1: - resolution: {integrity: sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==} + /@ampproject/remapping@2.3.0: + resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} dependencies: - '@jridgewell/gen-mapping': 0.3.3 - '@jridgewell/trace-mapping': 0.3.18 + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 dev: true - /@babel/code-frame@7.22.5: - resolution: {integrity: sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==} + /@asamuzakjp/css-color@2.8.2: + resolution: {integrity: sha512-RtWv9jFN2/bLExuZgFFZ0I3pWWeezAHGgrmjqGGWclATl1aDe3yhCUaI0Ilkp6OCk9zX7+FjvDasEX8Q9Rxc5w==} + dependencies: + '@csstools/css-calc': 2.1.1(@csstools/css-parser-algorithms@3.0.4)(@csstools/css-tokenizer@3.0.3) + '@csstools/css-color-parser': 3.0.7(@csstools/css-parser-algorithms@3.0.4)(@csstools/css-tokenizer@3.0.3) + '@csstools/css-parser-algorithms': 3.0.4(@csstools/css-tokenizer@3.0.3) + '@csstools/css-tokenizer': 3.0.3 + lru-cache: 11.0.2 + dev: true + + /@babel/code-frame@7.24.7: + resolution: {integrity: sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/highlight': 7.24.7 + picocolors: 1.1.1 + dev: true + + /@babel/code-frame@7.26.2: + resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-validator-identifier': 7.25.9 + js-tokens: 4.0.0 + picocolors: 1.1.1 + dev: true + + /@babel/code-frame@7.27.1: + resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} engines: {node: '>=6.9.0'} dependencies: - '@babel/highlight': 7.22.5 + '@babel/helper-validator-identifier': 7.27.1 + js-tokens: 4.0.0 + picocolors: 1.1.1 + dev: true + + /@babel/compat-data@7.26.5: + resolution: {integrity: sha512-XvcZi1KWf88RVbF9wn8MN6tYFloU5qX8KjuF3E1PVBmJ9eypXfs4GRiJwLuTZL0iSnJUKn1BFPa5BPZZJyFzPg==} + engines: {node: '>=6.9.0'} + dev: true - /@babel/compat-data@7.22.9: - resolution: {integrity: sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ==} + /@babel/compat-data@7.27.1: + resolution: {integrity: sha512-Q+E+rd/yBzNQhXkG+zQnF58e4zoZfBedaxwzPmicKsiK3nt8iJYrSrDbjwFFDGC4f+rPafqRaPH6TsDoSvMf7A==} engines: {node: '>=6.9.0'} dev: true - /@babel/core@7.22.9: - resolution: {integrity: sha512-G2EgeufBcYw27U4hhoIwFcgc1XU7TlXJ3mv04oOv1WCuo900U/anZSPzEqNjwdjgffkk2Gs0AN0dW1CKVLcG7w==} + /@babel/core@7.26.0: + resolution: {integrity: sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==} engines: {node: '>=6.9.0'} dependencies: - '@ampproject/remapping': 2.2.1 - '@babel/code-frame': 7.22.5 - '@babel/generator': 7.22.9 - '@babel/helper-compilation-targets': 7.22.9(@babel/core@7.22.9) - '@babel/helper-module-transforms': 7.22.9(@babel/core@7.22.9) - '@babel/helpers': 7.22.6 - '@babel/parser': 7.22.7 - '@babel/template': 7.22.5 - '@babel/traverse': 7.22.8 - '@babel/types': 7.22.5 - convert-source-map: 1.9.0 - debug: 4.3.4 + '@ampproject/remapping': 2.3.0 + '@babel/code-frame': 7.26.2 + '@babel/generator': 7.26.5 + '@babel/helper-compilation-targets': 7.26.5 + '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.0) + '@babel/helpers': 7.26.0 + '@babel/parser': 7.26.5 + '@babel/template': 7.25.9 + '@babel/traverse': 7.26.5 + '@babel/types': 7.26.5 + convert-source-map: 2.0.0 + debug: 4.4.0 gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -434,220 +383,412 @@ packages: - supports-color dev: true - /@babel/generator@7.22.9: - resolution: {integrity: sha512-KtLMbmicyuK2Ak/FTCJVbDnkN1SlT8/kceFTiuDiiRUUSMnHMidxSCdG4ndkTOHHpoomWe/4xkvHkEOncwjYIw==} + /@babel/core@7.27.1: + resolution: {integrity: sha512-IaaGWsQqfsQWVLqMn9OB92MNN7zukfVA4s7KKAI0KfrrDsZ0yhi5uV4baBuLuN7n3vsZpwP8asPPcVwApxvjBQ==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.22.5 - '@jridgewell/gen-mapping': 0.3.3 - '@jridgewell/trace-mapping': 0.3.18 - jsesc: 2.5.2 + '@ampproject/remapping': 2.3.0 + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.27.1 + '@babel/helper-compilation-targets': 7.27.1 + '@babel/helper-module-transforms': 7.27.1(@babel/core@7.27.1) + '@babel/helpers': 7.27.1 + '@babel/parser': 7.27.1 + '@babel/template': 7.27.1 + '@babel/traverse': 7.27.1 + '@babel/types': 7.27.1 + convert-source-map: 2.0.0 + debug: 4.4.0 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color dev: true - /@babel/helper-compilation-targets@7.22.9(@babel/core@7.22.9): - resolution: {integrity: sha512-7qYrNM6HjpnPHJbopxmb8hSPoZ0gsX8IvUS32JGVoy+pU9e5N0nLr1VjJoR6kA4d9dmGLxNYOjeB8sUDal2WMw==} + /@babel/generator@7.26.5: + resolution: {integrity: sha512-2caSP6fN9I7HOe6nqhtft7V4g7/V/gfDsC3Ag4W7kEzzvRGKqiv0pu0HogPiZ3KaVSoNDhUws6IJjDjpfmYIXw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/parser': 7.26.5 + '@babel/types': 7.26.5 + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 + jsesc: 3.1.0 + dev: true + + /@babel/generator@7.27.1: + resolution: {integrity: sha512-UnJfnIpc/+JO0/+KRVQNGU+y5taA5vCbwN8+azkX6beii/ZF+enZJSOKo11ZSzGJjlNfJHfQtmQT8H+9TXPG2w==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/parser': 7.27.1 + '@babel/types': 7.27.1 + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 + jsesc: 3.1.0 + dev: true + + /@babel/helper-compilation-targets@7.26.5: + resolution: {integrity: sha512-IXuyn5EkouFJscIDuFF5EsiSolseme1s0CZB+QxVugqJLYmKdxI1VfIBOst0SUu4rnk2Z7kqTwmoO1lp3HIfnA==} engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 dependencies: - '@babel/compat-data': 7.22.9 - '@babel/core': 7.22.9 - '@babel/helper-validator-option': 7.22.5 - browserslist: 4.21.9 + '@babel/compat-data': 7.26.5 + '@babel/helper-validator-option': 7.25.9 + browserslist: 4.24.4 lru-cache: 5.1.1 semver: 6.3.1 dev: true - /@babel/helper-environment-visitor@7.22.5: - resolution: {integrity: sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==} + /@babel/helper-compilation-targets@7.27.1: + resolution: {integrity: sha512-2YaDd/Rd9E598B5+WIc8wJPmWETiiJXFYVE60oX8FDohv7rAUU3CQj+A1MgeEmcsk2+dQuEjIe/GDvig0SqL4g==} engines: {node: '>=6.9.0'} + dependencies: + '@babel/compat-data': 7.27.1 + '@babel/helper-validator-option': 7.27.1 + browserslist: 4.24.4 + lru-cache: 5.1.1 + semver: 6.3.1 dev: true - /@babel/helper-function-name@7.22.5: - resolution: {integrity: sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==} + /@babel/helper-module-imports@7.25.9: + resolution: {integrity: sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/template': 7.22.5 - '@babel/types': 7.22.5 + '@babel/traverse': 7.26.5 + '@babel/types': 7.26.5 + transitivePeerDependencies: + - supports-color dev: true - /@babel/helper-hoist-variables@7.22.5: - resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==} + /@babel/helper-module-imports@7.27.1: + resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.22.5 + '@babel/traverse': 7.27.1 + '@babel/types': 7.27.1 + transitivePeerDependencies: + - supports-color dev: true - /@babel/helper-module-imports@7.22.5: - resolution: {integrity: sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg==} + /@babel/helper-module-transforms@7.26.0(@babel/core@7.26.0): + resolution: {integrity: sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==} engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 dependencies: - '@babel/types': 7.22.5 + '@babel/core': 7.26.0 + '@babel/helper-module-imports': 7.25.9 + '@babel/helper-validator-identifier': 7.25.9 + '@babel/traverse': 7.26.5 + transitivePeerDependencies: + - supports-color dev: true - /@babel/helper-module-transforms@7.22.9(@babel/core@7.22.9): - resolution: {integrity: sha512-t+WA2Xn5K+rTeGtC8jCsdAH52bjggG5TKRuRrAGNM/mjIbO4GxvlLMFOEz9wXY5I2XQ60PMFsAG2WIcG82dQMQ==} + /@babel/helper-module-transforms@7.27.1(@babel/core@7.27.1): + resolution: {integrity: sha512-9yHn519/8KvTU5BjTVEEeIM3w9/2yXNKoD82JifINImhpKkARMJKPP59kLo+BafpdN5zgNeIcS4jsGDmd3l58g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.22.9 - '@babel/helper-environment-visitor': 7.22.5 - '@babel/helper-module-imports': 7.22.5 - '@babel/helper-simple-access': 7.22.5 - '@babel/helper-split-export-declaration': 7.22.6 - '@babel/helper-validator-identifier': 7.22.5 + '@babel/core': 7.27.1 + '@babel/helper-module-imports': 7.27.1 + '@babel/helper-validator-identifier': 7.27.1 + '@babel/traverse': 7.27.1 + transitivePeerDependencies: + - supports-color dev: true - /@babel/helper-plugin-utils@7.22.5: - resolution: {integrity: sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==} + /@babel/helper-plugin-utils@7.26.5: + resolution: {integrity: sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==} engines: {node: '>=6.9.0'} dev: true - /@babel/helper-simple-access@7.22.5: - resolution: {integrity: sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==} + /@babel/helper-string-parser@7.25.9: + resolution: {integrity: sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==} engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.22.5 dev: true - /@babel/helper-split-export-declaration@7.22.6: - resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==} + /@babel/helper-string-parser@7.27.1: + resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/helper-validator-identifier@7.25.9: + resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==} engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.22.5 dev: true - /@babel/helper-string-parser@7.22.5: - resolution: {integrity: sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==} + /@babel/helper-validator-identifier@7.27.1: + resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==} engines: {node: '>=6.9.0'} dev: true - /@babel/helper-validator-identifier@7.22.5: - resolution: {integrity: sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==} + /@babel/helper-validator-option@7.25.9: + resolution: {integrity: sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==} engines: {node: '>=6.9.0'} + dev: true - /@babel/helper-validator-option@7.22.5: - resolution: {integrity: sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw==} + /@babel/helper-validator-option@7.27.1: + resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} engines: {node: '>=6.9.0'} dev: true - /@babel/helpers@7.22.6: - resolution: {integrity: sha512-YjDs6y/fVOYFV8hAf1rxd1QvR9wJe1pDBZ2AREKq/SDayfPzgk0PBnVuTCE5X1acEpMMNOVUqoe+OwiZGJ+OaA==} + /@babel/helpers@7.26.0: + resolution: {integrity: sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/template': 7.22.5 - '@babel/traverse': 7.22.8 - '@babel/types': 7.22.5 - transitivePeerDependencies: - - supports-color + '@babel/template': 7.25.9 + '@babel/types': 7.26.5 + dev: true + + /@babel/helpers@7.27.1: + resolution: {integrity: sha512-FCvFTm0sWV8Fxhpp2McP5/W53GPllQ9QeQ7SiqGWjMf/LVG07lFa5+pgK05IRhVwtvafT22KF+ZSnM9I545CvQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/template': 7.27.1 + '@babel/types': 7.27.1 dev: true - /@babel/highlight@7.22.5: - resolution: {integrity: sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==} + /@babel/highlight@7.24.7: + resolution: {integrity: sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/helper-validator-identifier': 7.22.5 + '@babel/helper-validator-identifier': 7.25.9 chalk: 2.4.2 js-tokens: 4.0.0 + picocolors: 1.1.1 + dev: true + + /@babel/parser@7.26.5: + resolution: {integrity: sha512-SRJ4jYmXRqV1/Xc+TIVG84WjHBXKlxO9sHQnA2Pf12QQEAp1LOh6kDzNHXcUnbH1QI0FDoPPVOt+vyUDucxpaw==} + engines: {node: '>=6.0.0'} + hasBin: true + dependencies: + '@babel/types': 7.26.5 + dev: true - /@babel/parser@7.22.7: - resolution: {integrity: sha512-7NF8pOkHP5o2vpmGgNGcfAeCvOYhGLyA3Z4eBQkT1RJlWu47n63bCs93QfJ2hIAFCil7L5P2IWhs1oToVgrL0Q==} + /@babel/parser@7.27.1: + resolution: {integrity: sha512-I0dZ3ZpCrJ1c04OqlNsQcKiZlsrXf/kkE4FXzID9rIOYICsAbA8mMDzhW/luRNAHdCNt7os/u8wenklZDlUVUQ==} engines: {node: '>=6.0.0'} hasBin: true dependencies: - '@babel/types': 7.22.5 + '@babel/types': 7.27.1 + dev: true + + /@babel/plugin-transform-react-jsx-self@7.25.9(@babel/core@7.26.0): + resolution: {integrity: sha512-y8quW6p0WHkEhmErnfe58r7x0A70uKphQm8Sp8cV7tjNQwK56sNVK0M73LK3WuYmsuyrftut4xAkjjgU0twaMg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.26.5 + dev: true + + /@babel/plugin-transform-react-jsx-self@7.25.9(@babel/core@7.27.1): + resolution: {integrity: sha512-y8quW6p0WHkEhmErnfe58r7x0A70uKphQm8Sp8cV7tjNQwK56sNVK0M73LK3WuYmsuyrftut4xAkjjgU0twaMg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.27.1 + '@babel/helper-plugin-utils': 7.26.5 dev: true - /@babel/plugin-transform-react-jsx-self@7.22.5(@babel/core@7.22.9): - resolution: {integrity: sha512-nTh2ogNUtxbiSbxaT4Ds6aXnXEipHweN9YRgOX/oNXdf0cCrGn/+2LozFa3lnPV5D90MkjhgckCPBrsoSc1a7g==} + /@babel/plugin-transform-react-jsx-source@7.25.9(@babel/core@7.26.0): + resolution: {integrity: sha512-+iqjT8xmXhhYv4/uiYd8FNQsraMFZIfxVSqxxVSZP0WbbSAWvBXAul0m/zu+7Vv4O/3WtApy9pmaTMiumEZgfg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.9 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.26.5 dev: true - /@babel/plugin-transform-react-jsx-source@7.22.5(@babel/core@7.22.9): - resolution: {integrity: sha512-yIiRO6yobeEIaI0RTbIr8iAK9FcBHLtZq0S89ZPjDLQXBA4xvghaKqI0etp/tF3htTM0sazJKKLz9oEiGRtu7w==} + /@babel/plugin-transform-react-jsx-source@7.25.9(@babel/core@7.27.1): + resolution: {integrity: sha512-+iqjT8xmXhhYv4/uiYd8FNQsraMFZIfxVSqxxVSZP0WbbSAWvBXAul0m/zu+7Vv4O/3WtApy9pmaTMiumEZgfg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.22.9 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.27.1 + '@babel/helper-plugin-utils': 7.26.5 + dev: true + + /@babel/runtime@7.23.9: + resolution: {integrity: sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==} + engines: {node: '>=6.9.0'} + dependencies: + regenerator-runtime: 0.14.1 + dev: true + + /@babel/runtime@7.24.8: + resolution: {integrity: sha512-5F7SDGs1T72ZczbRwbGO9lQi0NLjQxzl6i4lJxLxfW9U5UluCSyEJeniWvnhl3/euNiqQVbo8zruhsDfid0esA==} + engines: {node: '>=6.9.0'} + dependencies: + regenerator-runtime: 0.14.1 + dev: true + + /@babel/template@7.25.9: + resolution: {integrity: sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.26.2 + '@babel/parser': 7.26.5 + '@babel/types': 7.26.5 dev: true - /@babel/runtime@7.22.6: - resolution: {integrity: sha512-wDb5pWm4WDdF6LFUde3Jl8WzPA+3ZbxYqkC6xAXuD3irdEHN1k0NfTRrJD8ZD378SJ61miMLCqIOXYhd8x+AJQ==} + /@babel/template@7.27.1: + resolution: {integrity: sha512-Fyo3ghWMqkHHpHQCoBs2VnYjR4iWFFjguTDEqA5WgZDOrFesVjMhMM2FSqTKSoUSDO1VQtavj8NFpdRBEvJTtg==} engines: {node: '>=6.9.0'} dependencies: - regenerator-runtime: 0.13.11 + '@babel/code-frame': 7.27.1 + '@babel/parser': 7.27.1 + '@babel/types': 7.27.1 + dev: true - /@babel/template@7.22.5: - resolution: {integrity: sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==} + /@babel/traverse@7.26.5: + resolution: {integrity: sha512-rkOSPOw+AXbgtwUga3U4u8RpoK9FEFWBNAlTpcnkLFjL5CT+oyHNuUUC/xx6XefEJ16r38r8Bc/lfp6rYuHeJQ==} engines: {node: '>=6.9.0'} dependencies: - '@babel/code-frame': 7.22.5 - '@babel/parser': 7.22.7 - '@babel/types': 7.22.5 + '@babel/code-frame': 7.26.2 + '@babel/generator': 7.26.5 + '@babel/parser': 7.26.5 + '@babel/template': 7.25.9 + '@babel/types': 7.26.5 + debug: 4.4.0 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color dev: true - /@babel/traverse@7.22.8: - resolution: {integrity: sha512-y6LPR+wpM2I3qJrsheCTwhIinzkETbplIgPBbwvqPKc+uljeA5gP+3nP8irdYt1mjQaDnlIcG+dw8OjAco4GXw==} + /@babel/traverse@7.27.1: + resolution: {integrity: sha512-ZCYtZciz1IWJB4U61UPu4KEaqyfj+r5T1Q5mqPo+IBpcG9kHv30Z0aD8LXPgC1trYa6rK0orRyAhqUgk4MjmEg==} engines: {node: '>=6.9.0'} dependencies: - '@babel/code-frame': 7.22.5 - '@babel/generator': 7.22.9 - '@babel/helper-environment-visitor': 7.22.5 - '@babel/helper-function-name': 7.22.5 - '@babel/helper-hoist-variables': 7.22.5 - '@babel/helper-split-export-declaration': 7.22.6 - '@babel/parser': 7.22.7 - '@babel/types': 7.22.5 - debug: 4.3.4 + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.27.1 + '@babel/parser': 7.27.1 + '@babel/template': 7.27.1 + '@babel/types': 7.27.1 + debug: 4.4.0 globals: 11.12.0 transitivePeerDependencies: - supports-color dev: true - /@babel/types@7.22.5: - resolution: {integrity: sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA==} + /@babel/types@7.26.5: + resolution: {integrity: sha512-L6mZmwFDK6Cjh1nRCLXpa6no13ZIioJDz7mdkzHv399pThrTa/k0nUlNaenOeh2kWu/iaOQYElEpKPUswUa9Vg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-string-parser': 7.25.9 + '@babel/helper-validator-identifier': 7.25.9 + dev: true + + /@babel/types@7.27.1: + resolution: {integrity: sha512-+EzkxvLNfiUeKMgy/3luqfsCWFRXLb7U6wNQTk60tovuckwB15B191tJWvpp4HjiQWdJkCxO3Wbvc6jlk3Xb2Q==} engines: {node: '>=6.9.0'} dependencies: - '@babel/helper-string-parser': 7.22.5 - '@babel/helper-validator-identifier': 7.22.5 - to-fast-properties: 2.0.0 + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.27.1 + dev: true + + /@bcoe/v8-coverage@1.0.2: + resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==} + engines: {node: '>=18'} + dev: true + + /@bundled-es-modules/cookie@2.0.1: + resolution: {integrity: sha512-8o+5fRPLNbjbdGRRmJj3h6Hh1AQJf2dk3qQ/5ZFb+PXkRNiSoMGGUKlsgLfrxneb72axVJyIYji64E2+nNfYyw==} + dependencies: + cookie: 0.7.2 + dev: true + + /@bundled-es-modules/statuses@1.0.1: + resolution: {integrity: sha512-yn7BklA5acgcBr+7w064fGV+SGIFySjCKpqjcWgBAIfrAkY+4GQTJJHQMeT3V/sgz23VTEVV8TtOmkvJAhFVfg==} + dependencies: + statuses: 2.0.1 + dev: true + + /@bundled-es-modules/tough-cookie@0.1.6: + resolution: {integrity: sha512-dvMHbL464C0zI+Yqxbz6kZ5TOEp7GLW+pry/RWndAR8MJQAXZ2rPmIs8tziTZjeIyhSNZgZbCePtfSbdWqStJw==} + dependencies: + '@types/tough-cookie': 4.0.5 + tough-cookie: 4.1.4 dev: true - /@bcoe/v8-coverage@0.2.3: - resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} + /@csstools/color-helpers@5.0.1: + resolution: {integrity: sha512-MKtmkA0BX87PKaO1NFRTFH+UnkgnmySQOvNxJubsadusqPEC2aJ9MOQiMceZJJ6oitUl/i0L6u0M1IrmAOmgBA==} + engines: {node: '>=18'} dev: true - /@esbuild-kit/cjs-loader@2.4.2: - resolution: {integrity: sha512-BDXFbYOJzT/NBEtp71cvsrGPwGAMGRB/349rwKuoxNSiKjPraNNnlK6MIIabViCjqZugu6j+xeMDlEkWdHHJSg==} + /@csstools/css-calc@2.1.1(@csstools/css-parser-algorithms@3.0.4)(@csstools/css-tokenizer@3.0.3): + resolution: {integrity: sha512-rL7kaUnTkL9K+Cvo2pnCieqNpTKgQzy5f+N+5Iuko9HAoasP+xgprVh7KN/MaJVvVL1l0EzQq2MoqBHKSrDrag==} + engines: {node: '>=18'} + peerDependencies: + '@csstools/css-parser-algorithms': ^3.0.4 + '@csstools/css-tokenizer': ^3.0.3 dependencies: - '@esbuild-kit/core-utils': 3.1.0 - get-tsconfig: 4.6.2 + '@csstools/css-parser-algorithms': 3.0.4(@csstools/css-tokenizer@3.0.3) + '@csstools/css-tokenizer': 3.0.3 dev: true - /@esbuild-kit/core-utils@3.1.0: - resolution: {integrity: sha512-Uuk8RpCg/7fdHSceR1M6XbSZFSuMrxcePFuGgyvsBn+u339dk5OeL4jv2EojwTN2st/unJGsVm4qHWjWNmJ/tw==} + /@csstools/css-color-parser@3.0.7(@csstools/css-parser-algorithms@3.0.4)(@csstools/css-tokenizer@3.0.3): + resolution: {integrity: sha512-nkMp2mTICw32uE5NN+EsJ4f5N+IGFeCFu4bGpiKgb2Pq/7J/MpyLBeQ5ry4KKtRFZaYs6sTmcMYrSRIyj5DFKA==} + engines: {node: '>=18'} + peerDependencies: + '@csstools/css-parser-algorithms': ^3.0.4 + '@csstools/css-tokenizer': ^3.0.3 dependencies: - esbuild: 0.17.19 - source-map-support: 0.5.21 + '@csstools/color-helpers': 5.0.1 + '@csstools/css-calc': 2.1.1(@csstools/css-parser-algorithms@3.0.4)(@csstools/css-tokenizer@3.0.3) + '@csstools/css-parser-algorithms': 3.0.4(@csstools/css-tokenizer@3.0.3) + '@csstools/css-tokenizer': 3.0.3 dev: true - /@esbuild-kit/esm-loader@2.5.5: - resolution: {integrity: sha512-Qwfvj/qoPbClxCRNuac1Du01r9gvNOT+pMYtJDapfB1eoGN1YlJ1BixLyL9WVENRx5RXgNLdfYdx/CuswlGhMw==} + /@csstools/css-parser-algorithms@3.0.4(@csstools/css-tokenizer@3.0.3): + resolution: {integrity: sha512-Up7rBoV77rv29d3uKHUIVubz1BTcgyUK72IvCQAbfbMv584xHcGKCKbWh7i8hPrRJ7qU4Y8IO3IY9m+iTB7P3A==} + engines: {node: '>=18'} + peerDependencies: + '@csstools/css-tokenizer': ^3.0.3 dependencies: - '@esbuild-kit/core-utils': 3.1.0 - get-tsconfig: 4.6.2 + '@csstools/css-tokenizer': 3.0.3 + dev: true + + /@csstools/css-tokenizer@3.0.3: + resolution: {integrity: sha512-UJnjoFsmxfKUdNYdWgOB0mWUypuLvAfQPH1+pyvRJs6euowbFkFC6P13w1l8mJyi3vxYMxc9kld5jZEGRQs6bw==} + engines: {node: '>=18'} + dev: true + + /@esbuild/aix-ppc64@0.19.12: + resolution: {integrity: sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [aix] + requiresBuild: true + dev: true + optional: true + + /@esbuild/aix-ppc64@0.24.2: + resolution: {integrity: sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + requiresBuild: true + dev: true + optional: true + + /@esbuild/aix-ppc64@0.25.1: + resolution: {integrity: sha512-kfYGy8IdzTGy+z0vFGvExZtxkFlA4zAxgKEahG9KE1ScBjpQnFsNOX8KTU5ojNru5ed5CVoJYXFtoxaq5nFbjQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + requiresBuild: true dev: true + optional: true - /@esbuild/android-arm64@0.17.19: - resolution: {integrity: sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==} + /@esbuild/android-arm64@0.19.12: + resolution: {integrity: sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==} engines: {node: '>=12'} cpu: [arm64] os: [android] @@ -655,17 +796,26 @@ packages: dev: true optional: true - /@esbuild/android-arm64@0.18.13: - resolution: {integrity: sha512-j7NhycJUoUAG5kAzGf4fPWfd17N6SM3o1X6MlXVqfHvs2buFraCJzos9vbeWjLxOyBKHyPOnuCuipbhvbYtTAg==} - engines: {node: '>=12'} + /@esbuild/android-arm64@0.24.2: + resolution: {integrity: sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==} + engines: {node: '>=18'} cpu: [arm64] os: [android] requiresBuild: true dev: true optional: true - /@esbuild/android-arm@0.17.19: - resolution: {integrity: sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==} + /@esbuild/android-arm64@0.25.1: + resolution: {integrity: sha512-50tM0zCJW5kGqgG7fQ7IHvQOcAn9TKiVRuQ/lN0xR+T2lzEFvAi1ZcS8DiksFcEpf1t/GYOeOfCAgDHFpkiSmA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-arm@0.19.12: + resolution: {integrity: sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==} engines: {node: '>=12'} cpu: [arm] os: [android] @@ -673,17 +823,26 @@ packages: dev: true optional: true - /@esbuild/android-arm@0.18.13: - resolution: {integrity: sha512-KwqFhxRFMKZINHzCqf8eKxE0XqWlAVPRxwy6rc7CbVFxzUWB2sA/s3hbMZeemPdhN3fKBkqOaFhTbS8xJXYIWQ==} - engines: {node: '>=12'} + /@esbuild/android-arm@0.24.2: + resolution: {integrity: sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-arm@0.25.1: + resolution: {integrity: sha512-dp+MshLYux6j/JjdqVLnMglQlFu+MuVeNrmT5nk6q07wNhCdSnB7QZj+7G8VMUGh1q+vj2Bq8kRsuyA00I/k+Q==} + engines: {node: '>=18'} cpu: [arm] os: [android] requiresBuild: true dev: true optional: true - /@esbuild/android-x64@0.17.19: - resolution: {integrity: sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==} + /@esbuild/android-x64@0.19.12: + resolution: {integrity: sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==} engines: {node: '>=12'} cpu: [x64] os: [android] @@ -691,17 +850,26 @@ packages: dev: true optional: true - /@esbuild/android-x64@0.18.13: - resolution: {integrity: sha512-M2eZkRxR6WnWfVELHmv6MUoHbOqnzoTVSIxgtsyhm/NsgmL+uTmag/VVzdXvmahak1I6sOb1K/2movco5ikDJg==} - engines: {node: '>=12'} + /@esbuild/android-x64@0.24.2: + resolution: {integrity: sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-x64@0.25.1: + resolution: {integrity: sha512-GCj6WfUtNldqUzYkN/ITtlhwQqGWu9S45vUXs7EIYf+7rCiiqH9bCloatO9VhxsL0Pji+PF4Lz2XXCES+Q8hDw==} + engines: {node: '>=18'} cpu: [x64] os: [android] requiresBuild: true dev: true optional: true - /@esbuild/darwin-arm64@0.17.19: - resolution: {integrity: sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==} + /@esbuild/darwin-arm64@0.19.12: + resolution: {integrity: sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==} engines: {node: '>=12'} cpu: [arm64] os: [darwin] @@ -709,17 +877,26 @@ packages: dev: true optional: true - /@esbuild/darwin-arm64@0.18.13: - resolution: {integrity: sha512-f5goG30YgR1GU+fxtaBRdSW3SBG9pZW834Mmhxa6terzcboz7P2R0k4lDxlkP7NYRIIdBbWp+VgwQbmMH4yV7w==} - engines: {node: '>=12'} + /@esbuild/darwin-arm64@0.24.2: + resolution: {integrity: sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-arm64@0.25.1: + resolution: {integrity: sha512-5hEZKPf+nQjYoSr/elb62U19/l1mZDdqidGfmFutVUjjUZrOazAtwK+Kr+3y0C/oeJfLlxo9fXb1w7L+P7E4FQ==} + engines: {node: '>=18'} cpu: [arm64] os: [darwin] requiresBuild: true dev: true optional: true - /@esbuild/darwin-x64@0.17.19: - resolution: {integrity: sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==} + /@esbuild/darwin-x64@0.19.12: + resolution: {integrity: sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==} engines: {node: '>=12'} cpu: [x64] os: [darwin] @@ -727,17 +904,26 @@ packages: dev: true optional: true - /@esbuild/darwin-x64@0.18.13: - resolution: {integrity: sha512-RIrxoKH5Eo+yE5BtaAIMZaiKutPhZjw+j0OCh8WdvKEKJQteacq0myZvBDLU+hOzQOZWJeDnuQ2xgSScKf1Ovw==} - engines: {node: '>=12'} + /@esbuild/darwin-x64@0.24.2: + resolution: {integrity: sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-x64@0.25.1: + resolution: {integrity: sha512-hxVnwL2Dqs3fM1IWq8Iezh0cX7ZGdVhbTfnOy5uURtao5OIVCEyj9xIzemDi7sRvKsuSdtCAhMKarxqtlyVyfA==} + engines: {node: '>=18'} cpu: [x64] os: [darwin] requiresBuild: true dev: true optional: true - /@esbuild/freebsd-arm64@0.17.19: - resolution: {integrity: sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==} + /@esbuild/freebsd-arm64@0.19.12: + resolution: {integrity: sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==} engines: {node: '>=12'} cpu: [arm64] os: [freebsd] @@ -745,17 +931,26 @@ packages: dev: true optional: true - /@esbuild/freebsd-arm64@0.18.13: - resolution: {integrity: sha512-AfRPhHWmj9jGyLgW/2FkYERKmYR+IjYxf2rtSLmhOrPGFh0KCETFzSjx/JX/HJnvIqHt/DRQD/KAaVsUKoI3Xg==} - engines: {node: '>=12'} + /@esbuild/freebsd-arm64@0.24.2: + resolution: {integrity: sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-arm64@0.25.1: + resolution: {integrity: sha512-1MrCZs0fZa2g8E+FUo2ipw6jw5qqQiH+tERoS5fAfKnRx6NXH31tXBKI3VpmLijLH6yriMZsxJtaXUyFt/8Y4A==} + engines: {node: '>=18'} cpu: [arm64] os: [freebsd] requiresBuild: true dev: true optional: true - /@esbuild/freebsd-x64@0.17.19: - resolution: {integrity: sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==} + /@esbuild/freebsd-x64@0.19.12: + resolution: {integrity: sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==} engines: {node: '>=12'} cpu: [x64] os: [freebsd] @@ -763,17 +958,26 @@ packages: dev: true optional: true - /@esbuild/freebsd-x64@0.18.13: - resolution: {integrity: sha512-pGzWWZJBInhIgdEwzn8VHUBang8UvFKsvjDkeJ2oyY5gZtAM6BaxK0QLCuZY+qoj/nx/lIaItH425rm/hloETA==} - engines: {node: '>=12'} + /@esbuild/freebsd-x64@0.24.2: + resolution: {integrity: sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-x64@0.25.1: + resolution: {integrity: sha512-0IZWLiTyz7nm0xuIs0q1Y3QWJC52R8aSXxe40VUxm6BB1RNmkODtW6LHvWRrGiICulcX7ZvyH6h5fqdLu4gkww==} + engines: {node: '>=18'} cpu: [x64] os: [freebsd] requiresBuild: true dev: true optional: true - /@esbuild/linux-arm64@0.17.19: - resolution: {integrity: sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==} + /@esbuild/linux-arm64@0.19.12: + resolution: {integrity: sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==} engines: {node: '>=12'} cpu: [arm64] os: [linux] @@ -781,26 +985,26 @@ packages: dev: true optional: true - /@esbuild/linux-arm64@0.18.13: - resolution: {integrity: sha512-hCzZbVJEHV7QM77fHPv2qgBcWxgglGFGCxk6KfQx6PsVIdi1u09X7IvgE9QKqm38OpkzaAkPnnPqwRsltvLkIQ==} - engines: {node: '>=12'} + /@esbuild/linux-arm64@0.24.2: + resolution: {integrity: sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==} + engines: {node: '>=18'} cpu: [arm64] os: [linux] requiresBuild: true dev: true optional: true - /@esbuild/linux-arm@0.17.19: - resolution: {integrity: sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==} - engines: {node: '>=12'} - cpu: [arm] + /@esbuild/linux-arm64@0.25.1: + resolution: {integrity: sha512-jaN3dHi0/DDPelk0nLcXRm1q7DNJpjXy7yWaWvbfkPvI+7XNSc/lDOnCLN7gzsyzgu6qSAmgSvP9oXAhP973uQ==} + engines: {node: '>=18'} + cpu: [arm64] os: [linux] requiresBuild: true dev: true optional: true - /@esbuild/linux-arm@0.18.13: - resolution: {integrity: sha512-4iMxLRMCxGyk7lEvkkvrxw4aJeC93YIIrfbBlUJ062kilUUnAiMb81eEkVvCVoh3ON283ans7+OQkuy1uHW+Hw==} + /@esbuild/linux-arm@0.19.12: + resolution: {integrity: sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==} engines: {node: '>=12'} cpu: [arm] os: [linux] @@ -808,53 +1012,80 @@ packages: dev: true optional: true - /@esbuild/linux-ia32@0.17.19: - resolution: {integrity: sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==} - engines: {node: '>=12'} - cpu: [ia32] + /@esbuild/linux-arm@0.24.2: + resolution: {integrity: sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==} + engines: {node: '>=18'} + cpu: [arm] os: [linux] requiresBuild: true dev: true optional: true - /@esbuild/linux-ia32@0.18.13: - resolution: {integrity: sha512-I3OKGbynl3AAIO6onXNrup/ttToE6Rv2XYfFgLK/wnr2J+1g+7k4asLrE+n7VMhaqX+BUnyWkCu27rl+62Adug==} - engines: {node: '>=12'} - cpu: [ia32] + /@esbuild/linux-arm@0.25.1: + resolution: {integrity: sha512-NdKOhS4u7JhDKw9G3cY6sWqFcnLITn6SqivVArbzIaf3cemShqfLGHYMx8Xlm/lBit3/5d7kXvriTUGa5YViuQ==} + engines: {node: '>=18'} + cpu: [arm] os: [linux] requiresBuild: true dev: true optional: true - /@esbuild/linux-loong64@0.17.19: - resolution: {integrity: sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==} + /@esbuild/linux-ia32@0.19.12: + resolution: {integrity: sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==} engines: {node: '>=12'} - cpu: [loong64] + cpu: [ia32] os: [linux] requiresBuild: true dev: true optional: true - /@esbuild/linux-loong64@0.18.13: - resolution: {integrity: sha512-8pcKDApAsKc6WW51ZEVidSGwGbebYw2qKnO1VyD8xd6JN0RN6EUXfhXmDk9Vc4/U3Y4AoFTexQewQDJGsBXBpg==} - engines: {node: '>=12'} - cpu: [loong64] + /@esbuild/linux-ia32@0.24.2: + resolution: {integrity: sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==} + engines: {node: '>=18'} + cpu: [ia32] os: [linux] requiresBuild: true dev: true optional: true - /@esbuild/linux-mips64el@0.17.19: - resolution: {integrity: sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==} - engines: {node: '>=12'} - cpu: [mips64el] + /@esbuild/linux-ia32@0.25.1: + resolution: {integrity: sha512-OJykPaF4v8JidKNGz8c/q1lBO44sQNUQtq1KktJXdBLn1hPod5rE/Hko5ugKKZd+D2+o1a9MFGUEIUwO2YfgkQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-loong64@0.19.12: + resolution: {integrity: sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-loong64@0.24.2: + resolution: {integrity: sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-loong64@0.25.1: + resolution: {integrity: sha512-nGfornQj4dzcq5Vp835oM/o21UMlXzn79KobKlcs3Wz9smwiifknLy4xDCLUU0BWp7b/houtdrgUz7nOGnfIYg==} + engines: {node: '>=18'} + cpu: [loong64] os: [linux] requiresBuild: true dev: true optional: true - /@esbuild/linux-mips64el@0.18.13: - resolution: {integrity: sha512-6GU+J1PLiVqWx8yoCK4Z0GnfKyCGIH5L2KQipxOtbNPBs+qNDcMJr9euxnyJ6FkRPyMwaSkjejzPSISD9hb+gg==} + /@esbuild/linux-mips64el@0.19.12: + resolution: {integrity: sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==} engines: {node: '>=12'} cpu: [mips64el] os: [linux] @@ -862,8 +1093,26 @@ packages: dev: true optional: true - /@esbuild/linux-ppc64@0.17.19: - resolution: {integrity: sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==} + /@esbuild/linux-mips64el@0.24.2: + resolution: {integrity: sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-mips64el@0.25.1: + resolution: {integrity: sha512-1osBbPEFYwIE5IVB/0g2X6i1qInZa1aIoj1TdL4AaAb55xIIgbg8Doq6a5BzYWgr+tEcDzYH67XVnTmUzL+nXg==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ppc64@0.19.12: + resolution: {integrity: sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==} engines: {node: '>=12'} cpu: [ppc64] os: [linux] @@ -871,17 +1120,26 @@ packages: dev: true optional: true - /@esbuild/linux-ppc64@0.18.13: - resolution: {integrity: sha512-pfn/OGZ8tyR8YCV7MlLl5hAit2cmS+j/ZZg9DdH0uxdCoJpV7+5DbuXrR+es4ayRVKIcfS9TTMCs60vqQDmh+w==} - engines: {node: '>=12'} + /@esbuild/linux-ppc64@0.24.2: + resolution: {integrity: sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ppc64@0.25.1: + resolution: {integrity: sha512-/6VBJOwUf3TdTvJZ82qF3tbLuWsscd7/1w+D9LH0W/SqUgM5/JJD0lrJ1fVIfZsqB6RFmLCe0Xz3fmZc3WtyVg==} + engines: {node: '>=18'} cpu: [ppc64] os: [linux] requiresBuild: true dev: true optional: true - /@esbuild/linux-riscv64@0.17.19: - resolution: {integrity: sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==} + /@esbuild/linux-riscv64@0.19.12: + resolution: {integrity: sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==} engines: {node: '>=12'} cpu: [riscv64] os: [linux] @@ -889,17 +1147,26 @@ packages: dev: true optional: true - /@esbuild/linux-riscv64@0.18.13: - resolution: {integrity: sha512-aIbhU3LPg0lOSCfVeGHbmGYIqOtW6+yzO+Nfv57YblEK01oj0mFMtvDJlOaeAZ6z0FZ9D13oahi5aIl9JFphGg==} - engines: {node: '>=12'} + /@esbuild/linux-riscv64@0.24.2: + resolution: {integrity: sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-riscv64@0.25.1: + resolution: {integrity: sha512-nSut/Mx5gnilhcq2yIMLMe3Wl4FK5wx/o0QuuCLMtmJn+WeWYoEGDN1ipcN72g1WHsnIbxGXd4i/MF0gTcuAjQ==} + engines: {node: '>=18'} cpu: [riscv64] os: [linux] requiresBuild: true dev: true optional: true - /@esbuild/linux-s390x@0.17.19: - resolution: {integrity: sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==} + /@esbuild/linux-s390x@0.19.12: + resolution: {integrity: sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==} engines: {node: '>=12'} cpu: [s390x] os: [linux] @@ -907,17 +1174,26 @@ packages: dev: true optional: true - /@esbuild/linux-s390x@0.18.13: - resolution: {integrity: sha512-Pct1QwF2sp+5LVi4Iu5Y+6JsGaV2Z2vm4O9Dd7XZ5tKYxEHjFtb140fiMcl5HM1iuv6xXO8O1Vrb1iJxHlv8UA==} - engines: {node: '>=12'} + /@esbuild/linux-s390x@0.24.2: + resolution: {integrity: sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==} + engines: {node: '>=18'} cpu: [s390x] os: [linux] requiresBuild: true dev: true optional: true - /@esbuild/linux-x64@0.17.19: - resolution: {integrity: sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==} + /@esbuild/linux-s390x@0.25.1: + resolution: {integrity: sha512-cEECeLlJNfT8kZHqLarDBQso9a27o2Zd2AQ8USAEoGtejOrCYHNtKP8XQhMDJMtthdF4GBmjR2au3x1udADQQQ==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-x64@0.19.12: + resolution: {integrity: sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==} engines: {node: '>=12'} cpu: [x64] os: [linux] @@ -925,26 +1201,44 @@ packages: dev: true optional: true - /@esbuild/linux-x64@0.18.13: - resolution: {integrity: sha512-zTrIP0KzYP7O0+3ZnmzvUKgGtUvf4+piY8PIO3V8/GfmVd3ZyHJGz7Ht0np3P1wz+I8qJ4rjwJKqqEAbIEPngA==} - engines: {node: '>=12'} + /@esbuild/linux-x64@0.24.2: + resolution: {integrity: sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==} + engines: {node: '>=18'} cpu: [x64] os: [linux] requiresBuild: true dev: true optional: true - /@esbuild/netbsd-x64@0.17.19: - resolution: {integrity: sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==} - engines: {node: '>=12'} + /@esbuild/linux-x64@0.25.1: + resolution: {integrity: sha512-xbfUhu/gnvSEg+EGovRc+kjBAkrvtk38RlerAzQxvMzlB4fXpCFCeUAYzJvrnhFtdeyVCDANSjJvOvGYoeKzFA==} + engines: {node: '>=18'} cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/netbsd-arm64@0.24.2: + resolution: {integrity: sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/netbsd-arm64@0.25.1: + resolution: {integrity: sha512-O96poM2XGhLtpTh+s4+nP7YCCAfb4tJNRVZHfIE7dgmax+yMP2WgMd2OecBuaATHKTHsLWHQeuaxMRnCsH8+5g==} + engines: {node: '>=18'} + cpu: [arm64] os: [netbsd] requiresBuild: true dev: true optional: true - /@esbuild/netbsd-x64@0.18.13: - resolution: {integrity: sha512-I6zs10TZeaHDYoGxENuksxE1sxqZpCp+agYeW039yqFwh3MgVvdmXL5NMveImOC6AtpLvE4xG5ujVic4NWFIDQ==} + /@esbuild/netbsd-x64@0.19.12: + resolution: {integrity: sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==} engines: {node: '>=12'} cpu: [x64] os: [netbsd] @@ -952,17 +1246,44 @@ packages: dev: true optional: true - /@esbuild/openbsd-x64@0.17.19: - resolution: {integrity: sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==} - engines: {node: '>=12'} + /@esbuild/netbsd-x64@0.24.2: + resolution: {integrity: sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/netbsd-x64@0.25.1: + resolution: {integrity: sha512-X53z6uXip6KFXBQ+Krbx25XHV/NCbzryM6ehOAeAil7X7oa4XIq+394PWGnwaSQ2WRA0KI6PUO6hTO5zeF5ijA==} + engines: {node: '>=18'} cpu: [x64] + os: [netbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/openbsd-arm64@0.24.2: + resolution: {integrity: sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/openbsd-arm64@0.25.1: + resolution: {integrity: sha512-Na9T3szbXezdzM/Kfs3GcRQNjHzM6GzFBeU1/6IV/npKP5ORtp9zbQjvkDJ47s6BCgaAZnnnu/cY1x342+MvZg==} + engines: {node: '>=18'} + cpu: [arm64] os: [openbsd] requiresBuild: true dev: true optional: true - /@esbuild/openbsd-x64@0.18.13: - resolution: {integrity: sha512-W5C5nczhrt1y1xPG5bV+0M12p2vetOGlvs43LH8SopQ3z2AseIROu09VgRqydx5qFN7y9qCbpgHLx0kb0TcW7g==} + /@esbuild/openbsd-x64@0.19.12: + resolution: {integrity: sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==} engines: {node: '>=12'} cpu: [x64] os: [openbsd] @@ -970,8 +1291,26 @@ packages: dev: true optional: true - /@esbuild/sunos-x64@0.17.19: - resolution: {integrity: sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==} + /@esbuild/openbsd-x64@0.24.2: + resolution: {integrity: sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/openbsd-x64@0.25.1: + resolution: {integrity: sha512-T3H78X2h1tszfRSf+txbt5aOp/e7TAz3ptVKu9Oyir3IAOFPGV6O9c2naym5TOriy1l0nNf6a4X5UXRZSGX/dw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/sunos-x64@0.19.12: + resolution: {integrity: sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==} engines: {node: '>=12'} cpu: [x64] os: [sunos] @@ -979,17 +1318,26 @@ packages: dev: true optional: true - /@esbuild/sunos-x64@0.18.13: - resolution: {integrity: sha512-X/xzuw4Hzpo/yq3YsfBbIsipNgmsm8mE/QeWbdGdTTeZ77fjxI2K0KP3AlhZ6gU3zKTw1bKoZTuKLnqcJ537qw==} - engines: {node: '>=12'} + /@esbuild/sunos-x64@0.24.2: + resolution: {integrity: sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + requiresBuild: true + dev: true + optional: true + + /@esbuild/sunos-x64@0.25.1: + resolution: {integrity: sha512-2H3RUvcmULO7dIE5EWJH8eubZAI4xw54H1ilJnRNZdeo8dTADEZ21w6J22XBkXqGJbe0+wnNJtw3UXRoLJnFEg==} + engines: {node: '>=18'} cpu: [x64] os: [sunos] requiresBuild: true dev: true optional: true - /@esbuild/win32-arm64@0.17.19: - resolution: {integrity: sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==} + /@esbuild/win32-arm64@0.19.12: + resolution: {integrity: sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==} engines: {node: '>=12'} cpu: [arm64] os: [win32] @@ -997,17 +1345,26 @@ packages: dev: true optional: true - /@esbuild/win32-arm64@0.18.13: - resolution: {integrity: sha512-4CGYdRQT/ILd+yLLE5i4VApMPfGE0RPc/wFQhlluDQCK09+b4JDbxzzjpgQqTPrdnP7r5KUtGVGZYclYiPuHrw==} - engines: {node: '>=12'} + /@esbuild/win32-arm64@0.24.2: + resolution: {integrity: sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-arm64@0.25.1: + resolution: {integrity: sha512-GE7XvrdOzrb+yVKB9KsRMq+7a2U/K5Cf/8grVFRAGJmfADr/e/ODQ134RK2/eeHqYV5eQRFxb1hY7Nr15fv1NQ==} + engines: {node: '>=18'} cpu: [arm64] os: [win32] requiresBuild: true dev: true optional: true - /@esbuild/win32-ia32@0.17.19: - resolution: {integrity: sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==} + /@esbuild/win32-ia32@0.19.12: + resolution: {integrity: sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==} engines: {node: '>=12'} cpu: [ia32] os: [win32] @@ -1015,17 +1372,26 @@ packages: dev: true optional: true - /@esbuild/win32-ia32@0.18.13: - resolution: {integrity: sha512-D+wKZaRhQI+MUGMH+DbEr4owC2D7XnF+uyGiZk38QbgzLcofFqIOwFs7ELmIeU45CQgfHNy9Q+LKW3cE8g37Kg==} - engines: {node: '>=12'} + /@esbuild/win32-ia32@0.24.2: + resolution: {integrity: sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-ia32@0.25.1: + resolution: {integrity: sha512-uOxSJCIcavSiT6UnBhBzE8wy3n0hOkJsBOzy7HDAuTDE++1DJMRRVCPGisULScHL+a/ZwdXPpXD3IyFKjA7K8A==} + engines: {node: '>=18'} cpu: [ia32] os: [win32] requiresBuild: true dev: true optional: true - /@esbuild/win32-x64@0.17.19: - resolution: {integrity: sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==} + /@esbuild/win32-x64@0.19.12: + resolution: {integrity: sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==} engines: {node: '>=12'} cpu: [x64] os: [win32] @@ -1033,39 +1399,108 @@ packages: dev: true optional: true - /@esbuild/win32-x64@0.18.13: - resolution: {integrity: sha512-iVl6lehAfJS+VmpF3exKpNQ8b0eucf5VWfzR8S7xFve64NBNz2jPUgx1X93/kfnkfgP737O+i1k54SVQS7uVZA==} - engines: {node: '>=12'} + /@esbuild/win32-x64@0.24.2: + resolution: {integrity: sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-x64@0.25.1: + resolution: {integrity: sha512-Y1EQdcfwMSeQN/ujR5VayLOJ1BHaK+ssyk0AEzPjC+t1lITgsnccPqFjb6V+LsTp/9Iov4ysfjxLaGJ9RPtkVg==} + engines: {node: '>=18'} cpu: [x64] os: [win32] requiresBuild: true dev: true optional: true - /@eslint-community/eslint-utils@4.4.0(eslint@8.45.0): + /@eslint-community/eslint-utils@4.4.0(eslint@9.26.0): resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 dependencies: - eslint: 8.45.0 - eslint-visitor-keys: 3.4.1 + eslint: 9.26.0 + eslint-visitor-keys: 3.4.3 dev: true - /@eslint-community/regexpp@4.5.1: - resolution: {integrity: sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ==} - engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + /@eslint-community/eslint-utils@4.6.0(eslint@9.26.0): + resolution: {integrity: sha512-WhCn7Z7TauhBtmzhvKpoQs0Wwb/kBcy4CwpuI0/eEIr2Lx2auxmulAzLr91wVZJaz47iUZdkXOK7WlAfxGKCnA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + dependencies: + eslint: 9.26.0 + eslint-visitor-keys: 3.4.3 dev: true - /@eslint/eslintrc@2.1.0: - resolution: {integrity: sha512-Lj7DECXqIVCqnqjjHMPna4vn6GJcMgul/wuS0je9OZ9gsL0zzDpKPVtcG1HaDVc+9y+qgXneTeUMbCqXJNpH1A==} + /@eslint-community/eslint-utils@4.7.0(eslint@9.26.0): + resolution: {integrity: sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + dependencies: + eslint: 9.26.0 + eslint-visitor-keys: 3.4.3 + dev: true + + /@eslint-community/regexpp@4.11.0: + resolution: {integrity: sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + dev: true + + /@eslint-community/regexpp@4.12.1: + resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + dev: true + + /@eslint/compat@1.2.9(eslint@9.26.0): + resolution: {integrity: sha512-gCdSY54n7k+driCadyMNv8JSPzYLeDVM/ikZRtvtROBpRdFSkS8W9A82MqsaY7lZuwL0wiapgD0NT1xT0hyJsA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^9.10.0 + peerDependenciesMeta: + eslint: + optional: true + dependencies: + eslint: 9.26.0 + dev: true + + /@eslint/config-array@0.20.0: + resolution: {integrity: sha512-fxlS1kkIjx8+vy2SjuCB94q3htSNrufYTXubwiBFeaQHbH6Ipi43gFJq2zCMt6PHhImH3Xmr0NksKDvchWlpQQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dependencies: + '@eslint/object-schema': 2.1.6 + debug: 4.4.0 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@eslint/config-helpers@0.2.2: + resolution: {integrity: sha512-+GPzk8PlG0sPpzdU5ZvIRMPidzAnZDl/s9L+y13iodqvb8leL53bTannOrQ/Im7UkpsmFU5Ily5U60LWixnmLg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dev: true + + /@eslint/core@0.13.0: + resolution: {integrity: sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dependencies: + '@types/json-schema': 7.0.15 + dev: true + + /@eslint/eslintrc@3.3.1: + resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} dependencies: ajv: 6.12.6 - debug: 4.3.4 - espree: 9.6.1 - globals: 13.20.0 - ignore: 5.2.4 + debug: 4.4.0 + espree: 10.3.0 + globals: 14.0.0 + ignore: 5.3.2 import-fresh: 3.3.0 js-yaml: 4.1.0 minimatch: 3.1.2 @@ -1074,20 +1509,35 @@ packages: - supports-color dev: true - /@eslint/js@8.44.0: - resolution: {integrity: sha512-Ag+9YM4ocKQx9AarydN0KY2j0ErMHNIocPDrVo8zAE44xLTjEtz81OdR68/cydGtk6m6jDb5Za3r2useMzYmSw==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + /@eslint/js@9.26.0: + resolution: {integrity: sha512-I9XlJawFdSMvWjDt6wksMCrgns5ggLNfFwFvnShsleWruvXM514Qxk8V246efTw+eo9JABvVz+u3q2RiAowKxQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dev: true + + /@eslint/object-schema@2.1.6: + resolution: {integrity: sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} dev: true - /@humanwhocodes/config-array@0.11.10: - resolution: {integrity: sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==} - engines: {node: '>=10.10.0'} + /@eslint/plugin-kit@0.2.8: + resolution: {integrity: sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} dependencies: - '@humanwhocodes/object-schema': 1.2.1 - debug: 4.3.4 - minimatch: 3.1.2 - transitivePeerDependencies: - - supports-color + '@eslint/core': 0.13.0 + levn: 0.4.1 + dev: true + + /@humanfs/core@0.19.1: + resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} + engines: {node: '>=18.18.0'} + dev: true + + /@humanfs/node@0.16.6: + resolution: {integrity: sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==} + engines: {node: '>=18.18.0'} + dependencies: + '@humanfs/core': 0.19.1 + '@humanwhocodes/retry': 0.3.0 dev: true /@humanwhocodes/module-importer@1.0.1: @@ -1095,8 +1545,56 @@ packages: engines: {node: '>=12.22'} dev: true - /@humanwhocodes/object-schema@1.2.1: - resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} + /@humanwhocodes/retry@0.3.0: + resolution: {integrity: sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==} + engines: {node: '>=18.18'} + dev: true + + /@humanwhocodes/retry@0.4.2: + resolution: {integrity: sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==} + engines: {node: '>=18.18'} + dev: true + + /@inquirer/confirm@5.1.2(@types/node@20.11.26): + resolution: {integrity: sha512-VKgaKxw2I3cu2smedeMFyxuYyI+HABlFY1Px4j8NueA7xDskKAo9hxEQemTpp1Fu4OiTtOCgU4eK91BVuBKH3g==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + dependencies: + '@inquirer/core': 10.1.3(@types/node@20.11.26) + '@inquirer/type': 3.0.2(@types/node@20.11.26) + '@types/node': 20.11.26 + dev: true + + /@inquirer/core@10.1.3(@types/node@20.11.26): + resolution: {integrity: sha512-+7/dCYwDku2xfcWJWX6Urxb8aRz6d0K+4lRgIBM08ktE84dm++RPROgnVfWq4hLK5FVu/O4rbO9HnJtaz3pt2w==} + engines: {node: '>=18'} + dependencies: + '@inquirer/figures': 1.0.9 + '@inquirer/type': 3.0.2(@types/node@20.11.26) + ansi-escapes: 4.3.2 + cli-width: 4.1.0 + mute-stream: 2.0.0 + signal-exit: 4.1.0 + strip-ansi: 6.0.1 + wrap-ansi: 6.2.0 + yoctocolors-cjs: 2.1.2 + transitivePeerDependencies: + - '@types/node' + dev: true + + /@inquirer/figures@1.0.9: + resolution: {integrity: sha512-BXvGj0ehzrngHTPTDqUoDT3NXL8U0RxUk2zJm2A66RhCEIWdtU1v6GuUqNAgArW4PQ9CinqIWyHdQgdwOj06zQ==} + engines: {node: '>=18'} + dev: true + + /@inquirer/type@3.0.2(@types/node@20.11.26): + resolution: {integrity: sha512-ZhQ4TvhwHZF+lGhQ2O/rsjo80XoZR5/5qhOY3t6FJuX5XBg5Be8YzYTvaUGJnc12AUGI2nr4QSUE4PhKSigx7g==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + dependencies: + '@types/node': 20.11.26 dev: true /@isaacs/cliui@8.0.2: @@ -1116,120 +1614,147 @@ packages: engines: {node: '>=8'} dev: true - /@jest/schemas@29.6.0: - resolution: {integrity: sha512-rxLjXyJBTL4LQeJW3aKo0M/+GkCOXsO+8i9Iu7eDb6KwtP65ayoDsitrdPBtujxQ88k4wI2FNYfa6TOGwSn6cQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + /@jridgewell/gen-mapping@0.3.5: + resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} + engines: {node: '>=6.0.0'} dependencies: - '@sinclair/typebox': 0.27.8 + '@jridgewell/set-array': 1.2.1 + '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/trace-mapping': 0.3.25 dev: true - /@jridgewell/gen-mapping@0.3.3: - resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==} + /@jridgewell/resolve-uri@3.1.2: + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} engines: {node: '>=6.0.0'} - dependencies: - '@jridgewell/set-array': 1.1.2 - '@jridgewell/sourcemap-codec': 1.4.15 - '@jridgewell/trace-mapping': 0.3.18 dev: true - /@jridgewell/resolve-uri@3.1.0: - resolution: {integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==} + /@jridgewell/set-array@1.2.1: + resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} engines: {node: '>=6.0.0'} dev: true - /@jridgewell/set-array@1.1.2: - resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} - engines: {node: '>=6.0.0'} + /@jridgewell/sourcemap-codec@1.5.0: + resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} dev: true - /@jridgewell/sourcemap-codec@1.4.14: - resolution: {integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==} + /@jridgewell/trace-mapping@0.3.25: + resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.0 dev: true - /@jridgewell/sourcemap-codec@1.4.15: - resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} + /@microsoft/api-extractor-model@7.30.2: + resolution: {integrity: sha512-3/t2F+WhkJgBzSNwlkTIL0tBgUoBqDqL66pT+nh2mPbM0NIDGVGtpqbGWPgHIzn/mn7kGS/Ep8D8po58e8UUIw==} + dependencies: + '@microsoft/tsdoc': 0.15.1 + '@microsoft/tsdoc-config': 0.17.1 + '@rushstack/node-core-library': 5.10.2 + transitivePeerDependencies: + - '@types/node' dev: true - /@jridgewell/trace-mapping@0.3.18: - resolution: {integrity: sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==} + /@microsoft/api-extractor-model@7.30.4(@types/node@20.11.26): + resolution: {integrity: sha512-RobC0gyVYsd2Fao9MTKOfTdBm41P/bCMUmzS5mQ7/MoAKEqy0FOBph3JOYdq4X4BsEnMEiSHc+0NUNmdzxCpjA==} dependencies: - '@jridgewell/resolve-uri': 3.1.0 - '@jridgewell/sourcemap-codec': 1.4.14 + '@microsoft/tsdoc': 0.15.1 + '@microsoft/tsdoc-config': 0.17.1 + '@rushstack/node-core-library': 5.12.0(@types/node@20.11.26) + transitivePeerDependencies: + - '@types/node' dev: true - /@microsoft/api-extractor-model@7.27.4: - resolution: {integrity: sha512-HjqQFmuGPOS20rtnu+9Jj0QrqZyR59E+piUWXPMZTTn4jaZI+4UmsHSf3Id8vyueAhOBH2cgwBuRTE5R+MfSMw==} + /@microsoft/api-extractor@7.49.1: + resolution: {integrity: sha512-jRTR/XbQF2kb+dYn8hfYSicOGA99+Fo00GrsdMwdfE3eIgLtKdH6Qa2M3wZV9S2XmbgCaGX1OdPtYctbfu5jQg==} + hasBin: true dependencies: - '@microsoft/tsdoc': 0.14.2 - '@microsoft/tsdoc-config': 0.16.2 - '@rushstack/node-core-library': 3.59.5 + '@microsoft/api-extractor-model': 7.30.2 + '@microsoft/tsdoc': 0.15.1 + '@microsoft/tsdoc-config': 0.17.1 + '@rushstack/node-core-library': 5.10.2 + '@rushstack/rig-package': 0.5.3 + '@rushstack/terminal': 0.14.5 + '@rushstack/ts-command-line': 4.23.3 + lodash: 4.17.21 + minimatch: 3.0.8 + resolve: 1.22.8 + semver: 7.5.4 + source-map: 0.6.1 + typescript: 5.7.2 transitivePeerDependencies: - '@types/node' dev: true - /@microsoft/api-extractor@7.36.2: - resolution: {integrity: sha512-ONe/jOmTZtR3OjTkWKHmeSV1P5ozbHDxHr6FV3KoWyIl1AcPk2B3dmvVBM5eOlZB5bgM66nxcWQTZ6msQo2hHg==} + /@microsoft/api-extractor@7.52.1(@types/node@20.11.26): + resolution: {integrity: sha512-m3I5uAwE05orsu3D1AGyisX5KxsgVXB+U4bWOOaX/Z7Ftp/2Cy41qsNhO6LPvSxHBaapyser5dVorF1t5M6tig==} hasBin: true dependencies: - '@microsoft/api-extractor-model': 7.27.4 - '@microsoft/tsdoc': 0.14.2 - '@microsoft/tsdoc-config': 0.16.2 - '@rushstack/node-core-library': 3.59.5 - '@rushstack/rig-package': 0.4.0 - '@rushstack/ts-command-line': 4.15.1 - colors: 1.2.5 + '@microsoft/api-extractor-model': 7.30.4(@types/node@20.11.26) + '@microsoft/tsdoc': 0.15.1 + '@microsoft/tsdoc-config': 0.17.1 + '@rushstack/node-core-library': 5.12.0(@types/node@20.11.26) + '@rushstack/rig-package': 0.5.3 + '@rushstack/terminal': 0.15.1(@types/node@20.11.26) + '@rushstack/ts-command-line': 4.23.6(@types/node@20.11.26) lodash: 4.17.21 - resolve: 1.22.2 - semver: 7.3.8 + minimatch: 3.0.8 + resolve: 1.22.8 + semver: 7.5.4 source-map: 0.6.1 - typescript: 5.0.4 + typescript: 5.8.2 transitivePeerDependencies: - '@types/node' dev: true - /@microsoft/tsdoc-config@0.16.2: - resolution: {integrity: sha512-OGiIzzoBLgWWR0UdRJX98oYO+XKGf7tiK4Zk6tQ/E4IJqGCe7dvkTvgDZV5cFJUzLGDOjeAXrnZoA6QkVySuxw==} + /@microsoft/tsdoc-config@0.17.1: + resolution: {integrity: sha512-UtjIFe0C6oYgTnad4q1QP4qXwLhe6tIpNTRStJ2RZEPIkqQPREAwE5spzVxsdn9UaEMUqhh0AqSx3X4nWAKXWw==} dependencies: - '@microsoft/tsdoc': 0.14.2 - ajv: 6.12.6 + '@microsoft/tsdoc': 0.15.1 + ajv: 8.12.0 jju: 1.4.0 - resolve: 1.19.0 + resolve: 1.22.8 dev: true - /@microsoft/tsdoc@0.14.2: - resolution: {integrity: sha512-9b8mPpKrfeGRuhFH5iO1iwCLeIIsV6+H1sRfxbkoGXIyQE2BTsPd9zqSqQJ+pv5sJ/hT5M1zvOFL02MnEezFug==} + /@microsoft/tsdoc@0.15.1: + resolution: {integrity: sha512-4aErSrCR/On/e5G2hDP0wjooqDdauzEbIq8hIkIe5pXV0rtWJZvdCEKL0ykZxex+IxIwBp0eGeV48hQN07dXtw==} dev: true - /@mswjs/cookies@0.2.2: - resolution: {integrity: sha512-mlN83YSrcFgk7Dm1Mys40DLssI1KdJji2CMKN8eOlBqsTADYzj2+jWzsANsUTFbxDMWPD5e9bfA1RGqBpS3O1g==} - engines: {node: '>=14'} + /@modelcontextprotocol/sdk@1.11.0: + resolution: {integrity: sha512-k/1pb70eD638anoi0e8wUGAlbMJXyvdV4p62Ko+EZ7eBe1xMx8Uhak1R5DgfoofsK5IBBnRwsYGTaLZl+6/+RQ==} + engines: {node: '>=18'} dependencies: - '@types/set-cookie-parser': 2.4.2 - set-cookie-parser: 2.6.0 + content-type: 1.0.5 + cors: 2.8.5 + cross-spawn: 7.0.6 + eventsource: 3.0.6 + express: 5.1.0 + express-rate-limit: 7.5.0(express@5.1.0) + pkce-challenge: 5.0.0 + raw-body: 3.0.0 + zod: 3.24.4 + zod-to-json-schema: 3.24.5(zod@3.24.4) + transitivePeerDependencies: + - supports-color dev: true - /@mswjs/interceptors@0.17.9: - resolution: {integrity: sha512-4LVGt03RobMH/7ZrbHqRxQrS9cc2uh+iNKSj8UWr8M26A2i793ju+csaB5zaqYltqJmA2jUq4VeYfKmVqvsXQg==} - engines: {node: '>=14'} + /@mswjs/interceptors@0.37.5: + resolution: {integrity: sha512-AAwRb5vXFcY4L+FvZ7LZusDuZ0vEe0Zm8ohn1FM6/X7A3bj4mqmkAcGRWuvC2JwSygNwHAAmMnAI73vPHeqsHA==} + engines: {node: '>=18'} dependencies: - '@open-draft/until': 1.0.3 - '@types/debug': 4.1.8 - '@xmldom/xmldom': 0.8.9 - debug: 4.3.4 - headers-polyfill: 3.1.2 - outvariant: 1.4.0 - strict-event-emitter: 0.2.8 - web-encoding: 1.1.5 - transitivePeerDependencies: - - supports-color + '@open-draft/deferred-promise': 2.2.0 + '@open-draft/logger': 0.3.0 + '@open-draft/until': 2.1.0 + is-node-process: 1.2.0 + outvariant: 1.4.3 + strict-event-emitter: 0.5.1 dev: true - /@next/env@13.4.10: - resolution: {integrity: sha512-3G1yD/XKTSLdihyDSa8JEsaWOELY+OWe08o0LUYzfuHp1zHDA8SObQlzKt+v+wrkkPcnPweoLH1ImZeUa0A1NQ==} + /@next/env@14.1.0: + resolution: {integrity: sha512-Py8zIo+02ht82brwwhTg36iogzFqGLPXlRGKQw5s+qP/kMNc4MAyDeEwBKDijk6zTIbegEgu8Qy7C1LboslQAw==} dev: false - /@next/swc-darwin-arm64@13.4.10: - resolution: {integrity: sha512-4bsdfKmmg7mgFGph0UorD1xWfZ5jZEw4kKRHYEeTK9bT1QnMbPVPlVXQRIiFPrhoDQnZUoa6duuPUJIEGLV1Jg==} + /@next/swc-darwin-arm64@14.1.0: + resolution: {integrity: sha512-nUDn7TOGcIeyQni6lZHfzNoo9S0euXnu0jhsbMOmMJUBfgsnESdjN97kM7cBqQxZa8L/bM9om/S5/1dzCrW6wQ==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] @@ -1237,8 +1762,8 @@ packages: dev: false optional: true - /@next/swc-darwin-x64@13.4.10: - resolution: {integrity: sha512-ngXhUBbcZIWZWqNbQSNxQrB9T1V+wgfCzAor2olYuo/YpaL6mUYNUEgeBMhr8qwV0ARSgKaOp35lRvB7EmCRBg==} + /@next/swc-darwin-x64@14.1.0: + resolution: {integrity: sha512-1jgudN5haWxiAl3O1ljUS2GfupPmcftu2RYJqZiMJmmbBT5M1XDffjUtRUzP4W3cBHsrvkfOFdQ71hAreNQP6g==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] @@ -1246,8 +1771,8 @@ packages: dev: false optional: true - /@next/swc-linux-arm64-gnu@13.4.10: - resolution: {integrity: sha512-SjCZZCOmHD4uyM75MVArSAmF5Y+IJSGroPRj2v9/jnBT36SYFTORN8Ag/lhw81W9EeexKY/CUg2e9mdebZOwsg==} + /@next/swc-linux-arm64-gnu@14.1.0: + resolution: {integrity: sha512-RHo7Tcj+jllXUbK7xk2NyIDod3YcCPDZxj1WLIYxd709BQ7WuRYl3OWUNG+WUfqeQBds6kvZYlc42NJJTNi4tQ==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] @@ -1255,8 +1780,8 @@ packages: dev: false optional: true - /@next/swc-linux-arm64-musl@13.4.10: - resolution: {integrity: sha512-F+VlcWijX5qteoYIOxNiBbNE8ruaWuRlcYyIRK10CugqI/BIeCDzEDyrHIHY8AWwbkTwe6GRHabMdE688Rqq4Q==} + /@next/swc-linux-arm64-musl@14.1.0: + resolution: {integrity: sha512-v6kP8sHYxjO8RwHmWMJSq7VZP2nYCkRVQ0qolh2l6xroe9QjbgV8siTbduED4u0hlk0+tjS6/Tuy4n5XCp+l6g==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] @@ -1264,8 +1789,8 @@ packages: dev: false optional: true - /@next/swc-linux-x64-gnu@13.4.10: - resolution: {integrity: sha512-WDv1YtAV07nhfy3i1visr5p/tjiH6CeXp4wX78lzP1jI07t4PnHHG1WEDFOduXh3WT4hG6yN82EQBQHDi7hBrQ==} + /@next/swc-linux-x64-gnu@14.1.0: + resolution: {integrity: sha512-zJ2pnoFYB1F4vmEVlb/eSe+VH679zT1VdXlZKX+pE66grOgjmKJHKacf82g/sWE4MQ4Rk2FMBCRnX+l6/TVYzQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] @@ -1273,8 +1798,8 @@ packages: dev: false optional: true - /@next/swc-linux-x64-musl@13.4.10: - resolution: {integrity: sha512-zFkzqc737xr6qoBgDa3AwC7jPQzGLjDlkNmt/ljvQJ/Veri5ECdHjZCUuiTUfVjshNIIpki6FuP0RaQYK9iCRg==} + /@next/swc-linux-x64-musl@14.1.0: + resolution: {integrity: sha512-rbaIYFt2X9YZBSbH/CwGAjbBG2/MrACCVu2X0+kSykHzHnYH5FjHxwXLkcoJ10cX0aWCEynpu+rP76x0914atg==} engines: {node: '>= 10'} cpu: [x64] os: [linux] @@ -1282,8 +1807,8 @@ packages: dev: false optional: true - /@next/swc-win32-arm64-msvc@13.4.10: - resolution: {integrity: sha512-IboRS8IWz5mWfnjAdCekkl8s0B7ijpWeDwK2O8CdgZkoCDY0ZQHBSGiJ2KViAG6+BJVfLvcP+a2fh6cdyBr9QQ==} + /@next/swc-win32-arm64-msvc@14.1.0: + resolution: {integrity: sha512-o1N5TsYc8f/HpGt39OUQpQ9AKIGApd3QLueu7hXk//2xq5Z9OxmV6sQfNp8C7qYmiOlHYODOGqNNa0e9jvchGQ==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] @@ -1291,8 +1816,8 @@ packages: dev: false optional: true - /@next/swc-win32-ia32-msvc@13.4.10: - resolution: {integrity: sha512-bSA+4j8jY4EEiwD/M2bol4uVEu1lBlgsGdvM+mmBm/BbqofNBfaZ2qwSbwE2OwbAmzNdVJRFRXQZ0dkjopTRaQ==} + /@next/swc-win32-ia32-msvc@14.1.0: + resolution: {integrity: sha512-XXIuB1DBRCFwNO6EEzCTMHT5pauwaSj4SWs7CYnME57eaReAKBXCnkUE80p/pAZcewm7hs+vGvNqDPacEXHVkw==} engines: {node: '>= 10'} cpu: [ia32] os: [win32] @@ -1300,8 +1825,8 @@ packages: dev: false optional: true - /@next/swc-win32-x64-msvc@13.4.10: - resolution: {integrity: sha512-g2+tU63yTWmcVQKDGY0MV1PjjqgZtwM4rB1oVVi/v0brdZAcrcTV+04agKzWtvWroyFz6IqtT0MoZJA7PNyLVw==} + /@next/swc-win32-x64-msvc@14.1.0: + resolution: {integrity: sha512-9WEbVRRAqJ3YFVqEZIxUqkiO8l1nool1LmNxygr5HWF8AcSYsEpneUDhmjUVJEzO2A04+oPtZdombzzPPkTtgg==} engines: {node: '>= 10'} cpu: [x64] os: [win32] @@ -1327,11 +1852,22 @@ packages: engines: {node: '>= 8'} dependencies: '@nodelib/fs.scandir': 2.1.5 - fastq: 1.15.0 + fastq: 1.17.1 + dev: true + + /@open-draft/deferred-promise@2.2.0: + resolution: {integrity: sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA==} dev: true - /@open-draft/until@1.0.3: - resolution: {integrity: sha512-Aq58f5HiWdyDlFffbbSjAlv596h/cOnt2DO1w3DOC7OJ5EHs0hd/nycJfiu9RJbT6Yk6F1knnRRXNSpxoIVZ9Q==} + /@open-draft/logger@0.3.0: + resolution: {integrity: sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ==} + dependencies: + is-node-process: 1.2.0 + outvariant: 1.4.3 + dev: true + + /@open-draft/until@2.1.0: + resolution: {integrity: sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==} dev: true /@pkgjs/parseargs@0.11.0: @@ -1341,656 +1877,1208 @@ packages: dev: true optional: true - /@pkgr/utils@2.4.2: - resolution: {integrity: sha512-POgTXhjrTfbTV63DiFXav4lBHiICLKKwDeaKn9Nphwj7WH6m0hMMCaJkMyRWjgtPFyRKRVoMXXjczsTQRDEhYw==} + /@pkgr/core@0.2.2: + resolution: {integrity: sha512-25L86MyPvnlQoX2MTIV2OiUcb6vJ6aRbFa9pbwByn95INKD5mFH2smgjDhq+fwJoqAgvgbdJLj6Tz7V9X5CFAQ==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} - dependencies: - cross-spawn: 7.0.3 - fast-glob: 3.3.0 - is-glob: 4.0.3 - open: 9.1.0 - picocolors: 1.0.0 - tslib: 2.6.0 dev: true - /@remix-run/router@1.7.1: - resolution: {integrity: sha512-bgVQM4ZJ2u2CM8k1ey70o1ePFXsEzYVZoWghh6WjM8p59jQ7HxzbHW4SbnWFG7V9ig9chLawQxDTZ3xzOF8MkQ==} - engines: {node: '>=14'} + /@remix-run/router@1.15.3: + resolution: {integrity: sha512-Oy8rmScVrVxWZVOpEF57ovlnhpZ8CCPlnIIumVcV9nFdiSIrus99+Lw78ekXyGvVDlIsFJbSfmSovJUhCWYV3w==} + engines: {node: '>=14.0.0'} + dev: false - /@rollup/pluginutils@5.0.2: - resolution: {integrity: sha512-pTd9rIsP92h+B6wWwFbW8RkZv4hiR/xKsqre4SIuAOaOEQRxi0lqLke9k2/7WegC85GgUs9pjmOjCUi3In4vwA==} + /@rollup/pluginutils@5.1.4: + resolution: {integrity: sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ==} engines: {node: '>=14.0.0'} peerDependencies: - rollup: ^1.20.0||^2.0.0||^3.0.0 + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 peerDependenciesMeta: rollup: optional: true dependencies: - '@types/estree': 1.0.1 + '@types/estree': 1.0.6 estree-walker: 2.0.2 - picomatch: 2.3.1 - dev: true - - /@rushstack/node-core-library@3.59.5: - resolution: {integrity: sha512-1IpV7LufrI1EoVO8hYsb3t6L8L+yp40Sa0OaOV2CIu1zx4e6ZeVNaVIEXFgMXBKdGXkAh21MnCaIzlDNpG6ZQw==} - peerDependencies: - '@types/node': '*' - peerDependenciesMeta: - '@types/node': - optional: true - dependencies: - colors: 1.2.5 - fs-extra: 7.0.1 - import-lazy: 4.0.0 - jju: 1.4.0 - resolve: 1.22.2 - semver: 7.3.8 - z-schema: 5.0.5 + picomatch: 4.0.2 dev: true - /@rushstack/rig-package@0.4.0: - resolution: {integrity: sha512-FnM1TQLJYwSiurP6aYSnansprK5l8WUK8VG38CmAaZs29ZeL1msjK0AP1VS4ejD33G0kE/2cpsPsS9jDenBMxw==} - dependencies: - resolve: 1.22.2 - strip-json-comments: 3.1.1 + /@rollup/rollup-android-arm-eabi@4.30.1: + resolution: {integrity: sha512-pSWY+EVt3rJ9fQ3IqlrEUtXh3cGqGtPDH1FQlNZehO2yYxCHEX1SPsz1M//NXwYfbTlcKr9WObLnJX9FsS9K1Q==} + cpu: [arm] + os: [android] + requiresBuild: true dev: true + optional: true - /@rushstack/ts-command-line@4.15.1: - resolution: {integrity: sha512-EL4jxZe5fhb1uVL/P/wQO+Z8Rc8FMiWJ1G7VgnPDvdIt5GVjRfK7vwzder1CZQiX3x0PY6uxENYLNGTFd1InRQ==} - dependencies: - '@types/argparse': 1.0.38 - argparse: 1.0.10 - colors: 1.2.5 - string-argv: 0.3.2 + /@rollup/rollup-android-arm-eabi@4.40.1: + resolution: {integrity: sha512-kxz0YeeCrRUHz3zyqvd7n+TVRlNyTifBsmnmNPtk3hQURUyG9eAB+usz6DAwagMusjx/zb3AjvDUvhFGDAexGw==} + cpu: [arm] + os: [android] + requiresBuild: true dev: true + optional: true - /@sinclair/typebox@0.27.8: - resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} + /@rollup/rollup-android-arm-eabi@4.9.6: + resolution: {integrity: sha512-MVNXSSYN6QXOulbHpLMKYi60ppyO13W9my1qogeiAqtjb2yR4LSmfU2+POvDkLzhjYLXz9Rf9+9a3zFHW1Lecg==} + cpu: [arm] + os: [android] + requiresBuild: true dev: true + optional: true - /@swc/helpers@0.5.1: - resolution: {integrity: sha512-sJ902EfIzn1Fa+qYmjdQqh8tPsoxyBz+8yBKC2HKUxyezKJFwPGOn7pv4WY6QuQW//ySQi5lJjA/ZT9sNWWNTg==} + /@rollup/rollup-android-arm64@4.30.1: + resolution: {integrity: sha512-/NA2qXxE3D/BRjOJM8wQblmArQq1YoBVJjrjoTSBS09jgUisq7bqxNHJ8kjCHeV21W/9WDGwJEWSN0KQ2mtD/w==} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-android-arm64@4.40.1: + resolution: {integrity: sha512-PPkxTOisoNC6TpnDKatjKkjRMsdaWIhyuMkA4UsBXT9WEZY4uHezBTjs6Vl4PbqQQeu6oION1w2voYZv9yquCw==} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-android-arm64@4.9.6: + resolution: {integrity: sha512-T14aNLpqJ5wzKNf5jEDpv5zgyIqcpn1MlwCrUXLrwoADr2RkWA0vOWP4XxbO9aiO3dvMCQICZdKeDrFl7UMClw==} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-darwin-arm64@4.30.1: + resolution: {integrity: sha512-r7FQIXD7gB0WJ5mokTUgUWPl0eYIH0wnxqeSAhuIwvnnpjdVB8cRRClyKLQr7lgzjctkbp5KmswWszlwYln03Q==} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-darwin-arm64@4.40.1: + resolution: {integrity: sha512-VWXGISWFY18v/0JyNUy4A46KCFCb9NVsH+1100XP31lud+TzlezBbz24CYzbnA4x6w4hx+NYCXDfnvDVO6lcAA==} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-darwin-arm64@4.9.6: + resolution: {integrity: sha512-CqNNAyhRkTbo8VVZ5R85X73H3R5NX9ONnKbXuHisGWC0qRbTTxnF1U4V9NafzJbgGM0sHZpdO83pLPzq8uOZFw==} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-darwin-x64@4.30.1: + resolution: {integrity: sha512-x78BavIwSH6sqfP2xeI1hd1GpHL8J4W2BXcVM/5KYKoAD3nNsfitQhvWSw+TFtQTLZ9OmlF+FEInEHyubut2OA==} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-darwin-x64@4.40.1: + resolution: {integrity: sha512-nIwkXafAI1/QCS7pxSpv/ZtFW6TXcNUEHAIA9EIyw5OzxJZQ1YDrX+CL6JAIQgZ33CInl1R6mHet9Y/UZTg2Bw==} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-darwin-x64@4.9.6: + resolution: {integrity: sha512-zRDtdJuRvA1dc9Mp6BWYqAsU5oeLixdfUvkTHuiYOHwqYuQ4YgSmi6+/lPvSsqc/I0Omw3DdICx4Tfacdzmhog==} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-freebsd-arm64@4.30.1: + resolution: {integrity: sha512-HYTlUAjbO1z8ywxsDFWADfTRfTIIy/oUlfIDmlHYmjUP2QRDTzBuWXc9O4CXM+bo9qfiCclmHk1x4ogBjOUpUQ==} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-freebsd-arm64@4.40.1: + resolution: {integrity: sha512-BdrLJ2mHTrIYdaS2I99mriyJfGGenSaP+UwGi1kB9BLOCu9SR8ZpbkmmalKIALnRw24kM7qCN0IOm6L0S44iWw==} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-freebsd-x64@4.30.1: + resolution: {integrity: sha512-1MEdGqogQLccphhX5myCJqeGNYTNcmTyaic9S7CG3JhwuIByJ7J05vGbZxsizQthP1xpVx7kd3o31eOogfEirw==} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-freebsd-x64@4.40.1: + resolution: {integrity: sha512-VXeo/puqvCG8JBPNZXZf5Dqq7BzElNJzHRRw3vjBE27WujdzuOPecDPc/+1DcdcTptNBep3861jNq0mYkT8Z6Q==} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-arm-gnueabihf@4.30.1: + resolution: {integrity: sha512-PaMRNBSqCx7K3Wc9QZkFx5+CX27WFpAMxJNiYGAXfmMIKC7jstlr32UhTgK6T07OtqR+wYlWm9IxzennjnvdJg==} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-arm-gnueabihf@4.40.1: + resolution: {integrity: sha512-ehSKrewwsESPt1TgSE/na9nIhWCosfGSFqv7vwEtjyAqZcvbGIg4JAcV7ZEh2tfj/IlfBeZjgOXm35iOOjadcg==} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-arm-gnueabihf@4.9.6: + resolution: {integrity: sha512-oNk8YXDDnNyG4qlNb6is1ojTOGL/tRhbbKeE/YuccItzerEZT68Z9gHrY3ROh7axDc974+zYAPxK5SH0j/G+QQ==} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-arm-musleabihf@4.30.1: + resolution: {integrity: sha512-B8Rcyj9AV7ZlEFqvB5BubG5iO6ANDsRKlhIxySXcF1axXYUyqwBok+XZPgIYGBgs7LDXfWfifxhw0Ik57T0Yug==} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-arm-musleabihf@4.40.1: + resolution: {integrity: sha512-m39iO/aaurh5FVIu/F4/Zsl8xppd76S4qoID8E+dSRQvTyZTOI2gVk3T4oqzfq1PtcvOfAVlwLMK3KRQMaR8lg==} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-arm64-gnu@4.30.1: + resolution: {integrity: sha512-hqVyueGxAj3cBKrAI4aFHLV+h0Lv5VgWZs9CUGqr1z0fZtlADVV1YPOij6AhcK5An33EXaxnDLmJdQikcn5NEw==} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-arm64-gnu@4.40.1: + resolution: {integrity: sha512-Y+GHnGaku4aVLSgrT0uWe2o2Rq8te9hi+MwqGF9r9ORgXhmHK5Q71N757u0F8yU1OIwUIFy6YiJtKjtyktk5hg==} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-arm64-gnu@4.9.6: + resolution: {integrity: sha512-Z3O60yxPtuCYobrtzjo0wlmvDdx2qZfeAWTyfOjEDqd08kthDKexLpV97KfAeUXPosENKd8uyJMRDfFMxcYkDQ==} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-arm64-musl@4.30.1: + resolution: {integrity: sha512-i4Ab2vnvS1AE1PyOIGp2kXni69gU2DAUVt6FSXeIqUCPIR3ZlheMW3oP2JkukDfu3PsexYRbOiJrY+yVNSk9oA==} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-arm64-musl@4.40.1: + resolution: {integrity: sha512-jEwjn3jCA+tQGswK3aEWcD09/7M5wGwc6+flhva7dsQNRZZTe30vkalgIzV4tjkopsTS9Jd7Y1Bsj6a4lzz8gQ==} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-arm64-musl@4.9.6: + resolution: {integrity: sha512-gpiG0qQJNdYEVad+1iAsGAbgAnZ8j07FapmnIAQgODKcOTjLEWM9sRb+MbQyVsYCnA0Im6M6QIq6ax7liws6eQ==} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-loongarch64-gnu@4.30.1: + resolution: {integrity: sha512-fARcF5g296snX0oLGkVxPmysetwUk2zmHcca+e9ObOovBR++9ZPOhqFUM61UUZ2EYpXVPN1redgqVoBB34nTpQ==} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-loongarch64-gnu@4.40.1: + resolution: {integrity: sha512-ySyWikVhNzv+BV/IDCsrraOAZ3UaC8SZB67FZlqVwXwnFhPihOso9rPOxzZbjp81suB1O2Topw+6Ug3JNegejQ==} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-powerpc64le-gnu@4.30.1: + resolution: {integrity: sha512-GLrZraoO3wVT4uFXh67ElpwQY0DIygxdv0BNW9Hkm3X34wu+BkqrDrkcsIapAY+N2ATEbvak0XQ9gxZtCIA5Rw==} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-powerpc64le-gnu@4.40.1: + resolution: {integrity: sha512-BvvA64QxZlh7WZWqDPPdt0GH4bznuL6uOO1pmgPnnv86rpUpc8ZxgZwcEgXvo02GRIZX1hQ0j0pAnhwkhwPqWg==} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-riscv64-gnu@4.30.1: + resolution: {integrity: sha512-0WKLaAUUHKBtll0wvOmh6yh3S0wSU9+yas923JIChfxOaaBarmb/lBKPF0w/+jTVozFnOXJeRGZ8NvOxvk/jcw==} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-riscv64-gnu@4.40.1: + resolution: {integrity: sha512-EQSP+8+1VuSulm9RKSMKitTav89fKbHymTf25n5+Yr6gAPZxYWpj3DzAsQqoaHAk9YX2lwEyAf9S4W8F4l3VBQ==} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-riscv64-gnu@4.9.6: + resolution: {integrity: sha512-+uCOcvVmFUYvVDr27aiyun9WgZk0tXe7ThuzoUTAukZJOwS5MrGbmSlNOhx1j80GdpqbOty05XqSl5w4dQvcOA==} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-riscv64-musl@4.40.1: + resolution: {integrity: sha512-n/vQ4xRZXKuIpqukkMXZt9RWdl+2zgGNx7Uda8NtmLJ06NL8jiHxUawbwC+hdSq1rrw/9CghCpEONor+l1e2gA==} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-s390x-gnu@4.30.1: + resolution: {integrity: sha512-GWFs97Ruxo5Bt+cvVTQkOJ6TIx0xJDD/bMAOXWJg8TCSTEK8RnFeOeiFTxKniTc4vMIaWvCplMAFBt9miGxgkA==} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-s390x-gnu@4.40.1: + resolution: {integrity: sha512-h8d28xzYb98fMQKUz0w2fMc1XuGzLLjdyxVIbhbil4ELfk5/orZlSTpF/xdI9C8K0I8lCkq+1En2RJsawZekkg==} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-x64-gnu@4.30.1: + resolution: {integrity: sha512-UtgGb7QGgXDIO+tqqJ5oZRGHsDLO8SlpE4MhqpY9Llpzi5rJMvrK6ZGhsRCST2abZdBqIBeXW6WPD5fGK5SDwg==} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-x64-gnu@4.40.1: + resolution: {integrity: sha512-XiK5z70PEFEFqcNj3/zRSz/qX4bp4QIraTy9QjwJAb/Z8GM7kVUsD0Uk8maIPeTyPCP03ChdI+VVmJriKYbRHQ==} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-x64-gnu@4.9.6: + resolution: {integrity: sha512-HUNqM32dGzfBKuaDUBqFB7tP6VMN74eLZ33Q9Y1TBqRDn+qDonkAUyKWwF9BR9unV7QUzffLnz9GrnKvMqC/fw==} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-x64-musl@4.30.1: + resolution: {integrity: sha512-V9U8Ey2UqmQsBT+xTOeMzPzwDzyXmnAoO4edZhL7INkwQcaW1Ckv3WJX3qrrp/VHaDkEWIBWhRwP47r8cdrOow==} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-x64-musl@4.40.1: + resolution: {integrity: sha512-2BRORitq5rQ4Da9blVovzNCMaUlyKrzMSvkVR0D4qPuOy/+pMCrh1d7o01RATwVy+6Fa1WBw+da7QPeLWU/1mQ==} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-x64-musl@4.9.6: + resolution: {integrity: sha512-ch7M+9Tr5R4FK40FHQk8VnML0Szi2KRujUgHXd/HjuH9ifH72GUmw6lStZBo3c3GB82vHa0ZoUfjfcM7JiiMrQ==} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-win32-arm64-msvc@4.30.1: + resolution: {integrity: sha512-WabtHWiPaFF47W3PkHnjbmWawnX/aE57K47ZDT1BXTS5GgrBUEpvOzq0FI0V/UYzQJgdb8XlhVNH8/fwV8xDjw==} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-win32-arm64-msvc@4.40.1: + resolution: {integrity: sha512-b2bcNm9Kbde03H+q+Jjw9tSfhYkzrDUf2d5MAd1bOJuVplXvFhWz7tRtWvD8/ORZi7qSCy0idW6tf2HgxSXQSg==} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-win32-arm64-msvc@4.9.6: + resolution: {integrity: sha512-VD6qnR99dhmTQ1mJhIzXsRcTBvTjbfbGGwKAHcu+52cVl15AC/kplkhxzW/uT0Xl62Y/meBKDZvoJSJN+vTeGA==} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-win32-ia32-msvc@4.30.1: + resolution: {integrity: sha512-pxHAU+Zv39hLUTdQQHUVHf4P+0C47y/ZloorHpzs2SXMRqeAWmGghzAhfOlzFHHwjvgokdFAhC4V+6kC1lRRfw==} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-win32-ia32-msvc@4.40.1: + resolution: {integrity: sha512-DfcogW8N7Zg7llVEfpqWMZcaErKfsj9VvmfSyRjCyo4BI3wPEfrzTtJkZG6gKP/Z92wFm6rz2aDO7/JfiR/whA==} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-win32-ia32-msvc@4.9.6: + resolution: {integrity: sha512-J9AFDq/xiRI58eR2NIDfyVmTYGyIZmRcvcAoJ48oDld/NTR8wyiPUu2X/v1navJ+N/FGg68LEbX3Ejd6l8B7MQ==} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-win32-x64-msvc@4.30.1: + resolution: {integrity: sha512-D6qjsXGcvhTjv0kI4fU8tUuBDF/Ueee4SVX79VfNDXZa64TfCW1Slkb6Z7O1p7vflqZjcmOVdZlqf8gvJxc6og==} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-win32-x64-msvc@4.40.1: + resolution: {integrity: sha512-ECyOuDeH3C1I8jH2MK1RtBJW+YPMvSfT0a5NN0nHfQYnDSJ6tUiZH3gzwVP5/Kfh/+Tt7tpWVF9LXNTnhTJ3kA==} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-win32-x64-msvc@4.9.6: + resolution: {integrity: sha512-jqzNLhNDvIZOrt69Ce4UjGRpXJBzhUBzawMwnaDAwyHriki3XollsewxWzOzz+4yOFDkuJHtTsZFwMxhYJWmLQ==} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@rtsao/scc@1.1.0: + resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} + dev: true + + /@rushstack/node-core-library@5.10.2: + resolution: {integrity: sha512-xOF/2gVJZTfjTxbo4BDj9RtQq/HFnrrKdtem4JkyRLnwsRz2UDTg8gA1/et10fBx5RxmZD9bYVGST69W8ME5OQ==} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true + dependencies: + ajv: 8.13.0 + ajv-draft-04: 1.0.0(ajv@8.13.0) + ajv-formats: 3.0.1(ajv@8.13.0) + fs-extra: 7.0.1 + import-lazy: 4.0.0 + jju: 1.4.0 + resolve: 1.22.8 + semver: 7.5.4 + dev: true + + /@rushstack/node-core-library@5.12.0(@types/node@20.11.26): + resolution: {integrity: sha512-QSwwzgzWoil1SCQse+yCHwlhRxNv2dX9siPnAb9zR/UmMhac4mjMrlMZpk64BlCeOFi1kJKgXRkihSwRMbboAQ==} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true + dependencies: + '@types/node': 20.11.26 + ajv: 8.13.0 + ajv-draft-04: 1.0.0(ajv@8.13.0) + ajv-formats: 3.0.1(ajv@8.13.0) + fs-extra: 11.3.0 + import-lazy: 4.0.0 + jju: 1.4.0 + resolve: 1.22.8 + semver: 7.5.4 + dev: true + + /@rushstack/rig-package@0.5.3: + resolution: {integrity: sha512-olzSSjYrvCNxUFZowevC3uz8gvKr3WTpHQ7BkpjtRpA3wK+T0ybep/SRUMfr195gBzJm5gaXw0ZMgjIyHqJUow==} + dependencies: + resolve: 1.22.8 + strip-json-comments: 3.1.1 + dev: true + + /@rushstack/terminal@0.14.5: + resolution: {integrity: sha512-TEOpNwwmsZVrkp0omnuTUTGZRJKTr6n6m4OITiNjkqzLAkcazVpwR1SOtBg6uzpkIBLgrcNHETqI8rbw3uiUfw==} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true + dependencies: + '@rushstack/node-core-library': 5.10.2 + supports-color: 8.1.1 + dev: true + + /@rushstack/terminal@0.15.1(@types/node@20.11.26): + resolution: {integrity: sha512-3vgJYwumcjoDOXU3IxZfd616lqOdmr8Ezj4OWgJZfhmiBK4Nh7eWcv8sU8N/HdzXcuHDXCRGn/6O2Q75QvaZMA==} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true + dependencies: + '@rushstack/node-core-library': 5.12.0(@types/node@20.11.26) + '@types/node': 20.11.26 + supports-color: 8.1.1 + dev: true + + /@rushstack/ts-command-line@4.23.3: + resolution: {integrity: sha512-HazKL8fv4HMQMzrKJCrOrhyBPPdzk7iajUXgsASwjQ8ROo1cmgyqxt/k9+SdmrNLGE1zATgRqMUH3s/6smbRMA==} + dependencies: + '@rushstack/terminal': 0.14.5 + '@types/argparse': 1.0.38 + argparse: 1.0.10 + string-argv: 0.3.2 + transitivePeerDependencies: + - '@types/node' + dev: true + + /@rushstack/ts-command-line@4.23.6(@types/node@20.11.26): + resolution: {integrity: sha512-7WepygaF3YPEoToh4MAL/mmHkiIImQq3/uAkQX46kVoKTNOOlCtFGyNnze6OYuWw2o9rxsyrHVfIBKxq/am2RA==} + dependencies: + '@rushstack/terminal': 0.15.1(@types/node@20.11.26) + '@types/argparse': 1.0.38 + argparse: 1.0.10 + string-argv: 0.3.2 + transitivePeerDependencies: + - '@types/node' + dev: true + + /@sindresorhus/merge-streams@2.3.0: + resolution: {integrity: sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==} + engines: {node: '>=18'} + dev: true + + /@swc/helpers@0.5.2: + resolution: {integrity: sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw==} dependencies: - tslib: 2.6.0 + tslib: 2.8.1 dev: false - /@testing-library/dom@8.20.1: - resolution: {integrity: sha512-/DiOQ5xBxgdYRC8LNk7U+RWat0S3qRLeIw3ZIkMQ9kkVlRmwD/Eg8k8CqIpD6GW7u20JIUOfMKbxtiLutpjQ4g==} - engines: {node: '>=12'} + /@testing-library/dom@10.1.0: + resolution: {integrity: sha512-wdsYKy5zupPyLCW2Je5DLHSxSfbIp6h80WoHOQc+RPtmPGA52O9x5MJEkv92Sjonpq+poOAtUKhh1kBGAXBrNA==} + engines: {node: '>=18'} dependencies: - '@babel/code-frame': 7.22.5 - '@babel/runtime': 7.22.6 - '@types/aria-query': 5.0.1 - aria-query: 5.1.3 + '@babel/code-frame': 7.24.7 + '@babel/runtime': 7.24.8 + '@types/aria-query': 5.0.4 + aria-query: 5.3.0 chalk: 4.1.2 dom-accessibility-api: 0.5.16 lz-string: 1.5.0 pretty-format: 27.5.1 dev: true - /@testing-library/dom@9.3.1: - resolution: {integrity: sha512-0DGPd9AR3+iDTjGoMpxIkAsUihHZ3Ai6CneU6bRRrffXMgzCdlNk43jTrD2/5LT6CBb3MWTP8v510JzYtahD2w==} - engines: {node: '>=14'} + /@testing-library/dom@10.4.0: + resolution: {integrity: sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==} + engines: {node: '>=18'} dependencies: - '@babel/code-frame': 7.22.5 - '@babel/runtime': 7.22.6 - '@types/aria-query': 5.0.1 - aria-query: 5.1.3 + '@babel/code-frame': 7.24.7 + '@babel/runtime': 7.24.8 + '@types/aria-query': 5.0.4 + aria-query: 5.3.0 chalk: 4.1.2 dom-accessibility-api: 0.5.16 lz-string: 1.5.0 pretty-format: 27.5.1 + dev: true - /@testing-library/jest-dom@5.16.5: - resolution: {integrity: sha512-N5ixQ2qKpi5OLYfwQmUb/5mSV9LneAcaUfp32pn4yCnpb8r/Yz0pXFPck21dIicKmi+ta5WRAknkZCfA8refMA==} - engines: {node: '>=8', npm: '>=6', yarn: '>=1'} + /@testing-library/jest-dom@6.6.3: + resolution: {integrity: sha512-IteBhl4XqYNkM54f4ejhLRJiZNqcSCoXUOG2CPK7qbD322KjQozM4kHQOfkG2oln9b9HTYqs+Sae8vBATubxxA==} + engines: {node: '>=14', npm: '>=6', yarn: '>=1'} dependencies: - '@adobe/css-tools': 4.2.0 - '@babel/runtime': 7.22.6 - '@types/testing-library__jest-dom': 5.14.8 + '@adobe/css-tools': 4.4.0 aria-query: 5.3.0 chalk: 3.0.0 css.escape: 1.5.1 - dom-accessibility-api: 0.5.16 + dom-accessibility-api: 0.6.3 lodash: 4.17.21 redent: 3.0.0 + dev: true - /@testing-library/react@13.3.0(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-DB79aA426+deFgGSjnf5grczDPiL4taK3hFaa+M5q7q20Kcve9eQottOG5kZ74KEr55v0tU2CQormSSDK87zYQ==} - engines: {node: '>=12'} + /@testing-library/react@15.0.7(@types/react@19.0.5)(react-dom@19.0.0)(react@19.0.0): + resolution: {integrity: sha512-cg0RvEdD1TIhhkm1IeYMQxrzy0MtUNfa3minv4MjbgcYzJAZ7yD0i0lwoPOTPr+INtiXFezt2o8xMSnyHhEn2Q==} + engines: {node: '>=18'} peerDependencies: + '@types/react': ^18.0.0 react: ^18.0.0 react-dom: ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true dependencies: - '@babel/runtime': 7.22.6 - '@testing-library/dom': 8.20.1 + '@babel/runtime': 7.23.9 + '@testing-library/dom': 10.1.0 + '@types/react': 19.0.5 '@types/react-dom': 18.2.7 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) dev: true - /@testing-library/user-event@13.5.0(@testing-library/dom@9.3.1): - resolution: {integrity: sha512-5Kwtbo3Y/NowpkbRuSepbyMFkZmHgD+vPzYB/RJ4oxt5Gj/avFFBYjhw27cqSVPVw/3a67NK1PbiIr9k4Gwmdg==} - engines: {node: '>=10', npm: '>=6'} + /@testing-library/react@16.3.0(@testing-library/dom@10.4.0)(@types/react@19.1.2)(react-dom@19.1.0)(react@19.1.0): + resolution: {integrity: sha512-kFSyxiEDwv1WLl2fgsq6pPBbw5aWKrsY2/noi1Id0TK0UParSF62oFQFGHXIyaG4pp2tEub/Zlel+fjjZILDsw==} + engines: {node: '>=18'} peerDependencies: - '@testing-library/dom': '>=7.21.4' + '@testing-library/dom': ^10.0.0 + '@types/react': ^18.0.0 || ^19.0.0 + '@types/react-dom': ^18.0.0 || ^19.0.0 + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true dependencies: - '@babel/runtime': 7.22.6 - '@testing-library/dom': 9.3.1 - dev: false + '@babel/runtime': 7.24.8 + '@testing-library/dom': 10.4.0 + '@types/react': 19.1.2 + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + dev: true - /@testing-library/user-event@14.4.3(@testing-library/dom@9.3.1): - resolution: {integrity: sha512-kCUc5MEwaEMakkO5x7aoD+DLi02ehmEM2QCGWvNqAS1dV/fAvORWEjnjsEIvml59M7Y5kCkWN6fCCyPOe8OL6Q==} + /@testing-library/user-event@14.5.2(@testing-library/dom@10.4.0): + resolution: {integrity: sha512-YAh82Wh4TIrxYLmfGcixwD18oIjyC1pFQC2Y01F2lzV2HTMiYrI0nze0FD0ocB//CKS/7jIUgae+adPqxK5yCQ==} engines: {node: '>=12', npm: '>=6'} peerDependencies: '@testing-library/dom': '>=7.21.4' dependencies: - '@testing-library/dom': 9.3.1 - dev: true - - /@tootallnate/once@2.0.0: - resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==} - engines: {node: '>= 10'} - dev: true - - /@types/argparse@1.0.38: - resolution: {integrity: sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==} + '@testing-library/dom': 10.4.0 dev: true - /@types/aria-query@5.0.1: - resolution: {integrity: sha512-XTIieEY+gvJ39ChLcB4If5zHtPxt3Syj5rgZR+e1ctpmK8NjPf0zFqsz4JpLJT0xla9GFDKjy8Cpu331nrmE1Q==} - - /@types/chai-subset@1.3.3: - resolution: {integrity: sha512-frBecisrNGz+F4T6bcc+NLeolfiojh5FxW2klu669+8BARtyQv2C/GkNW6FUodVe4BroGMP/wER/YDGc7rEllw==} + /@testing-library/user-event@14.6.1(@testing-library/dom@10.4.0): + resolution: {integrity: sha512-vq7fv0rnt+QTXgPxr5Hjc210p6YKq2kmdziLgnsZGgLJ9e6VAShx1pACLuRjd/AS/sr7phAR58OIIpf0LlmQNw==} + engines: {node: '>=12', npm: '>=6'} + peerDependencies: + '@testing-library/dom': '>=7.21.4' dependencies: - '@types/chai': 4.3.5 + '@testing-library/dom': 10.4.0 dev: true - /@types/chai@4.3.5: - resolution: {integrity: sha512-mEo1sAde+UCE6b2hxn332f1g1E8WfYRu6p5SvTKr2ZKC1f7gFJXk4h5PyGP9Dt6gCaG8y8XhwnXWC6Iy2cmBng==} + /@types/argparse@1.0.38: + resolution: {integrity: sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==} dev: true - /@types/cookie@0.4.1: - resolution: {integrity: sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==} + /@types/aria-query@5.0.4: + resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==} dev: true - /@types/debug@4.1.8: - resolution: {integrity: sha512-/vPO1EPOs306Cvhwv7KfVfYvOJqA/S/AXjaHQiJboCZzcNDb+TIJFN9/2C9DZ//ijSKWioNyUxD792QmDJ+HKQ==} + /@types/babel__core@7.20.5: + resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} dependencies: - '@types/ms': 0.7.31 + '@babel/parser': 7.26.5 + '@babel/types': 7.26.5 + '@types/babel__generator': 7.6.8 + '@types/babel__template': 7.4.4 + '@types/babel__traverse': 7.20.5 dev: true - /@types/estree@1.0.1: - resolution: {integrity: sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==} + /@types/babel__generator@7.6.8: + resolution: {integrity: sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==} + dependencies: + '@babel/types': 7.26.5 dev: true - /@types/istanbul-lib-coverage@2.0.4: - resolution: {integrity: sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==} + /@types/babel__template@7.4.4: + resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} + dependencies: + '@babel/parser': 7.26.5 + '@babel/types': 7.26.5 dev: true - /@types/jest@27.5.2: - resolution: {integrity: sha512-mpT8LJJ4CMeeahobofYWIjFo0xonRS/HfxnVEPMPFSQdGUt1uHCnoPT7Zhb+sjDU2wz0oKV0OLUR0WzrHNgfeA==} + /@types/babel__traverse@7.20.5: + resolution: {integrity: sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ==} dependencies: - jest-matcher-utils: 27.5.1 - pretty-format: 27.5.1 - - /@types/js-levenshtein@1.1.1: - resolution: {integrity: sha512-qC4bCqYGy1y/NP7dDVr7KJarn+PbX1nSpwA7JXdu0HxT3QYjO8MJ+cntENtHFVy2dRAyBV23OZ6MxsW1AM1L8g==} + '@babel/types': 7.26.5 dev: true - /@types/json-schema@7.0.12: - resolution: {integrity: sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==} + /@types/cookie@0.6.0: + resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==} dev: true - /@types/json5@0.0.29: - resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} + /@types/estree@1.0.5: + resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} dev: true - /@types/minimist@1.2.2: - resolution: {integrity: sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==} + /@types/estree@1.0.6: + resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} dev: true - /@types/ms@0.7.31: - resolution: {integrity: sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==} + /@types/estree@1.0.7: + resolution: {integrity: sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==} dev: true - /@types/node@18.11.9: - resolution: {integrity: sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==} + /@types/json-schema@7.0.15: + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} dev: true - /@types/normalize-package-data@2.4.1: - resolution: {integrity: sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==} + /@types/json5@0.0.29: + resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} dev: true - /@types/prop-types@15.7.5: - resolution: {integrity: sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==} + /@types/node@20.11.26: + resolution: {integrity: sha512-YwOMmyhNnAWijOBQweOJnQPl068Oqd4K3OFbTc6AHJwzweUwwWG3GIFY74OKks2PJUDkQPeddOQES9mLn1CTEQ==} + dependencies: + undici-types: 5.26.5 dev: true /@types/react-dom@18.2.7: resolution: {integrity: sha512-GRaAEriuT4zp9N4p1i8BDBYmEyfo+xQ3yHjJU4eiK5NDa1RmUZG+unZABUTK4/Ox/M+GaHwb6Ow8rUITrtjszA==} dependencies: - '@types/react': 18.2.15 + '@types/react': 19.1.2 dev: true - /@types/react@18.2.15: - resolution: {integrity: sha512-oEjE7TQt1fFTFSbf8kkNuc798ahTUzn3Le67/PWjE8MAfYAD/qB7O8hSTcromLFqHCt9bcdOg5GXMokzTjJ5SA==} + /@types/react@19.0.5: + resolution: {integrity: sha512-i4OQzFiqsUCfoBns/KHpz+4QcvfjoCsTUi+mugo3lrSRA3+x0gJVvhZhAJrwLGEqz4EXiFVP4hPnOugx+m2uhg==} dependencies: - '@types/prop-types': 15.7.5 - '@types/scheduler': 0.16.3 csstype: 3.1.2 dev: true - /@types/scheduler@0.16.3: - resolution: {integrity: sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==} + /@types/react@19.1.2: + resolution: {integrity: sha512-oxLPMytKchWGbnQM9O7D67uPa9paTNxO7jVoNMXgkkErULBPhPARCfkKL9ytcIJJRGjbsVwW4ugJzyFFvm/Tiw==} + dependencies: + csstype: 3.1.2 dev: true - /@types/semver@7.5.0: - resolution: {integrity: sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==} + /@types/statuses@2.0.4: + resolution: {integrity: sha512-eqNDvZsCNY49OAXB0Firg/Sc2BgoWsntsLUdybGFOhAfCD6QJ2n9HXUIHGqt5qjrxmMv4wS8WLAw43ZkKcJ8Pw==} dev: true - /@types/set-cookie-parser@2.4.2: - resolution: {integrity: sha512-fBZgytwhYAUkj/jC/FAV4RQ5EerRup1YQsXQCh8rZfiHkc4UahC192oH0smGwsXol3cL3A5oETuAHeQHmhXM4w==} - dependencies: - '@types/node': 18.11.9 + /@types/tough-cookie@4.0.5: + resolution: {integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==} dev: true - /@types/testing-library__jest-dom@5.14.8: - resolution: {integrity: sha512-NRfJE9Cgpmu4fx716q9SYmU4jxxhYRU1BQo239Txt/9N3EC745XZX1Yl7h/SBIDlo1ANVOCRB4YDXjaQdoKCHQ==} - dependencies: - '@types/jest': 27.5.2 - - /@typescript-eslint/eslint-plugin@5.50.0(@typescript-eslint/parser@5.62.0)(eslint@8.45.0)(typescript@5.1.6): - resolution: {integrity: sha512-vwksQWSFZiUhgq3Kv7o1Jcj0DUNylwnIlGvKvLLYsq8pAWha6/WCnXUeaSoNNha/K7QSf2+jvmkxggC1u3pIwQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + /@typescript-eslint/eslint-plugin@8.32.0(@typescript-eslint/parser@8.32.0)(eslint@9.26.0)(typescript@5.8.3): + resolution: {integrity: sha512-/jU9ettcntkBFmWUzzGgsClEi2ZFiikMX5eEQsmxIAWMOn4H3D4rvHssstmAHGVvrYnaMqdWWWg0b5M6IN/MTQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^5.0.0 - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@typescript-eslint/parser': 5.62.0(eslint@8.45.0)(typescript@5.1.6) - '@typescript-eslint/scope-manager': 5.50.0 - '@typescript-eslint/type-utils': 5.50.0(eslint@8.45.0)(typescript@5.1.6) - '@typescript-eslint/utils': 5.50.0(eslint@8.45.0)(typescript@5.1.6) - debug: 4.3.4 - eslint: 8.45.0 - grapheme-splitter: 1.0.4 - ignore: 5.2.4 - natural-compare-lite: 1.4.0 - regexpp: 3.2.0 - semver: 7.5.4 - tsutils: 3.21.0(typescript@5.1.6) - typescript: 5.1.6 + '@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0 + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <5.9.0' + dependencies: + '@eslint-community/regexpp': 4.12.1 + '@typescript-eslint/parser': 8.32.0(eslint@9.26.0)(typescript@5.8.3) + '@typescript-eslint/scope-manager': 8.32.0 + '@typescript-eslint/type-utils': 8.32.0(eslint@9.26.0)(typescript@5.8.3) + '@typescript-eslint/utils': 8.32.0(eslint@9.26.0)(typescript@5.8.3) + '@typescript-eslint/visitor-keys': 8.32.0 + eslint: 9.26.0 + graphemer: 1.4.0 + ignore: 5.3.2 + natural-compare: 1.4.0 + ts-api-utils: 2.1.0(typescript@5.8.3) + typescript: 5.8.3 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/parser@5.62.0(eslint@8.45.0)(typescript@5.1.6): - resolution: {integrity: sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + /@typescript-eslint/parser@8.32.0(eslint@9.26.0)(typescript@5.8.3): + resolution: {integrity: sha512-B2MdzyWxCE2+SqiZHAjPphft+/2x2FlO9YBx7eKE1BCb+rqBlQdhtAEhzIEdozHd55DXPmxBdpMygFJjfjjA9A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@typescript-eslint/scope-manager': 5.62.0 - '@typescript-eslint/types': 5.62.0 - '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.1.6) - debug: 4.3.4 - eslint: 8.45.0 - typescript: 5.1.6 + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <5.9.0' + dependencies: + '@typescript-eslint/scope-manager': 8.32.0 + '@typescript-eslint/types': 8.32.0 + '@typescript-eslint/typescript-estree': 8.32.0(typescript@5.8.3) + '@typescript-eslint/visitor-keys': 8.32.0 + debug: 4.4.0 + eslint: 9.26.0 + typescript: 5.8.3 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/scope-manager@5.50.0: - resolution: {integrity: sha512-rt03kaX+iZrhssaT974BCmoUikYtZI24Vp/kwTSy841XhiYShlqoshRFDvN1FKKvU2S3gK+kcBW1EA7kNUrogg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + /@typescript-eslint/scope-manager@8.19.1: + resolution: {integrity: sha512-60L9KIuN/xgmsINzonOcMDSB8p82h95hoBfSBtXuO4jlR1R9L1xSkmVZKgCPVfavDlXihh4ARNjXhh1gGnLC7Q==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} dependencies: - '@typescript-eslint/types': 5.50.0 - '@typescript-eslint/visitor-keys': 5.50.0 + '@typescript-eslint/types': 8.19.1 + '@typescript-eslint/visitor-keys': 8.19.1 dev: true - /@typescript-eslint/scope-manager@5.62.0: - resolution: {integrity: sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + /@typescript-eslint/scope-manager@8.32.0: + resolution: {integrity: sha512-jc/4IxGNedXkmG4mx4nJTILb6TMjL66D41vyeaPWvDUmeYQzF3lKtN15WsAeTr65ce4mPxwopPSo1yUUAWw0hQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} dependencies: - '@typescript-eslint/types': 5.62.0 - '@typescript-eslint/visitor-keys': 5.62.0 + '@typescript-eslint/types': 8.32.0 + '@typescript-eslint/visitor-keys': 8.32.0 dev: true - /@typescript-eslint/type-utils@5.50.0(eslint@8.45.0)(typescript@5.1.6): - resolution: {integrity: sha512-dcnXfZ6OGrNCO7E5UY/i0ktHb7Yx1fV6fnQGGrlnfDhilcs6n19eIRcvLBqx6OQkrPaFlDPk3OJ0WlzQfrV0bQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + /@typescript-eslint/type-utils@8.32.0(eslint@9.26.0)(typescript@5.8.3): + resolution: {integrity: sha512-t2vouuYQKEKSLtJaa5bB4jHeha2HJczQ6E5IXPDPgIty9EqcJxpr1QHQ86YyIPwDwxvUmLfP2YADQ5ZY4qddZg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: '*' - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@typescript-eslint/typescript-estree': 5.50.0(typescript@5.1.6) - '@typescript-eslint/utils': 5.50.0(eslint@8.45.0)(typescript@5.1.6) - debug: 4.3.4 - eslint: 8.45.0 - tsutils: 3.21.0(typescript@5.1.6) - typescript: 5.1.6 + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <5.9.0' + dependencies: + '@typescript-eslint/typescript-estree': 8.32.0(typescript@5.8.3) + '@typescript-eslint/utils': 8.32.0(eslint@9.26.0)(typescript@5.8.3) + debug: 4.4.0 + eslint: 9.26.0 + ts-api-utils: 2.1.0(typescript@5.8.3) + typescript: 5.8.3 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/types@5.50.0: - resolution: {integrity: sha512-atruOuJpir4OtyNdKahiHZobPKFvZnBnfDiyEaBf6d9vy9visE7gDjlmhl+y29uxZ2ZDgvXijcungGFjGGex7w==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + /@typescript-eslint/types@8.19.1: + resolution: {integrity: sha512-JBVHMLj7B1K1v1051ZaMMgLW4Q/jre5qGK0Ew6UgXz1Rqh+/xPzV1aW581OM00X6iOfyr1be+QyW8LOUf19BbA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} dev: true - /@typescript-eslint/types@5.62.0: - resolution: {integrity: sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + /@typescript-eslint/types@8.32.0: + resolution: {integrity: sha512-O5Id6tGadAZEMThM6L9HmVf5hQUXNSxLVKeGJYWNhhVseps/0LddMkp7//VDkzwJ69lPL0UmZdcZwggj9akJaA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} dev: true - /@typescript-eslint/typescript-estree@5.50.0(typescript@5.1.6): - resolution: {integrity: sha512-Gq4zapso+OtIZlv8YNAStFtT6d05zyVCK7Fx3h5inlLBx2hWuc/0465C2mg/EQDDU2LKe52+/jN4f0g9bd+kow==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + /@typescript-eslint/typescript-estree@8.19.1(typescript@5.8.3): + resolution: {integrity: sha512-jk/TZwSMJlxlNnqhy0Eod1PNEvCkpY6MXOXE/WLlblZ6ibb32i2We4uByoKPv1d0OD2xebDv4hbs3fm11SMw8Q==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + typescript: '>=4.8.4 <5.8.0' dependencies: - '@typescript-eslint/types': 5.50.0 - '@typescript-eslint/visitor-keys': 5.50.0 - debug: 4.3.4 - globby: 11.1.0 + '@typescript-eslint/types': 8.19.1 + '@typescript-eslint/visitor-keys': 8.19.1 + debug: 4.4.0 + fast-glob: 3.3.2 is-glob: 4.0.3 - semver: 7.5.4 - tsutils: 3.21.0(typescript@5.1.6) - typescript: 5.1.6 + minimatch: 9.0.5 + semver: 7.6.3 + ts-api-utils: 2.0.0(typescript@5.8.3) + typescript: 5.8.3 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/typescript-estree@5.62.0(typescript@5.1.6): - resolution: {integrity: sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + /@typescript-eslint/typescript-estree@8.32.0(typescript@5.8.3): + resolution: {integrity: sha512-pU9VD7anSCOIoBFnhTGfOzlVFQIA1XXiQpH/CezqOBaDppRwTglJzCC6fUQGpfwey4T183NKhF1/mfatYmjRqQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + typescript: '>=4.8.4 <5.9.0' dependencies: - '@typescript-eslint/types': 5.62.0 - '@typescript-eslint/visitor-keys': 5.62.0 - debug: 4.3.4 - globby: 11.1.0 + '@typescript-eslint/types': 8.32.0 + '@typescript-eslint/visitor-keys': 8.32.0 + debug: 4.4.0 + fast-glob: 3.3.2 is-glob: 4.0.3 - semver: 7.5.4 - tsutils: 3.21.0(typescript@5.1.6) - typescript: 5.1.6 + minimatch: 9.0.5 + semver: 7.6.3 + ts-api-utils: 2.1.0(typescript@5.8.3) + typescript: 5.8.3 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/utils@5.50.0(eslint@8.45.0)(typescript@5.1.6): - resolution: {integrity: sha512-v/AnUFImmh8G4PH0NDkf6wA8hujNNcrwtecqW4vtQ1UOSNBaZl49zP1SHoZ/06e+UiwzHpgb5zP5+hwlYYWYAw==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + /@typescript-eslint/utils@8.19.1(eslint@9.26.0)(typescript@5.8.3): + resolution: {integrity: sha512-IxG5gLO0Ne+KaUc8iW1A+XuKLd63o4wlbI1Zp692n1xojCl/THvgIKXJXBZixTh5dd5+yTJ/VXH7GJaaw21qXA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - dependencies: - '@types/json-schema': 7.0.12 - '@types/semver': 7.5.0 - '@typescript-eslint/scope-manager': 5.50.0 - '@typescript-eslint/types': 5.50.0 - '@typescript-eslint/typescript-estree': 5.50.0(typescript@5.1.6) - eslint: 8.45.0 - eslint-scope: 5.1.1 - eslint-utils: 3.0.0(eslint@8.45.0) - semver: 7.5.4 + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <5.8.0' + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@9.26.0) + '@typescript-eslint/scope-manager': 8.19.1 + '@typescript-eslint/types': 8.19.1 + '@typescript-eslint/typescript-estree': 8.19.1(typescript@5.8.3) + eslint: 9.26.0 + typescript: 5.8.3 transitivePeerDependencies: - supports-color - - typescript dev: true - /@typescript-eslint/utils@5.62.0(eslint@8.45.0)(typescript@5.1.6): - resolution: {integrity: sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + /@typescript-eslint/utils@8.32.0(eslint@9.26.0)(typescript@5.8.3): + resolution: {integrity: sha512-8S9hXau6nQ/sYVtC3D6ISIDoJzS1NsCK+gluVhLN2YkBPX+/1wkwyUiDKnxRh15579WoOIyVWnoyIf3yGI9REw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.45.0) - '@types/json-schema': 7.0.12 - '@types/semver': 7.5.0 - '@typescript-eslint/scope-manager': 5.62.0 - '@typescript-eslint/types': 5.62.0 - '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.1.6) - eslint: 8.45.0 - eslint-scope: 5.1.1 - semver: 7.5.4 + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <5.9.0' + dependencies: + '@eslint-community/eslint-utils': 4.7.0(eslint@9.26.0) + '@typescript-eslint/scope-manager': 8.32.0 + '@typescript-eslint/types': 8.32.0 + '@typescript-eslint/typescript-estree': 8.32.0(typescript@5.8.3) + eslint: 9.26.0 + typescript: 5.8.3 transitivePeerDependencies: - supports-color - - typescript dev: true - /@typescript-eslint/visitor-keys@5.50.0: - resolution: {integrity: sha512-cdMeD9HGu6EXIeGOh2yVW6oGf9wq8asBgZx7nsR/D36gTfQ0odE5kcRYe5M81vjEFAcPeugXrHg78Imu55F6gg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + /@typescript-eslint/visitor-keys@8.19.1: + resolution: {integrity: sha512-fzmjU8CHK853V/avYZAvuVut3ZTfwN5YtMaoi+X9Y9MA9keaWNHC3zEQ9zvyX/7Hj+5JkNyK1l7TOR2hevHB6Q==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} dependencies: - '@typescript-eslint/types': 5.50.0 - eslint-visitor-keys: 3.4.1 + '@typescript-eslint/types': 8.19.1 + eslint-visitor-keys: 4.2.0 dev: true - /@typescript-eslint/visitor-keys@5.62.0: - resolution: {integrity: sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + /@typescript-eslint/visitor-keys@8.32.0: + resolution: {integrity: sha512-1rYQTCLFFzOI5Nl0c8LUpJT8HxpwVRn9E4CkMsYfuN6ctmQqExjSTzzSk0Tz2apmXy7WU6/6fyaZVVA/thPN+w==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} dependencies: - '@typescript-eslint/types': 5.62.0 - eslint-visitor-keys: 3.4.1 + '@typescript-eslint/types': 8.32.0 + eslint-visitor-keys: 4.2.0 dev: true - /@vitejs/plugin-react@4.0.3(vite@4.4.4): - resolution: {integrity: sha512-pwXDog5nwwvSIzwrvYYmA2Ljcd/ZNlcsSG2Q9CNDBwnsd55UGAyr2doXtB5j+2uymRCnCfExlznzzSFbBRcoCg==} + /@vitejs/plugin-react@4.3.4(vite@6.0.7): + resolution: {integrity: sha512-SCCPBJtYLdE8PX/7ZQAs1QAZ8Jqwih+0VBLum1EGqmCCQal+MIUqLCzj3ZUy8ufbC0cAM4LRlSTm7IQJwWT4ug==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: - vite: ^4.2.0 - dependencies: - '@babel/core': 7.22.9 - '@babel/plugin-transform-react-jsx-self': 7.22.5(@babel/core@7.22.9) - '@babel/plugin-transform-react-jsx-source': 7.22.5(@babel/core@7.22.9) - react-refresh: 0.14.0 - vite: 4.4.4(@types/node@18.11.9) + vite: ^4.2.0 || ^5.0.0 || ^6.0.0 + dependencies: + '@babel/core': 7.26.0 + '@babel/plugin-transform-react-jsx-self': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-react-jsx-source': 7.25.9(@babel/core@7.26.0) + '@types/babel__core': 7.20.5 + react-refresh: 0.14.2 + vite: 6.0.7(tsx@4.19.4) transitivePeerDependencies: - supports-color dev: true - /@vitest/coverage-c8@0.33.0(vitest@0.33.0): - resolution: {integrity: sha512-DaF1zJz4dcOZS4k/neiQJokmOWqsGXwhthfmUdPGorXIQHjdPvV6JQSYhQDI41MyI8c+IieQUdIDs5XAMHtDDw==} + /@vitejs/plugin-react@4.4.1(vite@6.3.5): + resolution: {integrity: sha512-IpEm5ZmeXAP/osiBXVVP5KjFMzbWOonMs0NaQQl+xYnUAcq4oHUBsF2+p4MgKWG4YMmFYJU8A6sxRPuowllm6w==} + engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: - vitest: '>=0.30.0 <1' - dependencies: - '@ampproject/remapping': 2.2.1 - c8: 7.14.0 - magic-string: 0.30.1 - picocolors: 1.0.0 - std-env: 3.3.3 - vitest: 0.33.0(jsdom@22.1.0) + vite: ^4.2.0 || ^5.0.0 || ^6.0.0 + dependencies: + '@babel/core': 7.27.1 + '@babel/plugin-transform-react-jsx-self': 7.25.9(@babel/core@7.27.1) + '@babel/plugin-transform-react-jsx-source': 7.25.9(@babel/core@7.27.1) + '@types/babel__core': 7.20.5 + react-refresh: 0.17.0 + vite: 6.3.5(@types/node@20.11.26)(tsx@4.19.4) + transitivePeerDependencies: + - supports-color dev: true - /@vitest/coverage-v8@0.33.0(vitest@0.33.0): - resolution: {integrity: sha512-Rj5IzoLF7FLj6yR7TmqsfRDSeaFki6NAJ/cQexqhbWkHEV2htlVGrmuOde3xzvFsCbLCagf4omhcIaVmfU8Okg==} + /@vitest/coverage-v8@3.1.3(vitest@3.1.3): + resolution: {integrity: sha512-cj76U5gXCl3g88KSnf80kof6+6w+K4BjOflCl7t6yRJPDuCrHtVu0SgNYOUARJOL5TI8RScDbm5x4s1/P9bvpw==} peerDependencies: - vitest: '>=0.32.0 <1' - dependencies: - '@ampproject/remapping': 2.2.1 - '@bcoe/v8-coverage': 0.2.3 - istanbul-lib-coverage: 3.2.0 - istanbul-lib-report: 3.0.0 - istanbul-lib-source-maps: 4.0.1 - istanbul-reports: 3.1.5 - magic-string: 0.30.1 - picocolors: 1.0.0 - std-env: 3.3.3 - test-exclude: 6.0.0 - v8-to-istanbul: 9.1.0 - vitest: 0.33.0(jsdom@22.1.0) + '@vitest/browser': 3.1.3 + vitest: 3.1.3 + peerDependenciesMeta: + '@vitest/browser': + optional: true + dependencies: + '@ampproject/remapping': 2.3.0 + '@bcoe/v8-coverage': 1.0.2 + debug: 4.4.0 + istanbul-lib-coverage: 3.2.2 + istanbul-lib-report: 3.0.1 + istanbul-lib-source-maps: 5.0.6 + istanbul-reports: 3.1.7 + magic-string: 0.30.17 + magicast: 0.3.5 + std-env: 3.9.0 + test-exclude: 7.0.1 + tinyrainbow: 2.0.0 + vitest: 3.1.3(@types/node@20.11.26)(jsdom@26.1.0)(msw@2.7.6)(tsx@4.19.4) transitivePeerDependencies: - supports-color dev: true - /@vitest/expect@0.33.0: - resolution: {integrity: sha512-sVNf+Gla3mhTCxNJx+wJLDPp/WcstOe0Ksqz4Vec51MmgMth/ia0MGFEkIZmVGeTL5HtjYR4Wl/ZxBxBXZJTzQ==} + /@vitest/expect@2.1.8: + resolution: {integrity: sha512-8ytZ/fFHq2g4PJVAtDX57mayemKgDR6X3Oa2Foro+EygiOJHUXhCqBAAKQYYajZpFoIfvBCF1j6R6IYRSIUFuw==} dependencies: - '@vitest/spy': 0.33.0 - '@vitest/utils': 0.33.0 - chai: 4.3.7 + '@vitest/spy': 2.1.8 + '@vitest/utils': 2.1.8 + chai: 5.2.0 + tinyrainbow: 1.2.0 dev: true - /@vitest/runner@0.33.0: - resolution: {integrity: sha512-UPfACnmCB6HKRHTlcgCoBh6ppl6fDn+J/xR8dTufWiKt/74Y9bHci5CKB8tESSV82zKYtkBJo9whU3mNvfaisg==} + /@vitest/expect@3.1.3: + resolution: {integrity: sha512-7FTQQuuLKmN1Ig/h+h/GO+44Q1IlglPlR2es4ab7Yvfx+Uk5xsv+Ykk+MEt/M2Yn/xGmzaLKxGw2lgy2bwuYqg==} dependencies: - '@vitest/utils': 0.33.0 - p-limit: 4.0.0 - pathe: 1.1.1 + '@vitest/spy': 3.1.3 + '@vitest/utils': 3.1.3 + chai: 5.2.0 + tinyrainbow: 2.0.0 dev: true - /@vitest/snapshot@0.33.0: - resolution: {integrity: sha512-tJjrl//qAHbyHajpFvr8Wsk8DIOODEebTu7pgBrP07iOepR5jYkLFiqLq2Ltxv+r0uptUb4izv1J8XBOwKkVYA==} + /@vitest/mocker@2.1.8(vite@5.1.6): + resolution: {integrity: sha512-7guJ/47I6uqfttp33mgo6ga5Gr1VnL58rcqYKyShoRK9ebu8T5Rs6HN3s1NABiBeVTdWNrwUMcHH54uXZBN4zA==} + peerDependencies: + msw: ^2.4.9 + vite: ^5.0.0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true dependencies: - magic-string: 0.30.1 - pathe: 1.1.1 - pretty-format: 29.6.1 + '@vitest/spy': 2.1.8 + estree-walker: 3.0.3 + magic-string: 0.30.17 + vite: 5.1.6 dev: true - /@vitest/spy@0.33.0: - resolution: {integrity: sha512-Kv+yZ4hnH1WdiAkPUQTpRxW8kGtH8VRTnus7ZTGovFYM1ZezJpvGtb9nPIjPnptHbsyIAxYZsEpVPYgtpjGnrg==} + /@vitest/mocker@3.1.3(msw@2.7.6)(vite@6.3.5): + resolution: {integrity: sha512-PJbLjonJK82uCWHjzgBJZuR7zmAOrSvKk1QBxrennDIgtH4uK0TB1PvYmc0XBCigxxtiAVPfWtAdy4lpz8SQGQ==} + peerDependencies: + msw: ^2.4.9 + vite: ^5.0.0 || ^6.0.0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true dependencies: - tinyspy: 2.1.1 + '@vitest/spy': 3.1.3 + estree-walker: 3.0.3 + magic-string: 0.30.17 + msw: 2.7.6(@types/node@20.11.26)(typescript@5.8.3) + vite: 6.3.5(@types/node@20.11.26)(tsx@4.19.4) dev: true - /@vitest/utils@0.33.0: - resolution: {integrity: sha512-pF1w22ic965sv+EN6uoePkAOTkAPWM03Ri/jXNyMIKBb/XHLDPfhLvf/Fa9g0YECevAIz56oVYXhodLvLQ/awA==} + /@vitest/pretty-format@2.1.8: + resolution: {integrity: sha512-9HiSZ9zpqNLKlbIDRWOnAWqgcA7xu+8YxXSekhr0Ykab7PAYFkhkwoqVArPOtJhPmYeE2YHgKZlj3CP36z2AJQ==} dependencies: - diff-sequences: 29.4.3 - loupe: 2.3.6 - pretty-format: 29.6.1 + tinyrainbow: 1.2.0 dev: true - /@volar/language-core@1.9.0: - resolution: {integrity: sha512-+PTRrGanAD2PxqMty0ZC46xhgW5BWzb67RLHhZyB3Im4+eMXsKlYjFUt7Z8ZCwTWQQOnj8NQ6gSgUEoOTwAHrQ==} + /@vitest/pretty-format@3.1.3: + resolution: {integrity: sha512-i6FDiBeJUGLDKADw2Gb01UtUNb12yyXAqC/mmRWuYl+m/U9GS7s8us5ONmGkGpUUo7/iAYzI2ePVfOZTYvUifA==} dependencies: - '@volar/source-map': 1.9.0 + tinyrainbow: 2.0.0 dev: true - /@volar/source-map@1.9.0: - resolution: {integrity: sha512-TQWLY8ozUOHBHTMC2pHZsNbtM25Q9QCEwAL8JFR/gmR9Yv0d9qup/gQdd5sDI7RmoPYKD+gqjLrbM4Ib41QSJQ==} + /@vitest/runner@2.1.8: + resolution: {integrity: sha512-17ub8vQstRnRlIU5k50bG+QOMLHRhYPAna5tw8tYbj+jzjcspnwnwtPtiOlkuKC4+ixDPTuLZiqiWWQ2PSXHVg==} dependencies: - muggle-string: 0.3.1 + '@vitest/utils': 2.1.8 + pathe: 1.1.2 dev: true - /@volar/typescript@1.9.0: - resolution: {integrity: sha512-B8X4/H6V93uD7zu5VCw05eB0Ukcc39SFKsZoeylkAk2sJ50oaJLpajnQ8Ov4c+FnVQ6iPA6Xy1qdWoWJjh6xEg==} + /@vitest/runner@3.1.3: + resolution: {integrity: sha512-Tae+ogtlNfFei5DggOsSUvkIaSuVywujMj6HzR97AHK6XK8i3BuVyIifWAm/sE3a15lF5RH9yQIrbXYuo0IFyA==} dependencies: - '@volar/language-core': 1.9.0 + '@vitest/utils': 3.1.3 + pathe: 2.0.3 dev: true - /@vue/compiler-core@3.3.4: - resolution: {integrity: sha512-cquyDNvZ6jTbf/+x+AgM2Arrp6G4Dzbb0R64jiG804HRMfRiFXWI6kqUVqZ6ZR0bQhIoQjB4+2bhNtVwndW15g==} + /@vitest/snapshot@2.1.8: + resolution: {integrity: sha512-20T7xRFbmnkfcmgVEz+z3AU/3b0cEzZOt/zmnvZEctg64/QZbSDJEVm9fLnnlSi74KibmRsO9/Qabi+t0vCRPg==} dependencies: - '@babel/parser': 7.22.7 - '@vue/shared': 3.3.4 - estree-walker: 2.0.2 - source-map-js: 1.0.2 + '@vitest/pretty-format': 2.1.8 + magic-string: 0.30.17 + pathe: 1.1.2 dev: true - /@vue/compiler-dom@3.3.4: - resolution: {integrity: sha512-wyM+OjOVpuUukIq6p5+nwHYtj9cFroz9cwkfmP9O1nzH68BenTTv0u7/ndggT8cIQlnBeOo6sUT/gvHcIkLA5w==} + /@vitest/snapshot@3.1.3: + resolution: {integrity: sha512-XVa5OPNTYUsyqG9skuUkFzAeFnEzDp8hQu7kZ0N25B1+6KjGm4hWLtURyBbsIAOekfWQ7Wuz/N/XXzgYO3deWQ==} dependencies: - '@vue/compiler-core': 3.3.4 - '@vue/shared': 3.3.4 + '@vitest/pretty-format': 3.1.3 + magic-string: 0.30.17 + pathe: 2.0.3 dev: true - /@vue/language-core@1.8.5(typescript@5.1.6): - resolution: {integrity: sha512-DKQNiNQzNV7nrkZQujvjfX73zqKdj2+KoM4YeKl+ft3f+crO3JB4ycPnmgaRMNX/ULJootdQPGHKFRl5cXxwaw==} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + /@vitest/spy@2.1.8: + resolution: {integrity: sha512-5swjf2q95gXeYPevtW0BLk6H8+bPlMb4Vw/9Em4hFxDcaOxS+e0LOX4yqNxoHzMR2akEB2xfpnWUzkZokmgWDg==} dependencies: - '@volar/language-core': 1.9.0 - '@volar/source-map': 1.9.0 - '@vue/compiler-dom': 3.3.4 - '@vue/reactivity': 3.3.4 - '@vue/shared': 3.3.4 - minimatch: 9.0.3 - muggle-string: 0.3.1 - typescript: 5.1.6 - vue-template-compiler: 2.7.14 + tinyspy: 3.0.2 dev: true - /@vue/reactivity@3.3.4: - resolution: {integrity: sha512-kLTDLwd0B1jG08NBF3R5rqULtv/f8x3rOFByTDz4J53ttIQEDmALqKqXY0J+XQeN0aV2FBxY8nJDf88yvOPAqQ==} + /@vitest/spy@3.1.3: + resolution: {integrity: sha512-x6w+ctOEmEXdWaa6TO4ilb7l9DxPR5bwEb6hILKuxfU1NqWT2mpJD9NJN7t3OTfxmVlOMrvtoFJGdgyzZ605lQ==} dependencies: - '@vue/shared': 3.3.4 + tinyspy: 3.0.2 dev: true - /@vue/shared@3.3.4: - resolution: {integrity: sha512-7OjdcV8vQ74eiz1TZLzZP4JwqM5fA94K6yntPS5Z25r9HDuGNzaGdgvwKYq6S+MxwF0TFRwe50fIR/MYnakdkQ==} + /@vitest/utils@2.1.8: + resolution: {integrity: sha512-dwSoui6djdwbfFmIgbIjX2ZhIoG7Ex/+xpxyiEgIGzjliY8xGkcpITKTlp6B4MgtGkF2ilvm97cPM96XZaAgcA==} + dependencies: + '@vitest/pretty-format': 2.1.8 + loupe: 3.1.3 + tinyrainbow: 1.2.0 dev: true - /@vue/typescript@1.8.5(typescript@5.1.6): - resolution: {integrity: sha512-domFBbNr3PEcjGBeB+cmgUM3cI6pJsJezguIUKZ1rphkfIkICyoMjCd3TitoP32yo2KABLiaXcGFzgFfQf6B3w==} + /@vitest/utils@3.1.3: + resolution: {integrity: sha512-2Ltrpht4OmHO9+c/nmHtF09HWiyWdworqnHIwjfvDyWjuwKbdkcS9AnhsDn+8E2RM4x++foD1/tNuLPVvWG1Rg==} dependencies: - '@volar/typescript': 1.9.0 - '@vue/language-core': 1.8.5(typescript@5.1.6) - transitivePeerDependencies: - - typescript + '@vitest/pretty-format': 3.1.3 + loupe: 3.1.3 + tinyrainbow: 2.0.0 dev: true - /@xmldom/xmldom@0.8.9: - resolution: {integrity: sha512-4VSbbcMoxc4KLjb1gs96SRmi7w4h1SF+fCoiK0XaQX62buCc1G5d0DC5bJ9xJBNPDSVCmIrcl8BiYxzjrqaaJA==} - engines: {node: '>=10.0.0'} + /@volar/language-core@2.4.11: + resolution: {integrity: sha512-lN2C1+ByfW9/JRPpqScuZt/4OrUUse57GLI6TbLgTIqBVemdl1wNcZ1qYGEo2+Gw8coYLgCy7SuKqn6IrQcQgg==} + dependencies: + '@volar/source-map': 2.4.11 dev: true - /@zxing/text-encoding@0.9.0: - resolution: {integrity: sha512-U/4aVJ2mxI0aDNI8Uq0wEhMgY+u4CNtEb0om3+y3+niDAsoTCOB33UF0sxpzqzdqXLqmvc+vZyAt4O8pPdfkwA==} - requiresBuild: true + /@volar/source-map@2.4.11: + resolution: {integrity: sha512-ZQpmafIGvaZMn/8iuvCFGrW3smeqkq/IIh9F1SdSx9aUl0J4Iurzd6/FhmjNO5g2ejF3rT45dKskgXWiofqlZQ==} dev: true - optional: true - /abab@2.0.6: - resolution: {integrity: sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==} + /@volar/typescript@2.4.11: + resolution: {integrity: sha512-2DT+Tdh88Spp5PyPbqhyoYavYCPDsqbHLFwcUI9K1NlY1YgUJvujGdrqUp0zWxnW7KWNTr3xSpMuv2WnaTKDAw==} + dependencies: + '@volar/language-core': 2.4.11 + path-browserify: 1.0.1 + vscode-uri: 3.0.8 dev: true - /acorn-jsx@5.3.2(acorn@8.10.0): - resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + /@vue/compiler-core@3.5.13: + resolution: {integrity: sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q==} + dependencies: + '@babel/parser': 7.26.5 + '@vue/shared': 3.5.13 + entities: 4.5.0 + estree-walker: 2.0.2 + source-map-js: 1.2.1 + dev: true + + /@vue/compiler-dom@3.5.13: + resolution: {integrity: sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA==} + dependencies: + '@vue/compiler-core': 3.5.13 + '@vue/shared': 3.5.13 + dev: true + + /@vue/compiler-vue2@2.7.16: + resolution: {integrity: sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==} + dependencies: + de-indent: 1.0.2 + he: 1.2.0 + dev: true + + /@vue/language-core@2.2.0(typescript@5.7.3): + resolution: {integrity: sha512-O1ZZFaaBGkKbsRfnVH1ifOK1/1BUkyK+3SQsfnh6PmMmD4qJcTU8godCeA96jjDRTL6zgnK7YzCHfaUlH2r0Mw==} peerDependencies: - acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true dependencies: - acorn: 8.10.0 + '@volar/language-core': 2.4.11 + '@vue/compiler-dom': 3.5.13 + '@vue/compiler-vue2': 2.7.16 + '@vue/shared': 3.5.13 + alien-signals: 0.4.14 + minimatch: 9.0.5 + muggle-string: 0.4.1 + path-browserify: 1.0.1 + typescript: 5.7.3 dev: true - /acorn-walk@8.2.0: - resolution: {integrity: sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==} - engines: {node: '>=0.4.0'} + /@vue/language-core@2.2.0(typescript@5.8.3): + resolution: {integrity: sha512-O1ZZFaaBGkKbsRfnVH1ifOK1/1BUkyK+3SQsfnh6PmMmD4qJcTU8godCeA96jjDRTL6zgnK7YzCHfaUlH2r0Mw==} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@volar/language-core': 2.4.11 + '@vue/compiler-dom': 3.5.13 + '@vue/compiler-vue2': 2.7.16 + '@vue/shared': 3.5.13 + alien-signals: 0.4.14 + minimatch: 9.0.5 + muggle-string: 0.4.1 + path-browserify: 1.0.1 + typescript: 5.8.3 + dev: true + + /@vue/shared@3.5.13: + resolution: {integrity: sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==} + dev: true + + /accepts@2.0.0: + resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} + engines: {node: '>= 0.6'} + dependencies: + mime-types: 3.0.1 + negotiator: 1.0.0 + dev: true + + /acorn-jsx@5.3.2(acorn@8.14.0): + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + acorn: 8.14.0 dev: true - /acorn@8.10.0: - resolution: {integrity: sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==} + /acorn@8.14.0: + resolution: {integrity: sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==} engines: {node: '>=0.4.0'} hasBin: true dev: true - /agent-base@6.0.2: - resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} - engines: {node: '>= 6.0.0'} - dependencies: - debug: 4.3.4 - transitivePeerDependencies: - - supports-color + /agent-base@7.1.3: + resolution: {integrity: sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==} + engines: {node: '>= 14'} dev: true /aggregate-error@4.0.1: @@ -2001,6 +3089,28 @@ packages: indent-string: 5.0.0 dev: true + /ajv-draft-04@1.0.0(ajv@8.13.0): + resolution: {integrity: sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==} + peerDependencies: + ajv: ^8.5.0 + peerDependenciesMeta: + ajv: + optional: true + dependencies: + ajv: 8.13.0 + dev: true + + /ajv-formats@3.0.1(ajv@8.13.0): + resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + dependencies: + ajv: 8.13.0 + dev: true + /ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} dependencies: @@ -2010,6 +3120,28 @@ packages: uri-js: 4.4.1 dev: true + /ajv@8.12.0: + resolution: {integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==} + dependencies: + fast-deep-equal: 3.1.3 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + uri-js: 4.4.1 + dev: true + + /ajv@8.13.0: + resolution: {integrity: sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA==} + dependencies: + fast-deep-equal: 3.1.3 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + uri-js: 4.4.1 + dev: true + + /alien-signals@0.4.14: + resolution: {integrity: sha512-itUAVzhczTmP2U5yX67xVpsbbOiquusbWVyA9N+sy6+r6YVbFkahXvNCeEPWEOMhwDYwbVbGHFkVL03N9I5g+Q==} + dev: true + /ansi-escapes@4.3.2: resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} engines: {node: '>=8'} @@ -2020,6 +3152,7 @@ packages: /ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} + dev: true /ansi-regex@6.0.1: resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} @@ -2031,30 +3164,25 @@ packages: engines: {node: '>=4'} dependencies: color-convert: 1.9.3 + dev: true /ansi-styles@4.3.0: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} dependencies: color-convert: 2.0.1 + dev: true /ansi-styles@5.2.0: resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} engines: {node: '>=10'} + dev: true /ansi-styles@6.2.1: resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} engines: {node: '>=12'} dev: true - /anymatch@3.1.3: - resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} - engines: {node: '>= 8'} - dependencies: - normalize-path: 3.0.0 - picomatch: 2.3.1 - dev: true - /argparse@1.0.10: resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} dependencies: @@ -2065,71 +3193,135 @@ packages: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} dev: true - /aria-query@5.1.3: - resolution: {integrity: sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==} - dependencies: - deep-equal: 2.2.2 - /aria-query@5.3.0: resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==} dependencies: dequal: 2.0.3 + dev: true + + /aria-query@5.3.2: + resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} + engines: {node: '>= 0.4'} + dev: true + + /array-buffer-byte-length@1.0.1: + resolution: {integrity: sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + is-array-buffer: 3.0.5 + dev: true - /array-buffer-byte-length@1.0.0: - resolution: {integrity: sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==} + /array-buffer-byte-length@1.0.2: + resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==} + engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.2 - is-array-buffer: 3.0.2 + call-bound: 1.0.3 + is-array-buffer: 3.0.5 + dev: true - /array-includes@3.1.6: - resolution: {integrity: sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==} + /array-includes@3.1.8: + resolution: {integrity: sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.2 - define-properties: 1.2.0 - es-abstract: 1.21.3 - get-intrinsic: 1.2.1 + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-object-atoms: 1.0.0 + get-intrinsic: 1.2.4 is-string: 1.0.7 dev: true - /array-union@2.1.0: - resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} - engines: {node: '>=8'} + /array.prototype.findlast@1.2.5: + resolution: {integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.23.9 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 + es-shim-unscopables: 1.0.2 dev: true - /array.prototype.flat@1.3.1: - resolution: {integrity: sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==} + /array.prototype.findlastindex@1.2.5: + resolution: {integrity: sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.2 - define-properties: 1.2.0 - es-abstract: 1.21.3 - es-shim-unscopables: 1.0.0 + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 + es-shim-unscopables: 1.0.2 dev: true - /array.prototype.flatmap@1.3.1: - resolution: {integrity: sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==} + /array.prototype.flat@1.3.2: + resolution: {integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.2 - define-properties: 1.2.0 - es-abstract: 1.21.3 - es-shim-unscopables: 1.0.0 + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-shim-unscopables: 1.0.2 dev: true - /array.prototype.tosorted@1.1.1: - resolution: {integrity: sha512-pZYPXPRl2PqWcsUs6LOMn+1f1532nEoPTYowBtqLwAW+W8vSVhkIGnmOX1t/UQjD6YGI0vcD2B1U7ZFGQH9jnQ==} + /array.prototype.flatmap@1.3.2: + resolution: {integrity: sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==} + engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.2 - define-properties: 1.2.0 - es-abstract: 1.21.3 - es-shim-unscopables: 1.0.0 - get-intrinsic: 1.2.1 + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-shim-unscopables: 1.0.2 dev: true - /arrify@1.0.1: - resolution: {integrity: sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==} - engines: {node: '>=0.10.0'} + /array.prototype.flatmap@1.3.3: + resolution: {integrity: sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.23.9 + es-shim-unscopables: 1.0.2 + dev: true + + /array.prototype.tosorted@1.1.4: + resolution: {integrity: sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.23.9 + es-errors: 1.3.0 + es-shim-unscopables: 1.0.2 + dev: true + + /arraybuffer.prototype.slice@1.0.3: + resolution: {integrity: sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==} + engines: {node: '>= 0.4'} + dependencies: + array-buffer-byte-length: 1.0.2 + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.23.9 + es-errors: 1.3.0 + get-intrinsic: 1.2.7 + is-array-buffer: 3.0.5 + is-shared-array-buffer: 1.0.4 + dev: true + + /arraybuffer.prototype.slice@1.0.4: + resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==} + engines: {node: '>= 0.4'} + dependencies: + array-buffer-byte-length: 1.0.2 + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.23.9 + es-errors: 1.3.0 + get-intrinsic: 1.2.7 + is-array-buffer: 3.0.5 dev: true /arrify@3.0.0: @@ -2137,76 +3329,67 @@ packages: engines: {node: '>=12'} dev: true - /assertion-error@1.1.0: - resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} + /assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} dev: true - /ast-types-flow@0.0.7: - resolution: {integrity: sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==} + /ast-types-flow@0.0.8: + resolution: {integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==} dev: true /asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} dev: true - /available-typed-arrays@1.0.5: - resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==} + /available-typed-arrays@1.0.7: + resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} + dependencies: + possible-typed-array-names: 1.0.0 + dev: true - /axe-core@4.7.2: - resolution: {integrity: sha512-zIURGIS1E1Q4pcrMjp+nnEh+16G56eG/MUllJH8yEvw7asDo7Ac9uhC9KIH5jzpITueEZolfYglnCGIuSBz39g==} + /axe-core@4.10.2: + resolution: {integrity: sha512-RE3mdQ7P3FRSe7eqCWoeQ/Z9QXrtniSjp1wUjt5nRC3WIpz5rSCve6o3fsZ2aCpJtrZjSZgjwXAoTO5k4tEI0w==} engines: {node: '>=4'} dev: true - /axobject-query@3.2.1: - resolution: {integrity: sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg==} - dependencies: - dequal: 2.0.3 + /axobject-query@4.1.0: + resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} + engines: {node: '>= 0.4'} dev: true /balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} dev: true - /base64-js@1.5.1: - resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - dev: true - - /big-integer@1.6.51: - resolution: {integrity: sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==} - engines: {node: '>=0.6'} - dev: true - - /binary-extensions@2.2.0: - resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} - engines: {node: '>=8'} - dev: true - - /bl@4.1.0: - resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + /body-parser@2.2.0: + resolution: {integrity: sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==} + engines: {node: '>=18'} dependencies: - buffer: 5.7.1 - inherits: 2.0.4 - readable-stream: 3.6.2 + bytes: 3.1.2 + content-type: 1.0.5 + debug: 4.4.0 + http-errors: 2.0.0 + iconv-lite: 0.6.3 + on-finished: 2.4.1 + qs: 6.14.0 + raw-body: 3.0.0 + type-is: 2.0.1 + transitivePeerDependencies: + - supports-color dev: true - /bootstrap@4.6.2(jquery@3.7.0)(popper.js@1.16.1): + /bootstrap@4.6.2(jquery@3.7.1)(popper.js@1.16.1): resolution: {integrity: sha512-51Bbp/Uxr9aTuy6ca/8FbFloBUJZLHwnhTcnjIeRn2suQWsWzcuJhGjKDB5eppVte/8oCdOL3VuwxvZDUggwGQ==} peerDependencies: jquery: 1.9.1 - 3 popper.js: ^1.16.1 dependencies: - jquery: 3.7.0 + jquery: 3.7.1 popper.js: 1.16.1 dev: true - /bplist-parser@0.2.0: - resolution: {integrity: sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw==} - engines: {node: '>= 5.10.0'} - dependencies: - big-integer: 1.6.51 - dev: true - /brace-expansion@1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} dependencies: @@ -2220,119 +3403,122 @@ packages: balanced-match: 1.0.2 dev: true - /braces@3.0.2: - resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} + /braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} dependencies: - fill-range: 7.0.1 + fill-range: 7.1.1 dev: true - /browserslist@4.21.9: - resolution: {integrity: sha512-M0MFoZzbUrRU4KNfCrDLnvyE7gub+peetoTid3TBIqtunaDJyXlwhakT+/VkvSXcfIzFfK/nkCs4nmyTmxdNSg==} + /browserslist@4.24.4: + resolution: {integrity: sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true dependencies: - caniuse-lite: 1.0.30001516 - electron-to-chromium: 1.4.461 - node-releases: 2.0.13 - update-browserslist-db: 1.0.11(browserslist@4.21.9) + caniuse-lite: 1.0.30001692 + electron-to-chromium: 1.5.80 + node-releases: 2.0.19 + update-browserslist-db: 1.1.2(browserslist@4.24.4) dev: true - /buffer-from@1.1.2: - resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + /busboy@1.6.0: + resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} + engines: {node: '>=10.16.0'} + dependencies: + streamsearch: 1.1.0 + dev: false + + /bytes@3.1.2: + resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} + engines: {node: '>= 0.8'} dev: true - /buffer@5.7.1: - resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} - dependencies: - base64-js: 1.5.1 - ieee754: 1.2.1 + /cac@6.7.14: + resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} + engines: {node: '>=8'} dev: true - /builtins@5.0.1: - resolution: {integrity: sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==} + /call-bind-apply-helpers@1.0.1: + resolution: {integrity: sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==} + engines: {node: '>= 0.4'} dependencies: - semver: 7.5.4 + es-errors: 1.3.0 + function-bind: 1.1.2 dev: true - /bundle-name@3.0.0: - resolution: {integrity: sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw==} - engines: {node: '>=12'} + /call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} dependencies: - run-applescript: 5.0.0 + es-errors: 1.3.0 + function-bind: 1.1.2 dev: true - /busboy@1.6.0: - resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} - engines: {node: '>=10.16.0'} + /call-bind@1.0.7: + resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} + engines: {node: '>= 0.4'} dependencies: - streamsearch: 1.1.0 - dev: false + es-define-property: 1.0.0 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.2.7 + set-function-length: 1.2.2 + dev: true - /c8@7.14.0: - resolution: {integrity: sha512-i04rtkkcNcCf7zsQcSv/T9EbUn4RXQ6mropeMcjFOsQXQ0iGLAr/xT6TImQg4+U9hmNpN9XdvPkjUL1IzbgxJw==} - engines: {node: '>=10.12.0'} - hasBin: true + /call-bind@1.0.8: + resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} + engines: {node: '>= 0.4'} dependencies: - '@bcoe/v8-coverage': 0.2.3 - '@istanbuljs/schema': 0.1.3 - find-up: 5.0.0 - foreground-child: 2.0.0 - istanbul-lib-coverage: 3.2.0 - istanbul-lib-report: 3.0.0 - istanbul-reports: 3.1.5 - rimraf: 3.0.2 - test-exclude: 6.0.0 - v8-to-istanbul: 9.1.0 - yargs: 16.2.0 - yargs-parser: 20.2.9 + call-bind-apply-helpers: 1.0.1 + es-define-property: 1.0.1 + get-intrinsic: 1.2.7 + set-function-length: 1.2.2 dev: true - /cac@6.7.14: - resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} - engines: {node: '>=8'} + /call-bound@1.0.3: + resolution: {integrity: sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind-apply-helpers: 1.0.1 + get-intrinsic: 1.2.7 dev: true - /call-bind@1.0.2: - resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==} + /call-bound@1.0.4: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} + engines: {node: '>= 0.4'} dependencies: - function-bind: 1.1.1 - get-intrinsic: 1.2.1 + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + dev: true /callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} dev: true - /camelcase-keys@8.0.2: - resolution: {integrity: sha512-qMKdlOfsjlezMqxkUGGMaWWs17i2HoL15tM+wtx8ld4nLrUwU58TFdvyGOz/piNP842KeO8yXvggVQSdQ828NA==} - engines: {node: '>=14.16'} - dependencies: - camelcase: 7.0.1 - map-obj: 4.3.0 - quick-lru: 6.1.1 - type-fest: 2.19.0 - dev: true + /caniuse-lite@1.0.30001692: + resolution: {integrity: sha512-A95VKan0kdtrsnMubMKxEKUKImOPSuCpYgxSQBo036P5YYgVIcOYJEgt/txJWqObiRQeISNCfef9nvlQ0vbV7A==} - /camelcase@7.0.1: - resolution: {integrity: sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==} - engines: {node: '>=14.16'} + /chai@5.1.2: + resolution: {integrity: sha512-aGtmf24DW6MLHHG5gCx4zaI3uBq3KRtxeVs0DjFH6Z0rDNbsvTxFASFvdj79pxjxZ8/5u3PIiN3IwEIQkiiuPw==} + engines: {node: '>=12'} + dependencies: + assertion-error: 2.0.1 + check-error: 2.1.1 + deep-eql: 5.0.2 + loupe: 3.1.3 + pathval: 2.0.0 dev: true - /caniuse-lite@1.0.30001516: - resolution: {integrity: sha512-Wmec9pCBY8CWbmI4HsjBeQLqDTqV91nFVR83DnZpYyRnPI1wePDsTg0bGLPC5VU/3OIZV1fmxEea1b+tFKe86g==} - - /chai@4.3.7: - resolution: {integrity: sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==} - engines: {node: '>=4'} + /chai@5.2.0: + resolution: {integrity: sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==} + engines: {node: '>=12'} dependencies: - assertion-error: 1.1.0 - check-error: 1.0.2 - deep-eql: 4.1.3 - get-func-name: 2.0.0 - loupe: 2.3.6 - pathval: 1.1.1 - type-detect: 4.0.8 + assertion-error: 2.0.1 + check-error: 2.1.1 + deep-eql: 5.0.2 + loupe: 3.1.3 + pathval: 2.0.0 dev: true /chalk@2.4.2: @@ -2342,6 +3528,7 @@ packages: ansi-styles: 3.2.1 escape-string-regexp: 1.0.5 supports-color: 5.5.0 + dev: true /chalk@3.0.0: resolution: {integrity: sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==} @@ -2349,13 +3536,6 @@ packages: dependencies: ansi-styles: 4.3.0 supports-color: 7.2.0 - - /chalk@4.1.1: - resolution: {integrity: sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==} - engines: {node: '>=10'} - dependencies: - ansi-styles: 4.3.0 - supports-color: 7.2.0 dev: true /chalk@4.1.2: @@ -2364,28 +3544,11 @@ packages: dependencies: ansi-styles: 4.3.0 supports-color: 7.2.0 - - /chardet@0.7.0: - resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==} - dev: true - - /check-error@1.0.2: - resolution: {integrity: sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==} dev: true - /chokidar@3.5.3: - resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} - engines: {node: '>= 8.10.0'} - dependencies: - anymatch: 3.1.3 - braces: 3.0.2 - glob-parent: 5.1.2 - is-binary-path: 2.1.0 - is-glob: 4.0.3 - normalize-path: 3.0.0 - readdirp: 3.6.0 - optionalDependencies: - fsevents: 2.3.2 + /check-error@2.1.1: + resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==} + engines: {node: '>= 16'} dev: true /clean-stack@4.2.0: @@ -2395,21 +3558,9 @@ packages: escape-string-regexp: 5.0.0 dev: true - /cli-cursor@3.1.0: - resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} - engines: {node: '>=8'} - dependencies: - restore-cursor: 3.1.0 - dev: true - - /cli-spinners@2.9.0: - resolution: {integrity: sha512-4/aL9X3Wh0yiMQlE+eeRhWP6vclO3QRtw1JHKIT0FFUs5FjpFmESqtMvYZ0+lbzBw900b95mS0hohy+qn2VK/g==} - engines: {node: '>=6'} - dev: true - - /cli-width@3.0.0: - resolution: {integrity: sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==} - engines: {node: '>= 10'} + /cli-width@4.1.0: + resolution: {integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==} + engines: {node: '>= 12'} dev: true /client-only@0.0.1: @@ -2433,31 +3584,26 @@ packages: wrap-ansi: 7.0.0 dev: true - /clone@1.0.4: - resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} - engines: {node: '>=0.8'} - dev: true - /color-convert@1.9.3: resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} dependencies: color-name: 1.1.3 + dev: true /color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} dependencies: color-name: 1.1.4 + dev: true /color-name@1.1.3: resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} + dev: true /color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - - /colors@1.2.5: - resolution: {integrity: sha512-erNRLao/Y3Fv54qUa0LBB+//Uf3YwMUmdJinN20yMXm9zdKKqH9wt7R9IIVZ+K7ShzfpLV/Zg8+VyrBJYB4lpg==} - engines: {node: '>=0.1.90'} + requiresBuild: true dev: true /combined-stream@1.0.8: @@ -2467,31 +3613,61 @@ packages: delayed-stream: 1.0.0 dev: true - /commander@9.5.0: - resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} - engines: {node: ^12.20.0 || >=14} - requiresBuild: true + /comment-parser@1.4.1: + resolution: {integrity: sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==} + engines: {node: '>= 12.0.0'} dev: true - optional: true - /comment-parser@1.3.1: - resolution: {integrity: sha512-B52sN2VNghyq5ofvUsqZjmk6YkihBX5vMSChmSK9v4ShjKf3Vk5Xcmgpw4o+iIgtrnM/u5FiMpz9VKb8lpBveA==} - engines: {node: '>= 12.0.0'} + /compare-versions@6.1.1: + resolution: {integrity: sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==} dev: true /concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} dev: true - /convert-source-map@1.9.0: - resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} + /confbox@0.1.8: + resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} + dev: true + + /confbox@0.2.1: + resolution: {integrity: sha512-hkT3yDPFbs95mNCy1+7qNKC6Pro+/ibzYxtM2iqEigpf0sVw+bg4Zh9/snjsBcf990vfIsg5+1U7VyiyBb3etg==} + dev: true + + /content-disposition@1.0.0: + resolution: {integrity: sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==} + engines: {node: '>= 0.6'} + dependencies: + safe-buffer: 5.2.1 + dev: true + + /content-type@1.0.5: + resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} + engines: {node: '>= 0.6'} + dev: true + + /convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} dev: true - /cookie@0.4.2: - resolution: {integrity: sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==} + /cookie-signature@1.2.2: + resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} + engines: {node: '>=6.6.0'} + dev: true + + /cookie@0.7.2: + resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} engines: {node: '>= 0.6'} dev: true + /copy-file@11.0.0: + resolution: {integrity: sha512-mFsNh/DIANLqFt5VHZoGirdg7bK5+oTWlhnGu6tgRhzBlnEKWaPX2xrFaLltii/6rmhqFMJqffUgknuRdpYlHw==} + engines: {node: '>=18'} + dependencies: + graceful-fs: 4.2.11 + p-event: 6.0.0 + dev: true + /copyfiles@2.4.1: resolution: {integrity: sha512-fereAvAvxDrQDOXybk3Qu3dPbOoKoysFMWtkY3mv5BsL8//OSZVL5DCLYqgRfY5cWirgRzlC+WSrxp6Bo3eNZg==} hasBin: true @@ -2509,6 +3685,14 @@ packages: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} dev: true + /cors@2.8.5: + resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==} + engines: {node: '>= 0.10'} + dependencies: + object-assign: 4.1.1 + vary: 1.1.2 + dev: true + /cp-file@10.0.0: resolution: {integrity: sha512-vy2Vi1r2epK5WqxOLnskeKeZkdZvTKfFZQCplE3XWsP+SUJyd5XAUFC9lFgTjjXJF2GMne/UML14iEmkAaDfFg==} engines: {node: '>=14.16'} @@ -2524,7 +3708,7 @@ packages: hasBin: true dependencies: cpy: 10.1.0 - meow: 12.0.1 + meow: 12.1.1 dev: true /cpy@10.1.0: @@ -2535,12 +3719,24 @@ packages: cp-file: 10.0.0 globby: 13.2.2 junk: 4.0.1 - micromatch: 4.0.5 + micromatch: 4.0.7 nested-error-stacks: 2.1.1 p-filter: 3.0.0 p-map: 6.0.0 dev: true + /cpy@11.1.0: + resolution: {integrity: sha512-QGHetPSSuprVs+lJmMDcivvrBwTKASzXQ5qxFvRC2RFESjjod71bDvFvhxTjDgkNjrrb72AI6JPjfYwxrIy33A==} + engines: {node: '>=18'} + dependencies: + copy-file: 11.0.0 + globby: 14.0.2 + junk: 4.0.1 + micromatch: 4.0.7 + p-filter: 4.1.0 + p-map: 7.0.2 + dev: true + /cross-env@7.0.3: resolution: {integrity: sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==} engines: {node: '>=10.14', npm: '>=6', yarn: '>=1'} @@ -2558,14 +3754,25 @@ packages: which: 2.0.2 dev: true + /cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + dev: true + /css.escape@1.5.1: resolution: {integrity: sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==} + dev: true - /cssstyle@3.0.0: - resolution: {integrity: sha512-N4u2ABATi3Qplzf0hWbVCdjenim8F3ojEXpBDF5hBpjzW182MjNGLqfmQ0SkSPeQ+V86ZXgeH8aXj6kayd4jgg==} - engines: {node: '>=14'} + /cssstyle@4.2.1: + resolution: {integrity: sha512-9+vem03dMXG7gDmZ62uqmRiMRNtinIZ9ZyuF6BdxzfOD+FdN5hretzynkn0ReS2DO2GSw76RWHs0UmJPI2zUjw==} + engines: {node: '>=18'} dependencies: - rrweb-cssom: 0.6.0 + '@asamuzakjp/css-color': 2.8.2 + rrweb-cssom: 0.8.0 dev: true /csstype@3.1.2: @@ -2576,13 +3783,66 @@ packages: resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} dev: true - /data-urls@4.0.0: - resolution: {integrity: sha512-/mMTei/JXPqvFqQtfyTowxmJVwr2PVAeCcDxyFf6LhoOu/09TX2OX3kb2wzi4DMXcfj4OItwDOnhl5oziPnT6g==} - engines: {node: '>=14'} + /data-urls@5.0.0: + resolution: {integrity: sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==} + engines: {node: '>=18'} + dependencies: + whatwg-mimetype: 4.0.0 + whatwg-url: 14.2.0 + dev: true + + /data-view-buffer@1.0.1: + resolution: {integrity: sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + es-errors: 1.3.0 + is-data-view: 1.0.2 + dev: true + + /data-view-buffer@1.0.2: + resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.3 + es-errors: 1.3.0 + is-data-view: 1.0.2 + dev: true + + /data-view-byte-length@1.0.1: + resolution: {integrity: sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + es-errors: 1.3.0 + is-data-view: 1.0.2 + dev: true + + /data-view-byte-length@1.0.2: + resolution: {integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.3 + es-errors: 1.3.0 + is-data-view: 1.0.2 + dev: true + + /data-view-byte-offset@1.0.0: + resolution: {integrity: sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + es-errors: 1.3.0 + is-data-view: 1.0.2 + dev: true + + /data-view-byte-offset@1.0.1: + resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} + engines: {node: '>= 0.4'} dependencies: - abab: 2.0.6 - whatwg-mimetype: 3.0.0 - whatwg-url: 12.0.1 + call-bound: 1.0.3 + es-errors: 1.3.0 + is-data-view: 1.0.2 dev: true /de-indent@1.0.2: @@ -2600,8 +3860,8 @@ packages: ms: 2.1.3 dev: true - /debug@4.3.4: - resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} + /debug@4.4.0: + resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} engines: {node: '>=6.0'} peerDependencies: supports-color: '*' @@ -2609,113 +3869,57 @@ packages: supports-color: optional: true dependencies: - ms: 2.1.2 - dev: true - - /decamelize-keys@2.0.1: - resolution: {integrity: sha512-nrNeSCtU2gV3Apcmn/EZ+aR20zKDuNDStV67jPiupokD3sOAFeMzslLMCFdKv1sPqzwoe5ZUhsSW9IAVgKSL/Q==} - engines: {node: '>=14.16'} - dependencies: - decamelize: 6.0.0 - map-obj: 4.3.0 - quick-lru: 6.1.1 - type-fest: 3.13.1 - dev: true - - /decamelize@6.0.0: - resolution: {integrity: sha512-Fv96DCsdOgB6mdGl67MT5JaTNKRzrzill5OH5s8bjYJXVlcXyPYGyPsUkWyGV5p1TXI5esYIYMMeDJL0hEIwaA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + ms: 2.1.3 dev: true /decimal.js@10.4.3: resolution: {integrity: sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==} dev: true - /deep-eql@4.1.3: - resolution: {integrity: sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==} - engines: {node: '>=6'} - dependencies: - type-detect: 4.0.8 + /decimal.js@10.5.0: + resolution: {integrity: sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw==} dev: true - /deep-equal@2.2.2: - resolution: {integrity: sha512-xjVyBf0w5vH0I42jdAZzOKVldmPgSulmiyPRywoyq7HXC9qdgo17kxJE+rdnif5Tz6+pIrpJI8dCpMNLIGkUiA==} - dependencies: - array-buffer-byte-length: 1.0.0 - call-bind: 1.0.2 - es-get-iterator: 1.1.3 - get-intrinsic: 1.2.1 - is-arguments: 1.1.1 - is-array-buffer: 3.0.2 - is-date-object: 1.0.5 - is-regex: 1.1.4 - is-shared-array-buffer: 1.0.2 - isarray: 2.0.5 - object-is: 1.1.5 - object-keys: 1.1.1 - object.assign: 4.1.4 - regexp.prototype.flags: 1.5.0 - side-channel: 1.0.4 - which-boxed-primitive: 1.0.2 - which-collection: 1.0.1 - which-typed-array: 1.1.10 + /deep-eql@5.0.2: + resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} + engines: {node: '>=6'} + dev: true /deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} dev: true - /default-browser-id@3.0.0: - resolution: {integrity: sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA==} - engines: {node: '>=12'} - dependencies: - bplist-parser: 0.2.0 - untildify: 4.0.0 - dev: true - - /default-browser@4.0.0: - resolution: {integrity: sha512-wX5pXO1+BrhMkSbROFsyxUm0i/cJEScyNhA4PPxc41ICuv05ZZB/MX28s8aZx6xjmatvebIapF6hLEKEcpneUA==} - engines: {node: '>=14.16'} - dependencies: - bundle-name: 3.0.0 - default-browser-id: 3.0.0 - execa: 7.1.1 - titleize: 3.0.0 - dev: true - - /defaults@1.0.4: - resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==} + /define-data-property@1.1.4: + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} + engines: {node: '>= 0.4'} dependencies: - clone: 1.0.4 - dev: true - - /define-lazy-prop@3.0.0: - resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==} - engines: {node: '>=12'} + es-define-property: 1.0.1 + es-errors: 1.3.0 + gopd: 1.2.0 dev: true - /define-properties@1.2.0: - resolution: {integrity: sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==} + /define-properties@1.2.1: + resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} dependencies: - has-property-descriptors: 1.0.0 + define-data-property: 1.1.4 + has-property-descriptors: 1.0.2 object-keys: 1.1.1 + dev: true /delayed-stream@1.0.0: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} dev: true + /depd@2.0.0: + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} + dev: true + /dequal@2.0.3: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} - - /diff-sequences@27.5.1: - resolution: {integrity: sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - - /diff-sequences@29.4.3: - resolution: {integrity: sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dev: true /dir-glob@3.0.1: @@ -2732,29 +3936,33 @@ packages: esutils: 2.0.3 dev: true - /doctrine@3.0.0: - resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} - engines: {node: '>=6.0.0'} - dependencies: - esutils: 2.0.3 - dev: true - /dom-accessibility-api@0.5.16: resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==} + dev: true - /domexception@4.0.0: - resolution: {integrity: sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==} - engines: {node: '>=12'} + /dom-accessibility-api@0.6.3: + resolution: {integrity: sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==} + dev: true + + /dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} dependencies: - webidl-conversions: 7.0.0 + call-bind-apply-helpers: 1.0.1 + es-errors: 1.3.0 + gopd: 1.2.0 dev: true /eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} dev: true - /electron-to-chromium@1.4.461: - resolution: {integrity: sha512-1JkvV2sgEGTDXjdsaQCeSwYYuhLRphRpc+g6EHTFELJXEiznLt3/0pZ9JuAOQ5p2rI3YxKTbivtvajirIfhrEQ==} + /ee-first@1.1.1: + resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + dev: true + + /electron-to-chromium@1.5.80: + resolution: {integrity: sha512-LTrKpW0AqIuHwmlVNV+cjFYTnXtM9K37OGhpe0ZI10ScPSxqVSryZHIY3WnCS5NSYbBODRTZyhRMS2h5FAEqAw==} dev: true /emoji-regex@8.0.0: @@ -2765,8 +3973,13 @@ packages: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} dev: true - /enhanced-resolve@5.15.0: - resolution: {integrity: sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==} + /encodeurl@2.0.0: + resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} + engines: {node: '>= 0.8'} + dev: true + + /enhanced-resolve@5.18.0: + resolution: {integrity: sha512-0/r0MySGYG8YqlayBZ6MuCfECmHFdJ5qyPh8s8wa5Hnm6SaFLSK1VYCbj+NKp090Nm1caZhD+QTnmxO7esYGyQ==} engines: {node: '>=10.13.0'} dependencies: graceful-fs: 4.2.11 @@ -2778,79 +3991,190 @@ packages: engines: {node: '>=0.12'} dev: true - /error-ex@1.3.2: - resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} - dependencies: - is-arrayish: 0.2.1 - dev: true - - /es-abstract@1.21.3: - resolution: {integrity: sha512-ZU4miiY1j3sGPFLJ34VJXEqhpmL+HGByCinGHv4HC+Fxl2fI2Z4yR6tl0mORnDr6PA8eihWo4LmSWDbvhALckg==} + /es-abstract@1.23.3: + resolution: {integrity: sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==} engines: {node: '>= 0.4'} dependencies: - array-buffer-byte-length: 1.0.0 - available-typed-arrays: 1.0.5 - call-bind: 1.0.2 - es-set-tostringtag: 2.0.1 + array-buffer-byte-length: 1.0.1 + arraybuffer.prototype.slice: 1.0.3 + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + data-view-buffer: 1.0.1 + data-view-byte-length: 1.0.1 + data-view-byte-offset: 1.0.0 + es-define-property: 1.0.0 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 + es-set-tostringtag: 2.1.0 es-to-primitive: 1.2.1 - function.prototype.name: 1.1.5 - get-intrinsic: 1.2.1 - get-symbol-description: 1.0.0 - globalthis: 1.0.3 - gopd: 1.0.1 - has: 1.0.3 - has-property-descriptors: 1.0.0 - has-proto: 1.0.1 - has-symbols: 1.0.3 - internal-slot: 1.0.5 - is-array-buffer: 3.0.2 + function.prototype.name: 1.1.6 + get-intrinsic: 1.2.7 + get-symbol-description: 1.0.2 + globalthis: 1.0.4 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + has-proto: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + internal-slot: 1.1.0 + is-array-buffer: 3.0.4 is-callable: 1.2.7 - is-negative-zero: 2.0.2 + is-data-view: 1.0.1 + is-negative-zero: 2.0.3 is-regex: 1.1.4 - is-shared-array-buffer: 1.0.2 + is-shared-array-buffer: 1.0.3 is-string: 1.0.7 - is-typed-array: 1.1.10 + is-typed-array: 1.1.13 is-weakref: 1.0.2 - object-inspect: 1.12.3 + object-inspect: 1.13.2 object-keys: 1.1.1 - object.assign: 4.1.4 - regexp.prototype.flags: 1.5.0 - safe-regex-test: 1.0.0 - string.prototype.trim: 1.2.7 - string.prototype.trimend: 1.0.6 - string.prototype.trimstart: 1.0.6 - typed-array-byte-offset: 1.0.0 - typed-array-length: 1.0.4 + object.assign: 4.1.5 + regexp.prototype.flags: 1.5.4 + safe-array-concat: 1.1.3 + safe-regex-test: 1.0.3 + string.prototype.trim: 1.2.9 + string.prototype.trimend: 1.0.8 + string.prototype.trimstart: 1.0.8 + typed-array-buffer: 1.0.2 + typed-array-byte-length: 1.0.1 + typed-array-byte-offset: 1.0.2 + typed-array-length: 1.0.6 unbox-primitive: 1.0.2 - which-typed-array: 1.1.10 + which-typed-array: 1.1.15 dev: true - /es-get-iterator@1.1.3: - resolution: {integrity: sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==} + /es-abstract@1.23.9: + resolution: {integrity: sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA==} + engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.2 - get-intrinsic: 1.2.1 - has-symbols: 1.0.3 - is-arguments: 1.1.1 - is-map: 2.0.2 - is-set: 2.0.2 - is-string: 1.0.7 - isarray: 2.0.5 - stop-iteration-iterator: 1.0.0 + array-buffer-byte-length: 1.0.2 + arraybuffer.prototype.slice: 1.0.4 + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.3 + data-view-buffer: 1.0.2 + data-view-byte-length: 1.0.2 + data-view-byte-offset: 1.0.1 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 + es-set-tostringtag: 2.1.0 + es-to-primitive: 1.3.0 + function.prototype.name: 1.1.8 + get-intrinsic: 1.2.7 + get-proto: 1.0.1 + get-symbol-description: 1.1.0 + globalthis: 1.0.4 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + has-proto: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + internal-slot: 1.1.0 + is-array-buffer: 3.0.5 + is-callable: 1.2.7 + is-data-view: 1.0.2 + is-regex: 1.2.1 + is-shared-array-buffer: 1.0.4 + is-string: 1.1.1 + is-typed-array: 1.1.15 + is-weakref: 1.1.0 + math-intrinsics: 1.1.0 + object-inspect: 1.13.3 + object-keys: 1.1.1 + object.assign: 4.1.7 + own-keys: 1.0.1 + regexp.prototype.flags: 1.5.4 + safe-array-concat: 1.1.3 + safe-push-apply: 1.0.0 + safe-regex-test: 1.1.0 + set-proto: 1.0.0 + string.prototype.trim: 1.2.10 + string.prototype.trimend: 1.0.9 + string.prototype.trimstart: 1.0.8 + typed-array-buffer: 1.0.3 + typed-array-byte-length: 1.0.3 + typed-array-byte-offset: 1.0.4 + typed-array-length: 1.0.7 + unbox-primitive: 1.1.0 + which-typed-array: 1.1.18 + dev: true + + /es-define-property@1.0.0: + resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==} + engines: {node: '>= 0.4'} + dependencies: + get-intrinsic: 1.2.7 + dev: true + + /es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + dev: true + + /es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + dev: true + + /es-iterator-helpers@1.2.1: + resolution: {integrity: sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.3 + define-properties: 1.2.1 + es-abstract: 1.23.9 + es-errors: 1.3.0 + es-set-tostringtag: 2.1.0 + function-bind: 1.1.2 + get-intrinsic: 1.2.7 + globalthis: 1.0.4 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + has-proto: 1.2.0 + has-symbols: 1.1.0 + internal-slot: 1.1.0 + iterator.prototype: 1.1.5 + safe-array-concat: 1.1.3 + dev: true + + /es-module-lexer@1.6.0: + resolution: {integrity: sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ==} + dev: true + + /es-module-lexer@1.7.0: + resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} + dev: true + + /es-object-atoms@1.0.0: + resolution: {integrity: sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==} + engines: {node: '>= 0.4'} + dependencies: + es-errors: 1.3.0 + dev: true + + /es-object-atoms@1.1.1: + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + engines: {node: '>= 0.4'} + dependencies: + es-errors: 1.3.0 + dev: true - /es-set-tostringtag@2.0.1: - resolution: {integrity: sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==} + /es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} engines: {node: '>= 0.4'} dependencies: - get-intrinsic: 1.2.1 - has: 1.0.3 - has-tostringtag: 1.0.0 + es-errors: 1.3.0 + get-intrinsic: 1.2.7 + has-tostringtag: 1.0.2 + hasown: 2.0.2 dev: true - /es-shim-unscopables@1.0.0: - resolution: {integrity: sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==} + /es-shim-unscopables@1.0.2: + resolution: {integrity: sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==} dependencies: - has: 1.0.3 + hasown: 2.0.2 dev: true /es-to-primitive@1.2.1: @@ -2858,78 +4182,129 @@ packages: engines: {node: '>= 0.4'} dependencies: is-callable: 1.2.7 - is-date-object: 1.0.5 - is-symbol: 1.0.4 + is-date-object: 1.1.0 + is-symbol: 1.1.1 + dev: true + + /es-to-primitive@1.3.0: + resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} + engines: {node: '>= 0.4'} + dependencies: + is-callable: 1.2.7 + is-date-object: 1.1.0 + is-symbol: 1.1.1 dev: true - /esbuild@0.17.19: - resolution: {integrity: sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==} + /esbuild@0.19.12: + resolution: {integrity: sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==} engines: {node: '>=12'} hasBin: true requiresBuild: true optionalDependencies: - '@esbuild/android-arm': 0.17.19 - '@esbuild/android-arm64': 0.17.19 - '@esbuild/android-x64': 0.17.19 - '@esbuild/darwin-arm64': 0.17.19 - '@esbuild/darwin-x64': 0.17.19 - '@esbuild/freebsd-arm64': 0.17.19 - '@esbuild/freebsd-x64': 0.17.19 - '@esbuild/linux-arm': 0.17.19 - '@esbuild/linux-arm64': 0.17.19 - '@esbuild/linux-ia32': 0.17.19 - '@esbuild/linux-loong64': 0.17.19 - '@esbuild/linux-mips64el': 0.17.19 - '@esbuild/linux-ppc64': 0.17.19 - '@esbuild/linux-riscv64': 0.17.19 - '@esbuild/linux-s390x': 0.17.19 - '@esbuild/linux-x64': 0.17.19 - '@esbuild/netbsd-x64': 0.17.19 - '@esbuild/openbsd-x64': 0.17.19 - '@esbuild/sunos-x64': 0.17.19 - '@esbuild/win32-arm64': 0.17.19 - '@esbuild/win32-ia32': 0.17.19 - '@esbuild/win32-x64': 0.17.19 - dev: true - - /esbuild@0.18.13: - resolution: {integrity: sha512-vhg/WR/Oiu4oUIkVhmfcc23G6/zWuEQKFS+yiosSHe4aN6+DQRXIfeloYGibIfVhkr4wyfuVsGNLr+sQU1rWWw==} - engines: {node: '>=12'} + '@esbuild/aix-ppc64': 0.19.12 + '@esbuild/android-arm': 0.19.12 + '@esbuild/android-arm64': 0.19.12 + '@esbuild/android-x64': 0.19.12 + '@esbuild/darwin-arm64': 0.19.12 + '@esbuild/darwin-x64': 0.19.12 + '@esbuild/freebsd-arm64': 0.19.12 + '@esbuild/freebsd-x64': 0.19.12 + '@esbuild/linux-arm': 0.19.12 + '@esbuild/linux-arm64': 0.19.12 + '@esbuild/linux-ia32': 0.19.12 + '@esbuild/linux-loong64': 0.19.12 + '@esbuild/linux-mips64el': 0.19.12 + '@esbuild/linux-ppc64': 0.19.12 + '@esbuild/linux-riscv64': 0.19.12 + '@esbuild/linux-s390x': 0.19.12 + '@esbuild/linux-x64': 0.19.12 + '@esbuild/netbsd-x64': 0.19.12 + '@esbuild/openbsd-x64': 0.19.12 + '@esbuild/sunos-x64': 0.19.12 + '@esbuild/win32-arm64': 0.19.12 + '@esbuild/win32-ia32': 0.19.12 + '@esbuild/win32-x64': 0.19.12 + dev: true + + /esbuild@0.24.2: + resolution: {integrity: sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==} + engines: {node: '>=18'} hasBin: true requiresBuild: true optionalDependencies: - '@esbuild/android-arm': 0.18.13 - '@esbuild/android-arm64': 0.18.13 - '@esbuild/android-x64': 0.18.13 - '@esbuild/darwin-arm64': 0.18.13 - '@esbuild/darwin-x64': 0.18.13 - '@esbuild/freebsd-arm64': 0.18.13 - '@esbuild/freebsd-x64': 0.18.13 - '@esbuild/linux-arm': 0.18.13 - '@esbuild/linux-arm64': 0.18.13 - '@esbuild/linux-ia32': 0.18.13 - '@esbuild/linux-loong64': 0.18.13 - '@esbuild/linux-mips64el': 0.18.13 - '@esbuild/linux-ppc64': 0.18.13 - '@esbuild/linux-riscv64': 0.18.13 - '@esbuild/linux-s390x': 0.18.13 - '@esbuild/linux-x64': 0.18.13 - '@esbuild/netbsd-x64': 0.18.13 - '@esbuild/openbsd-x64': 0.18.13 - '@esbuild/sunos-x64': 0.18.13 - '@esbuild/win32-arm64': 0.18.13 - '@esbuild/win32-ia32': 0.18.13 - '@esbuild/win32-x64': 0.18.13 - dev: true - - /escalade@3.1.1: - resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} + '@esbuild/aix-ppc64': 0.24.2 + '@esbuild/android-arm': 0.24.2 + '@esbuild/android-arm64': 0.24.2 + '@esbuild/android-x64': 0.24.2 + '@esbuild/darwin-arm64': 0.24.2 + '@esbuild/darwin-x64': 0.24.2 + '@esbuild/freebsd-arm64': 0.24.2 + '@esbuild/freebsd-x64': 0.24.2 + '@esbuild/linux-arm': 0.24.2 + '@esbuild/linux-arm64': 0.24.2 + '@esbuild/linux-ia32': 0.24.2 + '@esbuild/linux-loong64': 0.24.2 + '@esbuild/linux-mips64el': 0.24.2 + '@esbuild/linux-ppc64': 0.24.2 + '@esbuild/linux-riscv64': 0.24.2 + '@esbuild/linux-s390x': 0.24.2 + '@esbuild/linux-x64': 0.24.2 + '@esbuild/netbsd-arm64': 0.24.2 + '@esbuild/netbsd-x64': 0.24.2 + '@esbuild/openbsd-arm64': 0.24.2 + '@esbuild/openbsd-x64': 0.24.2 + '@esbuild/sunos-x64': 0.24.2 + '@esbuild/win32-arm64': 0.24.2 + '@esbuild/win32-ia32': 0.24.2 + '@esbuild/win32-x64': 0.24.2 + dev: true + + /esbuild@0.25.1: + resolution: {integrity: sha512-BGO5LtrGC7vxnqucAe/rmvKdJllfGaYWdyABvyMoXQlfYMb2bbRuReWR5tEGE//4LcNJj9XrkovTqNYRFZHAMQ==} + engines: {node: '>=18'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/aix-ppc64': 0.25.1 + '@esbuild/android-arm': 0.25.1 + '@esbuild/android-arm64': 0.25.1 + '@esbuild/android-x64': 0.25.1 + '@esbuild/darwin-arm64': 0.25.1 + '@esbuild/darwin-x64': 0.25.1 + '@esbuild/freebsd-arm64': 0.25.1 + '@esbuild/freebsd-x64': 0.25.1 + '@esbuild/linux-arm': 0.25.1 + '@esbuild/linux-arm64': 0.25.1 + '@esbuild/linux-ia32': 0.25.1 + '@esbuild/linux-loong64': 0.25.1 + '@esbuild/linux-mips64el': 0.25.1 + '@esbuild/linux-ppc64': 0.25.1 + '@esbuild/linux-riscv64': 0.25.1 + '@esbuild/linux-s390x': 0.25.1 + '@esbuild/linux-x64': 0.25.1 + '@esbuild/netbsd-arm64': 0.25.1 + '@esbuild/netbsd-x64': 0.25.1 + '@esbuild/openbsd-arm64': 0.25.1 + '@esbuild/openbsd-x64': 0.25.1 + '@esbuild/sunos-x64': 0.25.1 + '@esbuild/win32-arm64': 0.25.1 + '@esbuild/win32-ia32': 0.25.1 + '@esbuild/win32-x64': 0.25.1 + dev: true + + /escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} dev: true + /escape-html@1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + dev: true + /escape-string-regexp@1.0.5: resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} engines: {node: '>=0.8.0'} + dev: true /escape-string-regexp@4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} @@ -2941,84 +4316,42 @@ packages: engines: {node: '>=12'} dev: true - /eslint-config-standard-with-typescript@36.1.0(@typescript-eslint/eslint-plugin@5.50.0)(eslint-plugin-import@2.27.5)(eslint-plugin-n@16.0.1)(eslint-plugin-promise@6.1.1)(eslint@8.45.0)(typescript@5.1.6): - resolution: {integrity: sha512-Gpk+7Q3EHqIzTnqYs/LpfOwVb8+kocvlFLYhBdCmUy+EUpsC7067PaHhGSp8P4N+lC2KNGBZ7e2tiGyoRNSVHA==} + /eslint-compat-utils@0.5.1(eslint@9.26.0): + resolution: {integrity: sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q==} + engines: {node: '>=12'} peerDependencies: - '@typescript-eslint/eslint-plugin': ^5.50.0 - eslint: ^8.0.1 - eslint-plugin-import: ^2.25.2 - eslint-plugin-n: '^15.0.0 || ^16.0.0 ' - eslint-plugin-promise: ^6.0.0 - typescript: '*' + eslint: '>=6.0.0' dependencies: - '@typescript-eslint/eslint-plugin': 5.50.0(@typescript-eslint/parser@5.62.0)(eslint@8.45.0)(typescript@5.1.6) - '@typescript-eslint/parser': 5.62.0(eslint@8.45.0)(typescript@5.1.6) - eslint: 8.45.0 - eslint-config-standard: 17.1.0(eslint-plugin-import@2.27.5)(eslint-plugin-n@16.0.1)(eslint-plugin-promise@6.1.1)(eslint@8.45.0) - eslint-plugin-import: 2.27.5(@typescript-eslint/parser@5.62.0)(eslint-import-resolver-typescript@3.5.5)(eslint@8.45.0) - eslint-plugin-n: 16.0.1(eslint@8.45.0) - eslint-plugin-promise: 6.1.1(eslint@8.45.0) - typescript: 5.1.6 - transitivePeerDependencies: - - supports-color + eslint: 9.26.0 + semver: 7.6.3 dev: true - /eslint-config-standard@17.1.0(eslint-plugin-import@2.27.5)(eslint-plugin-n@16.0.1)(eslint-plugin-promise@6.1.1)(eslint@8.45.0): - resolution: {integrity: sha512-IwHwmaBNtDK4zDHQukFDW5u/aTb8+meQWZvNFWkiGmbWjD6bqyuSSBxxXKkCftCUzc1zwCH2m/baCNDLGmuO5Q==} - engines: {node: '>=12.0.0'} + /eslint-config-prettier@10.1.2(eslint@9.26.0): + resolution: {integrity: sha512-Epgp/EofAUeEpIdZkW60MHKvPyru1ruQJxPL+WIycnaPApuseK0Zpkrh/FwL9oIpQvIhJwV7ptOy0DWUjTlCiA==} + hasBin: true peerDependencies: - eslint: ^8.0.1 - eslint-plugin-import: ^2.25.2 - eslint-plugin-n: '^15.0.0 || ^16.0.0 ' - eslint-plugin-promise: ^6.0.0 + eslint: '>=7.0.0' dependencies: - eslint: 8.45.0 - eslint-plugin-import: 2.27.5(@typescript-eslint/parser@5.62.0)(eslint-import-resolver-typescript@3.5.5)(eslint@8.45.0) - eslint-plugin-n: 16.0.1(eslint@8.45.0) - eslint-plugin-promise: 6.1.1(eslint@8.45.0) + eslint: 9.26.0 dev: true - /eslint-define-config@1.21.0: - resolution: {integrity: sha512-OKfreV19Nw4yK4UX1CDkv5FXWdzeF+VSROsO28DVi1BrzqOD4a3U71LJqEhcupK65MoLXxARQ0pSg8bDvNPONA==} - engines: {node: ^16.13.0 || >=18.0.0, npm: '>=7.0.0', pnpm: '>= 8.6.0'} + /eslint-define-config@2.1.0: + resolution: {integrity: sha512-QUp6pM9pjKEVannNAbSJNeRuYwW3LshejfyBBpjeMGaJjaDUpVps4C6KVR8R7dWZnD3i0synmrE36znjTkJvdQ==} + engines: {node: '>=18.0.0', npm: '>=9.0.0', pnpm: '>=8.6.0'} dev: true - /eslint-import-resolver-node@0.3.7: - resolution: {integrity: sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==} + /eslint-import-resolver-node@0.3.9: + resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} dependencies: debug: 3.2.7 - is-core-module: 2.12.1 - resolve: 1.22.2 - transitivePeerDependencies: - - supports-color - dev: true - - /eslint-import-resolver-typescript@3.5.5(@typescript-eslint/parser@5.62.0)(eslint-plugin-import@2.27.5)(eslint@8.45.0): - resolution: {integrity: sha512-TdJqPHs2lW5J9Zpe17DZNQuDnox4xo2o+0tE7Pggain9Rbc19ik8kFtXdxZ250FVx2kF4vlt2RSf4qlUpG7bhw==} - engines: {node: ^14.18.0 || >=16.0.0} - peerDependencies: - eslint: '*' - eslint-plugin-import: '*' - dependencies: - debug: 4.3.4 - enhanced-resolve: 5.15.0 - eslint: 8.45.0 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@5.62.0)(eslint-import-resolver-node@0.3.7)(eslint-import-resolver-typescript@3.5.5)(eslint@8.45.0) - eslint-plugin-import: 2.27.5(@typescript-eslint/parser@5.62.0)(eslint-import-resolver-typescript@3.5.5)(eslint@8.45.0) - get-tsconfig: 4.6.2 - globby: 13.2.2 - is-core-module: 2.12.1 - is-glob: 4.0.3 - synckit: 0.8.5 + is-core-module: 2.16.1 + resolve: 1.22.8 transitivePeerDependencies: - - '@typescript-eslint/parser' - - eslint-import-resolver-node - - eslint-import-resolver-webpack - supports-color dev: true - /eslint-module-utils@2.8.0(@typescript-eslint/parser@5.62.0)(eslint-import-resolver-node@0.3.7)(eslint-import-resolver-typescript@3.5.5)(eslint@8.45.0): - resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==} + /eslint-module-utils@2.12.0(@typescript-eslint/parser@8.32.0)(eslint-import-resolver-node@0.3.9)(eslint@9.26.0): + resolution: {integrity: sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==} engines: {node: '>=4'} peerDependencies: '@typescript-eslint/parser': '*' @@ -3038,270 +4371,280 @@ packages: eslint-import-resolver-webpack: optional: true dependencies: - '@typescript-eslint/parser': 5.62.0(eslint@8.45.0)(typescript@5.1.6) + '@typescript-eslint/parser': 8.32.0(eslint@9.26.0)(typescript@5.8.3) debug: 3.2.7 - eslint: 8.45.0 - eslint-import-resolver-node: 0.3.7 - eslint-import-resolver-typescript: 3.5.5(@typescript-eslint/parser@5.62.0)(eslint-plugin-import@2.27.5)(eslint@8.45.0) + eslint: 9.26.0 + eslint-import-resolver-node: 0.3.9 transitivePeerDependencies: - supports-color dev: true - /eslint-plugin-es-x@7.1.0(eslint@8.45.0): - resolution: {integrity: sha512-AhiaF31syh4CCQ+C5ccJA0VG6+kJK8+5mXKKE7Qs1xcPRg02CDPOj3mWlQxuWS/AYtg7kxrDNgW9YW3vc0Q+Mw==} + /eslint-plugin-es-x@7.8.0(eslint@9.26.0): + resolution: {integrity: sha512-7Ds8+wAAoV3T+LAKeu39Y5BzXCrGKrcISfgKEqTS4BDN8SFEDQd0S43jiQ8vIa3wUKD07qitZdfzlenSi8/0qQ==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: eslint: '>=8' dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.45.0) - '@eslint-community/regexpp': 4.5.1 - eslint: 8.45.0 + '@eslint-community/eslint-utils': 4.6.0(eslint@9.26.0) + '@eslint-community/regexpp': 4.12.1 + eslint: 9.26.0 + eslint-compat-utils: 0.5.1(eslint@9.26.0) dev: true - /eslint-plugin-import@2.27.5(@typescript-eslint/parser@5.62.0)(eslint-import-resolver-typescript@3.5.5)(eslint@8.45.0): - resolution: {integrity: sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==} + /eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.32.0)(eslint@9.26.0): + resolution: {integrity: sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==} engines: {node: '>=4'} peerDependencies: '@typescript-eslint/parser': '*' - eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9 peerDependenciesMeta: '@typescript-eslint/parser': optional: true dependencies: - '@typescript-eslint/parser': 5.62.0(eslint@8.45.0)(typescript@5.1.6) - array-includes: 3.1.6 - array.prototype.flat: 1.3.1 - array.prototype.flatmap: 1.3.1 + '@rtsao/scc': 1.1.0 + '@typescript-eslint/parser': 8.32.0(eslint@9.26.0)(typescript@5.8.3) + array-includes: 3.1.8 + array.prototype.findlastindex: 1.2.5 + array.prototype.flat: 1.3.2 + array.prototype.flatmap: 1.3.2 debug: 3.2.7 doctrine: 2.1.0 - eslint: 8.45.0 - eslint-import-resolver-node: 0.3.7 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@5.62.0)(eslint-import-resolver-node@0.3.7)(eslint-import-resolver-typescript@3.5.5)(eslint@8.45.0) - has: 1.0.3 - is-core-module: 2.12.1 + eslint: 9.26.0 + eslint-import-resolver-node: 0.3.9 + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.32.0)(eslint-import-resolver-node@0.3.9)(eslint@9.26.0) + hasown: 2.0.2 + is-core-module: 2.16.1 is-glob: 4.0.3 minimatch: 3.1.2 - object.values: 1.1.6 - resolve: 1.22.2 + object.fromentries: 2.0.8 + object.groupby: 1.0.3 + object.values: 1.2.0 semver: 6.3.1 - tsconfig-paths: 3.14.2 + string.prototype.trimend: 1.0.8 + tsconfig-paths: 3.15.0 transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack - supports-color dev: true - /eslint-plugin-jsx-a11y@6.7.1(eslint@8.45.0): - resolution: {integrity: sha512-63Bog4iIethyo8smBklORknVjB0T2dwB8Mr/hIC+fBS0uyHdYYpzM/Ed+YC8VxTjlXHEWFOdmgwcDn1U2L9VCA==} + /eslint-plugin-jsx-a11y@6.10.2(eslint@9.26.0): + resolution: {integrity: sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==} engines: {node: '>=4.0'} peerDependencies: - eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 - dependencies: - '@babel/runtime': 7.22.6 - aria-query: 5.3.0 - array-includes: 3.1.6 - array.prototype.flatmap: 1.3.1 - ast-types-flow: 0.0.7 - axe-core: 4.7.2 - axobject-query: 3.2.1 + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9 + dependencies: + aria-query: 5.3.2 + array-includes: 3.1.8 + array.prototype.flatmap: 1.3.2 + ast-types-flow: 0.0.8 + axe-core: 4.10.2 + axobject-query: 4.1.0 damerau-levenshtein: 1.0.8 emoji-regex: 9.2.2 - eslint: 8.45.0 - has: 1.0.3 - jsx-ast-utils: 3.3.4 - language-tags: 1.0.5 + eslint: 9.26.0 + hasown: 2.0.2 + jsx-ast-utils: 3.3.5 + language-tags: 1.0.9 minimatch: 3.1.2 - object.entries: 1.1.6 - object.fromentries: 2.0.6 - semver: 6.3.1 + object.fromentries: 2.0.8 + safe-regex-test: 1.0.3 + string.prototype.includes: 2.0.1 dev: true - /eslint-plugin-n@16.0.1(eslint@8.45.0): - resolution: {integrity: sha512-CDmHegJN0OF3L5cz5tATH84RPQm9kG+Yx39wIqIwPR2C0uhBGMWfbbOtetR83PQjjidA5aXMu+LEFw1jaSwvTA==} - engines: {node: '>=16.0.0'} + /eslint-plugin-n@17.17.0(eslint@9.26.0): + resolution: {integrity: sha512-2VvPK7Mo73z1rDFb6pTvkH6kFibAmnTubFq5l83vePxu0WiY1s0LOtj2WHb6Sa40R3w4mnh8GFYbHBQyMlotKw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: '>=7.0.0' + eslint: '>=8.23.0' dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.45.0) - builtins: 5.0.1 - eslint: 8.45.0 - eslint-plugin-es-x: 7.1.0(eslint@8.45.0) - ignore: 5.2.4 - is-core-module: 2.12.1 - minimatch: 3.1.2 - resolve: 1.22.2 - semver: 7.5.4 + '@eslint-community/eslint-utils': 4.6.0(eslint@9.26.0) + enhanced-resolve: 5.18.0 + eslint: 9.26.0 + eslint-plugin-es-x: 7.8.0(eslint@9.26.0) + get-tsconfig: 4.8.1 + globals: 15.14.0 + ignore: 5.3.2 + minimatch: 9.0.5 + semver: 7.6.3 dev: true - /eslint-plugin-promise@6.1.1(eslint@8.45.0): - resolution: {integrity: sha512-tjqWDwVZQo7UIPMeDReOpUgHCmCiH+ePnVT+5zVapL0uuHnegBUs2smM13CzOs2Xb5+MHMRFTs9v24yjba4Oig==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + /eslint-plugin-no-only-tests@3.3.0: + resolution: {integrity: sha512-brcKcxGnISN2CcVhXJ/kEQlNa0MEfGRtwKtWA16SkqXHKitaKIMrfemJKLKX1YqDU5C/5JY3PvZXd5jEW04e0Q==} + engines: {node: '>=5.0.0'} + dev: true + + /eslint-plugin-prettier@5.4.0(eslint-config-prettier@10.1.2)(eslint@9.26.0)(prettier@3.5.3): + resolution: {integrity: sha512-BvQOvUhkVQM1i63iMETK9Hjud9QhqBnbtT1Zc642p9ynzBuCe5pybkOnvqZIBypXmMlsGcnU4HZ8sCTPfpAexA==} + engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: - eslint: ^7.0.0 || ^8.0.0 + '@types/eslint': '>=8.0.0' + eslint: '>=8.0.0' + eslint-config-prettier: '>= 7.0.0 <10.0.0 || >=10.1.0' + prettier: '>=3.0.0' + peerDependenciesMeta: + '@types/eslint': + optional: true + eslint-config-prettier: + optional: true dependencies: - eslint: 8.45.0 + eslint: 9.26.0 + eslint-config-prettier: 10.1.2(eslint@9.26.0) + prettier: 3.5.3 + prettier-linter-helpers: 1.0.0 + synckit: 0.11.3 dev: true - /eslint-plugin-react-hooks@4.6.0(eslint@8.45.0): - resolution: {integrity: sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==} + /eslint-plugin-react-hooks@5.2.0(eslint@9.26.0): + resolution: {integrity: sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==} engines: {node: '>=10'} peerDependencies: - eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 dependencies: - eslint: 8.45.0 + eslint: 9.26.0 dev: true - /eslint-plugin-react@7.32.2(eslint@8.45.0): - resolution: {integrity: sha512-t2fBMa+XzonrrNkyVirzKlvn5RXzzPwRHtMvLAtVZrt8oxgnTQaYbU6SXTOO1mwQgp1y5+toMSKInnzGr0Knqg==} + /eslint-plugin-react@7.37.5(eslint@9.26.0): + resolution: {integrity: sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==} engines: {node: '>=4'} peerDependencies: - eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 dependencies: - array-includes: 3.1.6 - array.prototype.flatmap: 1.3.1 - array.prototype.tosorted: 1.1.1 + array-includes: 3.1.8 + array.prototype.findlast: 1.2.5 + array.prototype.flatmap: 1.3.3 + array.prototype.tosorted: 1.1.4 doctrine: 2.1.0 - eslint: 8.45.0 + es-iterator-helpers: 1.2.1 + eslint: 9.26.0 estraverse: 5.3.0 - jsx-ast-utils: 3.3.4 + hasown: 2.0.2 + jsx-ast-utils: 3.3.5 minimatch: 3.1.2 - object.entries: 1.1.6 - object.fromentries: 2.0.6 - object.hasown: 1.1.2 - object.values: 1.1.6 + object.entries: 1.1.9 + object.fromentries: 2.0.8 + object.values: 1.2.1 prop-types: 15.8.1 - resolve: 2.0.0-next.4 + resolve: 2.0.0-next.5 semver: 6.3.1 - string.prototype.matchall: 4.0.8 + string.prototype.matchall: 4.0.12 + string.prototype.repeat: 1.0.0 dev: true - /eslint-plugin-regexp@1.15.0(eslint@8.45.0): - resolution: {integrity: sha512-YEtQPfdudafU7RBIFci81R/Q1yErm0mVh3BkGnXD2Dk8DLwTFdc2ITYH1wCnHKim2gnHfPFgrkh+b2ozyyU7ag==} - engines: {node: ^12 || >=14} + /eslint-plugin-regexp@2.7.0(eslint@9.26.0): + resolution: {integrity: sha512-U8oZI77SBtH8U3ulZ05iu0qEzIizyEDXd+BWHvyVxTOjGwcDcvy/kEpgFG4DYca2ByRLiVPFZ2GeH7j1pdvZTA==} + engines: {node: ^18 || >=20} peerDependencies: - eslint: '>=6.0.0' + eslint: '>=8.44.0' dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.45.0) - '@eslint-community/regexpp': 4.5.1 - comment-parser: 1.3.1 - eslint: 8.45.0 - grapheme-splitter: 1.0.4 - jsdoctypeparser: 9.0.0 - refa: 0.11.0 - regexp-ast-analysis: 0.6.0 - scslre: 0.2.0 + '@eslint-community/eslint-utils': 4.4.0(eslint@9.26.0) + '@eslint-community/regexpp': 4.11.0 + comment-parser: 1.4.1 + eslint: 9.26.0 + jsdoc-type-pratt-parser: 4.0.0 + refa: 0.12.1 + regexp-ast-analysis: 0.7.1 + scslre: 0.3.0 dev: true - /eslint-plugin-simple-import-sort@10.0.0(eslint@8.45.0): - resolution: {integrity: sha512-AeTvO9UCMSNzIHRkg8S6c3RPy5YEwKWSQPx3DYghLedo2ZQxowPFLGDN1AZ2evfg6r6mjBSZSLxLFsWSu3acsw==} + /eslint-plugin-simple-import-sort@12.1.1(eslint@9.26.0): + resolution: {integrity: sha512-6nuzu4xwQtE3332Uz0to+TxDQYRLTKRESSc2hefVT48Zc8JthmN23Gx9lnYhu0FtkRSL1oxny3kJ2aveVhmOVA==} peerDependencies: eslint: '>=5.0.0' dependencies: - eslint: 8.45.0 + eslint: 9.26.0 dev: true - /eslint-plugin-testing-library@5.11.0(eslint@8.45.0)(typescript@5.1.6): - resolution: {integrity: sha512-ELY7Gefo+61OfXKlQeXNIDVVLPcvKTeiQOoMZG9TeuWa7Ln4dUNRv8JdRWBQI9Mbb427XGlVB1aa1QPZxBJM8Q==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0, npm: '>=6'} + /eslint-plugin-testing-library@7.1.1(eslint@9.26.0)(typescript@5.8.3): + resolution: {integrity: sha512-nszC833aZPwB6tik1nMkbFqmtgIXTT0sfJEYs0zMBKMlkQ4to2079yUV96SvmLh00ovSBJI4pgcBC1TiIP8mXg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0, pnpm: ^9.14.0} peerDependencies: - eslint: ^7.5.0 || ^8.0.0 + eslint: ^8.57.0 || ^9.0.0 dependencies: - '@typescript-eslint/utils': 5.62.0(eslint@8.45.0)(typescript@5.1.6) - eslint: 8.45.0 + '@typescript-eslint/scope-manager': 8.19.1 + '@typescript-eslint/utils': 8.19.1(eslint@9.26.0)(typescript@5.8.3) + eslint: 9.26.0 transitivePeerDependencies: - supports-color - typescript dev: true - /eslint-scope@5.1.1: - resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} - engines: {node: '>=8.0.0'} - dependencies: - esrecurse: 4.3.0 - estraverse: 4.3.0 - dev: true - - /eslint-scope@7.2.1: - resolution: {integrity: sha512-CvefSOsDdaYYvxChovdrPo/ZGt8d5lrJWleAc1diXRKhHGiTYEI26cvo8Kle/wGnsizoCJjK73FMg1/IkIwiNA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + /eslint-scope@8.3.0: + resolution: {integrity: sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} dependencies: esrecurse: 4.3.0 estraverse: 5.3.0 dev: true - /eslint-utils@3.0.0(eslint@8.45.0): - resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==} - engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0} - peerDependencies: - eslint: '>=5' - dependencies: - eslint: 8.45.0 - eslint-visitor-keys: 2.1.0 - dev: true - - /eslint-visitor-keys@2.1.0: - resolution: {integrity: sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==} - engines: {node: '>=10'} + /eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true - /eslint-visitor-keys@3.4.1: - resolution: {integrity: sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + /eslint-visitor-keys@4.2.0: + resolution: {integrity: sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} dev: true - /eslint@8.45.0: - resolution: {integrity: sha512-pd8KSxiQpdYRfYa9Wufvdoct3ZPQQuVuU5O6scNgMuOMYuxvH0IGaYK0wUFjo4UYYQQCUndlXiMbnxopwvvTiw==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + /eslint@9.26.0: + resolution: {integrity: sha512-Hx0MOjPh6uK9oq9nVsATZKE/Wlbai7KFjfCuw9UHaguDW3x+HF0O5nIi3ud39TWgrTjTO5nHxmL3R1eANinWHQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} hasBin: true + peerDependencies: + jiti: '*' + peerDependenciesMeta: + jiti: + optional: true dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.45.0) - '@eslint-community/regexpp': 4.5.1 - '@eslint/eslintrc': 2.1.0 - '@eslint/js': 8.44.0 - '@humanwhocodes/config-array': 0.11.10 + '@eslint-community/eslint-utils': 4.6.0(eslint@9.26.0) + '@eslint-community/regexpp': 4.12.1 + '@eslint/config-array': 0.20.0 + '@eslint/config-helpers': 0.2.2 + '@eslint/core': 0.13.0 + '@eslint/eslintrc': 3.3.1 + '@eslint/js': 9.26.0 + '@eslint/plugin-kit': 0.2.8 + '@humanfs/node': 0.16.6 '@humanwhocodes/module-importer': 1.0.1 - '@nodelib/fs.walk': 1.2.8 + '@humanwhocodes/retry': 0.4.2 + '@modelcontextprotocol/sdk': 1.11.0 + '@types/estree': 1.0.6 + '@types/json-schema': 7.0.15 ajv: 6.12.6 chalk: 4.1.2 - cross-spawn: 7.0.3 - debug: 4.3.4 - doctrine: 3.0.0 + cross-spawn: 7.0.6 + debug: 4.4.0 escape-string-regexp: 4.0.0 - eslint-scope: 7.2.1 - eslint-visitor-keys: 3.4.1 - espree: 9.6.1 + eslint-scope: 8.3.0 + eslint-visitor-keys: 4.2.0 + espree: 10.3.0 esquery: 1.5.0 esutils: 2.0.3 fast-deep-equal: 3.1.3 - file-entry-cache: 6.0.1 + file-entry-cache: 8.0.0 find-up: 5.0.0 glob-parent: 6.0.2 - globals: 13.20.0 - graphemer: 1.4.0 - ignore: 5.2.4 + ignore: 5.3.2 imurmurhash: 0.1.4 is-glob: 4.0.3 - is-path-inside: 3.0.3 - js-yaml: 4.1.0 json-stable-stringify-without-jsonify: 1.0.1 - levn: 0.4.1 lodash.merge: 4.6.2 minimatch: 3.1.2 natural-compare: 1.4.0 optionator: 0.9.3 - strip-ansi: 6.0.1 - text-table: 0.2.0 + zod: 3.24.4 transitivePeerDependencies: - supports-color dev: true - /espree@9.6.1: - resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + /espree@10.3.0: + resolution: {integrity: sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} dependencies: - acorn: 8.10.0 - acorn-jsx: 5.3.2(acorn@8.10.0) - eslint-visitor-keys: 3.4.1 + acorn: 8.14.0 + acorn-jsx: 5.3.2(acorn@8.14.0) + eslint-visitor-keys: 4.2.0 dev: true /esquery@1.5.0: @@ -3318,11 +4661,6 @@ packages: estraverse: 5.3.0 dev: true - /estraverse@4.3.0: - resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} - engines: {node: '>=4.0'} - dev: true - /estraverse@5.3.0: resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} engines: {node: '>=4.0'} @@ -3332,68 +4670,109 @@ packages: resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} dev: true + /estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + dependencies: + '@types/estree': 1.0.6 + dev: true + /esutils@2.0.3: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} dev: true - /events@3.3.0: - resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} - engines: {node: '>=0.8.x'} + /etag@1.8.1: + resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} + engines: {node: '>= 0.6'} dev: true - /execa@5.1.1: - resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} - engines: {node: '>=10'} - dependencies: - cross-spawn: 7.0.3 - get-stream: 6.0.1 - human-signals: 2.1.0 - is-stream: 2.0.1 - merge-stream: 2.0.0 - npm-run-path: 4.0.1 - onetime: 5.1.2 - signal-exit: 3.0.7 - strip-final-newline: 2.0.0 + /eventsource-parser@3.0.1: + resolution: {integrity: sha512-VARTJ9CYeuQYb0pZEPbzi740OWFgpHe7AYJ2WFZVnUDUQp5Dk2yJUgF36YsZ81cOyxT0QxmXD2EQpapAouzWVA==} + engines: {node: '>=18.0.0'} dev: true - /execa@7.1.1: - resolution: {integrity: sha512-wH0eMf/UXckdUYnO21+HDztteVv05rq2GXksxT4fCGeHkBhw1DROXh40wcjMcRqDOWE7iPJ4n3M7e2+YFP+76Q==} - engines: {node: ^14.18.0 || ^16.14.0 || >=18.0.0} + /eventsource@3.0.6: + resolution: {integrity: sha512-l19WpE2m9hSuyP06+FbuUUf1G+R0SFLrtQfbRb9PRr+oimOfxQhgGCbVaXg5IvZyyTThJsxh6L/srkMiCeBPDA==} + engines: {node: '>=18.0.0'} dependencies: - cross-spawn: 7.0.3 - get-stream: 6.0.1 - human-signals: 4.3.1 - is-stream: 3.0.0 - merge-stream: 2.0.0 - npm-run-path: 5.1.0 - onetime: 6.0.0 - signal-exit: 3.0.7 - strip-final-newline: 3.0.0 - dev: true - - /external-editor@3.1.0: - resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==} - engines: {node: '>=4'} - dependencies: - chardet: 0.7.0 - iconv-lite: 0.4.24 - tmp: 0.0.33 + eventsource-parser: 3.0.1 + dev: true + + /expect-type@1.1.0: + resolution: {integrity: sha512-bFi65yM+xZgk+u/KRIpekdSYkTB5W1pEf0Lt8Q8Msh7b+eQ7LXVtIB1Bkm4fvclDEL1b2CZkMhv2mOeF8tMdkA==} + engines: {node: '>=12.0.0'} + dev: true + + /expect-type@1.2.1: + resolution: {integrity: sha512-/kP8CAwxzLVEeFrMm4kMmy4CCDlpipyA7MYLVrdJIkV0fYF0UaigQHRsxHiuY/GEea+bh4KSv3TIlgr+2UL6bw==} + engines: {node: '>=12.0.0'} + dev: true + + /express-rate-limit@7.5.0(express@5.1.0): + resolution: {integrity: sha512-eB5zbQh5h+VenMPM3fh+nw1YExi5nMr6HUCR62ELSP11huvxm/Uir1H1QEyTkk5QX6A58pX6NmaTMceKZ0Eodg==} + engines: {node: '>= 16'} + peerDependencies: + express: ^4.11 || 5 || ^5.0.0-beta.1 + dependencies: + express: 5.1.0 + dev: true + + /express@5.1.0: + resolution: {integrity: sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==} + engines: {node: '>= 18'} + dependencies: + accepts: 2.0.0 + body-parser: 2.2.0 + content-disposition: 1.0.0 + content-type: 1.0.5 + cookie: 0.7.2 + cookie-signature: 1.2.2 + debug: 4.4.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 2.1.0 + fresh: 2.0.0 + http-errors: 2.0.0 + merge-descriptors: 2.0.0 + mime-types: 3.0.1 + on-finished: 2.4.1 + once: 1.4.0 + parseurl: 1.3.3 + proxy-addr: 2.0.7 + qs: 6.14.0 + range-parser: 1.2.1 + router: 2.2.0 + send: 1.2.0 + serve-static: 2.2.0 + statuses: 2.0.1 + type-is: 2.0.1 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + dev: true + + /exsolve@1.0.4: + resolution: {integrity: sha512-xsZH6PXaER4XoV+NiT7JHp1bJodJVT+cxeSH1G0f0tlT0lJqYuHUP3bUx2HtfTDvOagMINYp8rsqusxud3RXhw==} dev: true /fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} dev: true - /fast-glob@3.3.0: - resolution: {integrity: sha512-ChDuvbOypPuNjO8yIDf36x7BlZX1smcUMTTcyoIjycexOxd6DFsKsg21qVBzEmr3G7fUKIRy2/psii+CIUt7FA==} + /fast-diff@1.3.0: + resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} + dev: true + + /fast-glob@3.3.2: + resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} engines: {node: '>=8.6.0'} dependencies: '@nodelib/fs.stat': 2.0.5 '@nodelib/fs.walk': 1.2.8 glob-parent: 5.1.2 merge2: 1.4.1 - micromatch: 4.0.5 + micromatch: 4.0.7 dev: true /fast-json-stable-stringify@2.1.0: @@ -3404,33 +4783,51 @@ packages: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} dev: true - /fastq@1.15.0: - resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==} + /fastq@1.17.1: + resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} dependencies: reusify: 1.0.4 dev: true - /figures@3.2.0: - resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==} - engines: {node: '>=8'} + /fdir@6.4.4(picomatch@4.0.2): + resolution: {integrity: sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true dependencies: - escape-string-regexp: 1.0.5 + picomatch: 4.0.2 dev: true - /file-entry-cache@6.0.1: - resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} - engines: {node: ^10.12.0 || >=12.0.0} + /file-entry-cache@8.0.0: + resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} + engines: {node: '>=16.0.0'} dependencies: - flat-cache: 3.0.4 + flat-cache: 4.0.1 dev: true - /fill-range@7.0.1: - resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} + /fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} dependencies: to-regex-range: 5.0.1 dev: true + /finalhandler@2.1.0: + resolution: {integrity: sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==} + engines: {node: '>= 0.8'} + dependencies: + debug: 4.4.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + on-finished: 2.4.1 + parseurl: 1.3.3 + statuses: 2.0.1 + transitivePeerDependencies: + - supports-color + dev: true + /find-up@5.0.0: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} @@ -3439,49 +4836,34 @@ packages: path-exists: 4.0.0 dev: true - /find-up@6.3.0: - resolution: {integrity: sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - dependencies: - locate-path: 7.2.0 - path-exists: 5.0.0 - dev: true - - /flat-cache@3.0.4: - resolution: {integrity: sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==} - engines: {node: ^10.12.0 || >=12.0.0} + /flat-cache@4.0.1: + resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} + engines: {node: '>=16'} dependencies: - flatted: 3.2.7 - rimraf: 3.0.2 + flatted: 3.2.9 + keyv: 4.5.4 dev: true - /flatted@3.2.7: - resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==} + /flatted@3.2.9: + resolution: {integrity: sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==} dev: true /for-each@0.3.3: resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} dependencies: is-callable: 1.2.7 - - /foreground-child@2.0.0: - resolution: {integrity: sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==} - engines: {node: '>=8.0.0'} - dependencies: - cross-spawn: 7.0.3 - signal-exit: 3.0.7 dev: true /foreground-child@3.1.1: resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==} engines: {node: '>=14'} dependencies: - cross-spawn: 7.0.3 - signal-exit: 4.0.2 + cross-spawn: 7.0.6 + signal-exit: 4.1.0 dev: true - /form-data@4.0.0: - resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} + /form-data@4.0.1: + resolution: {integrity: sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==} engines: {node: '>= 6'} dependencies: asynckit: 0.4.0 @@ -3489,6 +4871,25 @@ packages: mime-types: 2.1.35 dev: true + /forwarded@0.2.0: + resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} + engines: {node: '>= 0.6'} + dev: true + + /fresh@2.0.0: + resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} + engines: {node: '>= 0.8'} + dev: true + + /fs-extra@11.3.0: + resolution: {integrity: sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==} + engines: {node: '>=14.14'} + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.1.0 + universalify: 2.0.1 + dev: true + /fs-extra@7.0.1: resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} engines: {node: '>=6 <7 || >=8'} @@ -3502,29 +4903,43 @@ packages: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} dev: true - /fsevents@2.3.2: - resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} + /fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] requiresBuild: true dev: true optional: true - /function-bind@1.1.1: - resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} + /function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + dev: true + + /function.prototype.name@1.1.6: + resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.23.9 + functions-have-names: 1.2.3 + dev: true - /function.prototype.name@1.1.5: - resolution: {integrity: sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==} + /function.prototype.name@1.1.8: + resolution: {integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.2 - define-properties: 1.2.0 - es-abstract: 1.21.3 + call-bind: 1.0.8 + call-bound: 1.0.3 + define-properties: 1.2.1 functions-have-names: 1.2.3 + hasown: 2.0.2 + is-callable: 1.2.7 dev: true /functions-have-names@1.2.3: resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + dev: true /gensync@1.0.0-beta.2: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} @@ -3536,33 +4951,77 @@ packages: engines: {node: 6.* || 8.* || >= 10.*} dev: true - /get-func-name@2.0.0: - resolution: {integrity: sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==} + /get-intrinsic@1.2.4: + resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} + engines: {node: '>= 0.4'} + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + has-proto: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + dev: true + + /get-intrinsic@1.2.7: + resolution: {integrity: sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind-apply-helpers: 1.0.1 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + math-intrinsics: 1.1.0 dev: true - /get-intrinsic@1.2.1: - resolution: {integrity: sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==} + /get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} dependencies: - function-bind: 1.1.1 - has: 1.0.3 - has-proto: 1.0.1 - has-symbols: 1.0.3 + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + math-intrinsics: 1.1.0 + dev: true - /get-stream@6.0.1: - resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} - engines: {node: '>=10'} + /get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.0.0 + dev: true + + /get-symbol-description@1.0.2: + resolution: {integrity: sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + es-errors: 1.3.0 + get-intrinsic: 1.2.7 dev: true - /get-symbol-description@1.0.0: - resolution: {integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==} + /get-symbol-description@1.1.0: + resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.2 - get-intrinsic: 1.2.1 + call-bound: 1.0.3 + es-errors: 1.3.0 + get-intrinsic: 1.2.7 dev: true - /get-tsconfig@4.6.2: - resolution: {integrity: sha512-E5XrT4CbbXcXWy+1jChlZmrmCwd5KGx502kDCXJJ7y898TtWW9FwoG5HfOLVRKmlmDGkWN2HM9Ho+/Y8F0sJDg==} + /get-tsconfig@4.8.1: + resolution: {integrity: sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==} dependencies: resolve-pkg-maps: 1.0.0 dev: true @@ -3581,20 +5040,29 @@ packages: is-glob: 4.0.3 dev: true - /glob-to-regexp@0.4.1: - resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} - dev: false + /glob@10.4.5: + resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} + hasBin: true + dependencies: + foreground-child: 3.1.1 + jackspeak: 3.4.3 + minimatch: 9.0.5 + minipass: 7.1.2 + package-json-from-dist: 1.0.0 + path-scurry: 1.11.1 + dev: true - /glob@10.3.3: - resolution: {integrity: sha512-92vPiMb/iqpmEgsOoIDvTjc50wf9CCCvMzsi6W0JLPeUKE8TWP1a73PgqSrqy7iAZxaSD1YdzU7QZR5LF51MJw==} - engines: {node: '>=16 || 14 >=14.17'} + /glob@11.0.0: + resolution: {integrity: sha512-9UiX/Bl6J2yaBbxKoEBRm4Cipxgok8kQYcOPEhScPwebu2I0HoQOuYdIO6S3hLuWoZgpDpwQZMzTFxgpkyT76g==} + engines: {node: 20 || >=22} hasBin: true dependencies: foreground-child: 3.1.1 - jackspeak: 2.2.1 - minimatch: 9.0.3 - minipass: 7.0.2 - path-scurry: 1.10.1 + jackspeak: 4.0.1 + minimatch: 10.0.1 + minipass: 7.1.2 + package-json-from-dist: 1.0.0 + path-scurry: 2.0.0 dev: true /glob@7.2.3: @@ -3613,30 +5081,22 @@ packages: engines: {node: '>=4'} dev: true - /globals@13.20.0: - resolution: {integrity: sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==} - engines: {node: '>=8'} - dependencies: - type-fest: 0.20.2 + /globals@14.0.0: + resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} + engines: {node: '>=18'} dev: true - /globalthis@1.0.3: - resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==} - engines: {node: '>= 0.4'} - dependencies: - define-properties: 1.2.0 + /globals@15.14.0: + resolution: {integrity: sha512-OkToC372DtlQeje9/zHIo5CT8lRP/FUgEOKBEhU4e0abL7J7CD24fD9ohiLN5hagG/kWCYj4K5oaxxtj2Z0Dig==} + engines: {node: '>=18'} dev: true - /globby@11.1.0: - resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} - engines: {node: '>=10'} + /globalthis@1.0.4: + resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} + engines: {node: '>= 0.4'} dependencies: - array-union: 2.1.0 - dir-glob: 3.0.1 - fast-glob: 3.3.0 - ignore: 5.2.4 - merge2: 1.4.1 - slash: 3.0.0 + define-properties: 1.2.1 + gopd: 1.2.0 dev: true /globby@13.2.2: @@ -3644,144 +5104,136 @@ packages: engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} dependencies: dir-glob: 3.0.1 - fast-glob: 3.3.0 - ignore: 5.2.4 + fast-glob: 3.3.2 + ignore: 5.3.2 merge2: 1.4.1 slash: 4.0.0 dev: true - /gopd@1.0.1: - resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} + /globby@14.0.2: + resolution: {integrity: sha512-s3Fq41ZVh7vbbe2PN3nrW7yC7U7MFVc5c98/iTl9c2GawNMKx/J648KQRW6WKkuU8GIbbh2IXfIRQjOZnXcTnw==} + engines: {node: '>=18'} dependencies: - get-intrinsic: 1.2.1 + '@sindresorhus/merge-streams': 2.3.0 + fast-glob: 3.3.2 + ignore: 5.3.2 + path-type: 5.0.0 + slash: 5.1.0 + unicorn-magic: 0.1.0 + dev: true + + /gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + dev: true /graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - /grapheme-splitter@1.0.4: - resolution: {integrity: sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==} - dev: true - /graphemer@1.4.0: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} dev: true - /graphql@16.7.1: - resolution: {integrity: sha512-DRYR9tf+UGU0KOsMcKAlXeFfX89UiiIZ0dRU3mR0yJfu6OjZqUcp68NnFLnqQU5RexygFoDy1EW+ccOYcPfmHg==} + /graphql@16.10.0: + resolution: {integrity: sha512-AjqGKbDGUFRKIRCP9tCKiIGHyriz2oHEbPIbEtcSLSs4YjReZOIPQQWek4+6hjw62H9QShXHyaGivGiYVLeYFQ==} engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} dev: true - /hard-rejection@2.1.0: - resolution: {integrity: sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==} - engines: {node: '>=6'} - dev: true - /has-bigints@1.0.2: resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} + dev: true /has-flag@3.0.0: resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} engines: {node: '>=4'} + dev: true /has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} + dev: true - /has-property-descriptors@1.0.0: - resolution: {integrity: sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==} + /has-property-descriptors@1.0.2: + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} dependencies: - get-intrinsic: 1.2.1 + es-define-property: 1.0.1 + dev: true - /has-proto@1.0.1: - resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==} + /has-proto@1.2.0: + resolution: {integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==} engines: {node: '>= 0.4'} + dependencies: + dunder-proto: 1.0.1 + dev: true - /has-symbols@1.0.3: - resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} + /has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} engines: {node: '>= 0.4'} + dev: true - /has-tostringtag@1.0.0: - resolution: {integrity: sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==} + /has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} engines: {node: '>= 0.4'} dependencies: - has-symbols: 1.0.3 + has-symbols: 1.1.0 + dev: true - /has@1.0.3: - resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} - engines: {node: '>= 0.4.0'} + /hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} dependencies: - function-bind: 1.1.1 + function-bind: 1.1.2 + dev: true /he@1.2.0: resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} hasBin: true dev: true - /headers-polyfill@3.1.2: - resolution: {integrity: sha512-tWCK4biJ6hcLqTviLXVR9DTRfYGQMXEIUj3gwJ2rZ5wO/at3XtkI4g8mCvFdUF9l1KMBNCfmNAdnahm1cgavQA==} - dev: true - - /hosted-git-info@4.1.0: - resolution: {integrity: sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==} - engines: {node: '>=10'} - dependencies: - lru-cache: 6.0.0 - dev: true - - /hosted-git-info@6.1.1: - resolution: {integrity: sha512-r0EI+HBMcXadMrugk0GCQ+6BQV39PiWAZVfq7oIckeGiN7sjRGyQxPdft3nQekFTCQbYxLBH+/axZMeH8UX6+w==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - dependencies: - lru-cache: 7.18.3 + /headers-polyfill@4.0.2: + resolution: {integrity: sha512-EWGTfnTqAO2L/j5HZgoM/3z82L7necsJ0pO9Tp0X1wil3PDLrkypTBRgVO2ExehEEvUycejZD3FuRaXpZZc3kw==} dev: true - /html-encoding-sniffer@3.0.0: - resolution: {integrity: sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==} - engines: {node: '>=12'} + /html-encoding-sniffer@4.0.0: + resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==} + engines: {node: '>=18'} dependencies: - whatwg-encoding: 2.0.0 + whatwg-encoding: 3.1.1 dev: true /html-escaper@2.0.2: resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} dev: true - /http-proxy-agent@5.0.0: - resolution: {integrity: sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==} - engines: {node: '>= 6'} + /http-errors@2.0.0: + resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} + engines: {node: '>= 0.8'} dependencies: - '@tootallnate/once': 2.0.0 - agent-base: 6.0.2 - debug: 4.3.4 - transitivePeerDependencies: - - supports-color + depd: 2.0.0 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 2.0.1 + toidentifier: 1.0.1 dev: true - /https-proxy-agent@5.0.1: - resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} - engines: {node: '>= 6'} + /http-proxy-agent@7.0.2: + resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} + engines: {node: '>= 14'} dependencies: - agent-base: 6.0.2 - debug: 4.3.4 + agent-base: 7.1.3 + debug: 4.4.0 transitivePeerDependencies: - supports-color dev: true - /human-signals@2.1.0: - resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} - engines: {node: '>=10.17.0'} - dev: true - - /human-signals@4.3.1: - resolution: {integrity: sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==} - engines: {node: '>=14.18.0'} - dev: true - - /iconv-lite@0.4.24: - resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} - engines: {node: '>=0.10.0'} + /https-proxy-agent@7.0.6: + resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} + engines: {node: '>= 14'} dependencies: - safer-buffer: 2.1.2 + agent-base: 7.1.3 + debug: 4.4.0 + transitivePeerDependencies: + - supports-color dev: true /iconv-lite@0.6.3: @@ -3791,12 +5243,8 @@ packages: safer-buffer: 2.1.2 dev: true - /ieee754@1.2.1: - resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} - dev: true - - /ignore@5.2.4: - resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==} + /ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} dev: true @@ -3821,6 +5269,7 @@ packages: /indent-string@4.0.0: resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} engines: {node: '>=8'} + dev: true /indent-string@5.0.0: resolution: {integrity: sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==} @@ -3838,98 +5287,93 @@ packages: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} dev: true - /inquirer@8.2.5: - resolution: {integrity: sha512-QAgPDQMEgrDssk1XiwwHoOGYF9BAbUcc1+j+FhEvaOt8/cKRqyLn0U5qA6F74fGhTMGxf92pOvPBeh29jQJDTQ==} - engines: {node: '>=12.0.0'} + /internal-slot@1.1.0: + resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} + engines: {node: '>= 0.4'} dependencies: - ansi-escapes: 4.3.2 - chalk: 4.1.2 - cli-cursor: 3.1.0 - cli-width: 3.0.0 - external-editor: 3.1.0 - figures: 3.2.0 - lodash: 4.17.21 - mute-stream: 0.0.8 - ora: 5.4.1 - run-async: 2.4.1 - rxjs: 7.8.1 - string-width: 4.2.3 - strip-ansi: 6.0.1 - through: 2.3.8 - wrap-ansi: 7.0.0 + es-errors: 1.3.0 + hasown: 2.0.2 + side-channel: 1.1.0 dev: true - /internal-slot@1.0.5: - resolution: {integrity: sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==} + /ipaddr.js@1.9.1: + resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} + engines: {node: '>= 0.10'} + dev: true + + /is-array-buffer@3.0.4: + resolution: {integrity: sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==} engines: {node: '>= 0.4'} dependencies: - get-intrinsic: 1.2.1 - has: 1.0.3 - side-channel: 1.0.4 + call-bind: 1.0.8 + get-intrinsic: 1.2.7 + dev: true - /is-arguments@1.1.1: - resolution: {integrity: sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==} + /is-array-buffer@3.0.5: + resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.2 - has-tostringtag: 1.0.0 + call-bind: 1.0.8 + call-bound: 1.0.3 + get-intrinsic: 1.2.7 + dev: true - /is-array-buffer@3.0.2: - resolution: {integrity: sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==} + /is-async-function@2.0.0: + resolution: {integrity: sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==} + engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.2 - get-intrinsic: 1.2.1 - is-typed-array: 1.1.10 - - /is-arrayish@0.2.1: - resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + has-tostringtag: 1.0.2 dev: true - /is-bigint@1.0.4: - resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} + /is-bigint@1.1.0: + resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==} + engines: {node: '>= 0.4'} dependencies: has-bigints: 1.0.2 - - /is-binary-path@2.1.0: - resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} - engines: {node: '>=8'} - dependencies: - binary-extensions: 2.2.0 dev: true - /is-boolean-object@1.1.2: - resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} + /is-boolean-object@1.2.1: + resolution: {integrity: sha512-l9qO6eFlUETHtuihLcYOaLKByJ1f+N4kthcU9YjHy3N+B3hWv0y/2Nd0mu/7lTFnRQHTrSdXF50HQ3bl5fEnng==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.2 - has-tostringtag: 1.0.0 + call-bound: 1.0.3 + has-tostringtag: 1.0.2 + dev: true /is-callable@1.2.7: resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} engines: {node: '>= 0.4'} + dev: true - /is-core-module@2.12.1: - resolution: {integrity: sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==} + /is-core-module@2.16.1: + resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} + engines: {node: '>= 0.4'} dependencies: - has: 1.0.3 + hasown: 2.0.2 dev: true - /is-date-object@1.0.5: - resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} + /is-data-view@1.0.1: + resolution: {integrity: sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==} engines: {node: '>= 0.4'} dependencies: - has-tostringtag: 1.0.0 + is-typed-array: 1.1.15 + dev: true - /is-docker@2.2.1: - resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} - engines: {node: '>=8'} - hasBin: true + /is-data-view@1.0.2: + resolution: {integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.3 + get-intrinsic: 1.2.7 + is-typed-array: 1.1.15 dev: true - /is-docker@3.0.0: - resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - hasBin: true + /is-date-object@1.1.0: + resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.3 + has-tostringtag: 1.0.2 dev: true /is-extglob@2.1.1: @@ -3937,6 +5381,13 @@ packages: engines: {node: '>=0.10.0'} dev: true + /is-finalizationregistry@1.1.1: + resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.3 + dev: true + /is-fullwidth-code-point@3.0.0: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} @@ -3946,7 +5397,7 @@ packages: resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==} engines: {node: '>= 0.4'} dependencies: - has-tostringtag: 1.0.0 + has-tostringtag: 1.0.2 dev: true /is-glob@4.0.3: @@ -3956,24 +5407,13 @@ packages: is-extglob: 2.1.1 dev: true - /is-inside-container@1.0.0: - resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==} - engines: {node: '>=14.16'} - hasBin: true - dependencies: - is-docker: 3.0.0 - dev: true - - /is-interactive@1.0.0: - resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==} - engines: {node: '>=8'} + /is-map@2.0.3: + resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} + engines: {node: '>= 0.4'} dev: true - /is-map@2.0.2: - resolution: {integrity: sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==} - - /is-negative-zero@2.0.2: - resolution: {integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==} + /is-negative-zero@2.0.3: + resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} engines: {node: '>= 0.4'} dev: true @@ -3981,103 +5421,126 @@ packages: resolution: {integrity: sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==} dev: true - /is-number-object@1.0.7: - resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==} + /is-number-object@1.1.1: + resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==} engines: {node: '>= 0.4'} dependencies: - has-tostringtag: 1.0.0 + call-bound: 1.0.3 + has-tostringtag: 1.0.2 + dev: true /is-number@7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} dev: true - /is-path-inside@3.0.3: - resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} - engines: {node: '>=8'} - dev: true - - /is-plain-obj@1.1.0: - resolution: {integrity: sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==} - engines: {node: '>=0.10.0'} - dev: true - /is-potential-custom-element-name@1.0.1: resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} dev: true + /is-promise@4.0.0: + resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} + dev: true + /is-regex@1.1.4: resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.2 - has-tostringtag: 1.0.0 - - /is-set@2.0.2: - resolution: {integrity: sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==} + call-bind: 1.0.8 + has-tostringtag: 1.0.2 + dev: true - /is-shared-array-buffer@1.0.2: - resolution: {integrity: sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==} + /is-regex@1.2.1: + resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} + engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.2 + call-bound: 1.0.3 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + dev: true - /is-stream@2.0.1: - resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} - engines: {node: '>=8'} + /is-set@2.0.3: + resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} + engines: {node: '>= 0.4'} dev: true - /is-stream@3.0.0: - resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + /is-shared-array-buffer@1.0.3: + resolution: {integrity: sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + dev: true + + /is-shared-array-buffer@1.0.4: + resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.3 dev: true /is-string@1.0.7: resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} engines: {node: '>= 0.4'} dependencies: - has-tostringtag: 1.0.0 + has-tostringtag: 1.0.2 + dev: true - /is-symbol@1.0.4: - resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==} + /is-string@1.1.1: + resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==} engines: {node: '>= 0.4'} dependencies: - has-symbols: 1.0.3 + call-bound: 1.0.3 + has-tostringtag: 1.0.2 + dev: true - /is-typed-array@1.1.10: - resolution: {integrity: sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==} + /is-symbol@1.1.1: + resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==} engines: {node: '>= 0.4'} 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 + call-bound: 1.0.3 + has-symbols: 1.1.0 + safe-regex-test: 1.1.0 + dev: true - /is-unicode-supported@0.1.0: - resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} - engines: {node: '>=10'} + /is-typed-array@1.1.13: + resolution: {integrity: sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==} + engines: {node: '>= 0.4'} + dependencies: + which-typed-array: 1.1.18 dev: true - /is-weakmap@2.0.1: - resolution: {integrity: sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==} + /is-typed-array@1.1.15: + resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} + engines: {node: '>= 0.4'} + dependencies: + which-typed-array: 1.1.18 + dev: true + + /is-weakmap@2.0.2: + resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} + engines: {node: '>= 0.4'} + dev: true /is-weakref@1.0.2: resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} dependencies: - call-bind: 1.0.2 + call-bind: 1.0.8 dev: true - /is-weakset@2.0.2: - resolution: {integrity: sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==} + /is-weakref@1.1.0: + resolution: {integrity: sha512-SXM8Nwyys6nT5WP6pltOwKytLV7FqQ4UiibxVmW+EIosHcmCqkkjViTb5SNssDlkCiEYRP1/pdWUKVvZBmsR2Q==} + engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.2 - get-intrinsic: 1.2.1 + call-bound: 1.0.3 + dev: true - /is-wsl@2.2.0: - resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} - engines: {node: '>=8'} + /is-weakset@2.0.3: + resolution: {integrity: sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==} + engines: {node: '>= 0.4'} dependencies: - is-docker: 2.2.1 + call-bind: 1.0.8 + get-intrinsic: 1.2.7 dev: true /isarray@0.0.1: @@ -4090,90 +5553,85 @@ packages: /isarray@2.0.5: resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + dev: true /isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} dev: true - /istanbul-lib-coverage@3.2.0: - resolution: {integrity: sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==} + /istanbul-lib-coverage@3.2.2: + resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} engines: {node: '>=8'} dev: true - /istanbul-lib-report@3.0.0: - resolution: {integrity: sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==} - engines: {node: '>=8'} + /istanbul-lib-report@3.0.1: + resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} + engines: {node: '>=10'} dependencies: - istanbul-lib-coverage: 3.2.0 - make-dir: 3.1.0 + istanbul-lib-coverage: 3.2.2 + make-dir: 4.0.0 supports-color: 7.2.0 dev: true - /istanbul-lib-source-maps@4.0.1: - resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} + /istanbul-lib-source-maps@5.0.6: + resolution: {integrity: sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==} engines: {node: '>=10'} dependencies: - debug: 4.3.4 - istanbul-lib-coverage: 3.2.0 - source-map: 0.6.1 + '@jridgewell/trace-mapping': 0.3.25 + debug: 4.4.0 + istanbul-lib-coverage: 3.2.2 transitivePeerDependencies: - supports-color dev: true - /istanbul-reports@3.1.5: - resolution: {integrity: sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==} + /istanbul-reports@3.1.7: + resolution: {integrity: sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==} engines: {node: '>=8'} dependencies: html-escaper: 2.0.2 - istanbul-lib-report: 3.0.0 + istanbul-lib-report: 3.0.1 dev: true - /jackspeak@2.2.1: - resolution: {integrity: sha512-MXbxovZ/Pm42f6cDIDkl3xpwv1AGwObKwfmjs2nQePiy85tP3fatofl3FC1aBsOtP/6fq5SbtgHwWcMsLP+bDw==} - engines: {node: '>=14'} + /iterator.prototype@1.1.5: + resolution: {integrity: sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==} + engines: {node: '>= 0.4'} + dependencies: + define-data-property: 1.1.4 + es-object-atoms: 1.0.0 + get-intrinsic: 1.2.7 + get-proto: 1.0.1 + has-symbols: 1.1.0 + set-function-name: 2.0.2 + dev: true + + /jackspeak@3.4.3: + resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} dependencies: '@isaacs/cliui': 8.0.2 optionalDependencies: '@pkgjs/parseargs': 0.11.0 dev: true - /jest-diff@27.5.1: - resolution: {integrity: sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - dependencies: - chalk: 4.1.2 - diff-sequences: 27.5.1 - jest-get-type: 27.5.1 - pretty-format: 27.5.1 - - /jest-get-type@27.5.1: - resolution: {integrity: sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - - /jest-matcher-utils@27.5.1: - resolution: {integrity: sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + /jackspeak@4.0.1: + resolution: {integrity: sha512-cub8rahkh0Q/bw1+GxP7aeSe29hHHn2V4m29nnDlvCdlgU+3UGxkZp7Z53jLUdpX3jdTO0nJZUDl3xvbWc2Xog==} + engines: {node: 20 || >=22} dependencies: - chalk: 4.1.2 - jest-diff: 27.5.1 - jest-get-type: 27.5.1 - pretty-format: 27.5.1 + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + dev: true /jju@1.4.0: resolution: {integrity: sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==} dev: true - /jquery@3.7.0: - resolution: {integrity: sha512-umpJ0/k8X0MvD1ds0P9SfowREz2LenHsQaxSohMZ5OMNEU2r0tf8pdeEFTHMFxWVxKNyU9rTtK3CWzUCTKJUeQ==} - dev: true - - /js-levenshtein@1.1.6: - resolution: {integrity: sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==} - engines: {node: '>=0.10.0'} + /jquery@3.7.1: + resolution: {integrity: sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg==} dev: true /js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + dev: true /js-yaml@4.1.0: resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} @@ -4182,64 +5640,100 @@ packages: argparse: 2.0.1 dev: true - /jsdoctypeparser@9.0.0: - resolution: {integrity: sha512-jrTA2jJIL6/DAEILBEh2/w9QxCuwmvNXIry39Ay/HVfhE3o2yVV0U44blYkqdHA/OKloJEqvJy0xU+GSdE2SIw==} - engines: {node: '>=10'} - hasBin: true + /jsdoc-type-pratt-parser@4.0.0: + resolution: {integrity: sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ==} + engines: {node: '>=12.0.0'} + dev: true + + /jsdom@26.0.0: + resolution: {integrity: sha512-BZYDGVAIriBWTpIxYzrXjv3E/4u8+/pSG5bQdIYCbNCGOvsPkDQfTVLAIXAf9ETdCpduCVTkDe2NNZ8NIwUVzw==} + engines: {node: '>=18'} + peerDependencies: + canvas: ^3.0.0 + peerDependenciesMeta: + canvas: + optional: true + dependencies: + cssstyle: 4.2.1 + data-urls: 5.0.0 + decimal.js: 10.4.3 + form-data: 4.0.1 + html-encoding-sniffer: 4.0.0 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.6 + is-potential-custom-element-name: 1.0.1 + nwsapi: 2.2.16 + parse5: 7.2.1 + rrweb-cssom: 0.8.0 + saxes: 6.0.0 + symbol-tree: 3.2.4 + tough-cookie: 5.1.0 + w3c-xmlserializer: 5.0.0 + webidl-conversions: 7.0.0 + whatwg-encoding: 3.1.1 + whatwg-mimetype: 4.0.0 + whatwg-url: 14.1.0 + ws: 8.18.0 + xml-name-validator: 5.0.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate dev: true - /jsdom@22.1.0: - resolution: {integrity: sha512-/9AVW7xNbsBv6GfWho4TTNjEo9fe6Zhf9O7s0Fhhr3u+awPwAJMKwAMXnkk5vBxflqLW9hTHX/0cs+P3gW+cQw==} - engines: {node: '>=16'} + /jsdom@26.1.0: + resolution: {integrity: sha512-Cvc9WUhxSMEo4McES3P7oK3QaXldCfNWp7pl2NNeiIFlCoLr3kfq9kb1fxftiwk1FLV7CvpvDfonxtzUDeSOPg==} + engines: {node: '>=18'} peerDependencies: - canvas: ^2.5.0 + canvas: ^3.0.0 peerDependenciesMeta: canvas: optional: true dependencies: - abab: 2.0.6 - cssstyle: 3.0.0 - data-urls: 4.0.0 - decimal.js: 10.4.3 - domexception: 4.0.0 - form-data: 4.0.0 - html-encoding-sniffer: 3.0.0 - http-proxy-agent: 5.0.0 - https-proxy-agent: 5.0.1 + cssstyle: 4.2.1 + data-urls: 5.0.0 + decimal.js: 10.5.0 + html-encoding-sniffer: 4.0.0 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.6 is-potential-custom-element-name: 1.0.1 - nwsapi: 2.2.7 - parse5: 7.1.2 - rrweb-cssom: 0.6.0 + nwsapi: 2.2.16 + parse5: 7.2.1 + rrweb-cssom: 0.8.0 saxes: 6.0.0 symbol-tree: 3.2.4 - tough-cookie: 4.1.3 - w3c-xmlserializer: 4.0.0 + tough-cookie: 5.1.2 + w3c-xmlserializer: 5.0.0 webidl-conversions: 7.0.0 - whatwg-encoding: 2.0.0 - whatwg-mimetype: 3.0.0 - whatwg-url: 12.0.1 - ws: 8.13.0 - xml-name-validator: 4.0.0 + whatwg-encoding: 3.1.1 + whatwg-mimetype: 4.0.0 + whatwg-url: 14.2.0 + ws: 8.18.0 + xml-name-validator: 5.0.0 transitivePeerDependencies: - bufferutil - supports-color - utf-8-validate dev: true - /jsesc@2.5.2: - resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} - engines: {node: '>=4'} + /jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} hasBin: true dev: true - /json-parse-even-better-errors@2.3.1: - resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + /json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} dev: true /json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} dev: true + /json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + dev: true + /json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} dev: true @@ -4257,24 +5751,28 @@ packages: hasBin: true dev: true - /jsonc-parser@3.2.0: - resolution: {integrity: sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==} - dev: true - /jsonfile@4.0.0: resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} optionalDependencies: graceful-fs: 4.2.11 dev: true - /jsx-ast-utils@3.3.4: - resolution: {integrity: sha512-fX2TVdCViod6HwKEtSWGHs57oFhVfCMwieb9PuRDgjDPh5XeqJiHFFFJCHxU5cnTc3Bu/GRL+kPiFmw8XWOfKw==} + /jsonfile@6.1.0: + resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} + dependencies: + universalify: 2.0.1 + optionalDependencies: + graceful-fs: 4.2.11 + dev: true + + /jsx-ast-utils@3.3.5: + resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} engines: {node: '>=4.0'} dependencies: - array-includes: 3.1.6 - array.prototype.flat: 1.3.1 - object.assign: 4.1.4 - object.values: 1.1.6 + array-includes: 3.1.8 + array.prototype.flat: 1.3.2 + object.assign: 4.1.5 + object.values: 1.2.0 dev: true /junk@4.0.1: @@ -4282,9 +5780,10 @@ packages: engines: {node: '>=12.20'} dev: true - /kind-of@6.0.3: - resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} - engines: {node: '>=0.10.0'} + /keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + dependencies: + json-buffer: 3.0.1 dev: true /kolorist@1.8.0: @@ -4295,8 +5794,9 @@ packages: resolution: {integrity: sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==} dev: true - /language-tags@1.0.5: - resolution: {integrity: sha512-qJhlO9cGXi6hBGKoxEG/sKZDAHD5Hnu9Hs4WbOY3pCWXDhw0N8x1NenNzm2EnNLkLkk7J2SdxAkDSbb6ftT+UQ==} + /language-tags@1.0.9: + resolution: {integrity: sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==} + engines: {node: '>=0.10'} dependencies: language-subtag-registry: 0.3.22 dev: true @@ -4309,13 +5809,21 @@ packages: type-check: 0.4.0 dev: true - /lines-and-columns@1.2.4: - resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + /local-pkg@0.5.1: + resolution: {integrity: sha512-9rrA30MRRP3gBD3HTGnC6cDFpaE1kVDWxWgqWJUN0RvDNAo+Nz/9GxB+nHOH0ifbVFy0hSA1V6vFDvnx54lTEQ==} + engines: {node: '>=14'} + dependencies: + mlly: 1.7.4 + pkg-types: 1.3.0 dev: true - /local-pkg@0.4.3: - resolution: {integrity: sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==} + /local-pkg@1.1.1: + resolution: {integrity: sha512-WunYko2W1NcdfAFpuLUoucsgULmgDBRkdxHxWQ7mK0cQqwPiy8E1enjuRBrhLtZkB5iScJ1XIPdhVEFK8aOLSg==} engines: {node: '>=14'} + dependencies: + mlly: 1.7.4 + pkg-types: 2.1.0 + quansync: 0.2.10 dev: true /locate-path@6.0.0: @@ -4325,34 +5833,12 @@ packages: p-locate: 5.0.0 dev: true - /locate-path@7.2.0: - resolution: {integrity: sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - dependencies: - p-locate: 6.0.0 - dev: true - - /lodash.get@4.4.2: - resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==} - dev: true - - /lodash.isequal@4.5.0: - resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==} - dev: true - /lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} dev: true /lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} - - /log-symbols@4.1.0: - resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} - engines: {node: '>=10'} - dependencies: - chalk: 4.1.2 - is-unicode-supported: 0.1.0 dev: true /loose-envify@1.4.0: @@ -4360,18 +5846,22 @@ packages: hasBin: true dependencies: js-tokens: 4.0.0 + dev: true - /loupe@2.3.6: - resolution: {integrity: sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==} - dependencies: - get-func-name: 2.0.0 + /loupe@3.1.3: + resolution: {integrity: sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug==} dev: true - /lru-cache@10.0.0: - resolution: {integrity: sha512-svTf/fzsKHffP42sujkO/Rjs37BCIsQVRCeNYIm9WN8rgT7ffoUnRtZCqU+6BqcSBdv8gwJeTz8knJpgACeQMw==} + /lru-cache@10.2.0: + resolution: {integrity: sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==} engines: {node: 14 || >=16.14} dev: true + /lru-cache@11.0.2: + resolution: {integrity: sha512-123qHRfJBmo2jXDbo/a5YOQrJoHF/GNQTLzQ5+IdK5pWpceK17yRc6ozlWd25FxvGKQbIUs91fDFkXmDHTKcyA==} + engines: {node: 20 || >=22} + dev: true + /lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} dependencies: @@ -4385,54 +5875,50 @@ packages: yallist: 4.0.0 dev: true - /lru-cache@7.18.3: - resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} - engines: {node: '>=12'} - dev: true - /lz-string@1.5.0: resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} hasBin: true + dev: true - /magic-string@0.30.1: - resolution: {integrity: sha512-mbVKXPmS0z0G4XqFDCTllmDQ6coZzn94aMlb0o/A4HEHJCKcanlDZwYJgwnkmgD3jyWhUgj9VsPrfd972yPffA==} - engines: {node: '>=12'} + /magic-string@0.30.17: + resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} dependencies: - '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/sourcemap-codec': 1.5.0 dev: true - /make-dir@3.1.0: - resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==} - engines: {node: '>=8'} + /magicast@0.3.5: + resolution: {integrity: sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==} dependencies: - semver: 6.3.1 + '@babel/parser': 7.26.5 + '@babel/types': 7.26.5 + source-map-js: 1.2.1 dev: true - /map-obj@4.3.0: - resolution: {integrity: sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==} - engines: {node: '>=8'} + /make-dir@4.0.0: + resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} + engines: {node: '>=10'} + dependencies: + semver: 7.6.3 + dev: true + + /math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} dev: true - /meow@12.0.1: - resolution: {integrity: sha512-/QOqMALNoKQcJAOOdIXjNLtfcCdLXbMFyB1fOOPdm6RzfBTlsuodOCTBDjVbeUSmgDQb8UI2oONqYGtq1PKKKA==} + /media-typer@1.1.0: + resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} + engines: {node: '>= 0.8'} + dev: true + + /meow@12.1.1: + resolution: {integrity: sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw==} engines: {node: '>=16.10'} - dependencies: - '@types/minimist': 1.2.2 - camelcase-keys: 8.0.2 - decamelize: 6.0.0 - decamelize-keys: 2.0.1 - hard-rejection: 2.1.0 - minimist-options: 4.1.0 - normalize-package-data: 5.0.0 - read-pkg-up: 9.1.0 - redent: 4.0.0 - trim-newlines: 5.0.0 - type-fest: 3.13.1 - yargs-parser: 21.1.1 dev: true - /merge-stream@2.0.0: - resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + /merge-descriptors@2.0.0: + resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} + engines: {node: '>=18'} dev: true /merge2@1.4.1: @@ -4440,11 +5926,11 @@ packages: engines: {node: '>= 8'} dev: true - /micromatch@4.0.5: - resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} + /micromatch@4.0.7: + resolution: {integrity: sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==} engines: {node: '>=8.6'} dependencies: - braces: 3.0.2 + braces: 3.0.3 picomatch: 2.3.1 dev: true @@ -4453,6 +5939,11 @@ packages: engines: {node: '>= 0.6'} dev: true + /mime-db@1.54.0: + resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} + engines: {node: '>= 0.6'} + dev: true + /mime-types@2.1.35: resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} engines: {node: '>= 0.6'} @@ -4460,19 +5951,30 @@ packages: mime-db: 1.52.0 dev: true - /mimic-fn@2.1.0: - resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} - engines: {node: '>=6'} - dev: true - - /mimic-fn@4.0.0: - resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} - engines: {node: '>=12'} + /mime-types@3.0.1: + resolution: {integrity: sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==} + engines: {node: '>= 0.6'} + dependencies: + mime-db: 1.54.0 dev: true /min-indent@1.0.1: resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} engines: {node: '>=4'} + dev: true + + /minimatch@10.0.1: + resolution: {integrity: sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==} + engines: {node: 20 || >=22} + dependencies: + brace-expansion: 2.0.1 + dev: true + + /minimatch@3.0.8: + resolution: {integrity: sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==} + dependencies: + brace-expansion: 1.1.11 + dev: true /minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} @@ -4480,28 +5982,19 @@ packages: brace-expansion: 1.1.11 dev: true - /minimatch@9.0.3: - resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==} + /minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} engines: {node: '>=16 || 14 >=14.17'} dependencies: brace-expansion: 2.0.1 dev: true - /minimist-options@4.1.0: - resolution: {integrity: sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==} - engines: {node: '>= 6'} - dependencies: - arrify: 1.0.1 - is-plain-obj: 1.1.0 - kind-of: 6.0.3 - dev: true - /minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} dev: true - /minipass@7.0.2: - resolution: {integrity: sha512-eL79dXrE1q9dBbDCLg7xfn/vl7MS4F1gvJAgjJrQli/jbQWdUttuVawphqpffoIYfRdq78LHx6GP4bU/EQ2ATA==} + /minipass@7.1.2: + resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} engines: {node: '>=16 || 14 >=14.17'} dev: true @@ -4511,141 +6004,121 @@ packages: hasBin: true dev: true - /mlly@1.4.0: - resolution: {integrity: sha512-ua8PAThnTwpprIaU47EPeZ/bPUVp2QYBbWMphUQpVdBI3Lgqzm5KZQ45Agm3YJedHXaIHl6pBGabaLSUPPSptg==} + /mlly@1.7.4: + resolution: {integrity: sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==} dependencies: - acorn: 8.10.0 - pathe: 1.1.1 - pkg-types: 1.0.3 - ufo: 1.1.2 - dev: true - - /ms@2.1.2: - resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + acorn: 8.14.0 + pathe: 2.0.3 + pkg-types: 1.3.0 + ufo: 1.5.4 dev: true /ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} dev: true - /msw@1.2.2(typescript@5.1.6): - resolution: {integrity: sha512-GsW3PE/Es/a1tYThXcM8YHOZ1S1MtivcS3He/LQbbTCx3rbWJYCtWD5XXyJ53KlNPT7O1VI9sCW3xMtgFe8XpQ==} - engines: {node: '>=14'} + /msw@2.7.6(@types/node@20.11.26)(typescript@5.8.3): + resolution: {integrity: sha512-P+rwn43ktxN8ghcl8q+hSAUlEi0PbJpDhGmDkw4zeUnRj3hBCVynWD+dTu38yLYKCE9ZF1OYcvpy7CTBRcqkZA==} + engines: {node: '>=18'} hasBin: true requiresBuild: true peerDependencies: - typescript: '>= 4.4.x <= 5.1.x' + typescript: '>= 4.8.x' peerDependenciesMeta: typescript: optional: true dependencies: - '@mswjs/cookies': 0.2.2 - '@mswjs/interceptors': 0.17.9 - '@open-draft/until': 1.0.3 - '@types/cookie': 0.4.1 - '@types/js-levenshtein': 1.1.1 - chalk: 4.1.1 - chokidar: 3.5.3 - cookie: 0.4.2 - graphql: 16.7.1 - headers-polyfill: 3.1.2 - inquirer: 8.2.5 + '@bundled-es-modules/cookie': 2.0.1 + '@bundled-es-modules/statuses': 1.0.1 + '@bundled-es-modules/tough-cookie': 0.1.6 + '@inquirer/confirm': 5.1.2(@types/node@20.11.26) + '@mswjs/interceptors': 0.37.5 + '@open-draft/deferred-promise': 2.2.0 + '@open-draft/until': 2.1.0 + '@types/cookie': 0.6.0 + '@types/statuses': 2.0.4 + graphql: 16.10.0 + headers-polyfill: 4.0.2 is-node-process: 1.2.0 - js-levenshtein: 1.1.6 - node-fetch: 2.6.12 - outvariant: 1.4.0 - path-to-regexp: 6.2.1 - strict-event-emitter: 0.4.6 - type-fest: 2.19.0 - typescript: 5.1.6 + outvariant: 1.4.3 + path-to-regexp: 6.3.0 + picocolors: 1.1.1 + strict-event-emitter: 0.5.1 + type-fest: 4.32.0 + typescript: 5.8.3 yargs: 17.7.2 transitivePeerDependencies: - - encoding - - supports-color + - '@types/node' dev: true - /muggle-string@0.3.1: - resolution: {integrity: sha512-ckmWDJjphvd/FvZawgygcUeQCxzvohjFO5RxTjj4eq8kw359gFF3E1brjfI+viLMxss5JrHTDRHZvu2/tuy0Qg==} + /muggle-string@0.4.1: + resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==} dev: true - /mute-stream@0.0.8: - resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==} + /mute-stream@2.0.0: + resolution: {integrity: sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==} + engines: {node: ^18.17.0 || >=20.5.0} dev: true - /nanoid@3.3.6: - resolution: {integrity: sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==} + /nanoid@3.3.11: + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true - /natural-compare-lite@1.4.0: - resolution: {integrity: sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==} - dev: true - /natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} dev: true + /negotiator@1.0.0: + resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} + engines: {node: '>= 0.6'} + dev: true + /nested-error-stacks@2.1.1: resolution: {integrity: sha512-9iN1ka/9zmX1ZvLV9ewJYEk9h7RyRRtqdK0woXcqohu8EWIerfPUjYJPg0ULy0UqP7cslmdGc8xKDJcojlKiaw==} dev: true - /next@13.4.10(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-4ep6aKxVTQ7rkUW2fBLhpBr/5oceCuf4KmlUpvG/aXuDTIf9mexNSpabUD6RWPspu6wiJJvozZREhXhueYO36A==} - engines: {node: '>=16.8.0'} + /next@14.1.0(react-dom@19.1.0)(react@19.1.0): + resolution: {integrity: sha512-wlzrsbfeSU48YQBjZhDzOwhWhGsy+uQycR8bHAOt1LY1bn3zZEcDyHQOEoN3aWzQ8LHCAJ1nqrWCc9XF2+O45Q==} + engines: {node: '>=18.17.0'} hasBin: true peerDependencies: '@opentelemetry/api': ^1.1.0 - fibers: '>= 3.1.0' react: ^18.2.0 react-dom: ^18.2.0 sass: ^1.3.0 peerDependenciesMeta: '@opentelemetry/api': optional: true - fibers: - optional: true sass: optional: true dependencies: - '@next/env': 13.4.10 - '@swc/helpers': 0.5.1 + '@next/env': 14.1.0 + '@swc/helpers': 0.5.2 busboy: 1.6.0 - caniuse-lite: 1.0.30001516 - postcss: 8.4.14 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - styled-jsx: 5.1.1(react@18.2.0) - watchpack: 2.4.0 - zod: 3.21.4 + caniuse-lite: 1.0.30001692 + graceful-fs: 4.2.11 + postcss: 8.4.31 + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + styled-jsx: 5.1.1(react@19.1.0) optionalDependencies: - '@next/swc-darwin-arm64': 13.4.10 - '@next/swc-darwin-x64': 13.4.10 - '@next/swc-linux-arm64-gnu': 13.4.10 - '@next/swc-linux-arm64-musl': 13.4.10 - '@next/swc-linux-x64-gnu': 13.4.10 - '@next/swc-linux-x64-musl': 13.4.10 - '@next/swc-win32-arm64-msvc': 13.4.10 - '@next/swc-win32-ia32-msvc': 13.4.10 - '@next/swc-win32-x64-msvc': 13.4.10 + '@next/swc-darwin-arm64': 14.1.0 + '@next/swc-darwin-x64': 14.1.0 + '@next/swc-linux-arm64-gnu': 14.1.0 + '@next/swc-linux-arm64-musl': 14.1.0 + '@next/swc-linux-x64-gnu': 14.1.0 + '@next/swc-linux-x64-musl': 14.1.0 + '@next/swc-win32-arm64-msvc': 14.1.0 + '@next/swc-win32-ia32-msvc': 14.1.0 + '@next/swc-win32-x64-msvc': 14.1.0 transitivePeerDependencies: - '@babel/core' - babel-plugin-macros dev: false - /node-fetch@2.6.12: - resolution: {integrity: sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g==} - engines: {node: 4.x || >=6.0.0} - peerDependencies: - encoding: ^0.1.0 - peerDependenciesMeta: - encoding: - optional: true - dependencies: - whatwg-url: 5.0.0 - dev: true - - /node-releases@2.0.13: - resolution: {integrity: sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==} + /node-releases@2.0.19: + resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} dev: true /noms@0.0.0: @@ -4655,47 +6128,8 @@ packages: readable-stream: 1.0.34 dev: true - /normalize-package-data@3.0.3: - resolution: {integrity: sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==} - engines: {node: '>=10'} - dependencies: - hosted-git-info: 4.1.0 - is-core-module: 2.12.1 - semver: 7.5.4 - validate-npm-package-license: 3.0.4 - dev: true - - /normalize-package-data@5.0.0: - resolution: {integrity: sha512-h9iPVIfrVZ9wVYQnxFgtw1ugSvGEMOlyPWWtm8BMJhnwyEL/FLbYbTY3V3PpjI/BUK67n9PEWDu6eHzu1fB15Q==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - dependencies: - hosted-git-info: 6.1.1 - is-core-module: 2.12.1 - semver: 7.5.4 - validate-npm-package-license: 3.0.4 - dev: true - - /normalize-path@3.0.0: - resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} - engines: {node: '>=0.10.0'} - dev: true - - /npm-run-path@4.0.1: - resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} - engines: {node: '>=8'} - dependencies: - path-key: 3.1.1 - dev: true - - /npm-run-path@5.1.0: - resolution: {integrity: sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - dependencies: - path-key: 4.0.0 - dev: true - - /nwsapi@2.2.7: - resolution: {integrity: sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==} + /nwsapi@2.2.16: + resolution: {integrity: sha512-F1I/bimDpj3ncaNDhfyMWuFqmQDBwDB0Fogc2qpL3BWvkQteFD/8BzWuIRl83rq0DXfm8SGt/HFhLXZyljTXcQ==} dev: true /object-assign@4.1.1: @@ -4703,91 +6137,102 @@ packages: engines: {node: '>=0.10.0'} dev: true - /object-inspect@1.12.3: - resolution: {integrity: sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==} + /object-inspect@1.13.2: + resolution: {integrity: sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==} + engines: {node: '>= 0.4'} + dev: true - /object-is@1.1.5: - resolution: {integrity: sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==} + /object-inspect@1.13.3: + resolution: {integrity: sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==} engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.2 - define-properties: 1.2.0 + dev: true /object-keys@1.1.1: resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} engines: {node: '>= 0.4'} + dev: true - /object.assign@4.1.4: - resolution: {integrity: sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==} + /object.assign@4.1.5: + resolution: {integrity: sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.2 - define-properties: 1.2.0 - has-symbols: 1.0.3 + call-bind: 1.0.8 + define-properties: 1.2.1 + has-symbols: 1.1.0 object-keys: 1.1.1 + dev: true - /object.entries@1.1.6: - resolution: {integrity: sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w==} + /object.assign@4.1.7: + resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.2 - define-properties: 1.2.0 - es-abstract: 1.21.3 + call-bind: 1.0.8 + call-bound: 1.0.3 + define-properties: 1.2.1 + es-object-atoms: 1.0.0 + has-symbols: 1.1.0 + object-keys: 1.1.1 dev: true - /object.fromentries@2.0.6: - resolution: {integrity: sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg==} + /object.entries@1.1.9: + resolution: {integrity: sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.2 - define-properties: 1.2.0 - es-abstract: 1.21.3 + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 dev: true - /object.hasown@1.1.2: - resolution: {integrity: sha512-B5UIT3J1W+WuWIU55h0mjlwaqxiE5vYENJXIXZ4VFe05pNYrkKuK0U/6aFcb0pKywYJh7IhfoqUfKVmrJJHZHw==} + /object.fromentries@2.0.8: + resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==} + engines: {node: '>= 0.4'} dependencies: - define-properties: 1.2.0 - es-abstract: 1.21.3 + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-object-atoms: 1.0.0 dev: true - /object.values@1.1.6: - resolution: {integrity: sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==} + /object.groupby@1.0.3: + resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.2 - define-properties: 1.2.0 - es-abstract: 1.21.3 + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 dev: true - /once@1.4.0: - resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + /object.values@1.2.0: + resolution: {integrity: sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==} + engines: {node: '>= 0.4'} dependencies: - wrappy: 1.0.2 + call-bind: 1.0.7 + define-properties: 1.2.1 + es-object-atoms: 1.0.0 dev: true - /onetime@5.1.2: - resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} - engines: {node: '>=6'} + /object.values@1.2.1: + resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==} + engines: {node: '>= 0.4'} dependencies: - mimic-fn: 2.1.0 + call-bind: 1.0.8 + call-bound: 1.0.3 + define-properties: 1.2.1 + es-object-atoms: 1.0.0 dev: true - /onetime@6.0.0: - resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} - engines: {node: '>=12'} + /on-finished@2.4.1: + resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} + engines: {node: '>= 0.8'} dependencies: - mimic-fn: 4.0.0 + ee-first: 1.1.1 dev: true - /open@9.1.0: - resolution: {integrity: sha512-OS+QTnw1/4vrf+9hh1jc1jnYjzSG4ttTBB8UxOwAnInG3Uo4ssetzC1ihqaIHjLJnA5GGlRl6QlZXOTQhRBUvg==} - engines: {node: '>=14.16'} + /once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} dependencies: - default-browser: 4.0.0 - define-lazy-prop: 3.0.0 - is-inside-container: 1.0.0 - is-wsl: 2.2.0 + wrappy: 1.0.2 dev: true /optionator@0.9.3: @@ -4802,28 +6247,17 @@ packages: type-check: 0.4.0 dev: true - /ora@5.4.1: - resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==} - engines: {node: '>=10'} - dependencies: - bl: 4.1.0 - chalk: 4.1.2 - cli-cursor: 3.1.0 - cli-spinners: 2.9.0 - is-interactive: 1.0.0 - is-unicode-supported: 0.1.0 - log-symbols: 4.1.0 - strip-ansi: 6.0.1 - wcwidth: 1.0.1 - dev: true - - /os-tmpdir@1.0.2: - resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} - engines: {node: '>=0.10.0'} + /outvariant@1.4.3: + resolution: {integrity: sha512-+Sl2UErvtsoajRDKCE5/dBz4DIvHXQQnAxtQTF04OJxY0+DyZXSo5P5Bb7XYWOh81syohlYL24hbDwxedPUJCA==} dev: true - /outvariant@1.4.0: - resolution: {integrity: sha512-AlWY719RF02ujitly7Kk/0QlV+pXGFDHrHf9O2OKqyqgBieaPOIeuSkL8sRK6j2WK+/ZAURq2kZsY0d8JapUiw==} + /own-keys@1.0.1: + resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} + engines: {node: '>= 0.4'} + dependencies: + get-intrinsic: 1.2.7 + object-keys: 1.1.1 + safe-push-apply: 1.0.0 dev: true /p-event@5.0.1: @@ -4833,6 +6267,13 @@ packages: p-timeout: 5.1.0 dev: true + /p-event@6.0.0: + resolution: {integrity: sha512-Xbfxd0CfZmHLGKXH32k1JKjQYX6Rkv0UtQdaFJ8OyNcf+c0oWCeXHc1C4CX/IESZLmcvfPa5aFIO/vCr5gqtag==} + engines: {node: '>=16.17'} + dependencies: + p-timeout: 6.1.2 + dev: true + /p-filter@3.0.0: resolution: {integrity: sha512-QtoWLjXAW++uTX67HZQz1dbTpqBfiidsB6VtQUC9iR85S120+s0T5sO6s+B5MLzFcZkrEd/DGMmCjR+f2Qpxwg==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -4840,6 +6281,13 @@ packages: p-map: 5.5.0 dev: true + /p-filter@4.1.0: + resolution: {integrity: sha512-37/tPdZ3oJwHaS3gNJdenCDB3Tz26i9sjhnguBtvN0vYlRIiDNnvTWkuh+0hETV9rLPdJ3rlL3yVOYPIAnM8rw==} + engines: {node: '>=18'} + dependencies: + p-map: 7.0.2 + dev: true + /p-limit@3.1.0: resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} engines: {node: '>=10'} @@ -4847,13 +6295,6 @@ packages: yocto-queue: 0.1.0 dev: true - /p-limit@4.0.0: - resolution: {integrity: sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - dependencies: - yocto-queue: 1.0.0 - dev: true - /p-locate@5.0.0: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} @@ -4861,13 +6302,6 @@ packages: p-limit: 3.1.0 dev: true - /p-locate@6.0.0: - resolution: {integrity: sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - dependencies: - p-limit: 4.0.0 - dev: true - /p-map@5.5.0: resolution: {integrity: sha512-VFqfGDHlx87K66yZrNdI4YGtD70IRyd+zSvgks6mzHPRNkoKy+9EKP4SFC77/vTTQYmRmti7dvqC+m5jBrBAcg==} engines: {node: '>=12'} @@ -4880,11 +6314,25 @@ packages: engines: {node: '>=16'} dev: true + /p-map@7.0.2: + resolution: {integrity: sha512-z4cYYMMdKHzw4O5UkWJImbZynVIo0lSGTXc7bzB1e/rrDqkgGUNysK/o4bTr+0+xKvvLoTyGqYC4Fgljy9qe1Q==} + engines: {node: '>=18'} + dev: true + /p-timeout@5.1.0: resolution: {integrity: sha512-auFDyzzzGZZZdHz3BtET9VEz0SE/uMEAx7uWfGPucfzEwwe/xH0iVeZibQmANYE/hp9T2+UUZT5m+BKyrDp3Ew==} engines: {node: '>=12'} dev: true + /p-timeout@6.1.2: + resolution: {integrity: sha512-UbD77BuZ9Bc9aABo74gfXhNvzC9Tx7SxtHSh1fxvx3jTLLYvmVhiQZZrJzqqU0jKbN32kb5VOKiLEQI/3bIjgQ==} + engines: {node: '>=14.16'} + dev: true + + /package-json-from-dist@1.0.0: + resolution: {integrity: sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==} + dev: true + /parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} @@ -4892,20 +6340,19 @@ packages: callsites: 3.1.0 dev: true - /parse-json@5.2.0: - resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} - engines: {node: '>=8'} + /parse5@7.2.1: + resolution: {integrity: sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==} dependencies: - '@babel/code-frame': 7.22.5 - error-ex: 1.3.2 - json-parse-even-better-errors: 2.3.1 - lines-and-columns: 1.2.4 + entities: 4.5.0 dev: true - /parse5@7.1.2: - resolution: {integrity: sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==} - dependencies: - entities: 4.5.0 + /parseurl@1.3.3: + resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} + engines: {node: '>= 0.8'} + dev: true + + /path-browserify@1.0.1: + resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} dev: true /path-exists@4.0.0: @@ -4913,11 +6360,6 @@ packages: engines: {node: '>=8'} dev: true - /path-exists@5.0.0: - resolution: {integrity: sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - dev: true - /path-is-absolute@1.0.1: resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} engines: {node: '>=0.10.0'} @@ -4928,25 +6370,33 @@ packages: engines: {node: '>=8'} dev: true - /path-key@4.0.0: - resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} - engines: {node: '>=12'} - dev: true - /path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} dev: true - /path-scurry@1.10.1: - resolution: {integrity: sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==} - engines: {node: '>=16 || 14 >=14.17'} + /path-scurry@1.11.1: + resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} + engines: {node: '>=16 || 14 >=14.18'} + dependencies: + lru-cache: 10.2.0 + minipass: 7.1.2 + dev: true + + /path-scurry@2.0.0: + resolution: {integrity: sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==} + engines: {node: 20 || >=22} dependencies: - lru-cache: 10.0.0 - minipass: 7.0.2 + lru-cache: 11.0.2 + minipass: 7.1.2 + dev: true + + /path-to-regexp@6.3.0: + resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==} dev: true - /path-to-regexp@6.2.1: - resolution: {integrity: sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==} + /path-to-regexp@8.2.0: + resolution: {integrity: sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==} + engines: {node: '>=16'} dev: true /path-type@4.0.0: @@ -4954,28 +6404,56 @@ packages: engines: {node: '>=8'} dev: true - /pathe@1.1.1: - resolution: {integrity: sha512-d+RQGp0MAYTIaDBIMmOfMwz3E+LOZnxx1HZd5R18mmCZY0QBlK0LDZfPc8FW8Ed2DlvsuE6PRjroDY+wg4+j/Q==} + /path-type@5.0.0: + resolution: {integrity: sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg==} + engines: {node: '>=12'} + dev: true + + /pathe@1.1.2: + resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} dev: true - /pathval@1.1.1: - resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} + /pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} dev: true - /picocolors@1.0.0: - resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} + /pathval@2.0.0: + resolution: {integrity: sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==} + engines: {node: '>= 14.16'} + dev: true + + /picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} /picomatch@2.3.1: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} dev: true - /pkg-types@1.0.3: - resolution: {integrity: sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A==} + /picomatch@4.0.2: + resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} + engines: {node: '>=12'} + dev: true + + /pkce-challenge@5.0.0: + resolution: {integrity: sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ==} + engines: {node: '>=16.20.0'} + dev: true + + /pkg-types@1.3.0: + resolution: {integrity: sha512-kS7yWjVFCkIw9hqdJBoMxDdzEngmkr5FXeWZZfQ6GoYacjVnsW6l2CcYW/0ThD0vF4LPJgVYnrg4d0uuhwYQbg==} + dependencies: + confbox: 0.1.8 + mlly: 1.7.4 + pathe: 1.1.2 + dev: true + + /pkg-types@2.1.0: + resolution: {integrity: sha512-wmJwA+8ihJixSoHKxZJRBQG1oY8Yr9pGLzRmSsNms0iNWyHHAlZCa7mmKiFR10YPZuz/2k169JiS/inOjBCZ2A==} dependencies: - jsonc-parser: 3.2.0 - mlly: 1.4.0 - pathe: 1.1.1 + confbox: 0.2.1 + exsolve: 1.0.4 + pathe: 2.0.3 dev: true /popper.js@1.16.1: @@ -4983,22 +6461,45 @@ packages: deprecated: You can find the new Popper v2 at @popperjs/core, this package is dedicated to the legacy v1 dev: true - /postcss@8.4.14: - resolution: {integrity: sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==} + /possible-typed-array-names@1.0.0: + resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} + engines: {node: '>= 0.4'} + dev: true + + /postcss@8.4.31: + resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} engines: {node: ^10 || ^12 || >=14} dependencies: - nanoid: 3.3.6 - picocolors: 1.0.0 - source-map-js: 1.0.2 + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 dev: false - /postcss@8.4.26: - resolution: {integrity: sha512-jrXHFF8iTloAenySjM/ob3gSj7pCu0Ji49hnjqzsgSRa50hkWCKD0HQ+gMNJkW38jBI68MpAAg7ZWwHwX8NMMw==} + /postcss@8.4.35: + resolution: {integrity: sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==} + engines: {node: ^10 || ^12 || >=14} + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + dev: true + + /postcss@8.4.49: + resolution: {integrity: sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==} + engines: {node: ^10 || ^12 || >=14} + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + dev: true + + /postcss@8.5.3: + resolution: {integrity: sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==} engines: {node: ^10 || ^12 || >=14} dependencies: - nanoid: 3.3.6 - picocolors: 1.0.0 - source-map-js: 1.0.2 + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 dev: true /prelude-ls@1.2.1: @@ -5006,6 +6507,19 @@ packages: engines: {node: '>= 0.8.0'} dev: true + /prettier-linter-helpers@1.0.0: + resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==} + engines: {node: '>=6.0.0'} + dependencies: + fast-diff: 1.3.0 + dev: true + + /prettier@3.5.3: + resolution: {integrity: sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==} + engines: {node: '>=14'} + hasBin: true + dev: true + /pretty-format@27.5.1: resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} @@ -5013,14 +6527,6 @@ packages: ansi-regex: 5.0.1 ansi-styles: 5.2.0 react-is: 17.0.2 - - /pretty-format@29.6.1: - resolution: {integrity: sha512-7jRj+yXO0W7e4/tSJKoR7HRIHLPPjtNaUGG2xxKQnGvPNRkgWcQ0AZX6P4KBRJN4FcTBWb3sa7DVUJmocYuoog==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/schemas': 29.6.0 - ansi-styles: 5.2.0 - react-is: 18.2.0 dev: true /process-nextick-args@2.0.1: @@ -5035,15 +6541,34 @@ packages: react-is: 16.13.1 dev: true + /proxy-addr@2.0.7: + resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} + engines: {node: '>= 0.10'} + dependencies: + forwarded: 0.2.0 + ipaddr.js: 1.9.1 + dev: true + /psl@1.9.0: resolution: {integrity: sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==} dev: true - /punycode@2.3.0: - resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==} + /punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} dev: true + /qs@6.14.0: + resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==} + engines: {node: '>=0.6'} + dependencies: + side-channel: 1.1.0 + dev: true + + /quansync@0.2.10: + resolution: {integrity: sha512-t41VRkMYbkHyCYmOvx/6URnN80H7k4X0lLdBMGsz+maAwrJQYB1djpV6vHrQIBE0WBSGqhtEHrK9U3DWWH8v7A==} + dev: true + /querystringify@2.2.0: resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} dev: true @@ -5052,19 +6577,36 @@ packages: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} dev: true - /quick-lru@6.1.1: - resolution: {integrity: sha512-S27GBT+F0NTRiehtbrgaSE1idUAJ5bX8dPAQTdylEyNlrdcH5X4Lz7Edz3DYzecbsCluD5zO8ZNEe04z3D3u6Q==} - engines: {node: '>=12'} + /range-parser@1.2.1: + resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} + engines: {node: '>= 0.6'} dev: true - /react-dom@18.2.0(react@18.2.0): - resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==} + /raw-body@3.0.0: + resolution: {integrity: sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==} + engines: {node: '>= 0.8'} + dependencies: + bytes: 3.1.2 + http-errors: 2.0.0 + iconv-lite: 0.6.3 + unpipe: 1.0.0 + dev: true + + /react-dom@19.0.0(react@19.0.0): + resolution: {integrity: sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ==} + peerDependencies: + react: ^19.0.0 + dependencies: + react: 19.0.0 + scheduler: 0.25.0 + + /react-dom@19.1.0(react@19.1.0): + resolution: {integrity: sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==} peerDependencies: - react: ^18.2.0 + react: ^19.1.0 dependencies: - loose-envify: 1.4.0 - react: 18.2.0 - scheduler: 0.23.0 + react: 19.1.0 + scheduler: 0.26.0 /react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} @@ -5072,61 +6614,48 @@ packages: /react-is@17.0.2: resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} + dev: true - /react-is@18.2.0: - resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==} + /react-refresh@0.14.2: + resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==} + engines: {node: '>=0.10.0'} dev: true - /react-refresh@0.14.0: - resolution: {integrity: sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==} + /react-refresh@0.17.0: + resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==} engines: {node: '>=0.10.0'} dev: true - /react-router-dom@6.14.1(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-ssF6M5UkQjHK70fgukCJyjlda0Dgono2QGwqGvuk7D+EDGHdacEN3Yke2LTMjkrpHuFwBfDFsEjGVXBDmL+bWw==} - engines: {node: '>=14'} + /react-router-dom@6.22.3(react-dom@19.0.0)(react@19.0.0): + resolution: {integrity: sha512-7ZILI7HjcE+p31oQvwbokjk6OA/bnFxrhJ19n82Ex9Ph8fNAq+Hm/7KchpMGlTgWhUxRHMMCut+vEtNpWpowKw==} + engines: {node: '>=14.0.0'} peerDependencies: react: '>=16.8' react-dom: '>=16.8' dependencies: - '@remix-run/router': 1.7.1 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - react-router: 6.14.1(react@18.2.0) + '@remix-run/router': 1.15.3 + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + react-router: 6.22.3(react@19.0.0) + dev: false - /react-router@6.14.1(react@18.2.0): - resolution: {integrity: sha512-U4PfgvG55LdvbQjg5Y9QRWyVxIdO1LlpYT7x+tMAxd9/vmiPuJhIwdxZuIQLN/9e3O4KFDHYfR9gzGeYMasW8g==} - engines: {node: '>=14'} + /react-router@6.22.3(react@19.0.0): + resolution: {integrity: sha512-dr2eb3Mj5zK2YISHK++foM9w4eBnO23eKnZEDs7c880P6oKbrjz/Svg9+nxqtHQK+oMW4OtjZca0RqPglXxguQ==} + engines: {node: '>=14.0.0'} peerDependencies: react: '>=16.8' dependencies: - '@remix-run/router': 1.7.1 - react: 18.2.0 + '@remix-run/router': 1.15.3 + react: 19.0.0 + dev: false - /react@18.2.0: - resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==} + /react@19.0.0: + resolution: {integrity: sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==} engines: {node: '>=0.10.0'} - dependencies: - loose-envify: 1.4.0 - - /read-pkg-up@9.1.0: - resolution: {integrity: sha512-vaMRR1AC1nrd5CQM0PhlRsO5oc2AAigqr7cCrZ/MW/Rsaflz4RlgzkpL4qoU/z1F6wrbd85iFv1OQj/y5RdGvg==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - dependencies: - find-up: 6.3.0 - read-pkg: 7.1.0 - type-fest: 2.19.0 - dev: true - /read-pkg@7.1.0: - resolution: {integrity: sha512-5iOehe+WF75IccPc30bWTbpdDQLOCc3Uu8bi3Dte3Eueij81yx1Mrufk8qBx/YAbR4uL1FdUr+7BKXDwEtisXg==} - engines: {node: '>=12.20'} - dependencies: - '@types/normalize-package-data': 2.4.1 - normalize-package-data: 3.0.3 - parse-json: 5.2.0 - type-fest: 2.19.0 - dev: true + /react@19.1.0: + resolution: {integrity: sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==} + engines: {node: '>=0.10.0'} /readable-stream@1.0.34: resolution: {integrity: sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==} @@ -5149,66 +6678,57 @@ packages: util-deprecate: 1.0.2 dev: true - /readable-stream@3.6.2: - resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} - engines: {node: '>= 6'} - dependencies: - inherits: 2.0.4 - string_decoder: 1.3.0 - util-deprecate: 1.0.2 - dev: true - - /readdirp@3.6.0: - resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} - engines: {node: '>=8.10.0'} - dependencies: - picomatch: 2.3.1 - dev: true - /redent@3.0.0: resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} engines: {node: '>=8'} dependencies: indent-string: 4.0.0 strip-indent: 3.0.0 + dev: true - /redent@4.0.0: - resolution: {integrity: sha512-tYkDkVVtYkSVhuQ4zBgfvciymHaeuel+zFKXShfDnFP5SyVEP7qo70Rf1jTOTCx3vGNAbnEi/xFkcfQVMIBWag==} - engines: {node: '>=12'} + /refa@0.12.1: + resolution: {integrity: sha512-J8rn6v4DBb2nnFqkqwy6/NnTYMcgLA+sLr0iIO41qpv0n+ngb7ksag2tMRl0inb1bbO/esUwzW1vbJi7K0sI0g==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} dependencies: - indent-string: 5.0.0 - strip-indent: 4.0.0 + '@eslint-community/regexpp': 4.11.0 dev: true - /refa@0.11.0: - resolution: {integrity: sha512-486O8/pQXwj9jV0mVvUnTsxq0uknpBnNJ0eCUhkZqJRQ8KutrT1PhzmumdCeM1hSBF2eMlFPmwECRER4IbKXlQ==} - engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + /reflect.getprototypeof@1.0.10: + resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} + engines: {node: '>= 0.4'} dependencies: - '@eslint-community/regexpp': 4.5.1 + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.23.9 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 + get-intrinsic: 1.2.7 + get-proto: 1.0.1 + which-builtin-type: 1.2.1 dev: true - /regenerator-runtime@0.13.11: - resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==} + /regenerator-runtime@0.14.1: + resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} + dev: true - /regexp-ast-analysis@0.6.0: - resolution: {integrity: sha512-OLxjyjPkVH+rQlBLb1I/P/VTmamSjGkvN5PTV5BXP432k3uVz727J7H29GA5IFiY0m7e1xBN7049Wn59FY3DEQ==} + /regexp-ast-analysis@0.7.1: + resolution: {integrity: sha512-sZuz1dYW/ZsfG17WSAG7eS85r5a0dDsvg+7BiiYR5o6lKCAtUrEwdmRmaGF6rwVj3LcmAeYkOWKEPlbPzN3Y3A==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} dependencies: - '@eslint-community/regexpp': 4.5.1 - refa: 0.11.0 + '@eslint-community/regexpp': 4.11.0 + refa: 0.12.1 dev: true - /regexp.prototype.flags@1.5.0: - resolution: {integrity: sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==} + /regexp.prototype.flags@1.5.4: + resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.2 - define-properties: 1.2.0 - functions-have-names: 1.2.3 - - /regexpp@3.2.0: - resolution: {integrity: sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==} - engines: {node: '>=8'} + call-bind: 1.0.8 + define-properties: 1.2.1 + es-errors: 1.3.0 + get-proto: 1.0.1 + gopd: 1.2.0 + set-function-name: 2.0.2 dev: true /require-directory@2.1.1: @@ -5216,6 +6736,11 @@ packages: engines: {node: '>=0.10.0'} dev: true + /require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + dev: true + /requires-port@1.0.0: resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} dev: true @@ -5229,81 +6754,135 @@ packages: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} dev: true - /resolve@1.19.0: - resolution: {integrity: sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==} - dependencies: - is-core-module: 2.12.1 - path-parse: 1.0.7 - dev: true - - /resolve@1.22.2: - resolution: {integrity: sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==} + /resolve@1.22.8: + resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} hasBin: true dependencies: - is-core-module: 2.12.1 + is-core-module: 2.16.1 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 dev: true - /resolve@2.0.0-next.4: - resolution: {integrity: sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==} + /resolve@2.0.0-next.5: + resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==} hasBin: true dependencies: - is-core-module: 2.12.1 + is-core-module: 2.16.1 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 dev: true - /restore-cursor@3.1.0: - resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} - engines: {node: '>=8'} - dependencies: - onetime: 5.1.2 - signal-exit: 3.0.7 - dev: true - /reusify@1.0.4: resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} dev: true - /rimraf@3.0.2: - resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + /rimraf@6.0.1: + resolution: {integrity: sha512-9dkvaxAsk/xNXSJzMgFqqMCuFgt2+KsOFek3TMLfo8NCPfWpBmqwyNn5Y+NX56QUYfCtsyhF3ayiboEoUmJk/A==} + engines: {node: 20 || >=22} hasBin: true dependencies: - glob: 7.2.3 + glob: 11.0.0 + package-json-from-dist: 1.0.0 dev: true - /rimraf@5.0.1: - resolution: {integrity: sha512-OfFZdwtd3lZ+XZzYP/6gTACubwFcHdLRqS9UX3UwpU2dnGQYkPFISRwvM3w9IiB2w7bW5qGo/uAwE4SmXXSKvg==} - engines: {node: '>=14'} + /rollup@4.30.1: + resolution: {integrity: sha512-mlJ4glW020fPuLi7DkM/lN97mYEZGWeqBnrljzN0gs7GLctqX3lNWxKQ7Gl712UAX+6fog/L3jh4gb7R6aVi3w==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true dependencies: - glob: 10.3.3 - dev: true - - /rollup@3.26.2: - resolution: {integrity: sha512-6umBIGVz93er97pMgQO08LuH3m6PUb3jlDUUGFsNJB6VgTCUaDFpupf5JfU30529m/UKOgmiX+uY6Sx8cOYpLA==} - engines: {node: '>=14.18.0', npm: '>=8.0.0'} + '@types/estree': 1.0.6 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.30.1 + '@rollup/rollup-android-arm64': 4.30.1 + '@rollup/rollup-darwin-arm64': 4.30.1 + '@rollup/rollup-darwin-x64': 4.30.1 + '@rollup/rollup-freebsd-arm64': 4.30.1 + '@rollup/rollup-freebsd-x64': 4.30.1 + '@rollup/rollup-linux-arm-gnueabihf': 4.30.1 + '@rollup/rollup-linux-arm-musleabihf': 4.30.1 + '@rollup/rollup-linux-arm64-gnu': 4.30.1 + '@rollup/rollup-linux-arm64-musl': 4.30.1 + '@rollup/rollup-linux-loongarch64-gnu': 4.30.1 + '@rollup/rollup-linux-powerpc64le-gnu': 4.30.1 + '@rollup/rollup-linux-riscv64-gnu': 4.30.1 + '@rollup/rollup-linux-s390x-gnu': 4.30.1 + '@rollup/rollup-linux-x64-gnu': 4.30.1 + '@rollup/rollup-linux-x64-musl': 4.30.1 + '@rollup/rollup-win32-arm64-msvc': 4.30.1 + '@rollup/rollup-win32-ia32-msvc': 4.30.1 + '@rollup/rollup-win32-x64-msvc': 4.30.1 + fsevents: 2.3.3 + dev: true + + /rollup@4.40.1: + resolution: {integrity: sha512-C5VvvgCCyfyotVITIAv+4efVytl5F7wt+/I2i9q9GZcEXW9BP52YYOXC58igUi+LFZVHukErIIqQSWwv/M3WRw==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true + dependencies: + '@types/estree': 1.0.7 optionalDependencies: - fsevents: 2.3.2 - dev: true - - /rrweb-cssom@0.6.0: - resolution: {integrity: sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==} - dev: true - - /run-applescript@5.0.0: - resolution: {integrity: sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg==} - engines: {node: '>=12'} + '@rollup/rollup-android-arm-eabi': 4.40.1 + '@rollup/rollup-android-arm64': 4.40.1 + '@rollup/rollup-darwin-arm64': 4.40.1 + '@rollup/rollup-darwin-x64': 4.40.1 + '@rollup/rollup-freebsd-arm64': 4.40.1 + '@rollup/rollup-freebsd-x64': 4.40.1 + '@rollup/rollup-linux-arm-gnueabihf': 4.40.1 + '@rollup/rollup-linux-arm-musleabihf': 4.40.1 + '@rollup/rollup-linux-arm64-gnu': 4.40.1 + '@rollup/rollup-linux-arm64-musl': 4.40.1 + '@rollup/rollup-linux-loongarch64-gnu': 4.40.1 + '@rollup/rollup-linux-powerpc64le-gnu': 4.40.1 + '@rollup/rollup-linux-riscv64-gnu': 4.40.1 + '@rollup/rollup-linux-riscv64-musl': 4.40.1 + '@rollup/rollup-linux-s390x-gnu': 4.40.1 + '@rollup/rollup-linux-x64-gnu': 4.40.1 + '@rollup/rollup-linux-x64-musl': 4.40.1 + '@rollup/rollup-win32-arm64-msvc': 4.40.1 + '@rollup/rollup-win32-ia32-msvc': 4.40.1 + '@rollup/rollup-win32-x64-msvc': 4.40.1 + fsevents: 2.3.3 + dev: true + + /rollup@4.9.6: + resolution: {integrity: sha512-05lzkCS2uASX0CiLFybYfVkwNbKZG5NFQ6Go0VWyogFTXXbR039UVsegViTntkk4OglHBdF54ccApXRRuXRbsg==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true dependencies: - execa: 5.1.1 + '@types/estree': 1.0.5 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.9.6 + '@rollup/rollup-android-arm64': 4.9.6 + '@rollup/rollup-darwin-arm64': 4.9.6 + '@rollup/rollup-darwin-x64': 4.9.6 + '@rollup/rollup-linux-arm-gnueabihf': 4.9.6 + '@rollup/rollup-linux-arm64-gnu': 4.9.6 + '@rollup/rollup-linux-arm64-musl': 4.9.6 + '@rollup/rollup-linux-riscv64-gnu': 4.9.6 + '@rollup/rollup-linux-x64-gnu': 4.9.6 + '@rollup/rollup-linux-x64-musl': 4.9.6 + '@rollup/rollup-win32-arm64-msvc': 4.9.6 + '@rollup/rollup-win32-ia32-msvc': 4.9.6 + '@rollup/rollup-win32-x64-msvc': 4.9.6 + fsevents: 2.3.3 + dev: true + + /router@2.2.0: + resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} + engines: {node: '>= 18'} + dependencies: + debug: 4.4.0 + depd: 2.0.0 + is-promise: 4.0.0 + parseurl: 1.3.3 + path-to-regexp: 8.2.0 + transitivePeerDependencies: + - supports-color dev: true - /run-async@2.4.1: - resolution: {integrity: sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==} - engines: {node: '>=0.12.0'} + /rrweb-cssom@0.8.0: + resolution: {integrity: sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==} dev: true /run-parallel@1.2.0: @@ -5312,10 +6891,15 @@ packages: queue-microtask: 1.2.3 dev: true - /rxjs@7.8.1: - resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==} + /safe-array-concat@1.1.3: + resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==} + engines: {node: '>=0.4'} dependencies: - tslib: 2.6.0 + call-bind: 1.0.8 + call-bound: 1.0.3 + get-intrinsic: 1.2.7 + has-symbols: 1.1.0 + isarray: 2.0.5 dev: true /safe-buffer@5.1.2: @@ -5326,14 +6910,32 @@ packages: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} dev: true - /safe-regex-test@1.0.0: - resolution: {integrity: sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==} + /safe-push-apply@1.0.0: + resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==} + engines: {node: '>= 0.4'} + dependencies: + es-errors: 1.3.0 + isarray: 2.0.5 + dev: true + + /safe-regex-test@1.0.3: + resolution: {integrity: sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==} + engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.2 - get-intrinsic: 1.2.1 + call-bind: 1.0.7 + es-errors: 1.3.0 is-regex: 1.1.4 dev: true + /safe-regex-test@1.1.0: + resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.3 + es-errors: 1.3.0 + is-regex: 1.2.1 + dev: true + /safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} dev: true @@ -5345,17 +6947,19 @@ packages: xmlchars: 2.2.0 dev: true - /scheduler@0.23.0: - resolution: {integrity: sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==} - dependencies: - loose-envify: 1.4.0 + /scheduler@0.25.0: + resolution: {integrity: sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==} + + /scheduler@0.26.0: + resolution: {integrity: sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==} - /scslre@0.2.0: - resolution: {integrity: sha512-4hc49fUMmX3jM0XdFUAPBrs1xwEcdHa0KyjEsjFs+Zfc66mpFpq5YmRgDtl+Ffo6AtJIilfei+yKw8fUn3N88w==} + /scslre@0.3.0: + resolution: {integrity: sha512-3A6sD0WYP7+QrjbfNA2FN3FsOaGGFoekCVgTyypy53gPxhbkCIjtO6YWgdrfM+n/8sI8JeXZOIxsHjMTNxQ4nQ==} + engines: {node: ^14.0.0 || >=16.0.0} dependencies: - '@eslint-community/regexpp': 4.5.1 - refa: 0.11.0 - regexp-ast-analysis: 0.6.0 + '@eslint-community/regexpp': 4.11.0 + refa: 0.12.1 + regexp-ast-analysis: 0.7.1 dev: true /semver@6.3.1: @@ -5363,24 +6967,84 @@ packages: hasBin: true dev: true - /semver@7.3.8: - resolution: {integrity: sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==} + /semver@7.5.4: + resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} engines: {node: '>=10'} hasBin: true dependencies: lru-cache: 6.0.0 dev: true - /semver@7.5.4: - resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} + /semver@7.6.3: + resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} engines: {node: '>=10'} hasBin: true + dev: true + + /send@1.2.0: + resolution: {integrity: sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==} + engines: {node: '>= 18'} dependencies: - lru-cache: 6.0.0 + debug: 4.4.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 2.0.0 + http-errors: 2.0.0 + mime-types: 3.0.1 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.1 + transitivePeerDependencies: + - supports-color + dev: true + + /serve-static@2.2.0: + resolution: {integrity: sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==} + engines: {node: '>= 18'} + dependencies: + encodeurl: 2.0.0 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 1.2.0 + transitivePeerDependencies: + - supports-color + dev: true + + /set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} + engines: {node: '>= 0.4'} + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.2.7 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + dev: true + + /set-function-name@2.0.2: + resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} + engines: {node: '>= 0.4'} + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + functions-have-names: 1.2.3 + has-property-descriptors: 1.0.2 + dev: true + + /set-proto@1.0.0: + resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} + engines: {node: '>= 0.4'} + dependencies: + dunder-proto: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 dev: true - /set-cookie-parser@2.6.0: - resolution: {integrity: sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==} + /setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} dev: true /shebang-command@2.0.0: @@ -5395,29 +7059,53 @@ packages: engines: {node: '>=8'} dev: true - /side-channel@1.0.4: - resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==} + /side-channel-list@1.0.0: + resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} + engines: {node: '>= 0.4'} + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.3 + dev: true + + /side-channel-map@1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.2 - get-intrinsic: 1.2.1 - object-inspect: 1.12.3 + call-bound: 1.0.3 + es-errors: 1.3.0 + get-intrinsic: 1.2.7 + object-inspect: 1.13.3 + dev: true - /siginfo@2.0.0: - resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + /side-channel-weakmap@1.0.2: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.3 + es-errors: 1.3.0 + get-intrinsic: 1.2.7 + object-inspect: 1.13.3 + side-channel-map: 1.0.1 dev: true - /signal-exit@3.0.7: - resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + /side-channel@1.1.0: + resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} + engines: {node: '>= 0.4'} + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.3 + side-channel-list: 1.0.0 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 dev: true - /signal-exit@4.0.2: - resolution: {integrity: sha512-MY2/qGx4enyjprQnFaZsHib3Yadh3IXyV2C321GY0pjGfVBu4un0uDJkwgdxqO+Rdx8JMT8IfJIRwbYVz3Ob3Q==} - engines: {node: '>=14'} + /siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} dev: true - /slash@3.0.0: - resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} - engines: {node: '>=8'} + /signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} dev: true /slash@4.0.0: @@ -5425,44 +7113,20 @@ packages: engines: {node: '>=12'} dev: true - /source-map-js@1.0.2: - resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} - engines: {node: '>=0.10.0'} - - /source-map-support@0.5.21: - resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} - dependencies: - buffer-from: 1.1.2 - source-map: 0.6.1 + /slash@5.1.0: + resolution: {integrity: sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==} + engines: {node: '>=14.16'} dev: true + /source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + /source-map@0.6.1: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} dev: true - /spdx-correct@3.2.0: - resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==} - dependencies: - spdx-expression-parse: 3.0.1 - spdx-license-ids: 3.0.13 - dev: true - - /spdx-exceptions@2.3.0: - resolution: {integrity: sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==} - dev: true - - /spdx-expression-parse@3.0.1: - resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} - dependencies: - spdx-exceptions: 2.3.0 - spdx-license-ids: 3.0.13 - dev: true - - /spdx-license-ids@3.0.13: - resolution: {integrity: sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==} - dev: true - /sprintf-js@1.0.3: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} dev: true @@ -5471,29 +7135,26 @@ packages: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} dev: true - /std-env@3.3.3: - resolution: {integrity: sha512-Rz6yejtVyWnVjC1RFvNmYL10kgjC49EOghxWn0RFqlCHGFpQx+Xe7yW3I4ceK1SGrWIGMjD5Kbue8W/udkbMJg==} + /statuses@2.0.1: + resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} + engines: {node: '>= 0.8'} dev: true - /stop-iteration-iterator@1.0.0: - resolution: {integrity: sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==} - engines: {node: '>= 0.4'} - dependencies: - internal-slot: 1.0.5 + /std-env@3.8.0: + resolution: {integrity: sha512-Bc3YwwCB+OzldMxOXJIIvC6cPRWr/LxOp48CdQTOkPyk/t4JWWJbrilwBd7RJzKV8QW7tJkcgAmeuLLJugl5/w==} + dev: true + + /std-env@3.9.0: + resolution: {integrity: sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==} + dev: true /streamsearch@1.1.0: resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} engines: {node: '>=10.0.0'} dev: false - /strict-event-emitter@0.2.8: - resolution: {integrity: sha512-KDf/ujU8Zud3YaLtMCcTI4xkZlZVIYxTLr+XIULexP+77EEVWixeXroLUXQXiVtH4XH2W7jr/3PT1v3zBuvc3A==} - dependencies: - events: 3.3.0 - dev: true - - /strict-event-emitter@0.4.6: - resolution: {integrity: sha512-12KWeb+wixJohmnwNFerbyiBrAlq5qJLwIt38etRtKtmmHyDSoGlIqFE9wx+4IwG0aDjI7GV8tc8ZccjWZZtTg==} + /strict-event-emitter@0.5.1: + resolution: {integrity: sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ==} dev: true /string-argv@0.3.2: @@ -5519,42 +7180,89 @@ packages: strip-ansi: 7.1.0 dev: true - /string.prototype.matchall@4.0.8: - resolution: {integrity: sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg==} + /string.prototype.includes@2.0.1: + resolution: {integrity: sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + dev: true + + /string.prototype.matchall@4.0.12: + resolution: {integrity: sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.3 + define-properties: 1.2.1 + es-abstract: 1.23.9 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 + get-intrinsic: 1.2.7 + gopd: 1.2.0 + has-symbols: 1.1.0 + internal-slot: 1.1.0 + regexp.prototype.flags: 1.5.4 + set-function-name: 2.0.2 + side-channel: 1.1.0 + dev: true + + /string.prototype.repeat@1.0.0: + resolution: {integrity: sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==} + dependencies: + define-properties: 1.2.1 + es-abstract: 1.23.9 + dev: true + + /string.prototype.trim@1.2.10: + resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==} + engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.2 - define-properties: 1.2.0 - es-abstract: 1.21.3 - get-intrinsic: 1.2.1 - has-symbols: 1.0.3 - internal-slot: 1.0.5 - regexp.prototype.flags: 1.5.0 - side-channel: 1.0.4 + call-bind: 1.0.8 + call-bound: 1.0.3 + define-data-property: 1.1.4 + define-properties: 1.2.1 + es-abstract: 1.23.9 + es-object-atoms: 1.0.0 + has-property-descriptors: 1.0.2 dev: true - /string.prototype.trim@1.2.7: - resolution: {integrity: sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==} + /string.prototype.trim@1.2.9: + resolution: {integrity: sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.2 - define-properties: 1.2.0 - es-abstract: 1.21.3 + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.23.9 + es-object-atoms: 1.0.0 + dev: true + + /string.prototype.trimend@1.0.8: + resolution: {integrity: sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-object-atoms: 1.0.0 dev: true - /string.prototype.trimend@1.0.6: - resolution: {integrity: sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==} + /string.prototype.trimend@1.0.9: + resolution: {integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==} + engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.2 - define-properties: 1.2.0 - es-abstract: 1.21.3 + call-bind: 1.0.8 + call-bound: 1.0.3 + define-properties: 1.2.1 + es-object-atoms: 1.0.0 dev: true - /string.prototype.trimstart@1.0.6: - resolution: {integrity: sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==} + /string.prototype.trimstart@1.0.8: + resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} + engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.2 - define-properties: 1.2.0 - es-abstract: 1.21.3 + call-bind: 1.0.8 + define-properties: 1.2.1 + es-object-atoms: 1.0.0 dev: true /string_decoder@0.10.31: @@ -5567,12 +7275,6 @@ packages: safe-buffer: 5.1.2 dev: true - /string_decoder@1.3.0: - resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} - dependencies: - safe-buffer: 5.2.1 - dev: true - /strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} @@ -5592,27 +7294,11 @@ packages: engines: {node: '>=4'} dev: true - /strip-final-newline@2.0.0: - resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} - engines: {node: '>=6'} - dev: true - - /strip-final-newline@3.0.0: - resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} - engines: {node: '>=12'} - dev: true - /strip-indent@3.0.0: resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} engines: {node: '>=8'} dependencies: min-indent: 1.0.1 - - /strip-indent@4.0.0: - resolution: {integrity: sha512-mnVSV2l+Zv6BLpSD/8V87CW/y9EmmbYzGCIavsnsI6/nwn26DwffM/yztm30Z/I2DY9wdS3vXVCMnHDgZaVNoA==} - engines: {node: '>=12'} - dependencies: - min-indent: 1.0.1 dev: true /strip-json-comments@3.1.1: @@ -5620,13 +7306,7 @@ packages: engines: {node: '>=8'} dev: true - /strip-literal@1.0.1: - resolution: {integrity: sha512-QZTsipNpa2Ppr6v1AmJHESqJ3Uz247MUS0OjrnnZjFAvEoWqxuyFuXn2xLgMtRnijJShAa1HL0gtJyUs7u7n3Q==} - dependencies: - acorn: 8.10.0 - dev: true - - /styled-jsx@5.1.1(react@18.2.0): + /styled-jsx@5.1.1(react@19.1.0): resolution: {integrity: sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==} engines: {node: '>= 12.0.0'} peerDependencies: @@ -5640,7 +7320,7 @@ packages: optional: true dependencies: client-only: 0.0.1 - react: 18.2.0 + react: 19.1.0 dev: false /supports-color@5.5.0: @@ -5648,12 +7328,21 @@ packages: engines: {node: '>=4'} dependencies: has-flag: 3.0.0 + dev: true /supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} dependencies: has-flag: 4.0.0 + dev: true + + /supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + dependencies: + has-flag: 4.0.0 + dev: true /supports-preserve-symlinks-flag@1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} @@ -5664,12 +7353,12 @@ packages: resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} dev: true - /synckit@0.8.5: - resolution: {integrity: sha512-L1dapNV6vu2s/4Sputv8xGsCdAVlb5nRDMFU/E27D44l5U6cw1g0dGd45uLc+OXjNMmF4ntiMdCimzcjFKQI8Q==} + /synckit@0.11.3: + resolution: {integrity: sha512-szhWDqNNI9etJUvbZ1/cx1StnZx8yMmFxme48SwR4dty4ioSY50KEZlpv0qAfgc1fpRzuh9hBXEzoCpJ779dLg==} engines: {node: ^14.18.0 || >=16.0.0} dependencies: - '@pkgr/utils': 2.4.2 - tslib: 2.6.0 + '@pkgr/core': 0.2.2 + tslib: 2.8.1 dev: true /tapable@2.2.1: @@ -5677,17 +7366,13 @@ packages: engines: {node: '>=6'} dev: true - /test-exclude@6.0.0: - resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} - engines: {node: '>=8'} + /test-exclude@7.0.1: + resolution: {integrity: sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==} + engines: {node: '>=18'} dependencies: '@istanbuljs/schema': 0.1.3 - glob: 7.2.3 - minimatch: 3.1.2 - dev: true - - /text-table@0.2.0: - resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + glob: 10.4.5 + minimatch: 9.0.5 dev: true /through2@2.0.5: @@ -5697,39 +7382,56 @@ packages: xtend: 4.0.2 dev: true - /through@2.3.8: - resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} + /tinybench@2.9.0: + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + dev: true + + /tinyexec@0.3.2: + resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + dev: true + + /tinyglobby@0.2.13: + resolution: {integrity: sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==} + engines: {node: '>=12.0.0'} + dependencies: + fdir: 6.4.4(picomatch@4.0.2) + picomatch: 4.0.2 + dev: true + + /tinypool@1.0.1: + resolution: {integrity: sha512-URZYihUbRPcGv95En+sz6MfghfIc2OJ1sv/RmhWZLouPY0/8Vo80viwPvg3dlaS9fuq7fQMEfgRRK7BBZThBEA==} + engines: {node: ^18.0.0 || >=20.0.0} dev: true - /tinybench@2.5.0: - resolution: {integrity: sha512-kRwSG8Zx4tjF9ZiyH4bhaebu+EDz1BOx9hOigYHlUW4xxI/wKIUQUqo018UlU4ar6ATPBsaMrdbKZ+tmPdohFA==} + /tinypool@1.0.2: + resolution: {integrity: sha512-al6n+QEANGFOMf/dmUMsuS5/r9B06uwlyNjZZql/zv8J7ybHCgoihBNORZCY2mzUuAnomQa2JdhyHKzZxPCrFA==} + engines: {node: ^18.0.0 || >=20.0.0} dev: true - /tinypool@0.6.0: - resolution: {integrity: sha512-FdswUUo5SxRizcBc6b1GSuLpLjisa8N8qMyYoP3rl+bym+QauhtJP5bvZY1ytt8krKGmMLYIRl36HBZfeAoqhQ==} + /tinyrainbow@1.2.0: + resolution: {integrity: sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==} engines: {node: '>=14.0.0'} dev: true - /tinyspy@2.1.1: - resolution: {integrity: sha512-XPJL2uSzcOyBMky6OFrusqWlzfFrXtE0hPuMgW8A2HmaqrPo4ZQHRN/V0QXN3FSjKxpsbRrFc5LI7KOwBsT1/w==} + /tinyrainbow@2.0.0: + resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==} engines: {node: '>=14.0.0'} dev: true - /titleize@3.0.0: - resolution: {integrity: sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==} - engines: {node: '>=12'} + /tinyspy@3.0.2: + resolution: {integrity: sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==} + engines: {node: '>=14.0.0'} dev: true - /tmp@0.0.33: - resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} - engines: {node: '>=0.6.0'} - dependencies: - os-tmpdir: 1.0.2 + /tldts-core@6.1.71: + resolution: {integrity: sha512-LRbChn2YRpic1KxY+ldL1pGXN/oVvKfCVufwfVzEQdFYNo39uF7AJa/WXdo+gYO7PTvdfkCPCed6Hkvz/kR7jg==} dev: true - /to-fast-properties@2.0.0: - resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} - engines: {node: '>=4'} + /tldts@6.1.71: + resolution: {integrity: sha512-LQIHmHnuzfZgZWAf2HzL83TIIrD8NhhI0DVxqo9/FdOd4ilec+NTNZOlDZf7EwrTNoutccbsHjvWHYXLAtvxjw==} + hasBin: true + dependencies: + tldts-core: 6.1.71 dev: true /to-regex-range@5.0.1: @@ -5739,67 +7441,88 @@ packages: is-number: 7.0.0 dev: true - /tough-cookie@4.1.3: - resolution: {integrity: sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==} + /toidentifier@1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} + dev: true + + /tough-cookie@4.1.4: + resolution: {integrity: sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==} engines: {node: '>=6'} dependencies: psl: 1.9.0 - punycode: 2.3.0 + punycode: 2.3.1 universalify: 0.2.0 url-parse: 1.5.10 dev: true - /tr46@0.0.3: - resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + /tough-cookie@5.1.0: + resolution: {integrity: sha512-rvZUv+7MoBYTiDmFPBrhL7Ujx9Sk+q9wwm22x8c8T5IJaR+Wsyc7TNxbVxo84kZoRJZZMazowFLqpankBEQrGg==} + engines: {node: '>=16'} + dependencies: + tldts: 6.1.71 dev: true - /tr46@4.1.1: - resolution: {integrity: sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==} - engines: {node: '>=14'} + /tough-cookie@5.1.2: + resolution: {integrity: sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==} + engines: {node: '>=16'} dependencies: - punycode: 2.3.0 + tldts: 6.1.71 dev: true - /trim-newlines@5.0.0: - resolution: {integrity: sha512-kstfs+hgwmdsOadN3KgA+C68wPJwnZq4DN6WMDCvZapDWEF34W2TyPKN2v2+BJnZgIz5QOfxFeldLyYvdgRAwg==} - engines: {node: '>=14.16'} + /tr46@5.0.0: + resolution: {integrity: sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==} + engines: {node: '>=18'} + dependencies: + punycode: 2.3.1 dev: true - /tsconfig-paths@3.14.2: - resolution: {integrity: sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==} + /tr46@5.1.0: + resolution: {integrity: sha512-IUWnUK7ADYR5Sl1fZlO1INDUhVhatWl7BtJWsIhwJ0UAK7ilzzIa8uIqOO/aYVWHZPJkKbEL+362wrzoeRF7bw==} + engines: {node: '>=18'} dependencies: - '@types/json5': 0.0.29 - json5: 1.0.2 - minimist: 1.2.8 - strip-bom: 3.0.0 + punycode: 2.3.1 dev: true - /tslib@1.14.1: - resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} + /ts-api-utils@2.0.0(typescript@5.8.3): + resolution: {integrity: sha512-xCt/TOAc+EOHS1XPnijD3/yzpH6qg2xppZO1YDqGoVsNXfQfzHpOdNuXwrwOU8u4ITXJyDCTyt8w5g1sZv9ynQ==} + engines: {node: '>=18.12'} + peerDependencies: + typescript: '>=4.8.4' + dependencies: + typescript: 5.8.3 dev: true - /tslib@2.6.0: - resolution: {integrity: sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA==} - - /tsutils@3.21.0(typescript@5.1.6): - resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} - engines: {node: '>= 6'} + /ts-api-utils@2.1.0(typescript@5.8.3): + resolution: {integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==} + engines: {node: '>=18.12'} peerDependencies: - typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' + typescript: '>=4.8.4' + dependencies: + typescript: 5.8.3 + dev: true + + /tsconfig-paths@3.15.0: + resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} dependencies: - tslib: 1.14.1 - typescript: 5.1.6 + '@types/json5': 0.0.29 + json5: 1.0.2 + minimist: 1.2.8 + strip-bom: 3.0.0 dev: true - /tsx@3.12.7: - resolution: {integrity: sha512-C2Ip+jPmqKd1GWVQDvz/Eyc6QJbGfE7NrR3fx5BpEHMZsEHoIxHL1j+lKdGobr8ovEyqeNkPLSKp6SCSOt7gmw==} + /tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + /tsx@4.19.4: + resolution: {integrity: sha512-gK5GVzDkJK1SI1zwHf32Mqxf2tSJkNx+eYcNly5+nHvWqXUJYUkWBQtKauoESz3ymezAI++ZwT855x5p5eop+Q==} + engines: {node: '>=18.0.0'} hasBin: true dependencies: - '@esbuild-kit/cjs-loader': 2.4.2 - '@esbuild-kit/core-utils': 3.1.0 - '@esbuild-kit/esm-loader': 2.5.5 + esbuild: 0.25.1 + get-tsconfig: 4.8.1 optionalDependencies: - fsevents: 2.3.2 + fsevents: 2.3.3 dev: true /type-check@0.4.0: @@ -5809,72 +7532,167 @@ packages: prelude-ls: 1.2.1 dev: true - /type-detect@4.0.8: - resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} - engines: {node: '>=4'} + /type-fest@0.21.3: + resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} + engines: {node: '>=10'} + dev: true + + /type-fest@4.32.0: + resolution: {integrity: sha512-rfgpoi08xagF3JSdtJlCwMq9DGNDE0IMh3Mkpc1wUypg9vPi786AiqeBBKcqvIkq42azsBM85N490fyZjeUftw==} + engines: {node: '>=16'} + dev: true + + /type-is@2.0.1: + resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==} + engines: {node: '>= 0.6'} + dependencies: + content-type: 1.0.5 + media-typer: 1.1.0 + mime-types: 3.0.1 + dev: true + + /typed-array-buffer@1.0.2: + resolution: {integrity: sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + es-errors: 1.3.0 + is-typed-array: 1.1.15 + dev: true + + /typed-array-buffer@1.0.3: + resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.3 + es-errors: 1.3.0 + is-typed-array: 1.1.15 dev: true - /type-fest@0.20.2: - resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} - engines: {node: '>=10'} + /typed-array-byte-length@1.0.1: + resolution: {integrity: sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + for-each: 0.3.3 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 dev: true - /type-fest@0.21.3: - resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} - engines: {node: '>=10'} + /typed-array-byte-length@1.0.3: + resolution: {integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + for-each: 0.3.3 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 dev: true - /type-fest@2.19.0: - resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==} - engines: {node: '>=12.20'} + /typed-array-byte-offset@1.0.2: + resolution: {integrity: sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==} + engines: {node: '>= 0.4'} + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + for-each: 0.3.3 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 dev: true - /type-fest@3.13.1: - resolution: {integrity: sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==} - engines: {node: '>=14.16'} + /typed-array-byte-offset@1.0.4: + resolution: {integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==} + engines: {node: '>= 0.4'} + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + for-each: 0.3.3 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 + reflect.getprototypeof: 1.0.10 dev: true - /typed-array-byte-offset@1.0.0: - resolution: {integrity: sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==} + /typed-array-length@1.0.6: + resolution: {integrity: sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==} engines: {node: '>= 0.4'} dependencies: - available-typed-arrays: 1.0.5 - call-bind: 1.0.2 + call-bind: 1.0.8 for-each: 0.3.3 - has-proto: 1.0.1 - is-typed-array: 1.1.10 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 + possible-typed-array-names: 1.0.0 dev: true - /typed-array-length@1.0.4: - resolution: {integrity: sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==} + /typed-array-length@1.0.7: + resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} + engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.2 + call-bind: 1.0.8 for-each: 0.3.3 - is-typed-array: 1.1.10 + gopd: 1.2.0 + is-typed-array: 1.1.15 + possible-typed-array-names: 1.0.0 + reflect.getprototypeof: 1.0.10 dev: true - /typescript@5.0.4: - resolution: {integrity: sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==} - engines: {node: '>=12.20'} + /typescript@5.7.2: + resolution: {integrity: sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==} + engines: {node: '>=14.17'} + hasBin: true + dev: true + + /typescript@5.7.3: + resolution: {integrity: sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==} + engines: {node: '>=14.17'} + hasBin: true + + /typescript@5.8.2: + resolution: {integrity: sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==} + engines: {node: '>=14.17'} hasBin: true dev: true - /typescript@5.1.6: - resolution: {integrity: sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==} + /typescript@5.8.3: + resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==} engines: {node: '>=14.17'} hasBin: true + dev: true - /ufo@1.1.2: - resolution: {integrity: sha512-TrY6DsjTQQgyS3E3dBaOXf0TpPD8u9FVrVYmKVegJuFw51n/YB9XPt+U6ydzFG5ZIN7+DIjPbNmXoBj9esYhgQ==} + /ufo@1.5.4: + resolution: {integrity: sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==} dev: true /unbox-primitive@1.0.2: resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} dependencies: - call-bind: 1.0.2 + call-bind: 1.0.8 + has-bigints: 1.0.2 + has-symbols: 1.1.0 + which-boxed-primitive: 1.1.1 + dev: true + + /unbox-primitive@1.1.0: + resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.3 has-bigints: 1.0.2 - has-symbols: 1.0.3 - which-boxed-primitive: 1.0.2 + has-symbols: 1.1.0 + which-boxed-primitive: 1.1.1 + dev: true + + /undici-types@5.26.5: + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + dev: true + + /unicorn-magic@0.1.0: + resolution: {integrity: sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==} + engines: {node: '>=18'} dev: true /universalify@0.1.2: @@ -5887,26 +7705,36 @@ packages: engines: {node: '>= 4.0.0'} dev: true + /universalify@2.0.1: + resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} + engines: {node: '>= 10.0.0'} + dev: true + + /unpipe@1.0.0: + resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} + engines: {node: '>= 0.8'} + dev: true + /untildify@4.0.0: resolution: {integrity: sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==} engines: {node: '>=8'} dev: true - /update-browserslist-db@1.0.11(browserslist@4.21.9): - resolution: {integrity: sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==} + /update-browserslist-db@1.1.2(browserslist@4.24.4): + resolution: {integrity: sha512-PPypAm5qvlD7XMZC3BujecnaOxwhrtoFR+Dqkk5Aa/6DssiH0ibKoketaj9w8LP7Bont1rYeoV5plxD7RTEPRg==} hasBin: true peerDependencies: browserslist: '>= 4.21.0' dependencies: - browserslist: 4.21.9 - escalade: 3.1.1 - picocolors: 1.0.0 + browserslist: 4.24.4 + escalade: 3.2.0 + picocolors: 1.1.1 dev: true /uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} dependencies: - punycode: 2.3.0 + punycode: 2.3.1 dev: true /url-parse@1.5.10: @@ -5920,62 +7748,59 @@ packages: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} dev: true - /util@0.12.5: - resolution: {integrity: sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==} - dependencies: - inherits: 2.0.4 - is-arguments: 1.1.1 - is-generator-function: 1.0.10 - is-typed-array: 1.1.10 - which-typed-array: 1.1.10 - dev: true - - /v8-to-istanbul@9.1.0: - resolution: {integrity: sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA==} - engines: {node: '>=10.12.0'} - dependencies: - '@jridgewell/trace-mapping': 0.3.18 - '@types/istanbul-lib-coverage': 2.0.4 - convert-source-map: 1.9.0 + /vary@1.1.2: + resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} + engines: {node: '>= 0.8'} dev: true - /validate-npm-package-license@3.0.4: - resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} + /vite-node@2.1.8: + resolution: {integrity: sha512-uPAwSr57kYjAUux+8E2j0q0Fxpn8M9VoyfGiRI8Kfktz9NcYMCenwY5RnZxnF1WTu3TGiYipirIzacLL3VVGFg==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true dependencies: - spdx-correct: 3.2.0 - spdx-expression-parse: 3.0.1 - dev: true - - /validator@13.9.0: - resolution: {integrity: sha512-B+dGG8U3fdtM0/aNK4/X8CXq/EcxU2WPrPEkJGslb47qyHsxmbggTWK0yEA4qnYVNF+nxNlN88o14hIcPmSIEA==} - engines: {node: '>= 0.10'} + cac: 6.7.14 + debug: 4.4.0 + es-module-lexer: 1.6.0 + pathe: 1.1.2 + vite: 5.1.6 + transitivePeerDependencies: + - '@types/node' + - less + - lightningcss + - sass + - stylus + - sugarss + - supports-color + - terser dev: true - /vite-node@0.33.0(@types/node@18.11.9): - resolution: {integrity: sha512-19FpHYbwWWxDr73ruNahC+vtEdza52kA90Qb3La98yZ0xULqV8A5JLNPUff0f5zID4984tW7l3DH2przTJUZSw==} - engines: {node: '>=v14.18.0'} + /vite-node@3.1.3(@types/node@20.11.26)(tsx@4.19.4): + resolution: {integrity: sha512-uHV4plJ2IxCl4u1up1FQRrqclylKAogbtBfOTwcuJ28xFi+89PZ57BRh+naIRvH70HPwxy5QHYzg1OrEaC7AbA==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true dependencies: cac: 6.7.14 - debug: 4.3.4 - mlly: 1.4.0 - pathe: 1.1.1 - picocolors: 1.0.0 - vite: 4.4.4(@types/node@18.11.9) + debug: 4.4.0 + es-module-lexer: 1.7.0 + pathe: 2.0.3 + vite: 6.3.5(@types/node@20.11.26)(tsx@4.19.4) transitivePeerDependencies: - '@types/node' + - jiti - less - lightningcss - sass + - sass-embedded - stylus - sugarss - supports-color - terser + - tsx + - yaml dev: true - /vite-plugin-dts@3.3.0(typescript@5.1.6)(vite@4.4.4): - resolution: {integrity: sha512-9jm7wV8fkA4JaKmZdeg/X71dMi8l9SbdmzQRafW4ea1fOfd/LHBDKuwFuxKpK8h1h8O7abKycXS087EP7EL8Hw==} - engines: {node: ^14.18.0 || >=16.0.0} + /vite-plugin-dts@4.5.0(typescript@5.7.3)(vite@6.0.7): + resolution: {integrity: sha512-M1lrPTdi7gilLYRZoLmGYnl4fbPryVYsehPN9JgaxjJKTs8/f7tuAlvCCvOLB5gRDQTTKnptBcB0ACsaw2wNLw==} peerDependencies: typescript: '*' vite: '*' @@ -5983,26 +7808,90 @@ packages: vite: optional: true dependencies: - '@microsoft/api-extractor': 7.36.2 - '@rollup/pluginutils': 5.0.2 - '@vue/language-core': 1.8.5(typescript@5.1.6) - debug: 4.3.4 + '@microsoft/api-extractor': 7.49.1 + '@rollup/pluginutils': 5.1.4 + '@volar/typescript': 2.4.11 + '@vue/language-core': 2.2.0(typescript@5.7.3) + compare-versions: 6.1.1 + debug: 4.4.0 kolorist: 1.8.0 - typescript: 5.1.6 - vite: 4.4.4(@types/node@18.11.9) - vue-tsc: 1.8.5(typescript@5.1.6) + local-pkg: 0.5.1 + magic-string: 0.30.17 + typescript: 5.7.3 + vite: 6.0.7(tsx@4.19.4) transitivePeerDependencies: - '@types/node' - rollup - supports-color dev: true - /vite@4.4.4(@types/node@18.11.9): - resolution: {integrity: sha512-4mvsTxjkveWrKDJI70QmelfVqTm+ihFAb6+xf4sjEU2TmUCTlVX87tmg/QooPEMQb/lM9qGHT99ebqPziEd3wg==} - engines: {node: ^14.18.0 || >=16.0.0} + /vite-plugin-dts@4.5.3(@types/node@20.11.26)(typescript@5.8.3)(vite@6.3.5): + resolution: {integrity: sha512-P64VnD00dR+e8S26ESoFELqc17+w7pKkwlBpgXteOljFyT0zDwD8hH4zXp49M/kciy//7ZbVXIwQCekBJjfWzA==} + peerDependencies: + typescript: '*' + vite: '*' + peerDependenciesMeta: + vite: + optional: true + dependencies: + '@microsoft/api-extractor': 7.52.1(@types/node@20.11.26) + '@rollup/pluginutils': 5.1.4 + '@volar/typescript': 2.4.11 + '@vue/language-core': 2.2.0(typescript@5.8.3) + compare-versions: 6.1.1 + debug: 4.4.0 + kolorist: 1.8.0 + local-pkg: 1.1.1 + magic-string: 0.30.17 + typescript: 5.8.3 + vite: 6.3.5(@types/node@20.11.26)(tsx@4.19.4) + transitivePeerDependencies: + - '@types/node' + - rollup + - supports-color + dev: true + + /vite@5.1.6: + resolution: {integrity: sha512-yYIAZs9nVfRJ/AiOLCA91zzhjsHUgMjB+EigzFb6W2XTLO8JixBCKCjvhKZaye+NKYHCrkv3Oh50dH9EdLU2RA==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || >=20.0.0 + less: '*' + lightningcss: ^1.21.0 + sass: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + dependencies: + esbuild: 0.19.12 + postcss: 8.5.3 + rollup: 4.9.6 + optionalDependencies: + fsevents: 2.3.3 + dev: true + + /vite@5.1.6(@types/node@20.11.26): + resolution: {integrity: sha512-yYIAZs9nVfRJ/AiOLCA91zzhjsHUgMjB+EigzFb6W2XTLO8JixBCKCjvhKZaye+NKYHCrkv3Oh50dH9EdLU2RA==} + engines: {node: ^18.0.0 || >=20.0.0} hasBin: true peerDependencies: - '@types/node': '>= 14' + '@types/node': ^18.0.0 || >=20.0.0 less: '*' lightningcss: ^1.21.0 sass: '*' @@ -6025,30 +7914,130 @@ packages: terser: optional: true dependencies: - '@types/node': 18.11.9 - esbuild: 0.18.13 - postcss: 8.4.26 - rollup: 3.26.2 + '@types/node': 20.11.26 + esbuild: 0.19.12 + postcss: 8.4.35 + rollup: 4.9.6 + optionalDependencies: + fsevents: 2.3.3 + dev: true + + /vite@6.0.7(tsx@4.19.4): + resolution: {integrity: sha512-RDt8r/7qx9940f8FcOIAH9PTViRrghKaK2K1jY3RaAURrEUbm9Du1mJ72G+jlhtG3WwodnfzY8ORQZbBavZEAQ==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 + jiti: '>=1.21.0' + less: '*' + lightningcss: ^1.21.0 + sass: '*' + sass-embedded: '*' + stylus: '*' + sugarss: '*' + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + dependencies: + esbuild: 0.24.2 + postcss: 8.4.49 + rollup: 4.30.1 + tsx: 4.19.4 + optionalDependencies: + fsevents: 2.3.3 + dev: true + + /vite@6.3.5(@types/node@20.11.26)(tsx@4.19.4): + resolution: {integrity: sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 + jiti: '>=1.21.0' + less: '*' + lightningcss: ^1.21.0 + sass: '*' + sass-embedded: '*' + stylus: '*' + sugarss: '*' + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + dependencies: + '@types/node': 20.11.26 + esbuild: 0.25.1 + fdir: 6.4.4(picomatch@4.0.2) + picomatch: 4.0.2 + postcss: 8.5.3 + rollup: 4.40.1 + tinyglobby: 0.2.13 + tsx: 4.19.4 optionalDependencies: - fsevents: 2.3.2 + fsevents: 2.3.3 dev: true - /vitest@0.33.0(jsdom@22.1.0): - resolution: {integrity: sha512-1CxaugJ50xskkQ0e969R/hW47za4YXDUfWJDxip1hwbnhUjYolpfUn2AMOulqG/Dtd9WYAtkHmM/m3yKVrEejQ==} - engines: {node: '>=v14.18.0'} + /vitest@2.1.8(jsdom@26.0.0): + resolution: {integrity: sha512-1vBKTZskHw/aosXqQUlVWWlGUxSJR8YtiyZDJAFeW2kPAeX6S3Sool0mjspO+kXLuxVWlEDDowBAeqeAQefqLQ==} + engines: {node: ^18.0.0 || >=20.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' - '@vitest/browser': '*' - '@vitest/ui': '*' + '@types/node': ^18.0.0 || >=20.0.0 + '@vitest/browser': 2.1.8 + '@vitest/ui': 2.1.8 happy-dom: '*' jsdom: '*' - playwright: '*' - safaridriver: '*' - webdriverio: '*' peerDependenciesMeta: '@edge-runtime/vm': optional: true + '@types/node': + optional: true '@vitest/browser': optional: true '@vitest/ui': @@ -6057,41 +8046,32 @@ packages: optional: true jsdom: optional: true - playwright: - optional: true - safaridriver: - optional: true - webdriverio: - optional: true dependencies: - '@types/chai': 4.3.5 - '@types/chai-subset': 1.3.3 - '@types/node': 18.11.9 - '@vitest/expect': 0.33.0 - '@vitest/runner': 0.33.0 - '@vitest/snapshot': 0.33.0 - '@vitest/spy': 0.33.0 - '@vitest/utils': 0.33.0 - acorn: 8.10.0 - acorn-walk: 8.2.0 - cac: 6.7.14 - chai: 4.3.7 - debug: 4.3.4 - jsdom: 22.1.0 - local-pkg: 0.4.3 - magic-string: 0.30.1 - pathe: 1.1.1 - picocolors: 1.0.0 - std-env: 3.3.3 - strip-literal: 1.0.1 - tinybench: 2.5.0 - tinypool: 0.6.0 - vite: 4.4.4(@types/node@18.11.9) - vite-node: 0.33.0(@types/node@18.11.9) - why-is-node-running: 2.2.2 + '@vitest/expect': 2.1.8 + '@vitest/mocker': 2.1.8(vite@5.1.6) + '@vitest/pretty-format': 2.1.8 + '@vitest/runner': 2.1.8 + '@vitest/snapshot': 2.1.8 + '@vitest/spy': 2.1.8 + '@vitest/utils': 2.1.8 + chai: 5.1.2 + debug: 4.4.0 + expect-type: 1.1.0 + jsdom: 26.0.0 + magic-string: 0.30.17 + pathe: 1.1.2 + std-env: 3.8.0 + tinybench: 2.9.0 + tinyexec: 0.3.2 + tinypool: 1.0.1 + tinyrainbow: 1.2.0 + vite: 5.1.6 + vite-node: 2.1.8 + why-is-node-running: 2.3.0 transitivePeerDependencies: - less - lightningcss + - msw - sass - stylus - sugarss @@ -6099,121 +8079,182 @@ packages: - terser dev: true - /vue-template-compiler@2.7.14: - resolution: {integrity: sha512-zyA5Y3ArvVG0NacJDkkzJuPQDF8RFeRlzV2vLeSnhSpieO6LK2OVbdLPi5MPPs09Ii+gMO8nY4S3iKQxBxDmWQ==} - dependencies: - de-indent: 1.0.2 - he: 1.2.0 - dev: true - - /vue-tsc@1.8.5(typescript@5.1.6): - resolution: {integrity: sha512-Jr8PTghJIwp69MFsEZoADDcv2l+lXA8juyN/5AYA5zxyZNvIHjSbgKgkYIYc1qnihrOyIG1VOnfk4ZE0jqn8bw==} + /vitest@3.1.3(@types/node@20.11.26)(jsdom@26.1.0)(msw@2.7.6)(tsx@4.19.4): + resolution: {integrity: sha512-188iM4hAHQ0km23TN/adso1q5hhwKqUpv+Sd6p5sOuh6FhQnRNW3IsiIpvxqahtBabsJ2SLZgmGSpcYK4wQYJw==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true peerDependencies: - typescript: '*' - dependencies: - '@vue/language-core': 1.8.5(typescript@5.1.6) - '@vue/typescript': 1.8.5(typescript@5.1.6) - semver: 7.5.4 - typescript: 5.1.6 - dev: true - - /w3c-xmlserializer@4.0.0: - resolution: {integrity: sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==} - engines: {node: '>=14'} + '@edge-runtime/vm': '*' + '@types/debug': ^4.1.12 + '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 + '@vitest/browser': 3.1.3 + '@vitest/ui': 3.1.3 + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@types/debug': + optional: true + '@types/node': + optional: true + '@vitest/browser': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true dependencies: - xml-name-validator: 4.0.0 + '@types/node': 20.11.26 + '@vitest/expect': 3.1.3 + '@vitest/mocker': 3.1.3(msw@2.7.6)(vite@6.3.5) + '@vitest/pretty-format': 3.1.3 + '@vitest/runner': 3.1.3 + '@vitest/snapshot': 3.1.3 + '@vitest/spy': 3.1.3 + '@vitest/utils': 3.1.3 + chai: 5.2.0 + debug: 4.4.0 + expect-type: 1.2.1 + jsdom: 26.1.0 + magic-string: 0.30.17 + pathe: 2.0.3 + std-env: 3.9.0 + tinybench: 2.9.0 + tinyexec: 0.3.2 + tinyglobby: 0.2.13 + tinypool: 1.0.2 + tinyrainbow: 2.0.0 + vite: 6.3.5(@types/node@20.11.26)(tsx@4.19.4) + vite-node: 3.1.3(@types/node@20.11.26)(tsx@4.19.4) + why-is-node-running: 2.3.0 + transitivePeerDependencies: + - jiti + - less + - lightningcss + - msw + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - yaml dev: true - /watchpack@2.4.0: - resolution: {integrity: sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==} - engines: {node: '>=10.13.0'} - dependencies: - glob-to-regexp: 0.4.1 - graceful-fs: 4.2.11 - dev: false - - /wcwidth@1.0.1: - resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} - dependencies: - defaults: 1.0.4 + /vscode-uri@3.0.8: + resolution: {integrity: sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==} dev: true - /web-encoding@1.1.5: - resolution: {integrity: sha512-HYLeVCdJ0+lBYV2FvNZmv3HJ2Nt0QYXqZojk3d9FJOLkwnuhzM9tmamh8d7HPM8QqjKH8DeHkFTx+CFlWpZZDA==} + /w3c-xmlserializer@5.0.0: + resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} + engines: {node: '>=18'} dependencies: - util: 0.12.5 - optionalDependencies: - '@zxing/text-encoding': 0.9.0 + xml-name-validator: 5.0.0 dev: true - /web-vitals@3.4.0: - resolution: {integrity: sha512-n9fZ5/bG1oeDkyxLWyep0eahrNcPDF6bFqoyispt7xkW0xhDzpUBTgyDKqWDi1twT0MgH4HvvqzpUyh0ZxZV4A==} + /web-vitals@4.2.4: + resolution: {integrity: sha512-r4DIlprAGwJ7YM11VZp4R884m0Vmgr6EAKe3P+kO0PPj3Unqyvv59rczf6UiGcb9Z8QxZVcqKNwv/g0WNdWwsw==} dev: false - /webidl-conversions@3.0.1: - resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} - dev: true - /webidl-conversions@7.0.0: resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} engines: {node: '>=12'} dev: true - /whatwg-encoding@2.0.0: - resolution: {integrity: sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==} - engines: {node: '>=12'} + /whatwg-encoding@3.1.1: + resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} + engines: {node: '>=18'} dependencies: iconv-lite: 0.6.3 dev: true - /whatwg-mimetype@3.0.0: - resolution: {integrity: sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==} - engines: {node: '>=12'} + /whatwg-mimetype@4.0.0: + resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} + engines: {node: '>=18'} dev: true - /whatwg-url@12.0.1: - resolution: {integrity: sha512-Ed/LrqB8EPlGxjS+TrsXcpUond1mhccS3pchLhzSgPCnTimUCKj3IZE75pAs5m6heB2U2TMerKFUXheyHY+VDQ==} - engines: {node: '>=14'} + /whatwg-url@14.1.0: + resolution: {integrity: sha512-jlf/foYIKywAt3x/XWKZ/3rz8OSJPiWktjmk891alJUEjiVxKX9LEO92qH3hv4aJ0mN3MWPvGMCy8jQi95xK4w==} + engines: {node: '>=18'} dependencies: - tr46: 4.1.1 + tr46: 5.0.0 webidl-conversions: 7.0.0 dev: true - /whatwg-url@5.0.0: - resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + /whatwg-url@14.2.0: + resolution: {integrity: sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==} + engines: {node: '>=18'} dependencies: - tr46: 0.0.3 - webidl-conversions: 3.0.1 + tr46: 5.1.0 + webidl-conversions: 7.0.0 dev: true - /which-boxed-primitive@1.0.2: - resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} + /which-boxed-primitive@1.1.1: + resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==} + engines: {node: '>= 0.4'} dependencies: - is-bigint: 1.0.4 - is-boolean-object: 1.1.2 - is-number-object: 1.0.7 - is-string: 1.0.7 - is-symbol: 1.0.4 + is-bigint: 1.1.0 + is-boolean-object: 1.2.1 + is-number-object: 1.1.1 + is-string: 1.1.1 + is-symbol: 1.1.1 + dev: true + + /which-builtin-type@1.2.1: + resolution: {integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.3 + function.prototype.name: 1.1.8 + has-tostringtag: 1.0.2 + is-async-function: 2.0.0 + is-date-object: 1.1.0 + is-finalizationregistry: 1.1.1 + is-generator-function: 1.0.10 + is-regex: 1.2.1 + is-weakref: 1.1.0 + isarray: 2.0.5 + which-boxed-primitive: 1.1.1 + which-collection: 1.0.2 + which-typed-array: 1.1.18 + dev: true + + /which-collection@1.0.2: + resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} + engines: {node: '>= 0.4'} + dependencies: + is-map: 2.0.3 + is-set: 2.0.3 + is-weakmap: 2.0.2 + is-weakset: 2.0.3 + dev: true - /which-collection@1.0.1: - resolution: {integrity: sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==} + /which-typed-array@1.1.15: + resolution: {integrity: sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==} + engines: {node: '>= 0.4'} dependencies: - is-map: 2.0.2 - is-set: 2.0.2 - is-weakmap: 2.0.1 - is-weakset: 2.0.2 + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + for-each: 0.3.3 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + dev: true - /which-typed-array@1.1.10: - resolution: {integrity: sha512-uxoA5vLUfRPdjCuJ1h5LlYdmTLbYfums398v3WLkM+i/Wltl2/XyZpQWKbN++ck5L64SR/grOHqtXCUKmlZPNA==} + /which-typed-array@1.1.18: + resolution: {integrity: sha512-qEcY+KJYlWyLH9vNbsr6/5j59AXk5ni5aakf8ldzBvGde6Iz4sxZGkJyWSAueTG7QhOvNRYb1lDdFmL5Td0QKA==} engines: {node: '>= 0.4'} dependencies: - available-typed-arrays: 1.0.5 - call-bind: 1.0.2 + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.3 for-each: 0.3.3 - gopd: 1.0.1 - has-tostringtag: 1.0.0 - is-typed-array: 1.1.10 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + dev: true /which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} @@ -6223,8 +8264,8 @@ packages: isexe: 2.0.0 dev: true - /why-is-node-running@2.2.2: - resolution: {integrity: sha512-6tSwToZxTOcotxHeA+qGCq1mVzKR3CwcJGmVcY+QE8SHy6TnpFnh8PAvPNHYr7EcuVeG0QSMxtYCuO1ta/G/oA==} + /why-is-node-running@2.3.0: + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} engines: {node: '>=8'} hasBin: true dependencies: @@ -6232,6 +8273,15 @@ packages: stackback: 0.0.2 dev: true + /wrap-ansi@6.2.0: + resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} + engines: {node: '>=8'} + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + dev: true + /wrap-ansi@7.0.0: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} @@ -6254,8 +8304,8 @@ packages: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} dev: true - /ws@8.13.0: - resolution: {integrity: sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==} + /ws@8.18.0: + resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} engines: {node: '>=10.0.0'} peerDependencies: bufferutil: ^4.0.1 @@ -6267,9 +8317,9 @@ packages: optional: true dev: true - /xml-name-validator@4.0.0: - resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==} - engines: {node: '>=12'} + /xml-name-validator@5.0.0: + resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==} + engines: {node: '>=18'} dev: true /xmlchars@2.2.0: @@ -6309,7 +8359,7 @@ packages: engines: {node: '>=10'} dependencies: cliui: 7.0.4 - escalade: 3.1.1 + escalade: 3.2.0 get-caller-file: 2.0.5 require-directory: 2.1.1 string-width: 4.2.3 @@ -6322,7 +8372,7 @@ packages: engines: {node: '>=12'} dependencies: cliui: 8.0.1 - escalade: 3.1.1 + escalade: 3.2.0 get-caller-file: 2.0.5 require-directory: 2.1.1 string-width: 4.2.3 @@ -6335,23 +8385,19 @@ packages: engines: {node: '>=10'} dev: true - /yocto-queue@1.0.0: - resolution: {integrity: sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==} - engines: {node: '>=12.20'} + /yoctocolors-cjs@2.1.2: + resolution: {integrity: sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA==} + engines: {node: '>=18'} dev: true - /z-schema@5.0.5: - resolution: {integrity: sha512-D7eujBWkLa3p2sIpJA0d1pr7es+a7m0vFAnZLlCEKq/Ij2k0MLi9Br2UPxoxdYystm5K1yeBGzub0FlYUEWj2Q==} - engines: {node: '>=8.0.0'} - hasBin: true + /zod-to-json-schema@3.24.5(zod@3.24.4): + resolution: {integrity: sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g==} + peerDependencies: + zod: ^3.24.1 dependencies: - lodash.get: 4.4.2 - lodash.isequal: 4.5.0 - validator: 13.9.0 - optionalDependencies: - commander: 9.5.0 + zod: 3.24.4 dev: true - /zod@3.21.4: - resolution: {integrity: sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==} - dev: false + /zod@3.24.4: + resolution: {integrity: sha512-OdqJE9UDRPwWsrHjLN2F8bPxvwJBK22EHLWtanu0LSYr5YqzsaaW3RMgmjwr8Rypg5k+meEJdSPXJZXE/yqOMg==} + dev: true diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index ed54ecd09..15989339b 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,3 +1,3 @@ packages: - 'packages/*' - - 'examples/*' \ No newline at end of file + - 'examples/*' diff --git a/readme.md b/readme.md deleted file mode 100644 index fc9af3e02..000000000 --- a/readme.md +++ /dev/null @@ -1,342 +0,0 @@ -# @axa-fr/react-oidc - -[![Continuous Integration](https://github.com/AxaGuilDEv/react-oidc/actions/workflows/npm-publish.yml/badge.svg)](https://github.com/AxaGuilDEv/react-oidc/actions/workflows/npm-publish.yml) -[![Quality Gate](https://sonarcloud.io/api/project_badges/measure?project=AxaGuilDEv_react-oidc&metric=alert_status)](https://sonarcloud.io/dashboard?id=AxaGuilDEv_react-oidc) [![Reliability](https://sonarcloud.io/api/project_badges/measure?project=AxaGuilDEv_react-oidc&metric=reliability_rating)](https://sonarcloud.io/component_measures?id=AxaGuilDEv_react-oidc&metric=reliability_rating) [![Security](https://sonarcloud.io/api/project_badges/measure?project=AxaGuilDEv_react-oidc&metric=security_rating)](https://sonarcloud.io/component_measures?id=AxaGuilDEv_react-oidc&metric=security_rating) [![Code Coverage](https://sonarcloud.io/api/project_badges/measure?project=AxaGuilDEv_react-oidc&metric=coverage)](https://sonarcloud.io/component_measures?id=AxaGuilDEv_react-oidc&metric=Coverage) [![Twitter](https://img.shields.io/twitter/follow/GuildDEvOpen?style=social)](https://twitter.com/intent/follow?screen_name=GuildDEvOpen) - -- Try the demo react at https://black-rock-0dc6b0d03.1.azurestaticapps.net/ -- Try the demo vanilla at https://icy-glacier-004ab4303.2.azurestaticapps.net/ - -

- Sample React Oicd -

- -A set of react components to make Oidc (OpenID Connect) client easy. It aim to simplify OAuth authentication between multiples providers. It is compatible with NextJS. - -- [About](#about) -- [Getting Started](#getting-started) -- [Run The Demo](#run-the-demo) -- [Run The NextJS Demo](#run-the-nextjs-demo) -- [How It Works](#how-it-works) -- Packages - - [`@axa-fr/react-oidc`](./packages/react#readme.md) [![npm version](https://badge.fury.io/js/%40axa-fr%2Freact-oidc.svg)](https://badge.fury.io/js/%40axa-fr%2Freact-oidc) - - [`@axa-fr/vanilla-oidc`](./packages/vanilla#readme.md) [![npm version](https://badge.fury.io/js/%40axa-fr%2Fvanilla-oidc.svg)](https://badge.fury.io/js/%40axa-fr%2Fvanilla-oidc) - - [`@axa-fr/react-oidc-context`](./packages/context#readme.md) [![npm version](https://badge.fury.io/js/%40axa-fr%2Freact-oidc-context.svg)](https://badge.fury.io/js/%40axa-fr%2Freact-oidc-context) **Will be deprecated in v6: has been renamed to @axa-fr/react-oidc** - - [`@axa-fr/react-oidc-context-fetch`](./packages/context-fetch#readme.md) [![npm version](https://badge.fury.io/js/%40axa-fr%2Freact-oidc-context-fetch.svg)](https://badge.fury.io/js/%40axa-fr%2Freact-oidc-context-fetch) **Deprecated in v4** - - [`@axa-fr/react-oidc-redux`](./packages/redux#readme.md) [![npm version](https://badge.fury.io/js/%40axa-fr%2Freact-oidc-redux.svg)](https://badge.fury.io/js/%40axa-fr%2Freact-oidc-redux) **Deprecated in v4 : use react-oidc-context which works with redux and in fact does not use any react context** - - [`@axa-fr/react-oidc-redux-fetch`](./packages/redux-fetch#readme.md) [![npm version](https://badge.fury.io/js/%40axa-fr%2Freact-oidc-redux-fetch.svg)](https://badge.fury.io/js/%40axa-fr%2Freact-oidc-redux-fetch) **Deprecated in v4** - - [`@axa-fr/react-oidc-fetch-observable`](./packages/fetch-observable#readme.md) [![npm version](https://badge.fury.io/js/%40axa-fr%2Freact-oidc-fetch-observable.svg)](https://badge.fury.io/js/%40axa-fr%2Freact-oidc-fetch-observable) **Deprecated in v4** -- [Migrations](#migrations) -- [Contribute](#contribute) - -## About - -These libraries is used to manage client authentication. - -- **Secure** : - - With the use of Service Worker, your tokens (refresh_token and access_token) are not accessible to the JavaScript client code (big protection against XSRF attacks) - - OIDC using client side Code Credential Grant with pkce only -- **Lightweight** -- **Simple** - - refresh_token and access_token are auto refreshed in background - - with the use of the Service Worker, you do not need to inject the access_token in every fetch, you have only to configure OidcTrustedDomains.js file -- **No cookies problem** : You can disable silent signin (that internally use an iFrame). For your information, your OIDC server should be in the same domain of your website in order to be able to send OIDC server cookies from your website via an internal IFRAME, else, you may encounter COOKIES problem. -- **Multiple Authentication** : - - You can authenticate many times to the same provider with different scope (for example you can acquire a new 'payment' scope for a payment) - - You can authenticate to multiple different providers inside the same SPA (single page application) website -- **Flexible** : - - Work with Service Worker (more secure) and without for older browser (less secure) - -

- Schema Authorization Code Grant with pcke flow on the using service worker -
- The service worker catch access_token and refresh_token that will never be accessible to the client. -

- -Works perfectly well with: - -- [Auth0](https://auth0.com/) -- [Duende Identity Server](https://duendesoftware.com/) -- Google -- AWS -- [Keycloak](https://www.keycloak.org/) -- all OIDC compatible providers - -

- @axa-fr/react-oidc is one of the securest way to Authenticate. -
- @axa-fr/react-oidc is one of the securest way to Authenticate. -

- -

- Service Worker lifetime drawback. -
- Service Worker lifetime drawback. -

- -

- Silent-Signing constraints. -
- Silent-Signing constraints. -

- -

- @axa-fr/react-oidc is the simplest and cheapest. -
- @axa-fr/react-oidc is the simplest and cheapest. -

- -## Getting Started - -### Getting Started React using create-react-app - -```sh -npm install @axa-fr/react-oidc --save - -# If you have a "public" folder, the 2 files will be created : -# ./public/OidcServiceWorker.js <-- will be updated at each "npm install" -# ./public/OidcTrustedDomains.js <-- won't be updated if already exist -``` - -If you require a very secure mode where `refresh_token` and `access_token` will be hidden behind a service worker that will proxify requests. -The only file you should edit is `OidcTrustedDomains.js`. - -```javascript -import React from 'react'; -import { render } from 'react-dom'; -import { BrowserRouter as Router } from 'react-router-dom'; -import { OidcProvider } from '@axa-fr/react-oidc'; -import Header from './Layout/Header'; -import Routes from './Router'; - -// This configuration use the ServiceWorker mode only -// "access_token" will be provided automaticaly to the urls and domains configured inside "OidcTrustedDomains.js" -const configuration = { - client_id: 'interactive.public.short', - redirect_uri: window.location.origin + '/authentication/callback', - silent_redirect_uri: window.location.origin + '/authentication/silent-callback', // Optional activate silent-signin that use cookies between OIDC server and client javascript to restore the session - scope: 'openid profile email api offline_access', - authority: 'https://demo.duendesoftware.com', - service_worker_relative_url:'/OidcServiceWorker.js', - service_worker_only:true, -}; - -const App = () => ( - - -
- - - -); - -render(, document.getElementById('root')); -``` - -#### Trusted Domains - -Any domain that has a match in the `OidcTrustedDomains.js` will have the access token automatically injected on requests. - -The `OidcTrustedDomains.js` format is key (`default` being the default key) that has an array of string URLs or RegExp to match trusted domain URLs. - -> **Warning** -> You could use a wildcard for the value, by either providing the wildcard string value `'*'` or a RegExp such as `RegExp('^http.*')` , but you are reducing the security of your application by doing so and it is strongly discouraged. - -```javascript -// OidcTrustedDomains.js - -// Add below trusted domains, access tokens will automatically injected to be send to -// trusted domain can also be a path like https://www.myapi.com/users, -// then all subroute like https://www.myapi.com/useers/1 will be authorized to send access_token to. - -// Domains used by OIDC server must be also declared here -const trustedDomains = { - default:[ - "https://demo.duendesoftware.com", - "https://www.myapi.com/users", - new RegExp('^(https://[a-zA-Z0-9-]+.domain.com/api/)')] -}; - -// Service worker will continue to give access token to the JavaScript client -// Ideal to hide refresh token from client JavaScript, but to retrieve access_token for some -// scenarios which require it. For example, to send it via websocket connection. -trustedDomains.config_show_access_token = { domains : ["https://demo.duendesoftware.com"], showAccessToken: true }; - -// This example defines domains used by OIDC server separately from domains to which access tokens will be injected. -trustedDomains.config_separate_oidc_access_token_domains = { - oidcDomains: ["https://demo.duendesoftware.com"], - accessTokenDomains: ["https://myapi"] -}; - -``` - -#### How to consume - -`useOidc` returns all props from the Hook : - -```javascript -import React from 'react'; -import {useOidc} from "./oidc"; - -export const Home = () => { - - const { login, logout, isAuthenticated} = useOidc(); - - return ( -
-
-
-
Welcome!
-

React Demo Application protected by OpenID Connect

- {!isAuthenticated && - } - {isAuthenticated && - } -
-
-
- ) -}; - -``` - -The Hook method exposes : - -- isAuthenticated : if the user is logged in or not -- logout: logout function (return a promise) -- login: login function 'return a promise' - -"OidcSecure" component trigger authentication in case user is not authenticated. So, the children of that component can be accessible only once you are connected. - -```javascript -import React from 'react'; -import { OidcSecure } from '@axa-fr/react-oidc'; - -const AdminSecure = () => ( - -

My sub component

-
-); - -export default AdminSecure; -``` - -How to get IDToken - -```javascript -import { useOidcIdToken } from '@axa-fr/react-oidc'; - -const DisplayIdToken =() => { - const{ idToken, idTokenPayload } = useOidcIdToken(); - - if(!idToken){ - return

you are not authentified

- } - - return ( -
-
-
ID Token
- {

{JSON.stringify(idToken)}

} - {idTokenPayload != null && -

{JSON.stringify(idTokenPayload)}

} -
-
- ); -} -``` - -#### How to get User Information - -```javascript -import {useOidcUser} from '@axa-fr/react-oidc'; - -const DisplayUserInfo = () => { - const {oidcUser, oidcUserLoadingState} = useOidcUser(); - - switch (oidcUserLoadingState) { - case OidcUserStatus.Loading: - return

User Information are loading

; - case OidcUserStatus.Unauthenticated: - return

you are not authenticated

; - case OidcUserStatus.LoadingError: - return

Fail to load user information

; - default: - return ( -
-
-
User information
-

{JSON.stringify(oidcUser)}

-
-
- ); - } -}; -``` - -More documentation : - -- [`@axa-fr/react-oidc`](./packages/react#readme) - -### Getting Started Vanilla - -More documentation : - -- [`@axa-fr/vanilla-oidc`](./packages/vanilla#readme) - -## Run The Demo - -```sh -git clone https://github.com/AxaGuilDEv/react-oidc.git -cd react-oidc/packages/react -pnpm install -pnpm start -# then navigate to http://localhost:4200 -``` - -## Run The NextJS Demo - -```sh -git clone https://github.com/AxaGuilDEv/react-oidc.git -cd react-oidc/packages/nextjs-demo -pnpm install -pnpm run dev -# then navigate to http://localhost:3001 -``` - -## How It Works - -These components encapsulate the use of "`@axa-fr/vanilla-oidc`" in order to hide workflow complexity. -Internally, native History API is used to be router library agnostic. - -More information about OIDC - -- [French : Augmentez la sécurité et la simplicité de votre Système d’Information OpenID Connect](https://medium.com/just-tech-it-now/augmentez-la-s%C3%A9curit%C3%A9-et-la-simplicit%C3%A9-de-votre-syst%C3%A8me-dinformation-avec-oauth-2-0-cf0732d71284) -- [English : Increase the security and simplicity of your information system with OpenID Connect](https://medium.com/just-tech-it-now/increase-the-security-and-simplicity-of-your-information-system-with-openid-connect-fa8c26b99d6d) - -## Migrations - -v4 is a complete rewrite. It uses the libraries ["App-AuthJS"](https://github.com/openid/AppAuth-JS) instead of oidc-client. -In v4 we have chosen to remove a lot of the surface API in order to simplify usage and enforce security. -In this version you can use a ServiceWorker that will hide the `refresh_token` and `access_token` (more secure). - -- Migrating from v3 to v4 [`guide`](./MIGRATION_GUIDE_V3_TO_V4.md) -- Migrating from v3 to v5 [`guide`](./MIGRATION_GUIDE_V3_TO_V5.md) -- Migrating from v4 to v5 [`guide`](./MIGRATION_GUIDE_V4_TO_V5.md) -- Migrating from v5 to v6 [`guide`](./MIGRATION_GUIDE_V5_TO_V6.md) - -## Contribute - -- [How to run the solution and to contribute](./CONTRIBUTING.md) -- [Please respect our code of conduct](./CODE_OF_CONDUCT.md) diff --git a/scripts/publish-changelog.js b/scripts/publish-changelog.js deleted file mode 100644 index bee28d60e..000000000 --- a/scripts/publish-changelog.js +++ /dev/null @@ -1,16 +0,0 @@ -const fs = require('fs-extra'); -const VERSION = require('../packages/react/package.json').version; - -try { - const execSync = require('child_process').execSync; - child = execSync( - `npm run changelog && git add . && git commit -m "docs(changelog) update to new ${VERSION}" && git push` - ); - console.log('error', child.error); - console.log('stdout ', child.stdout); - console.log('stderr ', child.stderr); - - console.log('success!'); -} catch (err) { - console.error(err); -} diff --git a/scripts/twitter.js b/scripts/twitter.js deleted file mode 100644 index d53a261c6..000000000 --- a/scripts/twitter.js +++ /dev/null @@ -1,30 +0,0 @@ -const Twit = require("twit"); // eslint-disable-line - -/* should be ran with "node twitter consumer_key consumer_secret access_token access_token_secret" - in this order -*/ -const argv = process.argv; - -const T = new Twit({ - consumer_key: argv[2], - consumer_secret: argv[3], - access_token: argv[4], - access_token_secret: argv[5], - timeout_ms: 60 * 1000, - strictSSL: true -}); - -const json = require("../packages/context/package.json"); - -const message = `Hey a new version (${ - json.version -}) of the @axa-fr/react-oidc is available on @github and @npm! -check out the new changelog https://github.com/AxaGuilDEv/react-oidc/blob/master/CHANGELOG.md`; - -T.post("statuses/update", { status: message }, err => { - if (!err) { - console.log("Greate job"); // eslint-disable-line - } else { - console.error(err); - } -}); diff --git a/tsconfig.base.json b/tsconfig.base.json new file mode 100644 index 000000000..f8cc4cd65 --- /dev/null +++ b/tsconfig.base.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "declaration": true, + "emitDeclarationOnly": true, + "strict": true, + "allowJs": true, + "noEmit": true, + "moduleResolution": "node", + "esModuleInterop": true, + "skipLibCheck": true, + "verbatimModuleSyntax": true + } +} diff --git a/tsconfig.eslint.json b/tsconfig.eslint.json new file mode 100644 index 000000000..ffcbb9477 --- /dev/null +++ b/tsconfig.eslint.json @@ -0,0 +1,3 @@ +{ + "extends": "./tsconfig.base.json" +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 000000000..7704e13bc --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,5 @@ +// Yes this file is intentionally empty! +// --- +// Having a blank `tsconfig.json` file prevents TypeScript from crawling up your directory tree +// and possibly picking up a parent `tsconfig.json` (which, unsurprisingly, is very hard to debug) +{}